forked from cerc-io/plugeth
Merge branch 'develop' into jsonrpc
This commit is contained in:
commit
7a894e3738
@ -46,7 +46,7 @@ Go Ethereum comes with several binaries found in
|
||||
* `mist` Official Ethereum Browser
|
||||
* `ethereum` Ethereum CLI
|
||||
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suit:
|
||||
`ethtest "`cat myfile.json`"`.
|
||||
`cat file | ethtest`.
|
||||
* `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
|
||||
10000 -price 0 -dump`. See `-h` for a detailed description.
|
||||
|
||||
|
@ -9,15 +9,16 @@ import Ethereum 1.0
|
||||
|
||||
Rectangle {
|
||||
id: window
|
||||
objectName: "browserView"
|
||||
anchors.fill: parent
|
||||
color: "#00000000"
|
||||
anchors.fill: parent
|
||||
color: "#00000000"
|
||||
|
||||
property var title: "Browser"
|
||||
property var title: "DApps"
|
||||
property var iconSource: "../browser.png"
|
||||
property var menuItem
|
||||
property var hideUrl: true
|
||||
|
||||
property alias url: webview.url
|
||||
property alias windowTitle: webview.title
|
||||
property alias webView: webview
|
||||
|
||||
property var cleanPath: false
|
||||
@ -66,8 +67,7 @@ Rectangle {
|
||||
webview.url = "http://etherian.io"
|
||||
}
|
||||
|
||||
signal messages(var messages, int id);
|
||||
onMessages: {
|
||||
function messages(messages, id) {
|
||||
// Bit of a cheat to get proper JSON
|
||||
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
|
||||
webview.postEvent("eth_changed", id, m);
|
||||
@ -139,315 +139,310 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// Border
|
||||
Rectangle {
|
||||
id: divider
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: navBar.bottom
|
||||
}
|
||||
z: -1
|
||||
height: 1
|
||||
color: "#CCCCCC"
|
||||
}
|
||||
// Border
|
||||
Rectangle {
|
||||
id: divider
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: navBar.bottom
|
||||
}
|
||||
z: -1
|
||||
height: 1
|
||||
color: "#CCCCCC"
|
||||
}
|
||||
|
||||
WebView {
|
||||
objectName: "webView"
|
||||
id: webview
|
||||
ScrollView {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
top: divider.bottom
|
||||
}
|
||||
|
||||
function injectJs(js) {
|
||||
webview.experimental.navigatorQtObjectEnabled = true;
|
||||
webview.experimental.evaluateJavaScript(js)
|
||||
webview.experimental.javascriptEnabled = true;
|
||||
}
|
||||
|
||||
function sendMessage(data) {
|
||||
webview.experimental.postMessage(JSON.stringify(data))
|
||||
}
|
||||
|
||||
|
||||
experimental.preferences.javascriptEnabled: true
|
||||
experimental.preferences.webGLEnabled: true
|
||||
experimental.itemSelector: MouseArea {
|
||||
// To avoid conflicting with ListView.model when inside Initiator context.
|
||||
property QtObject selectorModel: model
|
||||
WebView {
|
||||
objectName: "webView"
|
||||
id: webview
|
||||
anchors.fill: parent
|
||||
onClicked: selectorModel.reject()
|
||||
|
||||
Menu {
|
||||
visible: true
|
||||
id: itemSelector
|
||||
function sendMessage(data) {
|
||||
webview.experimental.postMessage(JSON.stringify(data))
|
||||
}
|
||||
|
||||
Instantiator {
|
||||
model: selectorModel.items
|
||||
delegate: MenuItem {
|
||||
text: model.text
|
||||
onTriggered: {
|
||||
selectorModel.accept(index)
|
||||
experimental.preferences.javascriptEnabled: true
|
||||
experimental.preferences.webAudioEnabled: true
|
||||
experimental.preferences.pluginsEnabled: true
|
||||
experimental.preferences.navigatorQtObjectEnabled: true
|
||||
experimental.preferences.developerExtrasEnabled: true
|
||||
experimental.preferences.webGLEnabled: true
|
||||
experimental.preferences.notificationsEnabled: true
|
||||
experimental.preferences.localStorageEnabled: true
|
||||
experimental.userAgent:"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Mist/0.1 Safari/537.36"
|
||||
|
||||
experimental.itemSelector: MouseArea {
|
||||
// To avoid conflicting with ListView.model when inside Initiator context.
|
||||
property QtObject selectorModel: model
|
||||
anchors.fill: parent
|
||||
onClicked: selectorModel.reject()
|
||||
|
||||
Menu {
|
||||
visible: true
|
||||
id: itemSelector
|
||||
|
||||
Instantiator {
|
||||
model: selectorModel.items
|
||||
delegate: MenuItem {
|
||||
text: model.text
|
||||
onTriggered: {
|
||||
selectorModel.accept(index)
|
||||
}
|
||||
}
|
||||
onObjectAdded: itemSelector.insertItem(index, object)
|
||||
onObjectRemoved: itemSelector.removeItem(object)
|
||||
}
|
||||
onObjectAdded: itemSelector.insertItem(index, object)
|
||||
onObjectRemoved: itemSelector.removeItem(object)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
itemSelector.popup()
|
||||
}
|
||||
}
|
||||
experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
|
||||
experimental.onMessageReceived: {
|
||||
//console.log("[onMessageReceived]: ", message.data)
|
||||
var data = JSON.parse(message.data)
|
||||
|
||||
try {
|
||||
switch(data.call) {
|
||||
case "eth_compile":
|
||||
postData(data._id, eth.compile(data.args[0]))
|
||||
break
|
||||
|
||||
case "eth_coinbase":
|
||||
postData(data._id, eth.coinBase())
|
||||
|
||||
case "eth_account":
|
||||
postData(data._id, eth.key().address);
|
||||
|
||||
case "eth_istening":
|
||||
postData(data._id, eth.isListening())
|
||||
|
||||
break
|
||||
|
||||
case "eth_mining":
|
||||
postData(data._id, eth.isMining())
|
||||
|
||||
break
|
||||
|
||||
case "eth_peerCount":
|
||||
postData(data._id, eth.peerCount())
|
||||
|
||||
break
|
||||
|
||||
case "eth_countAt":
|
||||
require(1)
|
||||
postData(data._id, eth.txCountAt(data.args[0]))
|
||||
|
||||
break
|
||||
|
||||
case "eth_codeAt":
|
||||
require(1)
|
||||
var code = eth.codeAt(data.args[0])
|
||||
postData(data._id, code);
|
||||
|
||||
break
|
||||
|
||||
case "eth_blockByNumber":
|
||||
require(1)
|
||||
var block = eth.blockByNumber(data.args[0])
|
||||
postData(data._id, block)
|
||||
break
|
||||
|
||||
case "eth_blockByHash":
|
||||
require(1)
|
||||
var block = eth.blockByHash(data.args[0])
|
||||
postData(data._id, block)
|
||||
break
|
||||
|
||||
require(2)
|
||||
var block = eth.blockByHash(data.args[0])
|
||||
postData(data._id, block.transactions[data.args[1]])
|
||||
break
|
||||
|
||||
case "eth_transactionByHash":
|
||||
case "eth_transactionByNumber":
|
||||
require(2)
|
||||
|
||||
var block;
|
||||
if (data.call === "transactionByHash")
|
||||
block = eth.blockByHash(data.args[0])
|
||||
else
|
||||
block = eth.blockByNumber(data.args[0])
|
||||
|
||||
var tx = block.transactions.get(data.args[1])
|
||||
|
||||
postData(data._id, tx)
|
||||
break
|
||||
|
||||
case "eth_uncleByHash":
|
||||
case "eth_uncleByNumber":
|
||||
require(2)
|
||||
|
||||
var block;
|
||||
if (data.call === "uncleByHash")
|
||||
block = eth.blockByHash(data.args[0])
|
||||
else
|
||||
block = eth.blockByNumber(data.args[0])
|
||||
|
||||
var uncle = block.uncles.get(data.args[1])
|
||||
|
||||
postData(data._id, uncle)
|
||||
|
||||
break
|
||||
|
||||
case "transact":
|
||||
require(5)
|
||||
|
||||
var tx = eth.transact(data.args)
|
||||
postData(data._id, tx)
|
||||
|
||||
break
|
||||
|
||||
case "eth_stateAt":
|
||||
require(2);
|
||||
|
||||
var storage = eth.storageAt(data.args[0], data.args[1]);
|
||||
postData(data._id, storage)
|
||||
|
||||
break
|
||||
|
||||
case "eth_call":
|
||||
require(1);
|
||||
var ret = eth.call(data.args)
|
||||
postData(data._id, ret)
|
||||
break
|
||||
|
||||
case "eth_balanceAt":
|
||||
require(1);
|
||||
|
||||
postData(data._id, eth.balanceAt(data.args[0]));
|
||||
break
|
||||
|
||||
case "eth_watch":
|
||||
require(2)
|
||||
eth.watch(data.args[0], data.args[1])
|
||||
|
||||
case "eth_disconnect":
|
||||
require(1)
|
||||
postData(data._id, null)
|
||||
break;
|
||||
|
||||
case "eth_newFilterString":
|
||||
require(1)
|
||||
var id = eth.newFilterString(data.args[0], window)
|
||||
postData(data._id, id);
|
||||
break;
|
||||
|
||||
case "eth_newFilter":
|
||||
require(1)
|
||||
var id = eth.newFilter(data.args[0], window)
|
||||
|
||||
postData(data._id, id);
|
||||
break;
|
||||
|
||||
case "eth_filterLogs":
|
||||
require(1);
|
||||
|
||||
var messages = eth.messages(data.args[0]);
|
||||
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
|
||||
postData(data._id, m);
|
||||
|
||||
break;
|
||||
|
||||
case "eth_deleteFilter":
|
||||
require(1);
|
||||
eth.uninstallFilter(data.args[0])
|
||||
break;
|
||||
|
||||
|
||||
case "shh_newFilter":
|
||||
require(1);
|
||||
var id = shh.watch(data.args[0], window);
|
||||
postData(data._id, id);
|
||||
break;
|
||||
|
||||
case "shh_newIdentity":
|
||||
var id = shh.newIdentity()
|
||||
postData(data._id, id)
|
||||
|
||||
break
|
||||
|
||||
case "shh_post":
|
||||
require(1);
|
||||
|
||||
var params = data.args[0];
|
||||
var fields = ["payload", "to", "from"];
|
||||
for(var i = 0; i < fields.length; i++) {
|
||||
params[fields[i]] = params[fields[i]] || "";
|
||||
}
|
||||
if(typeof params.payload !== "object") { params.payload = [params.payload]; } //params.payload = params.payload.join(""); }
|
||||
params.topics = params.topics || [];
|
||||
params.priority = params.priority || 1000;
|
||||
params.ttl = params.ttl || 100;
|
||||
|
||||
shh.post(params.payload, params.to, params.from, params.topics, params.priority, params.ttl);
|
||||
|
||||
break;
|
||||
|
||||
case "shh_getMessages":
|
||||
require(1);
|
||||
|
||||
var m = shh.messages(data.args[0]);
|
||||
var messages = JSON.parse(JSON.parse(JSON.stringify(m)));
|
||||
postData(data._id, messages);
|
||||
|
||||
break;
|
||||
|
||||
case "ssh_newGroup":
|
||||
postData(data._id, "");
|
||||
break;
|
||||
}
|
||||
} catch(e) {
|
||||
console.log(data.call + ": " + e)
|
||||
|
||||
postData(data._id, null);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
itemSelector.popup()
|
||||
function post(seed, data) {
|
||||
postData(data._id, data)
|
||||
}
|
||||
}
|
||||
experimental.preferences.webAudioEnabled: true
|
||||
experimental.preferences.navigatorQtObjectEnabled: true
|
||||
experimental.preferences.developerExtrasEnabled: true
|
||||
experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
|
||||
experimental.onMessageReceived: {
|
||||
console.log("[onMessageReceived]: ", message.data)
|
||||
// TODO move to messaging.js
|
||||
var data = JSON.parse(message.data)
|
||||
|
||||
try {
|
||||
switch(data.call) {
|
||||
case "eth_compile":
|
||||
postData(data._id, eth.compile(data.args[0]))
|
||||
break
|
||||
|
||||
case "eth_coinbase":
|
||||
postData(data._id, eth.coinBase())
|
||||
|
||||
case "eth_account":
|
||||
postData(data._id, eth.key().address);
|
||||
|
||||
case "eth_istening":
|
||||
postData(data._id, eth.isListening())
|
||||
|
||||
break
|
||||
|
||||
case "eth_mining":
|
||||
postData(data._id, eth.isMining())
|
||||
|
||||
break
|
||||
|
||||
case "eth_peerCount":
|
||||
postData(data._id, eth.peerCount())
|
||||
|
||||
break
|
||||
|
||||
case "eth_countAt":
|
||||
require(1)
|
||||
postData(data._id, eth.txCountAt(data.args[0]))
|
||||
|
||||
break
|
||||
|
||||
case "eth_codeAt":
|
||||
require(1)
|
||||
var code = eth.codeAt(data.args[0])
|
||||
postData(data._id, code);
|
||||
|
||||
break
|
||||
|
||||
case "eth_blockByNumber":
|
||||
require(1)
|
||||
var block = eth.blockByNumber(data.args[0])
|
||||
postData(data._id, block)
|
||||
break
|
||||
|
||||
case "eth_blockByHash":
|
||||
require(1)
|
||||
var block = eth.blockByHash(data.args[0])
|
||||
postData(data._id, block)
|
||||
break
|
||||
|
||||
require(2)
|
||||
var block = eth.blockByHash(data.args[0])
|
||||
postData(data._id, block.transactions[data.args[1]])
|
||||
break
|
||||
|
||||
case "eth_transactionByHash":
|
||||
case "eth_transactionByNumber":
|
||||
require(2)
|
||||
|
||||
var block;
|
||||
if (data.call === "transactionByHash")
|
||||
block = eth.blockByHash(data.args[0])
|
||||
else
|
||||
block = eth.blockByNumber(data.args[0])
|
||||
|
||||
var tx = block.transactions.get(data.args[1])
|
||||
|
||||
postData(data._id, tx)
|
||||
break
|
||||
|
||||
case "eth_uncleByHash":
|
||||
case "eth_uncleByNumber":
|
||||
require(2)
|
||||
|
||||
var block;
|
||||
if (data.call === "uncleByHash")
|
||||
block = eth.blockByHash(data.args[0])
|
||||
else
|
||||
block = eth.blockByNumber(data.args[0])
|
||||
|
||||
var uncle = block.uncles.get(data.args[1])
|
||||
|
||||
postData(data._id, uncle)
|
||||
|
||||
break
|
||||
|
||||
case "transact":
|
||||
require(5)
|
||||
|
||||
var tx = eth.transact(data.args)
|
||||
postData(data._id, tx)
|
||||
|
||||
break
|
||||
|
||||
case "eth_stateAt":
|
||||
require(2);
|
||||
|
||||
var storage = eth.storageAt(data.args[0], data.args[1]);
|
||||
postData(data._id, storage)
|
||||
|
||||
break
|
||||
|
||||
case "eth_call":
|
||||
require(1);
|
||||
var ret = eth.call(data.args)
|
||||
postData(data._id, ret)
|
||||
break
|
||||
|
||||
case "eth_balanceAt":
|
||||
require(1);
|
||||
|
||||
postData(data._id, eth.balanceAt(data.args[0]));
|
||||
break
|
||||
|
||||
case "eth_watch":
|
||||
require(2)
|
||||
eth.watch(data.args[0], data.args[1])
|
||||
|
||||
case "eth_disconnect":
|
||||
require(1)
|
||||
postData(data._id, null)
|
||||
break;
|
||||
|
||||
case "eth_newFilterString":
|
||||
require(1)
|
||||
var id = eth.newFilterString(data.args[0])
|
||||
postData(data._id, id);
|
||||
break;
|
||||
|
||||
case "eth_newFilter":
|
||||
require(1)
|
||||
var id = eth.newFilter(data.args[0])
|
||||
|
||||
postData(data._id, id);
|
||||
break;
|
||||
|
||||
case "eth_filterLogs":
|
||||
require(1);
|
||||
|
||||
var messages = eth.messages(data.args[0]);
|
||||
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
|
||||
postData(data._id, m);
|
||||
|
||||
break;
|
||||
|
||||
case "eth_deleteFilter":
|
||||
require(1);
|
||||
eth.uninstallFilter(data.args[0])
|
||||
break;
|
||||
|
||||
|
||||
case "shh_newFilter":
|
||||
require(1);
|
||||
var id = shh.watch(data.args[0], window);
|
||||
postData(data._id, id);
|
||||
break;
|
||||
|
||||
case "shh_newIdentity":
|
||||
var id = shh.newIdentity()
|
||||
postData(data._id, id)
|
||||
|
||||
break
|
||||
|
||||
case "shh_post":
|
||||
require(1);
|
||||
|
||||
var params = data.args[0];
|
||||
var fields = ["payload", "to", "from"];
|
||||
for(var i = 0; i < fields.length; i++) {
|
||||
params[fields[i]] = params[fields[i]] || "";
|
||||
}
|
||||
if(typeof params.payload !== "object") { params.payload = [params.payload]; } //params.payload = params.payload.join(""); }
|
||||
params.topics = params.topics || [];
|
||||
params.priority = params.priority || 1000;
|
||||
params.ttl = params.ttl || 100;
|
||||
|
||||
shh.post(params.payload, params.to, params.from, params.topics, params.priority, params.ttl);
|
||||
|
||||
break;
|
||||
|
||||
case "shh_getMessages":
|
||||
require(1);
|
||||
|
||||
var m = shh.messages(data.args[0]);
|
||||
var messages = JSON.parse(JSON.parse(JSON.stringify(m)));
|
||||
postData(data._id, messages);
|
||||
|
||||
break;
|
||||
|
||||
case "ssh_newGroup":
|
||||
postData(data._id, "");
|
||||
break;
|
||||
function require(args, num) {
|
||||
if(args.length < num) {
|
||||
throw("required argument count of "+num+" got "+args.length);
|
||||
}
|
||||
} catch(e) {
|
||||
console.log(data.call + ": " + e)
|
||||
|
||||
postData(data._id, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function post(seed, data) {
|
||||
postData(data._id, data)
|
||||
}
|
||||
|
||||
function require(args, num) {
|
||||
if(args.length < num) {
|
||||
throw("required argument count of "+num+" got "+args.length);
|
||||
function postData(seed, data) {
|
||||
webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
|
||||
}
|
||||
function postEvent(event, id, data) {
|
||||
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
|
||||
}
|
||||
function onWatchedCb(data, id) {
|
||||
var messages = JSON.parse(data)
|
||||
postEvent("watched:"+id, messages)
|
||||
}
|
||||
function onNewBlockCb(block) {
|
||||
postEvent("block:new", block)
|
||||
}
|
||||
function onObjectChangeCb(stateObject) {
|
||||
postEvent("object:"+stateObject.address(), stateObject)
|
||||
}
|
||||
function onStorageChangeCb(storageObject) {
|
||||
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
|
||||
postEvent(ev, [storageObject.address, storageObject.value])
|
||||
}
|
||||
}
|
||||
function postData(seed, data) {
|
||||
webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
|
||||
}
|
||||
function postEvent(event, id, data) {
|
||||
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
|
||||
}
|
||||
|
||||
function onWatchedCb(data, id) {
|
||||
var messages = JSON.parse(data)
|
||||
postEvent("watched:"+id, messages)
|
||||
}
|
||||
|
||||
function onNewBlockCb(block) {
|
||||
postEvent("block:new", block)
|
||||
}
|
||||
function onObjectChangeCb(stateObject) {
|
||||
postEvent("object:"+stateObject.address(), stateObject)
|
||||
}
|
||||
function onStorageChangeCb(storageObject) {
|
||||
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
|
||||
postEvent(ev, [storageObject.address, storageObject.value])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: sizeGrip
|
||||
color: "gray"
|
||||
|
@ -13,7 +13,6 @@ ApplicationWindow {
|
||||
id: root
|
||||
|
||||
property var ethx : Eth.ethx
|
||||
property var browser
|
||||
|
||||
width: 1200
|
||||
height: 820
|
||||
@ -21,6 +20,7 @@ ApplicationWindow {
|
||||
|
||||
title: "Mist"
|
||||
|
||||
/*
|
||||
// This signal is used by the filter API. The filter API connects using this signal handler from
|
||||
// the different QML files and plugins.
|
||||
signal messages(var messages, int id);
|
||||
@ -30,6 +30,7 @@ ApplicationWindow {
|
||||
messages(data, receiverSeed);
|
||||
root.browser.view.messages(data, receiverSeed);
|
||||
}
|
||||
*/
|
||||
|
||||
TextField {
|
||||
id: copyElementHax
|
||||
@ -45,8 +46,6 @@ ApplicationWindow {
|
||||
// Takes care of loading all default plugins
|
||||
Component.onCompleted: {
|
||||
var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
||||
var browser = addPlugin("./browser.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
||||
root.browser = browser;
|
||||
addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
|
||||
|
||||
addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
|
||||
@ -55,17 +54,17 @@ ApplicationWindow {
|
||||
addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"});
|
||||
addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
|
||||
|
||||
addPlugin("./views/jeffcoin/jeffcoin.qml", {noAdd: true, close: false, section: "apps"})
|
||||
|
||||
mainSplit.setView(wallet.view, wallet.menuItem);
|
||||
|
||||
newBrowserTab("http://etherian.io");
|
||||
|
||||
// Command setup
|
||||
gui.sendCommand(0)
|
||||
}
|
||||
|
||||
function activeView(view, menuItem) {
|
||||
mainSplit.setView(view, menuItem)
|
||||
if (view.objectName === "browserView") {
|
||||
if (view.hideUrl) {
|
||||
urlPane.visible = false;
|
||||
mainView.anchors.top = rootView.top
|
||||
} else {
|
||||
@ -119,6 +118,13 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
function newBrowserTab(url) {
|
||||
var window = addPlugin("./browser.qml", {noAdd: true, close: true, section: "apps", active: true});
|
||||
window.view.url = url;
|
||||
window.menuItem.title = "Browser Tab";
|
||||
activeView(window.view, window.menuItem);
|
||||
}
|
||||
|
||||
menuBar: MenuBar {
|
||||
Menu {
|
||||
title: "File"
|
||||
@ -130,13 +136,6 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MenuItem {
|
||||
text: "Browser"
|
||||
onTriggered: eth.openBrowser()
|
||||
}
|
||||
*/
|
||||
|
||||
MenuItem {
|
||||
text: "Add plugin"
|
||||
onTriggered: {
|
||||
@ -146,6 +145,14 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "New tab"
|
||||
shortcut: "Ctrl+t"
|
||||
onTriggered: {
|
||||
newBrowserTab("http://etherian.io");
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
@ -205,21 +212,6 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
/*
|
||||
MenuItem {
|
||||
id: miningSpeed
|
||||
text: "Mining: Turbo"
|
||||
onTriggered: {
|
||||
gui.toggleTurboMining()
|
||||
if(text == "Mining: Turbo") {
|
||||
text = "Mining: Normal";
|
||||
} else {
|
||||
text = "Mining: Turbo";
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
Menu {
|
||||
@ -350,9 +342,6 @@ ApplicationWindow {
|
||||
views[i].menuItem.setSelection(false)
|
||||
}
|
||||
view.visible = true
|
||||
|
||||
//menu.border.color = "#CCCCCC"
|
||||
//menu.color = "#FFFFFFFF"
|
||||
menu.setSelection(true)
|
||||
}
|
||||
|
||||
@ -512,7 +501,15 @@ ApplicationWindow {
|
||||
|
||||
this.view.destroy()
|
||||
this.destroy()
|
||||
for (var i = 0; i < mainSplit.views.length; i++) {
|
||||
var view = mainSplit.views[i];
|
||||
if (view.menuItem === this) {
|
||||
mainSplit.views.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gui.removePlugin(this.path)
|
||||
activeView(mainSplit.views[0].view, mainSplit.views[0].menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -576,7 +573,7 @@ ApplicationWindow {
|
||||
|
||||
|
||||
Text {
|
||||
text: "APPS"
|
||||
text: "NET"
|
||||
font.bold: true
|
||||
anchors {
|
||||
left: parent.left
|
||||
@ -653,7 +650,7 @@ ApplicationWindow {
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if(/^https?/.test(this.text)) {
|
||||
activeView(root.browser.view, root.browser.menuItem);
|
||||
newBrowserTab(this.text);
|
||||
} else {
|
||||
addPlugin(this.text, {close: true, section: "apps"})
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ Rectangle {
|
||||
property var identity: ""
|
||||
Component.onCompleted: {
|
||||
identity = shh.newIdentity()
|
||||
console.log("New identity:", identity)
|
||||
|
||||
var t = shh.watch({}, root)
|
||||
}
|
||||
|
@ -312,23 +312,19 @@ func (self *UiLib) ToAscii(data string) string {
|
||||
}
|
||||
|
||||
/// Ethereum filter methods
|
||||
func (self *UiLib) NewFilter(object map[string]interface{}) (id int) {
|
||||
func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (id int) {
|
||||
filter := qt.NewFilterFromMap(object, self.eth)
|
||||
filter.MessageCallback = func(messages state.Messages) {
|
||||
self.win.Root().Call("invokeFilterCallback", xeth.ToJSMessages(messages), id)
|
||||
view.Call("messages", xeth.ToJSMessages(messages), id)
|
||||
}
|
||||
id = self.filterManager.InstallFilter(filter)
|
||||
return id
|
||||
}
|
||||
|
||||
func (self *UiLib) NewFilterString(typ string) (id int) {
|
||||
func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
|
||||
filter := core.NewFilter(self.eth)
|
||||
filter.BlockCallback = func(block *types.Block) {
|
||||
if self.win != nil && self.win.Root() != nil {
|
||||
self.win.Root().Call("invokeFilterCallback", "{}", id)
|
||||
} else {
|
||||
fmt.Println("QML is lagging")
|
||||
}
|
||||
view.Call("messages", "{}", id)
|
||||
}
|
||||
id = self.filterManager.InstallFilter(filter)
|
||||
return id
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
@ -251,15 +252,12 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
|
||||
return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Header().Time, sm.bc.CurrentBlock().Header().Time)
|
||||
}
|
||||
|
||||
/* XXX
|
||||
// New blocks must be within the 15 minute range of the last block.
|
||||
if diff > int64(15*time.Minute) {
|
||||
return ValidationError("Block is too far in the future of last block (> 15 minutes)")
|
||||
if block.Time() > time.Now().Unix() {
|
||||
return fmt.Errorf("block time is in the future")
|
||||
}
|
||||
*/
|
||||
|
||||
// Verify the nonce of the block. Return an error if it's not valid
|
||||
if !sm.Pow.Verify(block /*block.HashNoNonce(), block.Difficulty, block.Nonce*/) {
|
||||
if !sm.Pow.Verify(block) {
|
||||
return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce))
|
||||
}
|
||||
|
||||
@ -287,21 +285,6 @@ func (sm *BlockProcessor) AccumelateRewards(statedb *state.StateDB, block, paren
|
||||
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||
}
|
||||
|
||||
/*
|
||||
uncleParent := sm.bc.GetBlock(uncle.ParentHash)
|
||||
if uncleParent == nil {
|
||||
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||
}
|
||||
|
||||
if uncleParent.Number().Cmp(new(big.Int).Sub(parent.Number(), big.NewInt(6))) < 0 {
|
||||
return UncleError("Uncle too old")
|
||||
}
|
||||
|
||||
if knownUncles.Has(string(uncle.Hash())) {
|
||||
return UncleError("Uncle in chain")
|
||||
}
|
||||
*/
|
||||
|
||||
r := new(big.Int)
|
||||
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
|
||||
|
||||
|
@ -7,9 +7,9 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/ethutil"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/obscuren/secp256k1-go"
|
||||
)
|
||||
|
||||
func IsContractAddr(addr []byte) bool {
|
||||
|
116
crypto/crypto.go
116
crypto/crypto.go
@ -1,16 +1,25 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"code.google.com/p/go.crypto/pbkdf2"
|
||||
"code.google.com/p/go.crypto/ripemd160"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/ethutil"
|
||||
"github.com/obscuren/ecies"
|
||||
"github.com/obscuren/secp256k1-go"
|
||||
"github.com/obscuren/sha3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -101,7 +110,11 @@ func SigToPub(hash, sig []byte) *ecdsa.PublicKey {
|
||||
}
|
||||
|
||||
func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
||||
sig, err = secp256k1.Sign(hash, prv.D.Bytes())
|
||||
if len(hash) != 32 {
|
||||
return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
|
||||
}
|
||||
|
||||
sig, err = secp256k1.Sign(hash, ethutil.LeftPadBytes(prv.D.Bytes(), prv.Params().BitSize/8))
|
||||
return
|
||||
}
|
||||
|
||||
@ -113,3 +126,100 @@ func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
|
||||
key := ecies.ImportECDSA(prv)
|
||||
return key.Decrypt(rand.Reader, ct, nil, nil)
|
||||
}
|
||||
|
||||
// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
|
||||
func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key, error) {
|
||||
key, err := decryptPreSaleKey(keyJSON, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id := uuid.NewRandom()
|
||||
key.Id = &id
|
||||
err = keyStore.StoreKey(key, password)
|
||||
return key, err
|
||||
}
|
||||
|
||||
func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) {
|
||||
preSaleKeyStruct := struct {
|
||||
EncSeed string
|
||||
EthAddr string
|
||||
Email string
|
||||
BtcAddr string
|
||||
}{}
|
||||
err = json.Unmarshal(fileContent, &preSaleKeyStruct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
|
||||
iv := encSeedBytes[:16]
|
||||
cipherText := encSeedBytes[16:]
|
||||
/*
|
||||
See https://github.com/ethereum/pyethsaletool
|
||||
|
||||
pyethsaletool generates the encryption key from password by
|
||||
2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:().
|
||||
16 byte key length within PBKDF2 and resulting key is used as AES key
|
||||
*/
|
||||
passBytes := []byte(password)
|
||||
derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
|
||||
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
||||
ethPriv := Sha3(plainText)
|
||||
ecKey := ToECDSA(ethPriv)
|
||||
key = &Key{
|
||||
Id: nil,
|
||||
PrivateKey: ecKey,
|
||||
}
|
||||
derivedAddr := ethutil.Bytes2Hex(key.Address())
|
||||
expectedAddr := preSaleKeyStruct.EthAddr
|
||||
if derivedAddr != expectedAddr {
|
||||
err = errors.New("decrypted addr not equal to expected addr")
|
||||
}
|
||||
return key, err
|
||||
}
|
||||
|
||||
func aesCBCDecrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte, err error) {
|
||||
aesBlock, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return plainText, err
|
||||
}
|
||||
decrypter := cipher.NewCBCDecrypter(aesBlock, iv)
|
||||
paddedPlainText := make([]byte, len(cipherText))
|
||||
decrypter.CryptBlocks(paddedPlainText, cipherText)
|
||||
plainText = PKCS7Unpad(paddedPlainText)
|
||||
if plainText == nil {
|
||||
err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
|
||||
}
|
||||
return plainText, err
|
||||
}
|
||||
|
||||
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
|
||||
func PKCS7Pad(in []byte) []byte {
|
||||
padding := 16 - (len(in) % 16)
|
||||
if padding == 0 {
|
||||
padding = 16
|
||||
}
|
||||
for i := 0; i < padding; i++ {
|
||||
in = append(in, byte(padding))
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
func PKCS7Unpad(in []byte) []byte {
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
padding := in[len(in)-1]
|
||||
if int(padding) > len(in) || padding > aes.BlockSize {
|
||||
return nil
|
||||
} else if padding == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
|
||||
if in[i] != padding {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return in[:len(in)-int(padding)]
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/ethutil"
|
||||
"github.com/obscuren/secp256k1-go"
|
||||
)
|
||||
|
||||
// These tests are sanity checks.
|
||||
@ -52,7 +52,7 @@ func BenchmarkSha3(b *testing.B) {
|
||||
}
|
||||
|
||||
func Test0Key(t *testing.T) {
|
||||
|
||||
t.Skip()
|
||||
key := ethutil.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111")
|
||||
|
||||
p, err := secp256k1.GeneratePubKey(key)
|
||||
@ -60,3 +60,15 @@ func Test0Key(t *testing.T) {
|
||||
fmt.Printf("%x\n", p)
|
||||
fmt.Printf("%v %x\n", err, addr)
|
||||
}
|
||||
|
||||
func TestInvalidSign(t *testing.T) {
|
||||
_, err := Sign(make([]byte, 1), nil)
|
||||
if err == nil {
|
||||
t.Errorf("expected sign with hash 1 byte to error")
|
||||
}
|
||||
|
||||
_, err = Sign(make([]byte, 33), nil)
|
||||
if err == nil {
|
||||
t.Errorf("expected sign with hash 33 byte to error")
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ type encryptedKeyJSON struct {
|
||||
|
||||
func (k *Key) Address() []byte {
|
||||
pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey)
|
||||
return Sha3(pubBytes)[12:]
|
||||
return Sha3(pubBytes[1:])[12:]
|
||||
}
|
||||
|
||||
func (k *Key) MarshalJSON() (j []byte, err error) {
|
||||
@ -99,9 +99,10 @@ func NewKey(rand io.Reader) *Key {
|
||||
privateKeyMarshalled := elliptic.Marshal(S256(), x, y)
|
||||
privateKeyECDSA := ToECDSA(privateKeyMarshalled)
|
||||
|
||||
key := new(Key)
|
||||
id := uuid.NewRandom()
|
||||
key.Id = &id
|
||||
key.PrivateKey = privateKeyECDSA
|
||||
key := &Key{
|
||||
Id: &id,
|
||||
PrivateKey: privateKeyECDSA,
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
@ -178,22 +178,10 @@ func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
AES256Block, err := aes.NewCipher(derivedKey)
|
||||
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
AES256CBCDecrypter := cipher.NewCBCDecrypter(AES256Block, iv)
|
||||
paddedPlainText := make([]byte, len(cipherText))
|
||||
AES256CBCDecrypter.CryptBlocks(paddedPlainText, cipherText)
|
||||
|
||||
plainText := PKCS7Unpad(paddedPlainText)
|
||||
if plainText == nil {
|
||||
err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyBytes = plainText[:len(plainText)-32]
|
||||
keyBytesHash := plainText[len(plainText)-32:]
|
||||
if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
|
||||
@ -211,35 +199,3 @@ func getEntropyCSPRNG(n int) []byte {
|
||||
}
|
||||
return mainBuff
|
||||
}
|
||||
|
||||
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
|
||||
func PKCS7Pad(in []byte) []byte {
|
||||
padding := 16 - (len(in) % 16)
|
||||
if padding == 0 {
|
||||
padding = 16
|
||||
}
|
||||
for i := 0; i < padding; i++ {
|
||||
in = append(in, byte(padding))
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
func PKCS7Unpad(in []byte) []byte {
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
padding := in[len(in)-1]
|
||||
if int(padding) > len(in) || padding > aes.BlockSize {
|
||||
return nil
|
||||
} else if padding == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
|
||||
if in[i] != padding {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return in[:len(in)-int(padding)]
|
||||
}
|
||||
|
@ -83,3 +83,16 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportPreSaleKey(t *testing.T) {
|
||||
// file content of a presale key file generated with:
|
||||
// python pyethsaletool.py genwallet
|
||||
// with password "foo"
|
||||
fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
|
||||
ks := NewKeyStorePassphrase(DefaultDataDir())
|
||||
pass := "foo"
|
||||
_, err := ImportPreSaleKey(ks, []byte(fileContent), pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package crypto
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/ethutil"
|
||||
"github.com/obscuren/secp256k1-go"
|
||||
)
|
||||
|
||||
type KeyPair struct {
|
||||
|
24
crypto/secp256k1/.gitignore
vendored
Normal file
24
crypto/secp256k1/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
|
||||
*~
|
22
crypto/secp256k1/README.md
Normal file
22
crypto/secp256k1/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
secp256k1-go
|
||||
=======
|
||||
|
||||
golang secp256k1 library
|
||||
|
||||
Implements cryptographic operations for the secp256k1 ECDSA curve used by Bitcoin.
|
||||
|
||||
Installing
|
||||
===
|
||||
```
|
||||
sudo apt-get install gmp-dev
|
||||
```
|
||||
|
||||
Now compiles with cgo!
|
||||
|
||||
Test
|
||||
===
|
||||
|
||||
To run tests do
|
||||
```
|
||||
go tests
|
||||
```
|
192
crypto/secp256k1/notes.go
Normal file
192
crypto/secp256k1/notes.go
Normal file
@ -0,0 +1,192 @@
|
||||
package secp256k1
|
||||
|
||||
/*
|
||||
<HaltingState> sipa, int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
|
||||
<HaltingState> is that how i generate private/public keys?
|
||||
<sipa> HaltingState: you pass in a random 32-byte string as seckey
|
||||
<sipa> HaltingState: if it is valid, the corresponding pubkey is put in pubkey
|
||||
<sipa> and true is returned
|
||||
<sipa> otherwise, false is returned
|
||||
<sipa> around 1 in 2^128 32-byte strings are invalid, so the odds of even ever seeing one is extremely rare
|
||||
|
||||
<sipa> private keys are mathematically numbers
|
||||
<sipa> each has a corresponding point on the curve as public key
|
||||
<sipa> a private key is just a number
|
||||
<sipa> a public key is a point with x/y coordinates
|
||||
<sipa> almost every 256-bit number is a valid private key (one with a point on the curve corresponding to it)
|
||||
<sipa> HaltingState: ok?
|
||||
|
||||
<sipa> more than half of random points are not on the curve
|
||||
<sipa> and actually, it is less than the square root, not less than half, sorry :)
|
||||
!!!
|
||||
<sipa> a private key is a NUMBER
|
||||
<sipa> a public key is a POINT
|
||||
<gmaxwell> half the x,y values in the field are not on the curve, a private key is an integer.
|
||||
|
||||
<sipa> HaltingState: yes, n,q = private keys; N,Q = corresponding public keys (N=n*G, Q=q*G); then it follows that n*Q = n*q*G = q*n*G = q*N
|
||||
<sipa> that's the reason ECDH works
|
||||
<sipa> multiplication is associative and commutativ
|
||||
*/
|
||||
|
||||
/*
|
||||
<HaltingState> sipa, ok; i am doing compact signatures and I want to know; can someone change the signature to get another valid signature for same message without the private key
|
||||
<HaltingState> because i know they can do that for the normal 72 byte signatures that openssl was putting out
|
||||
<sipa> HaltingState: if you don't enforce non-malleability, yes
|
||||
<sipa> HaltingState: if you force the highest bit of t
|
||||
|
||||
<sipa> it _creates_ signatures that already satisfy that condition
|
||||
<sipa> but it will accept ones that don't
|
||||
<sipa> maybe i should change that, and be strict
|
||||
<HaltingState> yes; i want some way to know signature is valid but fails malleability
|
||||
<sipa> well if the highest bit of S is 1, you can take its complement
|
||||
<sipa> and end up with a valid signature
|
||||
<sipa> that is canonical
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
<HaltingState> sipa, I am signing messages and highest bit of the compact signature is 1!!!
|
||||
<HaltingState> if (b & 0x80) == 0x80 {
|
||||
<HaltingState> log.Panic("b= %v b2= %v \n", b, b&0x80)
|
||||
<HaltingState> }
|
||||
<sipa> what bit?
|
||||
* Pengoo has quit (Ping timeout: 272 seconds)
|
||||
<HaltingState> the highest bit of the first byte of signature
|
||||
<sipa> it's the highest bit of S
|
||||
<sipa> so the 32nd byte
|
||||
<HaltingState> wtf
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
For instance, nonces are used in HTTP digest access authentication to calculate an MD5 digest
|
||||
of the password. The nonces are different each time the 401 authentication challenge
|
||||
response code is presented, thus making replay attacks virtually impossible.
|
||||
|
||||
can verify client/server match without sending password over network
|
||||
*/
|
||||
|
||||
/*
|
||||
<hanihani> one thing I dont get about armory for instance,
|
||||
is how the hot-wallet can generate new addresses without
|
||||
knowing the master key
|
||||
*/
|
||||
|
||||
/*
|
||||
<HaltingState> i am yelling at the telehash people for using secp256r1
|
||||
instead of secp256k1; they thing r1 is "more secure" despite fact that
|
||||
there is no implementation that works and wrapping it is now taking
|
||||
up massive time, lol
|
||||
<gmaxwell> ...
|
||||
|
||||
<gmaxwell> You know that the *r curves are selected via an undisclosed
|
||||
secret process, right?
|
||||
<gmaxwell> HaltingState: telehash is offtopic for this channel.
|
||||
*/
|
||||
/*
|
||||
For instance, nonces are used in HTTP digest access authentication to calculate an MD5 digest
|
||||
of the password. The nonces are different each time the 401 authentication challenge
|
||||
response code is presented, thus making replay attacks virtually impossible.
|
||||
|
||||
can verify client/server match without sending password over network
|
||||
*/
|
||||
|
||||
/*
|
||||
void secp256k1_start(void);
|
||||
void secp256k1_stop(void);
|
||||
|
||||
* Verify an ECDSA signature.
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect signature
|
||||
* -1: invalid public key
|
||||
* -2: invalid signature
|
||||
*
|
||||
int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen,
|
||||
const unsigned char *sig, int siglen,
|
||||
const unsigned char *pubkey, int pubkeylen);
|
||||
|
||||
http://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html
|
||||
|
||||
Why did this work? ECDSA requires a random number for each signature. If this random
|
||||
number is ever used twice with the same private key it can be recovered.
|
||||
This transaction was generated by a hardware bitcoin wallet using a pseudo-random number
|
||||
generator that was returning the same “random” number every time.
|
||||
|
||||
Nonce is 32 bytes?
|
||||
|
||||
* Create an ECDSA signature.
|
||||
* Returns: 1: signature created
|
||||
* 0: nonce invalid, try another one
|
||||
* In: msg: the message being signed
|
||||
* msglen: the length of the message being signed
|
||||
* seckey: pointer to a 32-byte secret key (assumed to be valid)
|
||||
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
|
||||
* Out: sig: pointer to a 72-byte array where the signature will be placed.
|
||||
* siglen: pointer to an int, which will be updated to the signature length (<=72).
|
||||
*
|
||||
int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen,
|
||||
unsigned char *sig, int *siglen,
|
||||
const unsigned char *seckey,
|
||||
const unsigned char *nonce);
|
||||
|
||||
|
||||
* Create a compact ECDSA signature (64 byte + recovery id).
|
||||
* Returns: 1: signature created
|
||||
* 0: nonce invalid, try another one
|
||||
* In: msg: the message being signed
|
||||
* msglen: the length of the message being signed
|
||||
* seckey: pointer to a 32-byte secret key (assumed to be valid)
|
||||
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
|
||||
* Out: sig: pointer to a 64-byte array where the signature will be placed.
|
||||
* recid: pointer to an int, which will be updated to contain the recovery id.
|
||||
*
|
||||
int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *seckey,
|
||||
const unsigned char *nonce,
|
||||
int *recid);
|
||||
|
||||
* Recover an ECDSA public key from a compact signature.
|
||||
* Returns: 1: public key succesfully recovered (which guarantees a correct signature).
|
||||
* 0: otherwise.
|
||||
* In: msg: the message assumed to be signed
|
||||
* msglen: the length of the message
|
||||
* compressed: whether to recover a compressed or uncompressed pubkey
|
||||
* recid: the recovery id (as returned by ecdsa_sign_compact)
|
||||
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
|
||||
* pubkeylen: pointer to an int that will contain the pubkey length.
|
||||
*
|
||||
|
||||
recovery id is between 0 and 3
|
||||
|
||||
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
|
||||
const unsigned char *sig64,
|
||||
unsigned char *pubkey, int *pubkeylen,
|
||||
int compressed, int recid);
|
||||
|
||||
|
||||
* Verify an ECDSA secret key.
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* In: seckey: pointer to a 32-byte secret key
|
||||
*
|
||||
int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey);
|
||||
|
||||
** Just validate a public key.
|
||||
* Returns: 1: valid public key
|
||||
* 0: invalid public key
|
||||
*
|
||||
int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen);
|
||||
|
||||
** Compute the public key for a secret key.
|
||||
* In: compressed: whether the computed public key should be compressed
|
||||
* seckey: pointer to a 32-byte private key.
|
||||
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
|
||||
* area to store the public key.
|
||||
* pubkeylen: pointer to int that will be updated to contains the pubkey's
|
||||
* length.
|
||||
* Returns: 1: secret was valid, public key stores
|
||||
* 0: secret was invalid, try again.
|
||||
*
|
||||
int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
|
||||
*/
|
304
crypto/secp256k1/secp256.go
Normal file
304
crypto/secp256k1/secp256.go
Normal file
@ -0,0 +1,304 @@
|
||||
package secp256k1
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -std=gnu99 -Wno-error
|
||||
#cgo darwin CFLAGS: -I/usr/local/include
|
||||
#cgo LDFLAGS: -lgmp
|
||||
#cgo darwin LDFLAGS: -L/usr/local/lib
|
||||
#define USE_FIELD_10X26
|
||||
#define USE_NUM_GMP
|
||||
#define USE_FIELD_INV_BUILTIN
|
||||
#include "./secp256k1/src/secp256k1.c"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//#define USE_FIELD_5X64
|
||||
|
||||
/*
|
||||
Todo:
|
||||
> Centralize key management in module
|
||||
> add pubkey/private key struct
|
||||
> Dont let keys leave module; address keys as ints
|
||||
|
||||
> store private keys in buffer and shuffle (deters persistance on swap disc)
|
||||
> Byte permutation (changing)
|
||||
> xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?)
|
||||
|
||||
On Disk
|
||||
> Store keys in wallets
|
||||
> use slow key derivation function for wallet encryption key (2 seconds)
|
||||
*/
|
||||
|
||||
func init() {
|
||||
C.secp256k1_start() //takes 10ms to 100ms
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
C.secp256k1_stop()
|
||||
}
|
||||
|
||||
/*
|
||||
int secp256k1_ecdsa_pubkey_create(
|
||||
unsigned char *pubkey, int *pubkeylen,
|
||||
const unsigned char *seckey, int compressed);
|
||||
*/
|
||||
|
||||
/** Compute the public key for a secret key.
|
||||
* In: compressed: whether the computed public key should be compressed
|
||||
* seckey: pointer to a 32-byte private key.
|
||||
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
|
||||
* area to store the public key.
|
||||
* pubkeylen: pointer to int that will be updated to contains the pubkey's
|
||||
* length.
|
||||
* Returns: 1: secret was valid, public key stores
|
||||
* 0: secret was invalid, try again.
|
||||
*/
|
||||
|
||||
//pubkey, seckey
|
||||
|
||||
func GenerateKeyPair() ([]byte, []byte) {
|
||||
|
||||
pubkey_len := C.int(65)
|
||||
const seckey_len = 32
|
||||
|
||||
var pubkey []byte = make([]byte, pubkey_len)
|
||||
var seckey []byte = RandByte(seckey_len)
|
||||
|
||||
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
|
||||
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
|
||||
|
||||
ret := C.secp256k1_ecdsa_pubkey_create(
|
||||
pubkey_ptr, &pubkey_len,
|
||||
seckey_ptr, 0)
|
||||
|
||||
if ret != C.int(1) {
|
||||
return GenerateKeyPair() //invalid secret, try again
|
||||
}
|
||||
return pubkey, seckey
|
||||
}
|
||||
|
||||
func GeneratePubKey(seckey []byte) ([]byte, error) {
|
||||
pubkey_len := C.int(65)
|
||||
const seckey_len = 32
|
||||
|
||||
var pubkey []byte = make([]byte, pubkey_len)
|
||||
|
||||
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
|
||||
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
|
||||
|
||||
ret := C.secp256k1_ecdsa_pubkey_create(
|
||||
pubkey_ptr, &pubkey_len,
|
||||
seckey_ptr, 0)
|
||||
|
||||
if ret != C.int(1) {
|
||||
return nil, errors.New("Unable to generate pubkey from seckey")
|
||||
}
|
||||
|
||||
return pubkey, nil
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a compact ECDSA signature (64 byte + recovery id).
|
||||
* Returns: 1: signature created
|
||||
* 0: nonce invalid, try another one
|
||||
* In: msg: the message being signed
|
||||
* msglen: the length of the message being signed
|
||||
* seckey: pointer to a 32-byte secret key (assumed to be valid)
|
||||
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
|
||||
* Out: sig: pointer to a 64-byte array where the signature will be placed.
|
||||
* recid: pointer to an int, which will be updated to contain the recovery id.
|
||||
*/
|
||||
|
||||
/*
|
||||
int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *seckey,
|
||||
const unsigned char *nonce,
|
||||
int *recid);
|
||||
*/
|
||||
|
||||
func Sign(msg []byte, seckey []byte) ([]byte, error) {
|
||||
//var nonce []byte = RandByte(32)
|
||||
nonce := make([]byte, 32)
|
||||
for i := range msg {
|
||||
nonce[i] = msg[i] ^ seckey[i]
|
||||
}
|
||||
|
||||
var sig []byte = make([]byte, 65)
|
||||
var recid C.int
|
||||
|
||||
var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
|
||||
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
|
||||
var nonce_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&nonce[0]))
|
||||
var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
|
||||
|
||||
if C.secp256k1_ecdsa_seckey_verify(seckey_ptr) != C.int(1) {
|
||||
return nil, errors.New("Invalid secret key")
|
||||
}
|
||||
|
||||
ret := C.secp256k1_ecdsa_sign_compact(
|
||||
msg_ptr, C.int(len(msg)),
|
||||
sig_ptr,
|
||||
seckey_ptr,
|
||||
nonce_ptr,
|
||||
&recid)
|
||||
|
||||
sig[64] = byte(int(recid))
|
||||
|
||||
if ret != C.int(1) {
|
||||
// nonce invalid, retry
|
||||
return Sign(msg, seckey)
|
||||
}
|
||||
|
||||
return sig, nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify an ECDSA secret key.
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* In: seckey: pointer to a 32-byte secret key
|
||||
*/
|
||||
|
||||
func VerifySeckeyValidity(seckey []byte) error {
|
||||
if len(seckey) != 32 {
|
||||
return errors.New("priv key is not 32 bytes")
|
||||
}
|
||||
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
|
||||
ret := C.secp256k1_ecdsa_seckey_verify(seckey_ptr)
|
||||
if int(ret) != 1 {
|
||||
return errors.New("invalid seckey")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate a public key.
|
||||
* Returns: 1: valid public key
|
||||
* 0: invalid public key
|
||||
*/
|
||||
|
||||
func VerifyPubkeyValidity(pubkey []byte) error {
|
||||
if len(pubkey) != 65 {
|
||||
return errors.New("pub key is not 65 bytes")
|
||||
}
|
||||
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
|
||||
ret := C.secp256k1_ecdsa_pubkey_verify(pubkey_ptr, 65)
|
||||
if int(ret) != 1 {
|
||||
return errors.New("invalid pubkey")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifySignatureValidity(sig []byte) bool {
|
||||
//64+1
|
||||
if len(sig) != 65 {
|
||||
return false
|
||||
}
|
||||
//malleability check, highest bit must be 1
|
||||
if (sig[32] & 0x80) == 0x80 {
|
||||
return false
|
||||
}
|
||||
//recovery id check
|
||||
if sig[64] >= 4 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//for compressed signatures, does not need pubkey
|
||||
func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error {
|
||||
if msg == nil || sig == nil || pubkey1 == nil {
|
||||
return errors.New("inputs must be non-nil")
|
||||
}
|
||||
if len(sig) != 65 {
|
||||
return errors.New("invalid signature length")
|
||||
}
|
||||
if len(pubkey1) != 65 {
|
||||
return errors.New("Invalid public key length")
|
||||
}
|
||||
|
||||
//to enforce malleability, highest bit of S must be 0
|
||||
//S starts at 32nd byte
|
||||
if (sig[32] & 0x80) == 0x80 { //highest bit must be 1
|
||||
return errors.New("Signature not malleable")
|
||||
}
|
||||
|
||||
if sig[64] >= 4 {
|
||||
return errors.New("Recover byte invalid")
|
||||
}
|
||||
|
||||
// if pubkey recovered, signature valid
|
||||
pubkey2, err := RecoverPubkey(msg, sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(pubkey2) != 65 {
|
||||
return errors.New("Invalid recovered public key length")
|
||||
}
|
||||
if !bytes.Equal(pubkey1, pubkey2) {
|
||||
return errors.New("Public key does not match recovered public key")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
|
||||
const unsigned char *sig64,
|
||||
unsigned char *pubkey, int *pubkeylen,
|
||||
int compressed, int recid);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Recover an ECDSA public key from a compact signature.
|
||||
* Returns: 1: public key succesfully recovered (which guarantees a correct signature).
|
||||
* 0: otherwise.
|
||||
* In: msg: the message assumed to be signed
|
||||
* msglen: the length of the message
|
||||
* compressed: whether to recover a compressed or uncompressed pubkey
|
||||
* recid: the recovery id (as returned by ecdsa_sign_compact)
|
||||
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
|
||||
* pubkeylen: pointer to an int that will contain the pubkey length.
|
||||
*/
|
||||
|
||||
//recovers the public key from the signature
|
||||
//recovery of pubkey means correct signature
|
||||
func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
|
||||
if len(sig) != 65 {
|
||||
return nil, errors.New("Invalid signature length")
|
||||
}
|
||||
|
||||
var pubkey []byte = make([]byte, 65)
|
||||
|
||||
var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
|
||||
var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
|
||||
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
|
||||
|
||||
var pubkeylen C.int
|
||||
|
||||
ret := C.secp256k1_ecdsa_recover_compact(
|
||||
msg_ptr, C.int(len(msg)),
|
||||
sig_ptr,
|
||||
pubkey_ptr, &pubkeylen,
|
||||
C.int(0), C.int(sig[64]),
|
||||
)
|
||||
|
||||
if ret == C.int(0) {
|
||||
return nil, errors.New("Failed to recover public key")
|
||||
} else if pubkeylen != C.int(65) {
|
||||
return nil, errors.New("Impossible Error: Invalid recovered public key length")
|
||||
} else {
|
||||
return pubkey, nil
|
||||
}
|
||||
return nil, errors.New("Impossible Error: func RecoverPubkey has reached an unreachable state")
|
||||
}
|
96
crypto/secp256k1/secp256_rand.go
Normal file
96
crypto/secp256k1/secp256_rand.go
Normal file
@ -0,0 +1,96 @@
|
||||
package secp256k1
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"io"
|
||||
mrand "math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
Note:
|
||||
|
||||
- On windows cryto/rand uses CrytoGenRandom which uses RC4 which is insecure
|
||||
- Android random number generator is known to be insecure.
|
||||
- Linux uses /dev/urandom , which is thought to be secure and uses entropy pool
|
||||
|
||||
Therefore the output is salted.
|
||||
*/
|
||||
|
||||
//finalizer from MurmerHash3
|
||||
func mmh3f(key uint64) uint64 {
|
||||
key ^= key >> 33
|
||||
key *= 0xff51afd7ed558ccd
|
||||
key ^= key >> 33
|
||||
key *= 0xc4ceb9fe1a85ec53
|
||||
key ^= key >> 33
|
||||
return key
|
||||
}
|
||||
|
||||
//knuth hash
|
||||
func knuth_hash(in []byte) uint64 {
|
||||
var acc uint64 = 3074457345618258791
|
||||
for i := 0; i < len(in); i++ {
|
||||
acc += uint64(in[i])
|
||||
acc *= 3074457345618258799
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
var _rand *mrand.Rand
|
||||
|
||||
func init() {
|
||||
var seed1 uint64 = mmh3f(uint64(time.Now().UnixNano()))
|
||||
var seed2 uint64 = knuth_hash([]byte(strings.Join(os.Environ(), "")))
|
||||
var seed3 uint64 = mmh3f(uint64(os.Getpid()))
|
||||
|
||||
_rand = mrand.New(mrand.NewSource(int64(seed1 ^ seed2 ^ seed3)))
|
||||
}
|
||||
|
||||
func saltByte(buff []byte) []byte {
|
||||
for i := 0; i < len(buff); i++ {
|
||||
var v uint64 = uint64(_rand.Int63())
|
||||
var b byte
|
||||
for j := 0; j < 8; j++ {
|
||||
b ^= byte(v & 0xff)
|
||||
v = v >> 8
|
||||
}
|
||||
buff[i] = b
|
||||
}
|
||||
return buff
|
||||
}
|
||||
|
||||
//On Unix-like systems, Reader reads from /dev/urandom.
|
||||
//On Windows systems, Reader uses the CryptGenRandom API.
|
||||
|
||||
//use entropy pool etc and cryptographic random number generator
|
||||
//mix in time
|
||||
//mix in mix in cpu cycle count
|
||||
func RandByte(n int) []byte {
|
||||
buff := make([]byte, n)
|
||||
ret, err := io.ReadFull(crand.Reader, buff)
|
||||
if len(buff) != ret || err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
buff2 := RandByteWeakCrypto(n)
|
||||
for i := 0; i < n; i++ {
|
||||
buff[i] ^= buff2[2]
|
||||
}
|
||||
return buff
|
||||
}
|
||||
|
||||
/*
|
||||
On Unix-like systems, Reader reads from /dev/urandom.
|
||||
On Windows systems, Reader uses the CryptGenRandom API.
|
||||
*/
|
||||
func RandByteWeakCrypto(n int) []byte {
|
||||
buff := make([]byte, n)
|
||||
ret, err := io.ReadFull(crand.Reader, buff)
|
||||
if len(buff) != ret || err != nil {
|
||||
return nil
|
||||
}
|
||||
return buff
|
||||
}
|
228
crypto/secp256k1/secp256_test.go
Normal file
228
crypto/secp256k1/secp256_test.go
Normal file
@ -0,0 +1,228 @@
|
||||
package secp256k1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const TESTS = 10000 // how many tests
|
||||
const SigSize = 65 //64+1
|
||||
|
||||
func Test_Secp256_00(t *testing.T) {
|
||||
|
||||
var nonce []byte = RandByte(32) //going to get bitcoins stolen!
|
||||
|
||||
if len(nonce) != 32 {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//tests for Malleability
|
||||
//highest bit of S must be 0; 32nd byte
|
||||
func CompactSigTest(sig []byte) {
|
||||
|
||||
var b int = int(sig[32])
|
||||
if b < 0 {
|
||||
log.Panic()
|
||||
}
|
||||
if ((b >> 7) == 1) != ((b & 0x80) == 0x80) {
|
||||
log.Panic("b= %v b2= %v \n", b, b>>7)
|
||||
}
|
||||
if (b & 0x80) == 0x80 {
|
||||
log.Panic("b= %v b2= %v \n", b, b&0x80)
|
||||
}
|
||||
}
|
||||
|
||||
//test pubkey/private generation
|
||||
func Test_Secp256_01(t *testing.T) {
|
||||
pubkey, seckey := GenerateKeyPair()
|
||||
if err := VerifySeckeyValidity(seckey); err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
if err := VerifyPubkeyValidity(pubkey); err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
//test size of messages
|
||||
func Test_Secp256_02s(t *testing.T) {
|
||||
pubkey, seckey := GenerateKeyPair()
|
||||
msg := RandByte(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
CompactSigTest(sig)
|
||||
if sig == nil {
|
||||
t.Fatal("Signature nil")
|
||||
}
|
||||
if len(pubkey) != 65 {
|
||||
t.Fail()
|
||||
}
|
||||
if len(seckey) != 32 {
|
||||
t.Fail()
|
||||
}
|
||||
if len(sig) != 64+1 {
|
||||
t.Fail()
|
||||
}
|
||||
if int(sig[64]) > 4 {
|
||||
t.Fail()
|
||||
} //should be 0 to 4
|
||||
}
|
||||
|
||||
//test signing message
|
||||
func Test_Secp256_02(t *testing.T) {
|
||||
pubkey1, seckey := GenerateKeyPair()
|
||||
msg := RandByte(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
if sig == nil {
|
||||
t.Fatal("Signature nil")
|
||||
}
|
||||
|
||||
pubkey2, _ := RecoverPubkey(msg, sig)
|
||||
if pubkey2 == nil {
|
||||
t.Fatal("Recovered pubkey invalid")
|
||||
}
|
||||
if bytes.Equal(pubkey1, pubkey2) == false {
|
||||
t.Fatal("Recovered pubkey does not match")
|
||||
}
|
||||
|
||||
err := VerifySignature(msg, sig, pubkey1)
|
||||
if err != nil {
|
||||
t.Fatal("Signature invalid")
|
||||
}
|
||||
}
|
||||
|
||||
//test pubkey recovery
|
||||
func Test_Secp256_02a(t *testing.T) {
|
||||
pubkey1, seckey1 := GenerateKeyPair()
|
||||
msg := RandByte(32)
|
||||
sig, _ := Sign(msg, seckey1)
|
||||
|
||||
if sig == nil {
|
||||
t.Fatal("Signature nil")
|
||||
}
|
||||
err := VerifySignature(msg, sig, pubkey1)
|
||||
if err != nil {
|
||||
t.Fatal("Signature invalid")
|
||||
}
|
||||
|
||||
pubkey2, _ := RecoverPubkey(msg, sig)
|
||||
if len(pubkey1) != len(pubkey2) {
|
||||
t.Fatal()
|
||||
}
|
||||
for i, _ := range pubkey1 {
|
||||
if pubkey1[i] != pubkey2[i] {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
if bytes.Equal(pubkey1, pubkey2) == false {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
//test random messages for the same pub/private key
|
||||
func Test_Secp256_03(t *testing.T) {
|
||||
_, seckey := GenerateKeyPair()
|
||||
for i := 0; i < TESTS; i++ {
|
||||
msg := RandByte(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
CompactSigTest(sig)
|
||||
|
||||
sig[len(sig)-1] %= 4
|
||||
pubkey2, _ := RecoverPubkey(msg, sig)
|
||||
if pubkey2 == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//test random messages for different pub/private keys
|
||||
func Test_Secp256_04(t *testing.T) {
|
||||
for i := 0; i < TESTS; i++ {
|
||||
pubkey1, seckey := GenerateKeyPair()
|
||||
msg := RandByte(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
CompactSigTest(sig)
|
||||
|
||||
if sig[len(sig)-1] >= 4 {
|
||||
t.Fail()
|
||||
}
|
||||
pubkey2, _ := RecoverPubkey(msg, sig)
|
||||
if pubkey2 == nil {
|
||||
t.Fail()
|
||||
}
|
||||
if bytes.Equal(pubkey1, pubkey2) == false {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//test random signatures against fixed messages; should fail
|
||||
|
||||
//crashes:
|
||||
// -SIPA look at this
|
||||
|
||||
func randSig() []byte {
|
||||
sig := RandByte(65)
|
||||
sig[32] &= 0x70
|
||||
sig[64] %= 4
|
||||
return sig
|
||||
}
|
||||
|
||||
func Test_Secp256_06a_alt0(t *testing.T) {
|
||||
pubkey1, seckey := GenerateKeyPair()
|
||||
msg := RandByte(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
|
||||
if sig == nil {
|
||||
t.Fail()
|
||||
}
|
||||
if len(sig) != 65 {
|
||||
t.Fail()
|
||||
}
|
||||
for i := 0; i < TESTS; i++ {
|
||||
sig = randSig()
|
||||
pubkey2, _ := RecoverPubkey(msg, sig)
|
||||
|
||||
if bytes.Equal(pubkey1, pubkey2) == true {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if pubkey2 != nil && VerifySignature(msg, sig, pubkey2) != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if VerifySignature(msg, sig, pubkey1) == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//test random messages against valid signature: should fail
|
||||
|
||||
func Test_Secp256_06b(t *testing.T) {
|
||||
pubkey1, seckey := GenerateKeyPair()
|
||||
msg := RandByte(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
|
||||
fail_count := 0
|
||||
for i := 0; i < TESTS; i++ {
|
||||
msg = RandByte(32)
|
||||
pubkey2, _ := RecoverPubkey(msg, sig)
|
||||
if bytes.Equal(pubkey1, pubkey2) == true {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if pubkey2 != nil && VerifySignature(msg, sig, pubkey2) != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if VerifySignature(msg, sig, pubkey1) == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
if fail_count != 0 {
|
||||
fmt.Printf("ERROR: Accepted signature for %v of %v random messages\n", fail_count, TESTS)
|
||||
}
|
||||
}
|
19
crypto/secp256k1/secp256k1/COPYING
Normal file
19
crypto/secp256k1/secp256k1/COPYING
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2013 Pieter Wuille
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
55
crypto/secp256k1/secp256k1/Makefile
Normal file
55
crypto/secp256k1/secp256k1/Makefile
Normal file
@ -0,0 +1,55 @@
|
||||
$(shell CC=$(CC) YASM=$(YASM) ./configure)
|
||||
include config.mk
|
||||
|
||||
FILES := src/*.h src/impl/*.h
|
||||
|
||||
JAVA_FILES := src/java/org_bitcoin_NativeSecp256k1.h src/java/org_bitcoin_NativeSecp256k1.c
|
||||
|
||||
OBJS :=
|
||||
|
||||
ifeq ($(USE_ASM), 1)
|
||||
OBJS := $(OBJS) obj/field_5x$(HAVE_LIMB)_asm.o
|
||||
endif
|
||||
STD="gnu99"
|
||||
|
||||
default: tests libsecp256k1.a libsecp256k1.so
|
||||
|
||||
clean:
|
||||
rm -rf obj/*.o bench tests *.a *.so config.mk
|
||||
|
||||
obj/field_5x52_asm.o: src/field_5x52_asm.asm
|
||||
$(YASM) -f elf64 -o obj/field_5x52_asm.o src/field_5x52_asm.asm
|
||||
|
||||
obj/field_5x64_asm.o: src/field_5x64_asm.asm
|
||||
$(YASM) -f elf64 -o obj/field_5x64_asm.o src/field_5x64_asm.asm
|
||||
|
||||
obj/secp256k1.o: $(FILES) src/secp256k1.c include/secp256k1.h
|
||||
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) -DNDEBUG -$(OPTLEVEL) src/secp256k1.c -c -o obj/secp256k1.o
|
||||
|
||||
bench: $(FILES) src/bench.c $(OBJS)
|
||||
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DNDEBUG -$(OPTLEVEL) src/bench.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o bench
|
||||
|
||||
tests: $(FILES) src/tests.c $(OBJS)
|
||||
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY -fstack-protector-all -$(OPTLEVEL) -ggdb3 src/tests.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests
|
||||
|
||||
tests_fuzzer: $(FILES) src/tests_fuzzer.c obj/secp256k1.o $(OBJS)
|
||||
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY -fstack-protector-all -$(OPTLEVEL) -ggdb3 src/tests_fuzzer.c $(OBJS) obj/secp256k1.o $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests_fuzzer
|
||||
|
||||
coverage: $(FILES) src/tests.c $(OBJS)
|
||||
rm -rf tests.gcno tests.gcda tests_cov
|
||||
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY --coverage -$(OPTLEVEL) -g src/tests.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests_cov
|
||||
rm -rf lcov
|
||||
mkdir -p lcov
|
||||
cd lcov; lcov --directory ../ --zerocounters
|
||||
cd lcov; ../tests_cov
|
||||
cd lcov; lcov --directory ../ --capture --output-file secp256k1.info
|
||||
cd lcov; genhtml -o . secp256k1.info
|
||||
|
||||
libsecp256k1.a: obj/secp256k1.o $(OBJS)
|
||||
$(AR) -rs $@ $(OBJS) obj/secp256k1.o
|
||||
|
||||
libsecp256k1.so: obj/secp256k1.o $(OBJS)
|
||||
$(CC) -std=$(STD) $(LDFLAGS_EXTRA) $(OBJS) obj/secp256k1.o -shared -o libsecp256k1.so
|
||||
|
||||
libjavasecp256k1.so: $(OBJS) obj/secp256k1.o $(JAVA_FILES)
|
||||
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) -DNDEBUG -$(OPTLEVEL) -I. src/java/org_bitcoin_NativeSecp256k1.c $(LDFLAGS_EXTRA) $(OBJS) obj/secp256k1.o -shared -o libjavasecp256k1.so
|
3
crypto/secp256k1/secp256k1/TODO
Normal file
3
crypto/secp256k1/secp256k1/TODO
Normal file
@ -0,0 +1,3 @@
|
||||
* Unit tests for fieldelem/groupelem, including ones intended to
|
||||
trigger fieldelem's boundary cases.
|
||||
* Complete constant-time operations for signing/keygen
|
9
crypto/secp256k1/secp256k1/config.mk
Normal file
9
crypto/secp256k1/secp256k1/config.mk
Normal file
@ -0,0 +1,9 @@
|
||||
CC=cc
|
||||
YASM=yasm
|
||||
CFLAGS_EXTRA=-DUSE_FIELD_5X52 -DUSE_FIELD_5X52_ASM -DUSE_NUM_GMP -DUSE_FIELD_INV_NUM
|
||||
CFLAGS_TEST_EXTRA=-DENABLE_OPENSSL_TESTS
|
||||
LDFLAGS_EXTRA=-lgmp
|
||||
LDFLAGS_TEST_EXTRA=-lcrypto
|
||||
USE_ASM=1
|
||||
HAVE_LIMB=52
|
||||
OPTLEVEL=O2
|
175
crypto/secp256k1/secp256k1/configure
vendored
Executable file
175
crypto/secp256k1/secp256k1/configure
vendored
Executable file
@ -0,0 +1,175 @@
|
||||
#!/bin/sh
|
||||
|
||||
if test -f config.mk; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$CC"; then
|
||||
CC=cc
|
||||
fi
|
||||
|
||||
if test -z "$YASM"; then
|
||||
YASM=yasm
|
||||
fi
|
||||
|
||||
# test yasm
|
||||
$YASM -f elf64 -o /tmp/secp256k1-$$.o - <<EOF
|
||||
BITS 64
|
||||
GLOBAL testyasm
|
||||
ALIGN 32
|
||||
testyasm:
|
||||
xor r9,r9
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
$CC $CFLAGS -std=c99 -x c -c - -o /tmp/secp256k1-$$-2.o 2>/dev/null <<EOF
|
||||
void __attribute__ ((sysv_abi)) testyasm(void);
|
||||
int main() {
|
||||
testyasm();
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
$CC $CFLAGS -std=c99 /tmp/secp256k1-$$-2.o /tmp/secp256k1-$$.o -o /dev/null 2>/dev/null
|
||||
if [ "$?" = 0 ]; then
|
||||
HAVE_YASM=1
|
||||
fi
|
||||
rm -rf /tmp/secp256k1-$$-2.o /tmp/secp256k1-$$.o
|
||||
fi
|
||||
|
||||
# test openssl
|
||||
HAVE_OPENSSL=0
|
||||
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lcrypto 2>/dev/null <<EOF
|
||||
#include <openssl/bn.h>
|
||||
int main() {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
HAVE_OPENSSL=1
|
||||
fi
|
||||
|
||||
# test openssl/EC
|
||||
HAVE_OPENSSL_EC=0
|
||||
if [ "$HAVE_OPENSSL" = "1" ]; then
|
||||
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lcrypto 2>/dev/null <<EOF
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
int main() {
|
||||
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
|
||||
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
|
||||
EC_KEY_free(eckey);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
HAVE_OPENSSL_EC=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# test gmp
|
||||
HAVE_GMP=0
|
||||
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lgmp 2>/dev/null <<EOF
|
||||
#include <gmp.h>
|
||||
int main() {
|
||||
mpz_t n;
|
||||
mpz_init(n);
|
||||
mpz_clear(n);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
HAVE_GMP=1
|
||||
fi
|
||||
|
||||
# test __int128
|
||||
HAVE_INT128=0
|
||||
$CC $CFLAGS -std=c99 -x c - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <stdint.h>
|
||||
int main() {
|
||||
__int128 x = 0;
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
HAVE_INT128=1
|
||||
fi
|
||||
|
||||
#default limb size
|
||||
HAVE_LIMB=52
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--no-yasm)
|
||||
HAVE_YASM=0
|
||||
;;
|
||||
--no-gmp)
|
||||
HAVE_GMP=0
|
||||
;;
|
||||
--no-openssl)
|
||||
HAVE_OPENSSL=0
|
||||
;;
|
||||
--use-5x64)
|
||||
HAVE_LIMB=64
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
LINK_OPENSSL=0
|
||||
LINK_GMP=0
|
||||
USE_ASM=0
|
||||
|
||||
# select field implementation
|
||||
if [ "$HAVE_YASM" = "1" ]; then
|
||||
CFLAGS_FIELD="-DUSE_FIELD_5X$HAVE_LIMB -DUSE_FIELD_5X${HAVE_LIMB}_ASM"
|
||||
USE_ASM=1
|
||||
elif [ "$HAVE_INT128" = "1" ]; then
|
||||
CFLAGS_FIELD="-DUSE_FIELD_5X$HAVE_LIMB -DUSE_FIELD_5X${HAVE_LIMB}_INT128"
|
||||
elif [ "$HAVE_GMP" = "1" ]; then
|
||||
CFLAGS_FIELD="-DUSE_FIELD_GMP"
|
||||
LINK_GMP=1
|
||||
else
|
||||
CFLAGS_FIELD="-DUSE_FIELD_10X26"
|
||||
fi
|
||||
|
||||
# select num implementation
|
||||
if [ "$HAVE_GMP" = "1" ]; then
|
||||
CFLAGS_NUM="-DUSE_NUM_GMP -DUSE_FIELD_INV_NUM"
|
||||
LINK_GMP=1
|
||||
elif [ "$HAVE_OPENSSL" = "1" ]; then
|
||||
CFLAGS_NUM="-DUSE_NUM_OPENSSL -DUSE_FIELD_INV_BUILTIN"
|
||||
LINK_OPENSSL=1
|
||||
else
|
||||
echo "No usable num implementation found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CFLAGS_EXTRA="$CFLAGS_FIELD $CFLAGS_NUM"
|
||||
LDFLAGS_EXTRA=""
|
||||
if [ "$LINK_GMP" = "1" ]; then
|
||||
LDFLAGS_EXTRA="-lgmp"
|
||||
fi
|
||||
if [ "$LINK_OPENSSL" = "1" ]; then
|
||||
LDFLAGS_EXTRA="-lcrypto"
|
||||
else
|
||||
if [ "$HAVE_OPENSSL_EC" = "1" ]; then
|
||||
LDFLAGS_TEST_EXTRA="-lcrypto"
|
||||
fi
|
||||
fi
|
||||
|
||||
CFLAGS_TEST_EXTRA=""
|
||||
if [ "$HAVE_OPENSSL_EC" = "1" ]; then
|
||||
CFLAGS_TEST_EXTRA="-DENABLE_OPENSSL_TESTS"
|
||||
fi
|
||||
|
||||
echo "CC=$CC" > config.mk
|
||||
echo "YASM=$YASM" >>config.mk
|
||||
echo "CFLAGS_EXTRA=$CFLAGS_EXTRA" >> config.mk
|
||||
echo "CFLAGS_TEST_EXTRA=$CFLAGS_TEST_EXTRA" >> config.mk
|
||||
echo "LDFLAGS_EXTRA=$LDFLAGS_EXTRA" >> config.mk
|
||||
echo "LDFLAGS_TEST_EXTRA=$LDFLAGS_TEST_EXTRA" >> config.mk
|
||||
echo "USE_ASM=$USE_ASM" >>config.mk
|
||||
echo "HAVE_LIMB=$HAVE_LIMB" >>config.mk
|
||||
echo "OPTLEVEL=O2" >>config.mk
|
121
crypto/secp256k1/secp256k1/include/secp256k1.h
Normal file
121
crypto/secp256k1/secp256k1/include/secp256k1.h
Normal file
@ -0,0 +1,121 @@
|
||||
#ifndef _SECP256K1_
|
||||
#define _SECP256K1_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Initialize the library. This may take some time (10-100 ms).
|
||||
* You need to call this before calling any other function.
|
||||
* It cannot run in parallel with any other functions, but once
|
||||
* secp256k1_start() returns, all other functions are thread-safe.
|
||||
*/
|
||||
void secp256k1_start(void);
|
||||
|
||||
/** Free all memory associated with this library. After this, no
|
||||
* functions can be called anymore, except secp256k1_start()
|
||||
*/
|
||||
void secp256k1_stop(void);
|
||||
|
||||
/** Verify an ECDSA signature.
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect signature
|
||||
* -1: invalid public key
|
||||
* -2: invalid signature
|
||||
*/
|
||||
int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen,
|
||||
const unsigned char *sig, int siglen,
|
||||
const unsigned char *pubkey, int pubkeylen);
|
||||
|
||||
/** Create an ECDSA signature.
|
||||
* Returns: 1: signature created
|
||||
* 0: nonce invalid, try another one
|
||||
* In: msg: the message being signed
|
||||
* msglen: the length of the message being signed
|
||||
* seckey: pointer to a 32-byte secret key (assumed to be valid)
|
||||
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
|
||||
* Out: sig: pointer to a 72-byte array where the signature will be placed.
|
||||
* siglen: pointer to an int, which will be updated to the signature length (<=72).
|
||||
*/
|
||||
int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen,
|
||||
unsigned char *sig, int *siglen,
|
||||
const unsigned char *seckey,
|
||||
const unsigned char *nonce);
|
||||
|
||||
/** Create a compact ECDSA signature (64 byte + recovery id).
|
||||
* Returns: 1: signature created
|
||||
* 0: nonce invalid, try another one
|
||||
* In: msg: the message being signed
|
||||
* msglen: the length of the message being signed
|
||||
* seckey: pointer to a 32-byte secret key (assumed to be valid)
|
||||
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
|
||||
* Out: sig: pointer to a 64-byte array where the signature will be placed.
|
||||
* recid: pointer to an int, which will be updated to contain the recovery id.
|
||||
*/
|
||||
int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *seckey,
|
||||
const unsigned char *nonce,
|
||||
int *recid);
|
||||
|
||||
/** Recover an ECDSA public key from a compact signature.
|
||||
* Returns: 1: public key succesfully recovered (which guarantees a correct signature).
|
||||
* 0: otherwise.
|
||||
* In: msg: the message assumed to be signed
|
||||
* msglen: the length of the message
|
||||
* sig64: signature as 64 byte array
|
||||
* compressed: whether to recover a compressed or uncompressed pubkey
|
||||
* recid: the recovery id (as returned by ecdsa_sign_compact)
|
||||
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
|
||||
* pubkeylen: pointer to an int that will contain the pubkey length.
|
||||
*/
|
||||
|
||||
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
|
||||
const unsigned char *sig64,
|
||||
unsigned char *pubkey, int *pubkeylen,
|
||||
int compressed, int recid);
|
||||
|
||||
/** Verify an ECDSA secret key.
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* In: seckey: pointer to a 32-byte secret key
|
||||
*/
|
||||
int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey);
|
||||
|
||||
/** Just validate a public key.
|
||||
* Returns: 1: valid public key
|
||||
* 0: invalid public key
|
||||
*/
|
||||
int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen);
|
||||
|
||||
/** Compute the public key for a secret key.
|
||||
* In: compressed: whether the computed public key should be compressed
|
||||
* seckey: pointer to a 32-byte private key.
|
||||
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
|
||||
* area to store the public key.
|
||||
* pubkeylen: pointer to int that will be updated to contains the pubkey's
|
||||
* length.
|
||||
* Returns: 1: secret was valid, public key stores
|
||||
* 0: secret was invalid, try again.
|
||||
*/
|
||||
int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
|
||||
|
||||
int secp256k1_ecdsa_pubkey_decompress(unsigned char *pubkey, int *pubkeylen);
|
||||
|
||||
int secp256k1_ecdsa_privkey_export(const unsigned char *seckey,
|
||||
unsigned char *privkey, int *privkeylen,
|
||||
int compressed);
|
||||
|
||||
int secp256k1_ecdsa_privkey_import(unsigned char *seckey,
|
||||
const unsigned char *privkey, int privkeylen);
|
||||
|
||||
int secp256k1_ecdsa_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak);
|
||||
int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak);
|
||||
int secp256k1_ecdsa_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak);
|
||||
int secp256k1_ecdsa_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
64
crypto/secp256k1/secp256k1/src/bench.c
Normal file
64
crypto/secp256k1/secp256k1/src/bench.c
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "impl/num.h"
|
||||
#include "impl/field.h"
|
||||
#include "impl/group.h"
|
||||
#include "impl/ecmult.h"
|
||||
#include "impl/ecdsa.h"
|
||||
#include "impl/util.h"
|
||||
|
||||
void random_num_order(secp256k1_num_t *num) {
|
||||
do {
|
||||
unsigned char b32[32];
|
||||
secp256k1_rand256(b32);
|
||||
secp256k1_num_set_bin(num, b32, 32);
|
||||
if (secp256k1_num_is_zero(num))
|
||||
continue;
|
||||
if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
|
||||
continue;
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
secp256k1_fe_start();
|
||||
secp256k1_ge_start();
|
||||
secp256k1_ecmult_start();
|
||||
|
||||
secp256k1_fe_t x;
|
||||
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
|
||||
secp256k1_num_t r, s, m;
|
||||
secp256k1_num_init(&r);
|
||||
secp256k1_num_init(&s);
|
||||
secp256k1_num_init(&m);
|
||||
secp256k1_ecdsa_sig_t sig;
|
||||
secp256k1_ecdsa_sig_init(&sig);
|
||||
secp256k1_fe_set_hex(&x, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
|
||||
int cnt = 0;
|
||||
int good = 0;
|
||||
for (int i=0; i<1000000; i++) {
|
||||
random_num_order(&r);
|
||||
random_num_order(&s);
|
||||
random_num_order(&m);
|
||||
secp256k1_ecdsa_sig_set_rs(&sig, &r, &s);
|
||||
secp256k1_ge_t pubkey; secp256k1_ge_set_xo(&pubkey, &x, 1);
|
||||
if (secp256k1_ge_is_valid(&pubkey)) {
|
||||
cnt++;
|
||||
good += secp256k1_ecdsa_sig_verify(&sig, &pubkey, &m);
|
||||
}
|
||||
}
|
||||
printf("%i/%i\n", good, cnt);
|
||||
secp256k1_num_free(&r);
|
||||
secp256k1_num_free(&s);
|
||||
secp256k1_num_free(&m);
|
||||
secp256k1_ecdsa_sig_free(&sig);
|
||||
|
||||
secp256k1_ecmult_stop();
|
||||
secp256k1_ge_stop();
|
||||
secp256k1_fe_stop();
|
||||
return 0;
|
||||
}
|
28
crypto/secp256k1/secp256k1/src/ecdsa.h
Normal file
28
crypto/secp256k1/secp256k1/src/ecdsa.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_ECDSA_
|
||||
#define _SECP256K1_ECDSA_
|
||||
|
||||
#include "num.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_num_t r, s;
|
||||
} secp256k1_ecdsa_sig_t;
|
||||
|
||||
void static secp256k1_ecdsa_sig_init(secp256k1_ecdsa_sig_t *r);
|
||||
void static secp256k1_ecdsa_sig_free(secp256k1_ecdsa_sig_t *r);
|
||||
|
||||
int static secp256k1_ecdsa_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size);
|
||||
void static secp256k1_ecdsa_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed);
|
||||
int static secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
|
||||
int static secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
|
||||
int static secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message);
|
||||
int static secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *seckey, const secp256k1_num_t *message, const secp256k1_num_t *nonce, int *recid);
|
||||
int static secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid);
|
||||
void static secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s);
|
||||
int static secp256k1_ecdsa_privkey_parse(secp256k1_num_t *key, const unsigned char *privkey, int privkeylen);
|
||||
int static secp256k1_ecdsa_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_num_t *key, int compressed);
|
||||
|
||||
#endif
|
19
crypto/secp256k1/secp256k1/src/ecmult.h
Normal file
19
crypto/secp256k1/secp256k1/src/ecmult.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_ECMULT_
|
||||
#define _SECP256K1_ECMULT_
|
||||
|
||||
#include "num.h"
|
||||
#include "group.h"
|
||||
|
||||
static void secp256k1_ecmult_start(void);
|
||||
static void secp256k1_ecmult_stop(void);
|
||||
|
||||
/** Multiply with the generator: R = a*G */
|
||||
static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *a);
|
||||
/** Double multiply: R = na*A + ng*G */
|
||||
static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng);
|
||||
|
||||
#endif
|
101
crypto/secp256k1/secp256k1/src/field.h
Normal file
101
crypto/secp256k1/secp256k1/src/field.h
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_
|
||||
#define _SECP256K1_FIELD_
|
||||
|
||||
/** Field element module.
|
||||
*
|
||||
* Field elements can be represented in several ways, but code accessing
|
||||
* it (and implementations) need to take certain properaties into account:
|
||||
* - Each field element can be normalized or not.
|
||||
* - Each field element has a magnitude, which represents how far away
|
||||
* its representation is away from normalization. Normalized elements
|
||||
* always have a magnitude of 1, but a magnitude of 1 doesn't imply
|
||||
* normality.
|
||||
*/
|
||||
|
||||
#if defined(USE_FIELD_GMP)
|
||||
#include "field_gmp.h"
|
||||
#elif defined(USE_FIELD_10X26)
|
||||
#include "field_10x26.h"
|
||||
#elif defined(USE_FIELD_5X52)
|
||||
#include "field_5x52.h"
|
||||
#elif defined(USE_FIELD_5X64)
|
||||
#include "field_5x64.h"
|
||||
#else
|
||||
#error "Please select field implementation"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
secp256k1_num_t p;
|
||||
} secp256k1_fe_consts_t;
|
||||
|
||||
static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL;
|
||||
|
||||
/** Initialize field element precomputation data. */
|
||||
void static secp256k1_fe_start(void);
|
||||
|
||||
/** Unload field element precomputation data. */
|
||||
void static secp256k1_fe_stop(void);
|
||||
|
||||
/** Normalize a field element. */
|
||||
void static secp256k1_fe_normalize(secp256k1_fe_t *r);
|
||||
|
||||
/** Set a field element equal to a small integer. Resulting field element is normalized. */
|
||||
void static secp256k1_fe_set_int(secp256k1_fe_t *r, int a);
|
||||
|
||||
/** Verify whether a field element is zero. Requires the input to be normalized. */
|
||||
int static secp256k1_fe_is_zero(const secp256k1_fe_t *a);
|
||||
|
||||
/** Check the "oddness" of a field element. Requires the input to be normalized. */
|
||||
int static secp256k1_fe_is_odd(const secp256k1_fe_t *a);
|
||||
|
||||
/** Compare two field elements. Requires both inputs to be normalized */
|
||||
int static secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
|
||||
|
||||
/** Set a field element equal to 32-byte big endian value. Resulting field element is normalized. */
|
||||
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a);
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a);
|
||||
|
||||
/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
|
||||
* as an argument. The magnitude of the output is one higher. */
|
||||
void static secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m);
|
||||
|
||||
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
|
||||
* small integer. */
|
||||
void static secp256k1_fe_mul_int(secp256k1_fe_t *r, int a);
|
||||
|
||||
/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
|
||||
void static secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a);
|
||||
|
||||
/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
|
||||
* The output magnitude is 1 (but not guaranteed to be normalized). */
|
||||
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b);
|
||||
|
||||
/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
|
||||
* The output magnitude is 1 (but not guaranteed to be normalized). */
|
||||
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a);
|
||||
|
||||
/** Sets a field element to be the (modular) square root of another. Requires the inputs' magnitude to
|
||||
* be at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
|
||||
void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a);
|
||||
|
||||
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
|
||||
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
|
||||
void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a);
|
||||
|
||||
/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
|
||||
void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a);
|
||||
|
||||
|
||||
/** Convert a field element to a hexadecimal string. */
|
||||
void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a);
|
||||
|
||||
/** Convert a hexadecimal string to a field element. */
|
||||
void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen);
|
||||
|
||||
#endif
|
19
crypto/secp256k1/secp256k1/src/field_10x26.h
Normal file
19
crypto/secp256k1/secp256k1/src/field_10x26.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_
|
||||
#define _SECP256K1_FIELD_REPR_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
// X = sum(i=0..9, elem[i]*2^26) mod n
|
||||
uint32_t n[10];
|
||||
#ifdef VERIFY
|
||||
int magnitude;
|
||||
int normalized;
|
||||
#endif
|
||||
} secp256k1_fe_t;
|
||||
|
||||
#endif
|
19
crypto/secp256k1/secp256k1/src/field_5x52.h
Normal file
19
crypto/secp256k1/secp256k1/src/field_5x52.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_
|
||||
#define _SECP256K1_FIELD_REPR_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
// X = sum(i=0..4, elem[i]*2^52) mod n
|
||||
uint64_t n[5];
|
||||
#ifdef VERIFY
|
||||
int magnitude;
|
||||
int normalized;
|
||||
#endif
|
||||
} secp256k1_fe_t;
|
||||
|
||||
#endif
|
463
crypto/secp256k1/secp256k1/src/field_5x52_asm.asm
Normal file
463
crypto/secp256k1/secp256k1/src/field_5x52_asm.asm
Normal file
@ -0,0 +1,463 @@
|
||||
;; Added by Diederik Huys, March 2013
|
||||
;;
|
||||
;; Provided public procedures:
|
||||
;; secp256k1_fe_mul_inner
|
||||
;; secp256k1_fe_sqr_inner
|
||||
;;
|
||||
;; Needed tools: YASM (http://yasm.tortall.net)
|
||||
;;
|
||||
;;
|
||||
|
||||
BITS 64
|
||||
|
||||
;; Procedure ExSetMult
|
||||
;; Register Layout:
|
||||
;; INPUT: rdi = a->n
|
||||
;; rsi = b->n
|
||||
;; rdx = r->a
|
||||
;;
|
||||
;; INTERNAL: rdx:rax = multiplication accumulator
|
||||
;; r9:r8 = c
|
||||
;; r10-r13 = t0-t3
|
||||
;; r14 = b.n[0] / t4
|
||||
;; r15 = b.n[1] / t5
|
||||
;; rbx = b.n[2] / t6
|
||||
;; rcx = b.n[3] / t7
|
||||
;; rbp = Constant 0FFFFFFFFFFFFFh / t8
|
||||
;; rsi = b.n / b.n[4] / t9
|
||||
|
||||
GLOBAL secp256k1_fe_mul_inner
|
||||
ALIGN 32
|
||||
secp256k1_fe_mul_inner:
|
||||
push rbp
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
push rdx
|
||||
mov r14,[rsi+8*0] ; preload b.n[0]. This will be the case until
|
||||
; b.n[0] is no longer needed, then we reassign
|
||||
; r14 to t4
|
||||
;; c=a.n[0] * b.n[0]
|
||||
mov rax,[rdi+0*8] ; load a.n[0]
|
||||
mov rbp,0FFFFFFFFFFFFFh
|
||||
mul r14 ; rdx:rax=a.n[0]*b.n[0]
|
||||
mov r15,[rsi+1*8]
|
||||
mov r10,rbp ; load modulus into target register for t0
|
||||
mov r8,rax
|
||||
and r10,rax ; only need lower qword of c
|
||||
shrd r8,rdx,52
|
||||
xor r9,r9 ; c < 2^64, so we ditch the HO part
|
||||
|
||||
;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0]
|
||||
mov rax,[rdi+0*8]
|
||||
mul r15
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+1*8]
|
||||
mul r14
|
||||
mov r11,rbp
|
||||
mov rbx,[rsi+2*8]
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r11,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[0 1 2] * b.n[2 1 0]
|
||||
mov rax,[rdi+0*8]
|
||||
mul rbx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+1*8]
|
||||
mul r15
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+2*8]
|
||||
mul r14
|
||||
mov r12,rbp
|
||||
mov rcx,[rsi+3*8]
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r12,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[0 1 2 3] * b.n[3 2 1 0]
|
||||
mov rax,[rdi+0*8]
|
||||
mul rcx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+1*8]
|
||||
mul rbx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+2*8]
|
||||
mul r15
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+3*8]
|
||||
mul r14
|
||||
mov r13,rbp
|
||||
mov rsi,[rsi+4*8] ; load b.n[4] and destroy pointer
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r13,r8
|
||||
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
|
||||
;; c+=a.n[0 1 2 3 4] * b.n[4 3 2 1 0]
|
||||
mov rax,[rdi+0*8]
|
||||
mul rsi
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+1*8]
|
||||
mul rcx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+2*8]
|
||||
mul rbx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+3*8]
|
||||
mul r15
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+4*8]
|
||||
mul r14
|
||||
mov r14,rbp ; load modulus into t4 and destroy a.n[0]
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r14,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[1 2 3 4] * b.n[4 3 2 1]
|
||||
mov rax,[rdi+1*8]
|
||||
mul rsi
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+2*8]
|
||||
mul rcx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+3*8]
|
||||
mul rbx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+4*8]
|
||||
mul r15
|
||||
mov r15,rbp
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
and r15,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[2 3 4] * b.n[4 3 2]
|
||||
mov rax,[rdi+2*8]
|
||||
mul rsi
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+3*8]
|
||||
mul rcx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+4*8]
|
||||
mul rbx
|
||||
mov rbx,rbp
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
and rbx,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[3 4] * b.n[4 3]
|
||||
mov rax,[rdi+3*8]
|
||||
mul rsi
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,[rdi+4*8]
|
||||
mul rcx
|
||||
mov rcx,rbp
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and rcx,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[4] * b.n[4]
|
||||
mov rax,[rdi+4*8]
|
||||
mul rsi
|
||||
;; mov rbp,rbp ; modulus already there!
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and rbp,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
mov rsi,r8 ; load c into t9 and destroy b.n[4]
|
||||
|
||||
;; *******************************************************
|
||||
common_exit_norm:
|
||||
mov rdi,01000003D10h ; load constant
|
||||
|
||||
mov rax,r15 ; get t5
|
||||
mul rdi
|
||||
add rax,r10 ; +t0
|
||||
adc rdx,0
|
||||
mov r10,0FFFFFFFFFFFFFh ; modulus. Sadly, we ran out of registers!
|
||||
mov r8,rax ; +c
|
||||
and r10,rax
|
||||
shrd r8,rdx,52
|
||||
xor r9,r9
|
||||
|
||||
mov rax,rbx ; get t6
|
||||
mul rdi
|
||||
add rax,r11 ; +t1
|
||||
adc rdx,0
|
||||
mov r11,0FFFFFFFFFFFFFh ; modulus
|
||||
add r8,rax ; +c
|
||||
adc r9,rdx
|
||||
and r11,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
mov rax,rcx ; get t7
|
||||
mul rdi
|
||||
add rax,r12 ; +t2
|
||||
adc rdx,0
|
||||
pop rbx ; retrieve pointer to this.n
|
||||
mov r12,0FFFFFFFFFFFFFh ; modulus
|
||||
add r8,rax ; +c
|
||||
adc r9,rdx
|
||||
and r12,r8
|
||||
mov [rbx+2*8],r12 ; mov into this.n[2]
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
mov rax,rbp ; get t8
|
||||
mul rdi
|
||||
add rax,r13 ; +t3
|
||||
adc rdx,0
|
||||
mov r13,0FFFFFFFFFFFFFh ; modulus
|
||||
add r8,rax ; +c
|
||||
adc r9,rdx
|
||||
and r13,r8
|
||||
mov [rbx+3*8],r13 ; -> this.n[3]
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
mov rax,rsi ; get t9
|
||||
mul rdi
|
||||
add rax,r14 ; +t4
|
||||
adc rdx,0
|
||||
mov r14,0FFFFFFFFFFFFh ; !!!
|
||||
add r8,rax ; +c
|
||||
adc r9,rdx
|
||||
and r14,r8
|
||||
mov [rbx+4*8],r14 ; -> this.n[4]
|
||||
shrd r8,r9,48 ; !!!
|
||||
xor r9,r9
|
||||
|
||||
mov rax,01000003D1h
|
||||
mul r8
|
||||
add rax,r10
|
||||
adc rdx,0
|
||||
mov r10,0FFFFFFFFFFFFFh ; modulus
|
||||
mov r8,rax
|
||||
and rax,r10
|
||||
shrd r8,rdx,52
|
||||
mov [rbx+0*8],rax ; -> this.n[0]
|
||||
add r8,r11
|
||||
mov [rbx+1*8],r8 ; -> this.n[1]
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
|
||||
;; PROC ExSetSquare
|
||||
;; Register Layout:
|
||||
;; INPUT: rdi = a.n
|
||||
;; rsi = this.a
|
||||
;; INTERNAL: rdx:rax = multiplication accumulator
|
||||
;; r9:r8 = c
|
||||
;; r10-r13 = t0-t3
|
||||
;; r14 = a.n[0] / t4
|
||||
;; r15 = a.n[1] / t5
|
||||
;; rbx = a.n[2] / t6
|
||||
;; rcx = a.n[3] / t7
|
||||
;; rbp = 0FFFFFFFFFFFFFh / t8
|
||||
;; rsi = a.n[4] / t9
|
||||
GLOBAL secp256k1_fe_sqr_inner
|
||||
ALIGN 32
|
||||
secp256k1_fe_sqr_inner:
|
||||
push rbp
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
push rsi
|
||||
mov rbp,0FFFFFFFFFFFFFh
|
||||
|
||||
;; c=a.n[0] * a.n[0]
|
||||
mov r14,[rdi+0*8] ; r14=a.n[0]
|
||||
mov r10,rbp ; modulus
|
||||
mov rax,r14
|
||||
mul rax
|
||||
mov r15,[rdi+1*8] ; a.n[1]
|
||||
add r14,r14 ; r14=2*a.n[0]
|
||||
mov r8,rax
|
||||
and r10,rax ; only need lower qword
|
||||
shrd r8,rdx,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=2*a.n[0] * a.n[1]
|
||||
mov rax,r14 ; r14=2*a.n[0]
|
||||
mul r15
|
||||
mov rbx,[rdi+2*8] ; rbx=a.n[2]
|
||||
mov r11,rbp ; modulus
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r11,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1]
|
||||
mov rax,r14
|
||||
mul rbx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,r15
|
||||
mov r12,rbp ; modulus
|
||||
mul rax
|
||||
mov rcx,[rdi+3*8] ; rcx=a.n[3]
|
||||
add r15,r15 ; r15=a.n[1]*2
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r12,r8 ; only need lower dword
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2]
|
||||
mov rax,r14
|
||||
mul rcx
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,r15 ; rax=2*a.n[1]
|
||||
mov r13,rbp ; modulus
|
||||
mul rbx
|
||||
mov rsi,[rdi+4*8] ; rsi=a.n[4]
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r13,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=2*a.n[0]*a.n[4]+2*a.n[1]*a.n[3]+a.n[2]*a.n[2]
|
||||
mov rax,r14 ; last time we need 2*a.n[0]
|
||||
mul rsi
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,r15
|
||||
mul rcx
|
||||
mov r14,rbp ; modulus
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,rbx
|
||||
mul rax
|
||||
add rbx,rbx ; rcx=2*a.n[2]
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r14,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=2*a.n[1]*a.n[4]+2*a.n[2]*a.n[3]
|
||||
mov rax,r15 ; last time we need 2*a.n[1]
|
||||
mul rsi
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,rbx
|
||||
mul rcx
|
||||
mov r15,rbp ; modulus
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and r15,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=2*a.n[2]*a.n[4]+a.n[3]*a.n[3]
|
||||
mov rax,rbx ; last time we need 2*a.n[2]
|
||||
mul rsi
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
|
||||
mov rax,rcx ; a.n[3]
|
||||
mul rax
|
||||
mov rbx,rbp ; modulus
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and rbx,r8 ; only need lower dword
|
||||
lea rax,[2*rcx]
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=2*a.n[3]*a.n[4]
|
||||
mul rsi
|
||||
mov rcx,rbp ; modulus
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and rcx,r8 ; only need lower dword
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[4]*a.n[4]
|
||||
mov rax,rsi
|
||||
mul rax
|
||||
;; mov rbp,rbp ; modulus is already there!
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
and rbp,r8
|
||||
shrd r8,r9,52
|
||||
xor r9,r9
|
||||
|
||||
mov rsi,r8
|
||||
|
||||
;; *******************************************************
|
||||
jmp common_exit_norm
|
||||
end
|
||||
|
||||
|
19
crypto/secp256k1/secp256k1/src/field_5x64.h
Normal file
19
crypto/secp256k1/secp256k1/src/field_5x64.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_
|
||||
#define _SECP256K1_FIELD_REPR_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
// X = sum(i=0..4, elem[i]*2^64) mod n
|
||||
uint64_t n[5];
|
||||
#ifdef VERIFY
|
||||
int reduced; // n[4] == 0
|
||||
int normalized; // reduced and X < 2^256 - 0x100003D1
|
||||
#endif
|
||||
} secp256k1_fe_t;
|
||||
|
||||
#endif
|
332
crypto/secp256k1/secp256k1/src/field_5x64_asm.asm
Normal file
332
crypto/secp256k1/secp256k1/src/field_5x64_asm.asm
Normal file
@ -0,0 +1,332 @@
|
||||
;; Added by Diederik Huys, March 2013
|
||||
;;
|
||||
;; Provided public procedures:
|
||||
;; secp256k1_fe_mul_inner
|
||||
;; secp256k1_fe_sqr_inner
|
||||
;;
|
||||
;; Needed tools: YASM (http://yasm.tortall.net)
|
||||
;;
|
||||
;;
|
||||
|
||||
BITS 64
|
||||
|
||||
COMP_LIMB EQU 000000001000003D1h
|
||||
|
||||
;; Procedure ExSetMult
|
||||
;; Register Layout:
|
||||
;; INPUT: rdi = a->n
|
||||
;; rsi = b->n
|
||||
;; rdx = r->a
|
||||
;;
|
||||
;; INTERNAL: rdx:rax = multiplication accumulator
|
||||
;; r8-r10 = c0-c2
|
||||
;; r11-r15 = b.n[0]-b.n[4] / r3 - r7
|
||||
;; rbx = r0
|
||||
;; rcx = r1
|
||||
;; rbp = r2
|
||||
;;
|
||||
GLOBAL secp256k1_fe_mul_inner
|
||||
ALIGN 32
|
||||
secp256k1_fe_mul_inner:
|
||||
push rbp
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
push rdx
|
||||
|
||||
mov r11,[rsi+8*0] ; preload b.n[0]
|
||||
|
||||
;; step 1: mul_c2
|
||||
mov rax,[rdi+0*8] ; load a.n[0]
|
||||
mul r11 ; rdx:rax=a.n[0]*b.n[0]
|
||||
mov r12,[rsi+1*8] ; preload b.n[1]
|
||||
mov rbx,rax ; retire LO qword (r[0])
|
||||
mov r8,rdx ; save overflow
|
||||
xor r9,r9 ; overflow HO qwords
|
||||
xor r10,r10
|
||||
|
||||
;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0]
|
||||
mov rax,[rdi+0*8]
|
||||
mul r12
|
||||
mov r13,[rsi+2*8] ; preload b.n[2]
|
||||
add r8,rax ; still the same :-)
|
||||
adc r9,rdx ;
|
||||
adc r10,0 ; mmm...
|
||||
|
||||
mov rax,[rdi+1*8]
|
||||
mul r11
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
adc r10,0
|
||||
mov rcx,r8 ; retire r[1]
|
||||
xor r8,r8
|
||||
|
||||
;; c+=a.n[0 1 2] * b.n[2 1 0]
|
||||
mov rax,[rdi+0*8]
|
||||
mul r13
|
||||
mov r14,[rsi+3*8] ; preload b.n[3]
|
||||
add r9,rax
|
||||
adc r10,rdx
|
||||
adc r8,0
|
||||
|
||||
mov rax,[rdi+1*8]
|
||||
mul r12
|
||||
add r9,rax
|
||||
adc r10,rdx
|
||||
adc r8,0
|
||||
|
||||
mov rax,[rdi+2*8]
|
||||
mul r11
|
||||
add r9,rax
|
||||
adc r10,rdx
|
||||
adc r8,0
|
||||
mov rbp,r9 ; retire r[2]
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[0 1 2 3] * b.n[3 2 1 0]
|
||||
mov rax,[rdi+0*8]
|
||||
mul r14
|
||||
add r10,rax
|
||||
adc r8,rdx
|
||||
adc r9,0
|
||||
|
||||
mov rax,[rdi+1*8]
|
||||
mul r13
|
||||
add r10,rax
|
||||
adc r8,rdx
|
||||
adc r9,0
|
||||
|
||||
mov rax,[rdi+2*8]
|
||||
mul r12
|
||||
add r10,rax
|
||||
adc r8,rdx
|
||||
adc r9,0
|
||||
|
||||
mov rax,[rdi+3*8]
|
||||
mul r11
|
||||
add r10,rax
|
||||
adc r8,rdx
|
||||
adc r9,0
|
||||
mov r11,r10 ; retire r[3]
|
||||
xor r10,r10
|
||||
|
||||
;; c+=a.n[1 2 3] * b.n[3 2 1]
|
||||
mov rax,[rdi+1*8]
|
||||
mul r14
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
adc r10,0
|
||||
|
||||
mov rax,[rdi+2*8]
|
||||
mul r13
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
adc r10,0
|
||||
|
||||
mov rax,[rdi+3*8]
|
||||
mul r12
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
adc r10,0
|
||||
mov r12,r8 ; retire r[4]
|
||||
xor r8,r8
|
||||
|
||||
;; c+=a.n[2 3] * b.n[3 2]
|
||||
mov rax,[rdi+2*8]
|
||||
mul r14
|
||||
add r9,rax ; still the same :-)
|
||||
adc r10,rdx ;
|
||||
adc r8,0 ; mmm...
|
||||
|
||||
mov rax,[rdi+3*8]
|
||||
mul r13
|
||||
add r9,rax
|
||||
adc r10,rdx
|
||||
adc r8,0
|
||||
mov r13,r9 ; retire r[5]
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[3] * b.n[3]
|
||||
mov rax,[rdi+3*8]
|
||||
mul r14
|
||||
add r10,rax
|
||||
adc r8,rdx
|
||||
|
||||
mov r14,r10
|
||||
mov r15,r8
|
||||
|
||||
|
||||
;; *******************************************************
|
||||
common_exit_norm:
|
||||
mov rdi,COMP_LIMB
|
||||
mov rax,r12
|
||||
mul rdi
|
||||
add rax,rbx
|
||||
adc rcx,rdx
|
||||
pop rbx
|
||||
mov [rbx],rax
|
||||
|
||||
mov rax,r13 ; get r5
|
||||
mul rdi
|
||||
add rax,rcx ; +r1
|
||||
adc rbp,rdx
|
||||
mov [rbx+1*8],rax
|
||||
|
||||
mov rax,r14 ; get r6
|
||||
mul rdi
|
||||
add rax,rbp ; +r2
|
||||
adc r11,rdx
|
||||
mov [rbx+2*8],rax
|
||||
|
||||
mov rax,r15 ; get r7
|
||||
mul rdi
|
||||
add rax,r11 ; +r3
|
||||
adc rdx,0
|
||||
mov [rbx+3*8],rax
|
||||
mov [rbx+4*8],rdx
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
|
||||
;; PROC ExSetSquare
|
||||
;; Register Layout:
|
||||
;; INPUT: rdi = a.n
|
||||
;; rsi = this.a
|
||||
;; INTERNAL: rdx:rax = multiplication accumulator
|
||||
;; r8-r10 = c
|
||||
;; r11-r15 = a.n[0]-a.n[4] / r3-r7
|
||||
;; rbx = r0
|
||||
;; rcx = r1
|
||||
;; rbp = r2
|
||||
GLOBAL secp256k1_fe_sqr_inner
|
||||
|
||||
ALIGN 32
|
||||
secp256k1_fe_sqr_inner:
|
||||
push rbp
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
push rsi
|
||||
|
||||
mov r11,[rdi+8*0] ; preload a.n[0]
|
||||
|
||||
;; step 1: mul_c2
|
||||
mov rax,r11 ; load a.n[0]
|
||||
mul rax ; rdx:rax=a.n[0]²
|
||||
mov r12,[rdi+1*8] ; preload a.n[1]
|
||||
mov rbx,rax ; retire LO qword (r[0])
|
||||
mov r8,rdx ; save overflow
|
||||
xor r9,r9 ; overflow HO qwords
|
||||
xor r10,r10
|
||||
|
||||
;; c+=2*a.n[0] * a.n[1]
|
||||
mov rax,r11 ; load a.n[0]
|
||||
mul r12 ; rdx:rax=a.n[0] * a.n[1]
|
||||
mov r13,[rdi+2*8] ; preload a.n[2]
|
||||
add rax,rax ; rdx:rax*=2
|
||||
adc rdx,rdx
|
||||
adc r10,0
|
||||
add r8,rax ; still the same :-)
|
||||
adc r9,rdx
|
||||
adc r10,0 ; mmm...
|
||||
|
||||
mov rcx,r8 ; retire r[1]
|
||||
xor r8,r8
|
||||
|
||||
;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1]
|
||||
mov rax,r11 ; load a.n[0]
|
||||
mul r13 ; * a.n[2]
|
||||
mov r14,[rdi+3*8] ; preload a.n[3]
|
||||
add rax,rax ; rdx:rax*=2
|
||||
adc rdx,rdx
|
||||
adc r8,0
|
||||
add r9,rax
|
||||
adc r10,rdx
|
||||
adc r8,0
|
||||
|
||||
mov rax,r12
|
||||
mul rax
|
||||
add r9,rax
|
||||
adc r10,rdx
|
||||
adc r8,0
|
||||
|
||||
|
||||
mov rbp,r9
|
||||
xor r9,r9
|
||||
|
||||
;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2]
|
||||
mov rax,r11 ; load a.n[0]
|
||||
mul r14 ; * a.n[3]
|
||||
add rax,rax ; rdx:rax*=2
|
||||
adc rdx,rdx
|
||||
adc r9,0
|
||||
add r10,rax
|
||||
adc r8,rdx
|
||||
adc r9,0
|
||||
|
||||
mov rax,r12 ; load a.n[1]
|
||||
mul r13 ; * a.n[2]
|
||||
add rax,rax
|
||||
adc rdx,rdx
|
||||
adc r9,0
|
||||
add r10,rax
|
||||
adc r8,rdx
|
||||
adc r9,0
|
||||
|
||||
mov r11,r10
|
||||
xor r10,r10
|
||||
|
||||
;; c+=2*a.n[1]*a.n[3]+a.n[2]*a.n[2]
|
||||
mov rax,r12 ; load a.n[1]
|
||||
mul r14 ; * a.n[3]
|
||||
add rax,rax ; rdx:rax*=2
|
||||
adc rdx,rdx
|
||||
adc r10,0
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
adc r10,0
|
||||
|
||||
mov rax,r13
|
||||
mul rax
|
||||
add r8,rax
|
||||
adc r9,rdx
|
||||
adc r10,0
|
||||
|
||||
mov r12,r8
|
||||
xor r8,r8
|
||||
;; c+=2*a.n[2]*a.n[3]
|
||||
mov rax,r13 ; load a.n[2]
|
||||
mul r14 ; * a.n[3]
|
||||
add rax,rax ; rdx:rax*=2
|
||||
adc rdx,rdx
|
||||
adc r8,0
|
||||
add r9,rax
|
||||
adc r10,rdx
|
||||
adc r8,0
|
||||
|
||||
mov r13,r9
|
||||
xor r9,r9
|
||||
|
||||
;; c+=a.n[3]²
|
||||
mov rax,r14
|
||||
mul rax
|
||||
add r10,rax
|
||||
adc r8,rdx
|
||||
|
||||
mov r14,r10
|
||||
mov r15,r8
|
||||
|
||||
jmp common_exit_norm
|
||||
end
|
||||
|
||||
|
16
crypto/secp256k1/secp256k1/src/field_gmp.h
Normal file
16
crypto/secp256k1/secp256k1/src/field_gmp.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_
|
||||
#define _SECP256K1_FIELD_REPR_
|
||||
|
||||
#include <gmp.h>
|
||||
|
||||
#define FIELD_LIMBS ((256 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
|
||||
|
||||
typedef struct {
|
||||
mp_limb_t n[FIELD_LIMBS+1];
|
||||
} secp256k1_fe_t;
|
||||
|
||||
#endif
|
108
crypto/secp256k1/secp256k1/src/group.h
Normal file
108
crypto/secp256k1/secp256k1/src/group.h
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_GROUP_
|
||||
#define _SECP256K1_GROUP_
|
||||
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
|
||||
/** A group element of the secp256k1 curve, in affine coordinates. */
|
||||
typedef struct {
|
||||
secp256k1_fe_t x;
|
||||
secp256k1_fe_t y;
|
||||
int infinity; // whether this represents the point at infinity
|
||||
} secp256k1_ge_t;
|
||||
|
||||
/** A group element of the secp256k1 curve, in jacobian coordinates. */
|
||||
typedef struct {
|
||||
secp256k1_fe_t x; // actual X: x/z^2
|
||||
secp256k1_fe_t y; // actual Y: y/z^3
|
||||
secp256k1_fe_t z;
|
||||
int infinity; // whether this represents the point at infinity
|
||||
} secp256k1_gej_t;
|
||||
|
||||
/** Global constants related to the group */
|
||||
typedef struct {
|
||||
secp256k1_num_t order; // the order of the curve (= order of its generator)
|
||||
secp256k1_num_t half_order; // half the order of the curve (= order of its generator)
|
||||
secp256k1_ge_t g; // the generator point
|
||||
|
||||
// constants related to secp256k1's efficiently computable endomorphism
|
||||
secp256k1_fe_t beta;
|
||||
secp256k1_num_t lambda, a1b2, b1, a2;
|
||||
} secp256k1_ge_consts_t;
|
||||
|
||||
static const secp256k1_ge_consts_t *secp256k1_ge_consts = NULL;
|
||||
|
||||
/** Initialize the group module. */
|
||||
void static secp256k1_ge_start(void);
|
||||
|
||||
/** De-initialize the group module. */
|
||||
void static secp256k1_ge_stop(void);
|
||||
|
||||
/** Set a group element equal to the point at infinity */
|
||||
void static secp256k1_ge_set_infinity(secp256k1_ge_t *r);
|
||||
|
||||
/** Set a group element equal to the point with given X and Y coordinates */
|
||||
void static secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
|
||||
|
||||
/** Set a group element (jacobian) equal to the point with given X coordinate, and given oddness for Y.
|
||||
The result is not guaranteed to be valid. */
|
||||
void static secp256k1_ge_set_xo(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd);
|
||||
|
||||
/** Check whether a group element is the point at infinity. */
|
||||
int static secp256k1_ge_is_infinity(const secp256k1_ge_t *a);
|
||||
|
||||
/** Check whether a group element is valid (i.e., on the curve). */
|
||||
int static secp256k1_ge_is_valid(const secp256k1_ge_t *a);
|
||||
|
||||
void static secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a);
|
||||
|
||||
/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
|
||||
void static secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a);
|
||||
|
||||
/** Set a group element equal to another which is given in jacobian coordinates */
|
||||
void static secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a);
|
||||
|
||||
|
||||
/** Set a group element (jacobian) equal to the point at infinity. */
|
||||
void static secp256k1_gej_set_infinity(secp256k1_gej_t *r);
|
||||
|
||||
/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */
|
||||
void static secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
|
||||
|
||||
/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
|
||||
void static secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a);
|
||||
|
||||
/** Get the X coordinate of a group element (jacobian). */
|
||||
void static secp256k1_gej_get_x(secp256k1_fe_t *r, const secp256k1_gej_t *a);
|
||||
|
||||
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
|
||||
void static secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a);
|
||||
|
||||
/** Check whether a group element is the point at infinity. */
|
||||
int static secp256k1_gej_is_infinity(const secp256k1_gej_t *a);
|
||||
|
||||
/** Set r equal to the double of a. */
|
||||
void static secp256k1_gej_double(secp256k1_gej_t *r, const secp256k1_gej_t *a);
|
||||
|
||||
/** Set r equal to the sum of a and b. */
|
||||
void static secp256k1_gej_add(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b);
|
||||
|
||||
/** Set r equal to the sum of a and b (with b given in jacobian coordinates). This is more efficient
|
||||
than secp256k1_gej_add. */
|
||||
void static secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
|
||||
|
||||
/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
|
||||
void static secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a);
|
||||
|
||||
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
|
||||
void static secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a);
|
||||
|
||||
/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (given that a is
|
||||
not more than 256 bits). */
|
||||
void static secp256k1_gej_split_exp(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a);
|
||||
|
||||
#endif
|
309
crypto/secp256k1/secp256k1/src/impl/ecdsa.h
Normal file
309
crypto/secp256k1/secp256k1/src/impl/ecdsa.h
Normal file
@ -0,0 +1,309 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_ECDSA_IMPL_H_
|
||||
#define _SECP256K1_ECDSA_IMPL_H_
|
||||
|
||||
#include "../num.h"
|
||||
#include "../field.h"
|
||||
#include "../group.h"
|
||||
#include "../ecmult.h"
|
||||
#include "../ecdsa.h"
|
||||
|
||||
void static secp256k1_ecdsa_sig_init(secp256k1_ecdsa_sig_t *r) {
|
||||
secp256k1_num_init(&r->r);
|
||||
secp256k1_num_init(&r->s);
|
||||
}
|
||||
|
||||
void static secp256k1_ecdsa_sig_free(secp256k1_ecdsa_sig_t *r) {
|
||||
secp256k1_num_free(&r->r);
|
||||
secp256k1_num_free(&r->s);
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) {
|
||||
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
|
||||
secp256k1_fe_t x;
|
||||
secp256k1_fe_set_b32(&x, pub+1);
|
||||
secp256k1_ge_set_xo(elem, &x, pub[0] == 0x03);
|
||||
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
|
||||
secp256k1_fe_t x, y;
|
||||
secp256k1_fe_set_b32(&x, pub+1);
|
||||
secp256k1_fe_set_b32(&y, pub+33);
|
||||
secp256k1_ge_set_xy(elem, &x, &y);
|
||||
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07))
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return secp256k1_ge_is_valid(elem);
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
|
||||
if (sig[0] != 0x30) return 0;
|
||||
int lenr = sig[3];
|
||||
if (5+lenr >= size) return 0;
|
||||
int lens = sig[lenr+5];
|
||||
if (sig[1] != lenr+lens+4) return 0;
|
||||
if (lenr+lens+6 > size) return 0;
|
||||
if (sig[2] != 0x02) return 0;
|
||||
if (lenr == 0) return 0;
|
||||
if (sig[lenr+4] != 0x02) return 0;
|
||||
if (lens == 0) return 0;
|
||||
secp256k1_num_set_bin(&r->r, sig+4, lenr);
|
||||
secp256k1_num_set_bin(&r->s, sig+6+lenr, lens);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
|
||||
int lenR = (secp256k1_num_bits(&a->r) + 7)/8;
|
||||
if (lenR == 0 || secp256k1_num_get_bit(&a->r, lenR*8-1))
|
||||
lenR++;
|
||||
int lenS = (secp256k1_num_bits(&a->s) + 7)/8;
|
||||
if (lenS == 0 || secp256k1_num_get_bit(&a->s, lenS*8-1))
|
||||
lenS++;
|
||||
if (*size < 6+lenS+lenR)
|
||||
return 0;
|
||||
*size = 6 + lenS + lenR;
|
||||
sig[0] = 0x30;
|
||||
sig[1] = 4 + lenS + lenR;
|
||||
sig[2] = 0x02;
|
||||
sig[3] = lenR;
|
||||
secp256k1_num_get_bin(sig+4, lenR, &a->r);
|
||||
sig[4+lenR] = 0x02;
|
||||
sig[5+lenR] = lenS;
|
||||
secp256k1_num_get_bin(sig+lenR+6, lenS, &a->s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_sig_recompute(secp256k1_num_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) {
|
||||
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
|
||||
|
||||
if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
|
||||
return 0;
|
||||
if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
|
||||
return 0;
|
||||
if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
|
||||
return 0;
|
||||
|
||||
int ret = 0;
|
||||
secp256k1_num_t sn, u1, u2;
|
||||
secp256k1_num_init(&sn);
|
||||
secp256k1_num_init(&u1);
|
||||
secp256k1_num_init(&u2);
|
||||
secp256k1_num_mod_inverse(&sn, &sig->s, &c->order);
|
||||
secp256k1_num_mod_mul(&u1, &sn, message, &c->order);
|
||||
secp256k1_num_mod_mul(&u2, &sn, &sig->r, &c->order);
|
||||
secp256k1_gej_t pubkeyj; secp256k1_gej_set_ge(&pubkeyj, pubkey);
|
||||
secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1);
|
||||
if (!secp256k1_gej_is_infinity(&pr)) {
|
||||
secp256k1_fe_t xr; secp256k1_gej_get_x(&xr, &pr);
|
||||
secp256k1_fe_normalize(&xr);
|
||||
unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr);
|
||||
secp256k1_num_set_bin(r2, xrb, 32);
|
||||
secp256k1_num_mod(r2, &c->order);
|
||||
ret = 1;
|
||||
}
|
||||
secp256k1_num_free(&sn);
|
||||
secp256k1_num_free(&u1);
|
||||
secp256k1_num_free(&u2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid) {
|
||||
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
|
||||
|
||||
if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
|
||||
return 0;
|
||||
if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
|
||||
return 0;
|
||||
if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
|
||||
return 0;
|
||||
|
||||
secp256k1_num_t rx;
|
||||
secp256k1_num_init(&rx);
|
||||
secp256k1_num_copy(&rx, &sig->r);
|
||||
if (recid & 2) {
|
||||
secp256k1_num_add(&rx, &rx, &c->order);
|
||||
if (secp256k1_num_cmp(&rx, &secp256k1_fe_consts->p) >= 0)
|
||||
return 0;
|
||||
}
|
||||
unsigned char brx[32];
|
||||
secp256k1_num_get_bin(brx, 32, &rx);
|
||||
secp256k1_num_free(&rx);
|
||||
secp256k1_fe_t fx;
|
||||
secp256k1_fe_set_b32(&fx, brx);
|
||||
secp256k1_ge_t x;
|
||||
secp256k1_ge_set_xo(&x, &fx, recid & 1);
|
||||
if (!secp256k1_ge_is_valid(&x))
|
||||
return 0;
|
||||
secp256k1_gej_t xj;
|
||||
secp256k1_gej_set_ge(&xj, &x);
|
||||
secp256k1_num_t rn, u1, u2;
|
||||
secp256k1_num_init(&rn);
|
||||
secp256k1_num_init(&u1);
|
||||
secp256k1_num_init(&u2);
|
||||
secp256k1_num_mod_inverse(&rn, &sig->r, &c->order);
|
||||
secp256k1_num_mod_mul(&u1, &rn, message, &c->order);
|
||||
secp256k1_num_sub(&u1, &c->order, &u1);
|
||||
secp256k1_num_mod_mul(&u2, &rn, &sig->s, &c->order);
|
||||
secp256k1_gej_t qj;
|
||||
secp256k1_ecmult(&qj, &xj, &u2, &u1);
|
||||
if (secp256k1_gej_is_infinity(&qj))
|
||||
return 0;
|
||||
secp256k1_ge_set_gej(pubkey, &qj);
|
||||
secp256k1_num_free(&rn);
|
||||
secp256k1_num_free(&u1);
|
||||
secp256k1_num_free(&u2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) {
|
||||
secp256k1_num_t r2;
|
||||
secp256k1_num_init(&r2);
|
||||
int ret = 0;
|
||||
ret = secp256k1_ecdsa_sig_recompute(&r2, sig, pubkey, message) && secp256k1_num_cmp(&sig->r, &r2) == 0;
|
||||
secp256k1_num_free(&r2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *seckey, const secp256k1_num_t *message, const secp256k1_num_t *nonce, int *recid) {
|
||||
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
|
||||
|
||||
secp256k1_gej_t rp;
|
||||
secp256k1_ecmult_gen(&rp, nonce);
|
||||
secp256k1_ge_t r;
|
||||
secp256k1_ge_set_gej(&r, &rp);
|
||||
unsigned char b[32];
|
||||
secp256k1_fe_normalize(&r.x);
|
||||
secp256k1_fe_normalize(&r.y);
|
||||
secp256k1_fe_get_b32(b, &r.x);
|
||||
secp256k1_num_set_bin(&sig->r, b, 32);
|
||||
if (recid)
|
||||
*recid = (secp256k1_num_cmp(&sig->r, &c->order) >= 0 ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
|
||||
secp256k1_num_mod(&sig->r, &c->order);
|
||||
secp256k1_num_t n;
|
||||
secp256k1_num_init(&n);
|
||||
secp256k1_num_mod_mul(&n, &sig->r, seckey, &c->order);
|
||||
secp256k1_num_add(&n, &n, message);
|
||||
secp256k1_num_mod(&n, &c->order);
|
||||
secp256k1_num_mod_inverse(&sig->s, nonce, &c->order);
|
||||
secp256k1_num_mod_mul(&sig->s, &sig->s, &n, &c->order);
|
||||
secp256k1_num_free(&n);
|
||||
if (secp256k1_num_is_zero(&sig->s))
|
||||
return 0;
|
||||
if (secp256k1_num_cmp(&sig->s, &c->half_order) > 0) {
|
||||
secp256k1_num_sub(&sig->s, &c->order, &sig->s);
|
||||
if (recid)
|
||||
*recid ^= 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void static secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s) {
|
||||
secp256k1_num_copy(&sig->r, r);
|
||||
secp256k1_num_copy(&sig->s, s);
|
||||
}
|
||||
|
||||
void static secp256k1_ecdsa_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) {
|
||||
secp256k1_fe_normalize(&elem->x);
|
||||
secp256k1_fe_normalize(&elem->y);
|
||||
secp256k1_fe_get_b32(&pub[1], &elem->x);
|
||||
if (compressed) {
|
||||
*size = 33;
|
||||
pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
|
||||
} else {
|
||||
*size = 65;
|
||||
pub[0] = 0x04;
|
||||
secp256k1_fe_get_b32(&pub[33], &elem->y);
|
||||
}
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_privkey_parse(secp256k1_num_t *key, const unsigned char *privkey, int privkeylen) {
|
||||
const unsigned char *end = privkey + privkeylen;
|
||||
// sequence header
|
||||
if (end < privkey+1 || *privkey != 0x30)
|
||||
return 0;
|
||||
privkey++;
|
||||
// sequence length constructor
|
||||
int lenb = 0;
|
||||
if (end < privkey+1 || !(*privkey & 0x80))
|
||||
return 0;
|
||||
lenb = *privkey & ~0x80; privkey++;
|
||||
if (lenb < 1 || lenb > 2)
|
||||
return 0;
|
||||
if (end < privkey+lenb)
|
||||
return 0;
|
||||
// sequence length
|
||||
int len = 0;
|
||||
len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
|
||||
privkey += lenb;
|
||||
if (end < privkey+len)
|
||||
return 0;
|
||||
// sequence element 0: version number (=1)
|
||||
if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01)
|
||||
return 0;
|
||||
privkey += 3;
|
||||
// sequence element 1: octet string, up to 32 bytes
|
||||
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1])
|
||||
return 0;
|
||||
secp256k1_num_set_bin(key, privkey+2, privkey[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int static secp256k1_ecdsa_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_num_t *key, int compressed) {
|
||||
secp256k1_gej_t rp;
|
||||
secp256k1_ecmult_gen(&rp, key);
|
||||
secp256k1_ge_t r;
|
||||
secp256k1_ge_set_gej(&r, &rp);
|
||||
if (compressed) {
|
||||
static const unsigned char begin[] = {
|
||||
0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
|
||||
};
|
||||
static const unsigned char middle[] = {
|
||||
0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
|
||||
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
|
||||
0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
|
||||
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
|
||||
0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
|
||||
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
|
||||
};
|
||||
unsigned char *ptr = privkey;
|
||||
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
|
||||
secp256k1_num_get_bin(ptr, 32, key); ptr += 32;
|
||||
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
|
||||
int pubkeylen = 0;
|
||||
secp256k1_ecdsa_pubkey_serialize(&r, ptr, &pubkeylen, 1); ptr += pubkeylen;
|
||||
*privkeylen = ptr - privkey;
|
||||
} else {
|
||||
static const unsigned char begin[] = {
|
||||
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
|
||||
};
|
||||
static const unsigned char middle[] = {
|
||||
0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
|
||||
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
|
||||
0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
|
||||
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
|
||||
0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
|
||||
0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
|
||||
0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
|
||||
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
|
||||
};
|
||||
unsigned char *ptr = privkey;
|
||||
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
|
||||
secp256k1_num_get_bin(ptr, 32, key); ptr += 32;
|
||||
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
|
||||
int pubkeylen = 0;
|
||||
secp256k1_ecdsa_pubkey_serialize(&r, ptr, &pubkeylen, 0); ptr += pubkeylen;
|
||||
*privkeylen = ptr - privkey;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
238
crypto/secp256k1/secp256k1/src/impl/ecmult.h
Normal file
238
crypto/secp256k1/secp256k1/src/impl/ecmult.h
Normal file
@ -0,0 +1,238 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_ECMULT_IMPL_H_
|
||||
#define _SECP256K1_ECMULT_IMPL_H_
|
||||
|
||||
#include "../num.h"
|
||||
#include "../group.h"
|
||||
#include "../ecmult.h"
|
||||
|
||||
// optimal for 128-bit and 256-bit exponents.
|
||||
#define WINDOW_A 5
|
||||
|
||||
// larger numbers may result in slightly better performance, at the cost of
|
||||
// exponentially larger precomputed tables. WINDOW_G == 14 results in 640 KiB.
|
||||
#define WINDOW_G 14
|
||||
|
||||
/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table.
|
||||
* pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for
|
||||
* 2^(w-2) entries.
|
||||
*
|
||||
* There are two versions of this function:
|
||||
* - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation,
|
||||
* fast to precompute, but slower to use in later additions.
|
||||
* - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations,
|
||||
* (much) slower to precompute, but a bit faster to use in later additions.
|
||||
* To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as
|
||||
* G is constant, so it only needs to be done once in advance.
|
||||
*/
|
||||
void static secp256k1_ecmult_table_precomp_gej(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) {
|
||||
pre[0] = *a;
|
||||
secp256k1_gej_t d; secp256k1_gej_double(&d, &pre[0]);
|
||||
for (int i=1; i<(1 << (w-2)); i++)
|
||||
secp256k1_gej_add(&pre[i], &d, &pre[i-1]);
|
||||
}
|
||||
|
||||
void static secp256k1_ecmult_table_precomp_ge(secp256k1_ge_t *pre, const secp256k1_ge_t *a, int w) {
|
||||
pre[0] = *a;
|
||||
secp256k1_gej_t x; secp256k1_gej_set_ge(&x, a);
|
||||
secp256k1_gej_t d; secp256k1_gej_double(&d, &x);
|
||||
for (int i=1; i<(1 << (w-2)); i++) {
|
||||
secp256k1_gej_add_ge(&x, &d, &pre[i-1]);
|
||||
secp256k1_ge_set_gej(&pre[i], &x);
|
||||
}
|
||||
}
|
||||
|
||||
/** The number of entries a table with precomputed multiples needs to have. */
|
||||
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
|
||||
|
||||
/** The following two macro retrieves a particular odd multiple from a table
|
||||
* of precomputed multiples. */
|
||||
#define ECMULT_TABLE_GET(r,pre,n,w,neg) do { \
|
||||
assert(((n) & 1) == 1); \
|
||||
assert((n) >= -((1 << ((w)-1)) - 1)); \
|
||||
assert((n) <= ((1 << ((w)-1)) - 1)); \
|
||||
if ((n) > 0) \
|
||||
*(r) = (pre)[((n)-1)/2]; \
|
||||
else \
|
||||
(neg)((r), &(pre)[(-(n)-1)/2]); \
|
||||
} while(0)
|
||||
|
||||
#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_gej_neg)
|
||||
#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg)
|
||||
|
||||
typedef struct {
|
||||
secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of the generator
|
||||
secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of 2^128*generator
|
||||
secp256k1_ge_t prec[64][16]; // prec[j][i] = 16^j * (i+1) * G
|
||||
secp256k1_ge_t fin; // -(sum(prec[j][0], j=0..63))
|
||||
} secp256k1_ecmult_consts_t;
|
||||
|
||||
static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL;
|
||||
|
||||
static void secp256k1_ecmult_start(void) {
|
||||
if (secp256k1_ecmult_consts != NULL)
|
||||
return;
|
||||
|
||||
secp256k1_ecmult_consts_t *ret = (secp256k1_ecmult_consts_t*)malloc(sizeof(secp256k1_ecmult_consts_t));
|
||||
secp256k1_ecmult_consts = ret;
|
||||
|
||||
// get the generator
|
||||
const secp256k1_ge_t *g = &secp256k1_ge_consts->g;
|
||||
|
||||
// calculate 2^128*generator
|
||||
secp256k1_gej_t g_128j; secp256k1_gej_set_ge(&g_128j, g);
|
||||
for (int i=0; i<128; i++)
|
||||
secp256k1_gej_double(&g_128j, &g_128j);
|
||||
secp256k1_ge_t g_128; secp256k1_ge_set_gej(&g_128, &g_128j);
|
||||
|
||||
// precompute the tables with odd multiples
|
||||
secp256k1_ecmult_table_precomp_ge(ret->pre_g, g, WINDOW_G);
|
||||
secp256k1_ecmult_table_precomp_ge(ret->pre_g_128, &g_128, WINDOW_G);
|
||||
|
||||
// compute prec and fin
|
||||
secp256k1_gej_t gg; secp256k1_gej_set_ge(&gg, g);
|
||||
secp256k1_ge_t ad = *g;
|
||||
secp256k1_gej_t fn; secp256k1_gej_set_infinity(&fn);
|
||||
for (int j=0; j<64; j++) {
|
||||
secp256k1_ge_set_gej(&ret->prec[j][0], &gg);
|
||||
secp256k1_gej_add(&fn, &fn, &gg);
|
||||
for (int i=1; i<16; i++) {
|
||||
secp256k1_gej_add_ge(&gg, &gg, &ad);
|
||||
secp256k1_ge_set_gej(&ret->prec[j][i], &gg);
|
||||
}
|
||||
ad = ret->prec[j][15];
|
||||
}
|
||||
secp256k1_ge_set_gej(&ret->fin, &fn);
|
||||
secp256k1_ge_neg(&ret->fin, &ret->fin);
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_stop(void) {
|
||||
if (secp256k1_ecmult_consts == NULL)
|
||||
return;
|
||||
|
||||
secp256k1_ecmult_consts_t *c = (secp256k1_ecmult_consts_t*)secp256k1_ecmult_consts;
|
||||
free(c);
|
||||
secp256k1_ecmult_consts = NULL;
|
||||
}
|
||||
|
||||
/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
|
||||
* with the following guarantees:
|
||||
* - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)
|
||||
* - two non-zero entries in wnaf are separated by at least w-1 zeroes.
|
||||
* - the index of the highest non-zero entry in wnaf (=return value-1) is at most bits, where
|
||||
* bits is the number of bits necessary to represent the absolute value of the input.
|
||||
*/
|
||||
static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_num_t *a, int w) {
|
||||
int ret = 0;
|
||||
int zeroes = 0;
|
||||
secp256k1_num_t x;
|
||||
secp256k1_num_init(&x);
|
||||
secp256k1_num_copy(&x, a);
|
||||
int sign = 1;
|
||||
if (secp256k1_num_is_neg(&x)) {
|
||||
sign = -1;
|
||||
secp256k1_num_negate(&x);
|
||||
}
|
||||
while (!secp256k1_num_is_zero(&x)) {
|
||||
while (!secp256k1_num_is_odd(&x)) {
|
||||
zeroes++;
|
||||
secp256k1_num_shift(&x, 1);
|
||||
}
|
||||
int word = secp256k1_num_shift(&x, w);
|
||||
while (zeroes) {
|
||||
wnaf[ret++] = 0;
|
||||
zeroes--;
|
||||
}
|
||||
if (word & (1 << (w-1))) {
|
||||
secp256k1_num_inc(&x);
|
||||
wnaf[ret++] = sign * (word - (1 << w));
|
||||
} else {
|
||||
wnaf[ret++] = sign * word;
|
||||
}
|
||||
zeroes = w-1;
|
||||
}
|
||||
secp256k1_num_free(&x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void static secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *gn) {
|
||||
secp256k1_num_t n;
|
||||
secp256k1_num_init(&n);
|
||||
secp256k1_num_copy(&n, gn);
|
||||
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
|
||||
secp256k1_gej_set_ge(r, &c->prec[0][secp256k1_num_shift(&n, 4)]);
|
||||
for (int j=1; j<64; j++)
|
||||
secp256k1_gej_add_ge(r, r, &c->prec[j][secp256k1_num_shift(&n, 4)]);
|
||||
secp256k1_num_free(&n);
|
||||
secp256k1_gej_add_ge(r, r, &c->fin);
|
||||
}
|
||||
|
||||
void static secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng) {
|
||||
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
|
||||
|
||||
secp256k1_num_t na_1, na_lam;
|
||||
secp256k1_num_t ng_1, ng_128;
|
||||
secp256k1_num_init(&na_1);
|
||||
secp256k1_num_init(&na_lam);
|
||||
secp256k1_num_init(&ng_1);
|
||||
secp256k1_num_init(&ng_128);
|
||||
|
||||
// split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit)
|
||||
secp256k1_gej_split_exp(&na_1, &na_lam, na);
|
||||
// split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit)
|
||||
secp256k1_num_split(&ng_1, &ng_128, ng, 128);
|
||||
|
||||
// build wnaf representation for na_1, na_lam, ng_1, ng_128
|
||||
int wnaf_na_1[129]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
|
||||
int wnaf_na_lam[129]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
|
||||
int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G);
|
||||
int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
|
||||
|
||||
// calculate a_lam = a*lambda
|
||||
secp256k1_gej_t a_lam; secp256k1_gej_mul_lambda(&a_lam, a);
|
||||
|
||||
// calculate odd multiples of a and a_lam
|
||||
secp256k1_gej_t pre_a_1[ECMULT_TABLE_SIZE(WINDOW_A)], pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_ecmult_table_precomp_gej(pre_a_1, a, WINDOW_A);
|
||||
secp256k1_ecmult_table_precomp_gej(pre_a_lam, &a_lam, WINDOW_A);
|
||||
|
||||
int bits = bits_na_1;
|
||||
if (bits_na_lam > bits) bits = bits_na_lam;
|
||||
if (bits_ng_1 > bits) bits = bits_ng_1;
|
||||
if (bits_ng_128 > bits) bits = bits_ng_128;
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
secp256k1_gej_t tmpj;
|
||||
secp256k1_ge_t tmpa;
|
||||
|
||||
for (int i=bits-1; i>=0; i--) {
|
||||
secp256k1_gej_double(r, r);
|
||||
int n;
|
||||
if (i < bits_na_1 && (n = wnaf_na_1[i])) {
|
||||
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_1, n, WINDOW_A);
|
||||
secp256k1_gej_add(r, r, &tmpj);
|
||||
}
|
||||
if (i < bits_na_lam && (n = wnaf_na_lam[i])) {
|
||||
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A);
|
||||
secp256k1_gej_add(r, r, &tmpj);
|
||||
}
|
||||
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
|
||||
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
}
|
||||
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
|
||||
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
}
|
||||
}
|
||||
|
||||
secp256k1_num_free(&na_1);
|
||||
secp256k1_num_free(&na_lam);
|
||||
secp256k1_num_free(&ng_1);
|
||||
secp256k1_num_free(&ng_128);
|
||||
}
|
||||
|
||||
#endif
|
175
crypto/secp256k1/secp256k1/src/impl/field.h
Normal file
175
crypto/secp256k1/secp256k1/src/impl/field.h
Normal file
@ -0,0 +1,175 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_IMPL_H_
|
||||
#define _SECP256K1_FIELD_IMPL_H_
|
||||
|
||||
#if defined(USE_FIELD_GMP)
|
||||
#include "field_gmp.h"
|
||||
#elif defined(USE_FIELD_10X26)
|
||||
#include "field_10x26.h"
|
||||
#elif defined(USE_FIELD_5X52)
|
||||
#include "field_5x52.h"
|
||||
#elif defined(USE_FIELD_5X64)
|
||||
#include "field_5x64.h"
|
||||
#else
|
||||
#error "Please select field implementation"
|
||||
#endif
|
||||
|
||||
void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) {
|
||||
if (*rlen < 65) {
|
||||
*rlen = 65;
|
||||
return;
|
||||
}
|
||||
*rlen = 65;
|
||||
unsigned char tmp[32];
|
||||
secp256k1_fe_t b = *a;
|
||||
secp256k1_fe_normalize(&b);
|
||||
secp256k1_fe_get_b32(tmp, &b);
|
||||
for (int i=0; i<32; i++) {
|
||||
static const char *c = "0123456789ABCDEF";
|
||||
r[2*i] = c[(tmp[i] >> 4) & 0xF];
|
||||
r[2*i+1] = c[(tmp[i]) & 0xF];
|
||||
}
|
||||
r[64] = 0x00;
|
||||
}
|
||||
|
||||
void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
|
||||
unsigned char tmp[32] = {};
|
||||
static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
|
||||
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0};
|
||||
for (int i=0; i<32; i++) {
|
||||
if (alen > i*2)
|
||||
tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]];
|
||||
}
|
||||
secp256k1_fe_set_b32(r, tmp);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
// calculate a^p, with p={15,780,1022,1023}
|
||||
secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a);
|
||||
secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a);
|
||||
secp256k1_fe_t a6; secp256k1_fe_sqr(&a6, &a3);
|
||||
secp256k1_fe_t a12; secp256k1_fe_sqr(&a12, &a6);
|
||||
secp256k1_fe_t a15; secp256k1_fe_mul(&a15, &a12, &a3);
|
||||
secp256k1_fe_t a30; secp256k1_fe_sqr(&a30, &a15);
|
||||
secp256k1_fe_t a60; secp256k1_fe_sqr(&a60, &a30);
|
||||
secp256k1_fe_t a120; secp256k1_fe_sqr(&a120, &a60);
|
||||
secp256k1_fe_t a240; secp256k1_fe_sqr(&a240, &a120);
|
||||
secp256k1_fe_t a255; secp256k1_fe_mul(&a255, &a240, &a15);
|
||||
secp256k1_fe_t a510; secp256k1_fe_sqr(&a510, &a255);
|
||||
secp256k1_fe_t a750; secp256k1_fe_mul(&a750, &a510, &a240);
|
||||
secp256k1_fe_t a780; secp256k1_fe_mul(&a780, &a750, &a30);
|
||||
secp256k1_fe_t a1020; secp256k1_fe_sqr(&a1020, &a510);
|
||||
secp256k1_fe_t a1022; secp256k1_fe_mul(&a1022, &a1020, &a2);
|
||||
secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1022, a);
|
||||
secp256k1_fe_t x = a15;
|
||||
for (int i=0; i<21; i++) {
|
||||
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
|
||||
secp256k1_fe_mul(&x, &x, &a1023);
|
||||
}
|
||||
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
|
||||
secp256k1_fe_mul(&x, &x, &a1022);
|
||||
for (int i=0; i<2; i++) {
|
||||
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
|
||||
secp256k1_fe_mul(&x, &x, &a1023);
|
||||
}
|
||||
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
|
||||
secp256k1_fe_mul(r, &x, &a780);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
// calculate a^p, with p={45,63,1019,1023}
|
||||
secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a);
|
||||
secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a);
|
||||
secp256k1_fe_t a4; secp256k1_fe_sqr(&a4, &a2);
|
||||
secp256k1_fe_t a5; secp256k1_fe_mul(&a5, &a4, a);
|
||||
secp256k1_fe_t a10; secp256k1_fe_sqr(&a10, &a5);
|
||||
secp256k1_fe_t a11; secp256k1_fe_mul(&a11, &a10, a);
|
||||
secp256k1_fe_t a21; secp256k1_fe_mul(&a21, &a11, &a10);
|
||||
secp256k1_fe_t a42; secp256k1_fe_sqr(&a42, &a21);
|
||||
secp256k1_fe_t a45; secp256k1_fe_mul(&a45, &a42, &a3);
|
||||
secp256k1_fe_t a63; secp256k1_fe_mul(&a63, &a42, &a21);
|
||||
secp256k1_fe_t a126; secp256k1_fe_sqr(&a126, &a63);
|
||||
secp256k1_fe_t a252; secp256k1_fe_sqr(&a252, &a126);
|
||||
secp256k1_fe_t a504; secp256k1_fe_sqr(&a504, &a252);
|
||||
secp256k1_fe_t a1008; secp256k1_fe_sqr(&a1008, &a504);
|
||||
secp256k1_fe_t a1019; secp256k1_fe_mul(&a1019, &a1008, &a11);
|
||||
secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1019, &a4);
|
||||
secp256k1_fe_t x = a63;
|
||||
for (int i=0; i<21; i++) {
|
||||
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
|
||||
secp256k1_fe_mul(&x, &x, &a1023);
|
||||
}
|
||||
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
|
||||
secp256k1_fe_mul(&x, &x, &a1019);
|
||||
for (int i=0; i<2; i++) {
|
||||
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
|
||||
secp256k1_fe_mul(&x, &x, &a1023);
|
||||
}
|
||||
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
|
||||
secp256k1_fe_mul(r, &x, &a45);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
#if defined(USE_FIELD_INV_BUILTIN)
|
||||
secp256k1_fe_inv(r, a);
|
||||
#elif defined(USE_FIELD_INV_NUM)
|
||||
unsigned char b[32];
|
||||
secp256k1_fe_t c = *a;
|
||||
secp256k1_fe_normalize(&c);
|
||||
secp256k1_fe_get_b32(b, &c);
|
||||
secp256k1_num_t n;
|
||||
secp256k1_num_init(&n);
|
||||
secp256k1_num_set_bin(&n, b, 32);
|
||||
secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p);
|
||||
secp256k1_num_get_bin(b, 32, &n);
|
||||
secp256k1_num_free(&n);
|
||||
secp256k1_fe_set_b32(r, b);
|
||||
#else
|
||||
#error "Please select field inverse implementation"
|
||||
#endif
|
||||
}
|
||||
|
||||
void static secp256k1_fe_start(void) {
|
||||
static const unsigned char secp256k1_fe_consts_p[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
|
||||
};
|
||||
if (secp256k1_fe_consts == NULL) {
|
||||
secp256k1_fe_inner_start();
|
||||
secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_consts_t));
|
||||
secp256k1_num_init(&ret->p);
|
||||
secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p));
|
||||
secp256k1_fe_consts = ret;
|
||||
}
|
||||
}
|
||||
|
||||
void static secp256k1_fe_stop(void) {
|
||||
if (secp256k1_fe_consts != NULL) {
|
||||
secp256k1_fe_consts_t *c = (secp256k1_fe_consts_t*)secp256k1_fe_consts;
|
||||
secp256k1_num_free(&c->p);
|
||||
free((void*)c);
|
||||
secp256k1_fe_consts = NULL;
|
||||
secp256k1_fe_inner_stop();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
487
crypto/secp256k1/secp256k1/src/impl/field_10x26.h
Normal file
487
crypto/secp256k1/secp256k1/src/impl/field_10x26.h
Normal file
@ -0,0 +1,487 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "../num.h"
|
||||
#include "../field.h"
|
||||
|
||||
void static secp256k1_fe_inner_start(void) {}
|
||||
void static secp256k1_fe_inner_stop(void) {}
|
||||
|
||||
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
|
||||
// fog("normalize in: ", r);
|
||||
uint32_t c;
|
||||
c = r->n[0];
|
||||
uint32_t t0 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[1];
|
||||
uint32_t t1 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[2];
|
||||
uint32_t t2 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[3];
|
||||
uint32_t t3 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[4];
|
||||
uint32_t t4 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[5];
|
||||
uint32_t t5 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[6];
|
||||
uint32_t t6 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[7];
|
||||
uint32_t t7 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[8];
|
||||
uint32_t t8 = c & 0x3FFFFFFUL;
|
||||
c = (c >> 26) + r->n[9];
|
||||
uint32_t t9 = c & 0x03FFFFFUL;
|
||||
c >>= 22;
|
||||
/* r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
|
||||
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
|
||||
fog(" tm1: ", r);
|
||||
fprintf(stderr, "out c= %08lx\n", (unsigned long)c);*/
|
||||
|
||||
// The following code will not modify the t's if c is initially 0.
|
||||
uint32_t d = c * 0x3D1UL + t0;
|
||||
t0 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t1 + c*0x40;
|
||||
t1 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t2;
|
||||
t2 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t3;
|
||||
t3 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t4;
|
||||
t4 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t5;
|
||||
t5 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t6;
|
||||
t6 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t7;
|
||||
t7 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t8;
|
||||
t8 = d & 0x3FFFFFFULL;
|
||||
d = (d >> 26) + t9;
|
||||
t9 = d & 0x03FFFFFULL;
|
||||
assert((d >> 22) == 0);
|
||||
/* r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
|
||||
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
|
||||
fog(" tm2: ", r); */
|
||||
|
||||
// Subtract p if result >= p
|
||||
uint64_t low = ((uint64_t)t1 << 26) | t0;
|
||||
uint64_t mask = -(int64_t)((t9 < 0x03FFFFFUL) | (t8 < 0x3FFFFFFUL) | (t7 < 0x3FFFFFFUL) | (t6 < 0x3FFFFFFUL) | (t5 < 0x3FFFFFFUL) | (t4 < 0x3FFFFFFUL) | (t3 < 0x3FFFFFFUL) | (t2 < 0x3FFFFFFUL) | (low < 0xFFFFEFFFFFC2FULL));
|
||||
t9 &= mask;
|
||||
t8 &= mask;
|
||||
t7 &= mask;
|
||||
t6 &= mask;
|
||||
t5 &= mask;
|
||||
t4 &= mask;
|
||||
t3 &= mask;
|
||||
t2 &= mask;
|
||||
low -= (~mask & 0xFFFFEFFFFFC2FULL);
|
||||
|
||||
// push internal variables back
|
||||
r->n[0] = low & 0x3FFFFFFUL; r->n[1] = (low >> 26) & 0x3FFFFFFUL; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
|
||||
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
|
||||
/* fog(" out: ", r);*/
|
||||
|
||||
#ifdef VERIFY
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
|
||||
r->n[0] = a;
|
||||
r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
|
||||
#ifdef VERIFY
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: not constant time!
|
||||
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0 && a->n[5] == 0 && a->n[6] == 0 && a->n[7] == 0 && a->n[8] == 0 && a->n[9] == 0);
|
||||
}
|
||||
|
||||
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
// TODO: not constant time!
|
||||
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
assert(b->normalized);
|
||||
#endif
|
||||
return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3] && a->n[4] == b->n[4] &&
|
||||
a->n[5] == b->n[5] && a->n[6] == b->n[6] && a->n[7] == b->n[7] && a->n[8] == b->n[8] && a->n[9] == b->n[9]);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
|
||||
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
|
||||
for (int i=0; i<32; i++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
int limb = (8*i+2*j)/26;
|
||||
int shift = (8*i+2*j)%26;
|
||||
r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
|
||||
}
|
||||
}
|
||||
#ifdef VERIFY
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
for (int i=0; i<32; i++) {
|
||||
int c = 0;
|
||||
for (int j=0; j<4; j++) {
|
||||
int limb = (8*i+2*j)/26;
|
||||
int shift = (8*i+2*j)%26;
|
||||
c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
|
||||
}
|
||||
r[31-i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
|
||||
#ifdef VERIFY
|
||||
assert(a->magnitude <= m);
|
||||
r->magnitude = m + 1;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
r->n[0] = 0x3FFFC2FUL * (m + 1) - a->n[0];
|
||||
r->n[1] = 0x3FFFFBFUL * (m + 1) - a->n[1];
|
||||
r->n[2] = 0x3FFFFFFUL * (m + 1) - a->n[2];
|
||||
r->n[3] = 0x3FFFFFFUL * (m + 1) - a->n[3];
|
||||
r->n[4] = 0x3FFFFFFUL * (m + 1) - a->n[4];
|
||||
r->n[5] = 0x3FFFFFFUL * (m + 1) - a->n[5];
|
||||
r->n[6] = 0x3FFFFFFUL * (m + 1) - a->n[6];
|
||||
r->n[7] = 0x3FFFFFFUL * (m + 1) - a->n[7];
|
||||
r->n[8] = 0x3FFFFFFUL * (m + 1) - a->n[8];
|
||||
r->n[9] = 0x03FFFFFUL * (m + 1) - a->n[9];
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
|
||||
#ifdef VERIFY
|
||||
r->magnitude *= a;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
r->n[0] *= a;
|
||||
r->n[1] *= a;
|
||||
r->n[2] *= a;
|
||||
r->n[3] *= a;
|
||||
r->n[4] *= a;
|
||||
r->n[5] *= a;
|
||||
r->n[6] *= a;
|
||||
r->n[7] *= a;
|
||||
r->n[8] *= a;
|
||||
r->n[9] *= a;
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
r->magnitude += a->magnitude;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
r->n[0] += a->n[0];
|
||||
r->n[1] += a->n[1];
|
||||
r->n[2] += a->n[2];
|
||||
r->n[3] += a->n[3];
|
||||
r->n[4] += a->n[4];
|
||||
r->n[5] += a->n[5];
|
||||
r->n[6] += a->n[6];
|
||||
r->n[7] += a->n[7];
|
||||
r->n[8] += a->n[8];
|
||||
r->n[9] += a->n[9];
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_mul_inner(const uint32_t *a, const uint32_t *b, uint32_t *r) {
|
||||
uint64_t c = (uint64_t)a[0] * b[0];
|
||||
uint32_t t0 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[1] +
|
||||
(uint64_t)a[1] * b[0];
|
||||
uint32_t t1 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[2] +
|
||||
(uint64_t)a[1] * b[1] +
|
||||
(uint64_t)a[2] * b[0];
|
||||
uint32_t t2 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[3] +
|
||||
(uint64_t)a[1] * b[2] +
|
||||
(uint64_t)a[2] * b[1] +
|
||||
(uint64_t)a[3] * b[0];
|
||||
uint32_t t3 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[4] +
|
||||
(uint64_t)a[1] * b[3] +
|
||||
(uint64_t)a[2] * b[2] +
|
||||
(uint64_t)a[3] * b[1] +
|
||||
(uint64_t)a[4] * b[0];
|
||||
uint32_t t4 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[5] +
|
||||
(uint64_t)a[1] * b[4] +
|
||||
(uint64_t)a[2] * b[3] +
|
||||
(uint64_t)a[3] * b[2] +
|
||||
(uint64_t)a[4] * b[1] +
|
||||
(uint64_t)a[5] * b[0];
|
||||
uint32_t t5 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[6] +
|
||||
(uint64_t)a[1] * b[5] +
|
||||
(uint64_t)a[2] * b[4] +
|
||||
(uint64_t)a[3] * b[3] +
|
||||
(uint64_t)a[4] * b[2] +
|
||||
(uint64_t)a[5] * b[1] +
|
||||
(uint64_t)a[6] * b[0];
|
||||
uint32_t t6 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[7] +
|
||||
(uint64_t)a[1] * b[6] +
|
||||
(uint64_t)a[2] * b[5] +
|
||||
(uint64_t)a[3] * b[4] +
|
||||
(uint64_t)a[4] * b[3] +
|
||||
(uint64_t)a[5] * b[2] +
|
||||
(uint64_t)a[6] * b[1] +
|
||||
(uint64_t)a[7] * b[0];
|
||||
uint32_t t7 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[8] +
|
||||
(uint64_t)a[1] * b[7] +
|
||||
(uint64_t)a[2] * b[6] +
|
||||
(uint64_t)a[3] * b[5] +
|
||||
(uint64_t)a[4] * b[4] +
|
||||
(uint64_t)a[5] * b[3] +
|
||||
(uint64_t)a[6] * b[2] +
|
||||
(uint64_t)a[7] * b[1] +
|
||||
(uint64_t)a[8] * b[0];
|
||||
uint32_t t8 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[0] * b[9] +
|
||||
(uint64_t)a[1] * b[8] +
|
||||
(uint64_t)a[2] * b[7] +
|
||||
(uint64_t)a[3] * b[6] +
|
||||
(uint64_t)a[4] * b[5] +
|
||||
(uint64_t)a[5] * b[4] +
|
||||
(uint64_t)a[6] * b[3] +
|
||||
(uint64_t)a[7] * b[2] +
|
||||
(uint64_t)a[8] * b[1] +
|
||||
(uint64_t)a[9] * b[0];
|
||||
uint32_t t9 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[1] * b[9] +
|
||||
(uint64_t)a[2] * b[8] +
|
||||
(uint64_t)a[3] * b[7] +
|
||||
(uint64_t)a[4] * b[6] +
|
||||
(uint64_t)a[5] * b[5] +
|
||||
(uint64_t)a[6] * b[4] +
|
||||
(uint64_t)a[7] * b[3] +
|
||||
(uint64_t)a[8] * b[2] +
|
||||
(uint64_t)a[9] * b[1];
|
||||
uint32_t t10 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[2] * b[9] +
|
||||
(uint64_t)a[3] * b[8] +
|
||||
(uint64_t)a[4] * b[7] +
|
||||
(uint64_t)a[5] * b[6] +
|
||||
(uint64_t)a[6] * b[5] +
|
||||
(uint64_t)a[7] * b[4] +
|
||||
(uint64_t)a[8] * b[3] +
|
||||
(uint64_t)a[9] * b[2];
|
||||
uint32_t t11 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[3] * b[9] +
|
||||
(uint64_t)a[4] * b[8] +
|
||||
(uint64_t)a[5] * b[7] +
|
||||
(uint64_t)a[6] * b[6] +
|
||||
(uint64_t)a[7] * b[5] +
|
||||
(uint64_t)a[8] * b[4] +
|
||||
(uint64_t)a[9] * b[3];
|
||||
uint32_t t12 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[4] * b[9] +
|
||||
(uint64_t)a[5] * b[8] +
|
||||
(uint64_t)a[6] * b[7] +
|
||||
(uint64_t)a[7] * b[6] +
|
||||
(uint64_t)a[8] * b[5] +
|
||||
(uint64_t)a[9] * b[4];
|
||||
uint32_t t13 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[5] * b[9] +
|
||||
(uint64_t)a[6] * b[8] +
|
||||
(uint64_t)a[7] * b[7] +
|
||||
(uint64_t)a[8] * b[6] +
|
||||
(uint64_t)a[9] * b[5];
|
||||
uint32_t t14 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[6] * b[9] +
|
||||
(uint64_t)a[7] * b[8] +
|
||||
(uint64_t)a[8] * b[7] +
|
||||
(uint64_t)a[9] * b[6];
|
||||
uint32_t t15 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[7] * b[9] +
|
||||
(uint64_t)a[8] * b[8] +
|
||||
(uint64_t)a[9] * b[7];
|
||||
uint32_t t16 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[8] * b[9] +
|
||||
(uint64_t)a[9] * b[8];
|
||||
uint32_t t17 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[9] * b[9];
|
||||
uint32_t t18 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
uint32_t t19 = c;
|
||||
|
||||
c = t0 + (uint64_t)t10 * 0x3D10UL;
|
||||
t0 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t1 + (uint64_t)t10*0x400UL + (uint64_t)t11 * 0x3D10UL;
|
||||
t1 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t2 + (uint64_t)t11*0x400UL + (uint64_t)t12 * 0x3D10UL;
|
||||
t2 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t3 + (uint64_t)t12*0x400UL + (uint64_t)t13 * 0x3D10UL;
|
||||
r[3] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t4 + (uint64_t)t13*0x400UL + (uint64_t)t14 * 0x3D10UL;
|
||||
r[4] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t5 + (uint64_t)t14*0x400UL + (uint64_t)t15 * 0x3D10UL;
|
||||
r[5] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t6 + (uint64_t)t15*0x400UL + (uint64_t)t16 * 0x3D10UL;
|
||||
r[6] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t7 + (uint64_t)t16*0x400UL + (uint64_t)t17 * 0x3D10UL;
|
||||
r[7] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t8 + (uint64_t)t17*0x400UL + (uint64_t)t18 * 0x3D10UL;
|
||||
r[8] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t9 + (uint64_t)t18*0x400UL + (uint64_t)t19 * 0x1000003D10ULL;
|
||||
r[9] = c & 0x03FFFFFUL; c = c >> 22;
|
||||
uint64_t d = t0 + c * 0x3D1UL;
|
||||
r[0] = d & 0x3FFFFFFUL; d = d >> 26;
|
||||
d = d + t1 + c*0x40;
|
||||
r[1] = d & 0x3FFFFFFUL; d = d >> 26;
|
||||
r[2] = t2 + d;
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t *r) {
|
||||
uint64_t c = (uint64_t)a[0] * a[0];
|
||||
uint32_t t0 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[1];
|
||||
uint32_t t1 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[2] +
|
||||
(uint64_t)a[1] * a[1];
|
||||
uint32_t t2 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[3] +
|
||||
(uint64_t)(a[1]*2) * a[2];
|
||||
uint32_t t3 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[4] +
|
||||
(uint64_t)(a[1]*2) * a[3] +
|
||||
(uint64_t)a[2] * a[2];
|
||||
uint32_t t4 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[5] +
|
||||
(uint64_t)(a[1]*2) * a[4] +
|
||||
(uint64_t)(a[2]*2) * a[3];
|
||||
uint32_t t5 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[6] +
|
||||
(uint64_t)(a[1]*2) * a[5] +
|
||||
(uint64_t)(a[2]*2) * a[4] +
|
||||
(uint64_t)a[3] * a[3];
|
||||
uint32_t t6 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[7] +
|
||||
(uint64_t)(a[1]*2) * a[6] +
|
||||
(uint64_t)(a[2]*2) * a[5] +
|
||||
(uint64_t)(a[3]*2) * a[4];
|
||||
uint32_t t7 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[8] +
|
||||
(uint64_t)(a[1]*2) * a[7] +
|
||||
(uint64_t)(a[2]*2) * a[6] +
|
||||
(uint64_t)(a[3]*2) * a[5] +
|
||||
(uint64_t)a[4] * a[4];
|
||||
uint32_t t8 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[0]*2) * a[9] +
|
||||
(uint64_t)(a[1]*2) * a[8] +
|
||||
(uint64_t)(a[2]*2) * a[7] +
|
||||
(uint64_t)(a[3]*2) * a[6] +
|
||||
(uint64_t)(a[4]*2) * a[5];
|
||||
uint32_t t9 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[1]*2) * a[9] +
|
||||
(uint64_t)(a[2]*2) * a[8] +
|
||||
(uint64_t)(a[3]*2) * a[7] +
|
||||
(uint64_t)(a[4]*2) * a[6] +
|
||||
(uint64_t)a[5] * a[5];
|
||||
uint32_t t10 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[2]*2) * a[9] +
|
||||
(uint64_t)(a[3]*2) * a[8] +
|
||||
(uint64_t)(a[4]*2) * a[7] +
|
||||
(uint64_t)(a[5]*2) * a[6];
|
||||
uint32_t t11 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[3]*2) * a[9] +
|
||||
(uint64_t)(a[4]*2) * a[8] +
|
||||
(uint64_t)(a[5]*2) * a[7] +
|
||||
(uint64_t)a[6] * a[6];
|
||||
uint32_t t12 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[4]*2) * a[9] +
|
||||
(uint64_t)(a[5]*2) * a[8] +
|
||||
(uint64_t)(a[6]*2) * a[7];
|
||||
uint32_t t13 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[5]*2) * a[9] +
|
||||
(uint64_t)(a[6]*2) * a[8] +
|
||||
(uint64_t)a[7] * a[7];
|
||||
uint32_t t14 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[6]*2) * a[9] +
|
||||
(uint64_t)(a[7]*2) * a[8];
|
||||
uint32_t t15 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[7]*2) * a[9] +
|
||||
(uint64_t)a[8] * a[8];
|
||||
uint32_t t16 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)(a[8]*2) * a[9];
|
||||
uint32_t t17 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + (uint64_t)a[9] * a[9];
|
||||
uint32_t t18 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
uint32_t t19 = c;
|
||||
|
||||
c = t0 + (uint64_t)t10 * 0x3D10UL;
|
||||
t0 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t1 + (uint64_t)t10*0x400UL + (uint64_t)t11 * 0x3D10UL;
|
||||
t1 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t2 + (uint64_t)t11*0x400UL + (uint64_t)t12 * 0x3D10UL;
|
||||
t2 = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t3 + (uint64_t)t12*0x400UL + (uint64_t)t13 * 0x3D10UL;
|
||||
r[3] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t4 + (uint64_t)t13*0x400UL + (uint64_t)t14 * 0x3D10UL;
|
||||
r[4] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t5 + (uint64_t)t14*0x400UL + (uint64_t)t15 * 0x3D10UL;
|
||||
r[5] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t6 + (uint64_t)t15*0x400UL + (uint64_t)t16 * 0x3D10UL;
|
||||
r[6] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t7 + (uint64_t)t16*0x400UL + (uint64_t)t17 * 0x3D10UL;
|
||||
r[7] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t8 + (uint64_t)t17*0x400UL + (uint64_t)t18 * 0x3D10UL;
|
||||
r[8] = c & 0x3FFFFFFUL; c = c >> 26;
|
||||
c = c + t9 + (uint64_t)t18*0x400UL + (uint64_t)t19 * 0x1000003D10ULL;
|
||||
r[9] = c & 0x03FFFFFUL; c = c >> 22;
|
||||
uint64_t d = t0 + c * 0x3D1UL;
|
||||
r[0] = d & 0x3FFFFFFUL; d = d >> 26;
|
||||
d = d + t1 + c*0x40;
|
||||
r[1] = d & 0x3FFFFFFUL; d = d >> 26;
|
||||
r[2] = t2 + d;
|
||||
}
|
||||
|
||||
|
||||
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
#ifdef VERIFY
|
||||
assert(a->magnitude <= 8);
|
||||
assert(b->magnitude <= 8);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
secp256k1_fe_mul_inner(a->n, b->n, r->n);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->magnitude <= 8);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
secp256k1_fe_sqr_inner(a->n, r->n);
|
||||
}
|
||||
|
||||
#endif
|
196
crypto/secp256k1/secp256k1/src/impl/field_5x52.h
Normal file
196
crypto/secp256k1/secp256k1/src/impl/field_5x52.h
Normal file
@ -0,0 +1,196 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "../num.h"
|
||||
#include "../field.h"
|
||||
|
||||
#if defined(USE_FIELD_5X52_ASM)
|
||||
#include "field_5x52_asm.h"
|
||||
#elif defined(USE_FIELD_5X52_INT128)
|
||||
#include "field_5x52_int128.h"
|
||||
#else
|
||||
#error "Please select field_5x52 implementation"
|
||||
#endif
|
||||
|
||||
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
|
||||
* represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular,
|
||||
* each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element
|
||||
* is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations
|
||||
* accept any input with magnitude at most M, and have different rules for propagating magnitude to their
|
||||
* output.
|
||||
*/
|
||||
|
||||
void static secp256k1_fe_inner_start(void) {}
|
||||
void static secp256k1_fe_inner_stop(void) {}
|
||||
|
||||
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
|
||||
uint64_t c;
|
||||
c = r->n[0];
|
||||
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL;
|
||||
c = (c >> 52) + r->n[1];
|
||||
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL;
|
||||
c = (c >> 52) + r->n[2];
|
||||
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL;
|
||||
c = (c >> 52) + r->n[3];
|
||||
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL;
|
||||
c = (c >> 52) + r->n[4];
|
||||
uint64_t t4 = c & 0x0FFFFFFFFFFFFULL;
|
||||
c >>= 48;
|
||||
|
||||
// The following code will not modify the t's if c is initially 0.
|
||||
c = c * 0x1000003D1ULL + t0;
|
||||
t0 = c & 0xFFFFFFFFFFFFFULL;
|
||||
c = (c >> 52) + t1;
|
||||
t1 = c & 0xFFFFFFFFFFFFFULL;
|
||||
c = (c >> 52) + t2;
|
||||
t2 = c & 0xFFFFFFFFFFFFFULL;
|
||||
c = (c >> 52) + t3;
|
||||
t3 = c & 0xFFFFFFFFFFFFFULL;
|
||||
c = (c >> 52) + t4;
|
||||
t4 = c & 0x0FFFFFFFFFFFFULL;
|
||||
assert((c >> 48) == 0);
|
||||
|
||||
// Subtract p if result >= p
|
||||
uint64_t mask = -(int64_t)((t4 < 0xFFFFFFFFFFFFULL) | (t3 < 0xFFFFFFFFFFFFFULL) | (t2 < 0xFFFFFFFFFFFFFULL) | (t1 < 0xFFFFFFFFFFFFFULL) | (t0 < 0xFFFFEFFFFFC2FULL));
|
||||
t4 &= mask;
|
||||
t3 &= mask;
|
||||
t2 &= mask;
|
||||
t1 &= mask;
|
||||
t0 -= (~mask & 0xFFFFEFFFFFC2FULL);
|
||||
|
||||
// push internal variables back
|
||||
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
|
||||
|
||||
#ifdef VERIFY
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
|
||||
r->n[0] = a;
|
||||
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
#ifdef VERIFY
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: not constant time!
|
||||
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0);
|
||||
}
|
||||
|
||||
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
// TODO: not constant time!
|
||||
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
assert(b->normalized);
|
||||
#endif
|
||||
return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3] && a->n[4] == b->n[4]);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
|
||||
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
for (int i=0; i<32; i++) {
|
||||
for (int j=0; j<2; j++) {
|
||||
int limb = (8*i+4*j)/52;
|
||||
int shift = (8*i+4*j)%52;
|
||||
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
|
||||
}
|
||||
}
|
||||
#ifdef VERIFY
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
for (int i=0; i<32; i++) {
|
||||
int c = 0;
|
||||
for (int j=0; j<2; j++) {
|
||||
int limb = (8*i+4*j)/52;
|
||||
int shift = (8*i+4*j)%52;
|
||||
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
|
||||
}
|
||||
r[31-i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
|
||||
#ifdef VERIFY
|
||||
assert(a->magnitude <= m);
|
||||
r->magnitude = m + 1;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
r->n[0] = 0xFFFFEFFFFFC2FULL * (m + 1) - a->n[0];
|
||||
r->n[1] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[1];
|
||||
r->n[2] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[2];
|
||||
r->n[3] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[3];
|
||||
r->n[4] = 0x0FFFFFFFFFFFFULL * (m + 1) - a->n[4];
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
|
||||
#ifdef VERIFY
|
||||
r->magnitude *= a;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
r->n[0] *= a;
|
||||
r->n[1] *= a;
|
||||
r->n[2] *= a;
|
||||
r->n[3] *= a;
|
||||
r->n[4] *= a;
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
r->magnitude += a->magnitude;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
r->n[0] += a->n[0];
|
||||
r->n[1] += a->n[1];
|
||||
r->n[2] += a->n[2];
|
||||
r->n[3] += a->n[3];
|
||||
r->n[4] += a->n[4];
|
||||
}
|
||||
|
||||
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
#ifdef VERIFY
|
||||
assert(a->magnitude <= 8);
|
||||
assert(b->magnitude <= 8);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
secp256k1_fe_mul_inner(a->n, b->n, r->n);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->magnitude <= 8);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
secp256k1_fe_sqr_inner(a->n, r->n);
|
||||
}
|
||||
|
||||
#endif
|
11
crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h
Normal file
11
crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
|
||||
void __attribute__ ((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r);
|
||||
void __attribute__ ((sysv_abi)) secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r);
|
||||
|
||||
#endif
|
105
crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h
Normal file
105
crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void static inline secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r) {
|
||||
__int128 c = (__int128)a[0] * b[0];
|
||||
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
|
||||
c = c + (__int128)a[0] * b[1] +
|
||||
(__int128)a[1] * b[0];
|
||||
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
|
||||
c = c + (__int128)a[0] * b[2] +
|
||||
(__int128)a[1] * b[1] +
|
||||
(__int128)a[2] * b[0];
|
||||
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
|
||||
c = c + (__int128)a[0] * b[3] +
|
||||
(__int128)a[1] * b[2] +
|
||||
(__int128)a[2] * b[1] +
|
||||
(__int128)a[3] * b[0];
|
||||
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
|
||||
c = c + (__int128)a[0] * b[4] +
|
||||
(__int128)a[1] * b[3] +
|
||||
(__int128)a[2] * b[2] +
|
||||
(__int128)a[3] * b[1] +
|
||||
(__int128)a[4] * b[0];
|
||||
uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
|
||||
c = c + (__int128)a[1] * b[4] +
|
||||
(__int128)a[2] * b[3] +
|
||||
(__int128)a[3] * b[2] +
|
||||
(__int128)a[4] * b[1];
|
||||
uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
|
||||
c = c + (__int128)a[2] * b[4] +
|
||||
(__int128)a[3] * b[3] +
|
||||
(__int128)a[4] * b[2];
|
||||
uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
|
||||
c = c + (__int128)a[3] * b[4] +
|
||||
(__int128)a[4] * b[3];
|
||||
uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
|
||||
c = c + (__int128)a[4] * b[4];
|
||||
uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
|
||||
uint64_t t9 = c;
|
||||
|
||||
c = t0 + (__int128)t5 * 0x1000003D10ULL;
|
||||
t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
|
||||
c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
|
||||
t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
|
||||
c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
|
||||
r[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
|
||||
c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
|
||||
r[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
|
||||
c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
|
||||
r[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
|
||||
c = t0 + (__int128)c * 0x1000003D1ULL;
|
||||
r[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
|
||||
r[1] = t1 + c;
|
||||
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r) {
|
||||
__int128 c = (__int128)a[0] * a[0];
|
||||
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
|
||||
c = c + (__int128)(a[0]*2) * a[1];
|
||||
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
|
||||
c = c + (__int128)(a[0]*2) * a[2] +
|
||||
(__int128)a[1] * a[1];
|
||||
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
|
||||
c = c + (__int128)(a[0]*2) * a[3] +
|
||||
(__int128)(a[1]*2) * a[2];
|
||||
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
|
||||
c = c + (__int128)(a[0]*2) * a[4] +
|
||||
(__int128)(a[1]*2) * a[3] +
|
||||
(__int128)a[2] * a[2];
|
||||
uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
|
||||
c = c + (__int128)(a[1]*2) * a[4] +
|
||||
(__int128)(a[2]*2) * a[3];
|
||||
uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
|
||||
c = c + (__int128)(a[2]*2) * a[4] +
|
||||
(__int128)a[3] * a[3];
|
||||
uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
|
||||
c = c + (__int128)(a[3]*2) * a[4];
|
||||
uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
|
||||
c = c + (__int128)a[4] * a[4];
|
||||
uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
|
||||
uint64_t t9 = c;
|
||||
c = t0 + (__int128)t5 * 0x1000003D10ULL;
|
||||
t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
|
||||
c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
|
||||
t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
|
||||
c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
|
||||
r[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
|
||||
c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
|
||||
r[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
|
||||
c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
|
||||
r[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
|
||||
c = t0 + (__int128)c * 0x1000003D1ULL;
|
||||
r[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
|
||||
r[1] = t1 + c;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
371
crypto/secp256k1/secp256k1/src/impl/field_5x64.h
Normal file
371
crypto/secp256k1/secp256k1/src/impl/field_5x64.h
Normal file
@ -0,0 +1,371 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "../num.h"
|
||||
#include "../field.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "field_5x64_asm.h"
|
||||
|
||||
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
|
||||
* represented as 4 uint64_t's in base 2^64, and one overflow uint64_t.
|
||||
*/
|
||||
|
||||
#define FULL_LIMB (0xFFFFFFFFFFFFFFFFULL)
|
||||
#define LAST_LIMB (0xFFFFFFFEFFFFFC2FULL)
|
||||
#define COMP_LIMB (0x00000001000003D1ULL)
|
||||
|
||||
void static secp256k1_fe_inner_start(void) {}
|
||||
void static secp256k1_fe_inner_stop(void) {}
|
||||
|
||||
void static secp256k1_fe_reduce(secp256k1_fe_t *r) {
|
||||
unsigned __int128 c = (unsigned __int128)r->n[4] * COMP_LIMB + r->n[0];
|
||||
uint64_t n0 = c;
|
||||
c = (c >> 64) + r->n[1];
|
||||
uint64_t n1 = c;
|
||||
c = (c >> 64) + r->n[2];
|
||||
r->n[2] = c;
|
||||
c = (c >> 64) + r->n[3];
|
||||
r->n[3] = c;
|
||||
c = (c >> 64) * COMP_LIMB + n0;
|
||||
r->n[0] = c;
|
||||
r->n[1] = n1 + (c >> 64);
|
||||
assert(r->n[1] >= n1);
|
||||
r->n[4] = 0;
|
||||
#ifdef VERIFY
|
||||
r->reduced = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
|
||||
secp256k1_fe_reduce(r);
|
||||
|
||||
// Subtract p if result >= p
|
||||
uint64_t mask = -(int64_t)((r->n[0] < LAST_LIMB) | (r->n[1] != ~0ULL) | (r->n[2] != ~0ULL) | (r->n[3] != ~0ULL));
|
||||
r->n[0] -= (~mask & LAST_LIMB);
|
||||
r->n[1] &= mask;
|
||||
r->n[2] &= mask;
|
||||
r->n[3] &= mask;
|
||||
assert(r->n[4] == 0);
|
||||
|
||||
#ifdef VERIFY
|
||||
r->normalized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
|
||||
r->n[0] = a;
|
||||
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
|
||||
#ifdef VERIFY
|
||||
r->reduced = 1;
|
||||
r->normalized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: not constant time!
|
||||
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0);
|
||||
}
|
||||
|
||||
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
// TODO: not constant time!
|
||||
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
assert(b->normalized);
|
||||
#endif
|
||||
return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3]);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
|
||||
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
for (int i=0; i<32; i++) {
|
||||
r->n[i/8] |= (uint64_t)a[31-i] << (i&7)*8;
|
||||
}
|
||||
#ifdef VERIFY
|
||||
r->reduced = 1;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
assert(a->normalized);
|
||||
#endif
|
||||
for (int i=0; i<32; i++) {
|
||||
r[31-i] = a->n[i/8] >> ((i&7)*8);
|
||||
}
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *ac, int m) {
|
||||
secp256k1_fe_t a = *ac;
|
||||
secp256k1_fe_reduce(&a);
|
||||
unsigned __int128 c = (unsigned __int128)(~a.n[0]) + LAST_LIMB + 1;
|
||||
r->n[0] = c;
|
||||
c = (c >> 64) + (~a.n[1]) + FULL_LIMB;
|
||||
r->n[1] = c;
|
||||
c = (c >> 64) + (~a.n[2]) + FULL_LIMB;
|
||||
r->n[2] = c;
|
||||
c = (c >> 64) + (~a.n[3]) + FULL_LIMB;
|
||||
r->n[3] = c;
|
||||
r->n[4] = 0;
|
||||
#ifdef VERIFY
|
||||
r->reduced = 1;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
|
||||
#ifdef VERIFY
|
||||
r->reduced = 0;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
unsigned __int128 c = (unsigned __int128)r->n[0] * a;
|
||||
r->n[0] = c;
|
||||
c = (c >> 64) + (unsigned __int128)r->n[1] * a;
|
||||
r->n[1] = c;
|
||||
c = (c >> 64) + (unsigned __int128)r->n[2] * a;
|
||||
r->n[2] = c;
|
||||
c = (c >> 64) + (unsigned __int128)r->n[3] * a;
|
||||
r->n[3] = c;
|
||||
c = (c >> 64) + (unsigned __int128)r->n[4] * a;
|
||||
r->n[4] = c;
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
#ifdef VERIFY
|
||||
r->reduced = 0;
|
||||
r->normalized = 0;
|
||||
#endif
|
||||
unsigned __int128 c = (unsigned __int128)r->n[0] + a->n[0];
|
||||
r->n[0] = c;
|
||||
c = (unsigned __int128)r->n[1] + a->n[1] + (c >> 64);
|
||||
r->n[1] = c;
|
||||
c = (unsigned __int128)r->n[2] + a->n[2] + (c >> 64);
|
||||
r->n[2] = c;
|
||||
c = (unsigned __int128)r->n[3] + a->n[3] + (c >> 64);
|
||||
r->n[3] = c;
|
||||
c = (unsigned __int128)r->n[4] + a->n[4] + (c >> 64);
|
||||
r->n[4] = c;
|
||||
assert((c >> 64) == 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define muladd_c3(a,b,c0,c1,c2) { \
|
||||
unsigned __int128 q1 = ((unsigned __int128)(a)) * (b) + (c0); \
|
||||
(c0) = q1; \
|
||||
unsigned __int128 q2 = (q1 >> 64) + (c1) + (((unsigned __int128)(c2)) << 64); \
|
||||
(c1) = q2; \
|
||||
(c2) = q2 >> 64; \
|
||||
}
|
||||
|
||||
#define sqradd_c3(a,c0,c1,c2) muladd_c3(a,a,c0,c1,c2)
|
||||
|
||||
/*#define muladd_c3(a,b,c0,c1,c2) { \
|
||||
unsigned __int128 q = (unsigned __int128)(a) * (b) + (c0); \
|
||||
(c0) = q; \
|
||||
(c1) += (q >> 64); \
|
||||
(c2) += ((c1) < (q >> 64))?1:0; \
|
||||
}*/
|
||||
|
||||
#define muladd2_c3(a,b,c0,c1,c2) { \
|
||||
unsigned __int128 q = (unsigned __int128)(a) * (b); \
|
||||
uint64_t t1 = (q >> 64); \
|
||||
uint64_t t0 = q; \
|
||||
uint64_t t2 = t1+t1; (c2) += (t2<t1)?1:0; \
|
||||
t1 = t0+t0; t2 += (t1<t0)?1:0; \
|
||||
(c0) += t1; t2 += ((c0)<t1)?1:0; \
|
||||
(c1) += t2; (c2) += ((c1)<t2)?1:0; \
|
||||
}
|
||||
|
||||
/*#define muladd2_c3(a,b,c0,c1,c2) { \
|
||||
muladd_c3(a,b,c0,c1,c2); \
|
||||
muladd_c3(a,b,c0,c1,c2); \
|
||||
}*/
|
||||
#else
|
||||
|
||||
#define muladd_c3(a,b,c0,c1,c2) { \
|
||||
register uint64_t t1, t2; \
|
||||
asm ("mulq %3" \
|
||||
: "=a"(t1),"=d"(t2) \
|
||||
: "a"(a),"m"(b) \
|
||||
: "cc"); \
|
||||
asm ("addq %2,%0; adcq %3,%1" \
|
||||
: "+r"(c0),"+d"(t2) \
|
||||
: "a"(t1),"g"(0) \
|
||||
: "cc"); \
|
||||
asm ("addq %2,%0; adcq %3,%1" \
|
||||
: "+r"(c1),"+r"(c2) \
|
||||
: "d"(t2),"g"(0) \
|
||||
: "cc"); \
|
||||
}
|
||||
|
||||
#define sqradd_c3(a,c0,c1,c2) { \
|
||||
register uint64_t t1, t2; \
|
||||
asm ("mulq %2" \
|
||||
: "=a"(t1),"=d"(t2) \
|
||||
: "a"(a) \
|
||||
: "cc"); \
|
||||
asm ("addq %2,%0; adcq %3,%1" \
|
||||
: "+r"(c0),"+d"(t2) \
|
||||
: "a"(t1),"g"(0) \
|
||||
: "cc"); \
|
||||
asm ("addq %2,%0; adcq %3,%1" \
|
||||
: "+r"(c1),"+r"(c2) \
|
||||
: "d"(t2),"g"(0) \
|
||||
: "cc"); \
|
||||
}
|
||||
|
||||
#define muladd2_c3(a,b,c0,c1,c2) { \
|
||||
register uint64_t t1, t2; \
|
||||
asm ("mulq %3" \
|
||||
: "=a"(t1),"=d"(t2) \
|
||||
: "a"(a),"m"(b) \
|
||||
: "cc"); \
|
||||
asm ("addq %0,%0; adcq %2,%1" \
|
||||
: "+d"(t2),"+r"(c2) \
|
||||
: "g"(0) \
|
||||
: "cc"); \
|
||||
asm ("addq %0,%0; adcq %2,%1" \
|
||||
: "+a"(t1),"+d"(t2) \
|
||||
: "g"(0) \
|
||||
: "cc"); \
|
||||
asm ("addq %2,%0; adcq %3,%1" \
|
||||
: "+r"(c0),"+d"(t2) \
|
||||
: "a"(t1),"g"(0) \
|
||||
: "cc"); \
|
||||
asm ("addq %2,%0; adcq %3,%1" \
|
||||
: "+r"(c1),"+r"(c2) \
|
||||
: "d"(t2),"g"(0) \
|
||||
: "cc"); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define mul_c2(a,b,c0,c1) { \
|
||||
unsigned __int128 q = (unsigned __int128)(a) * (b); \
|
||||
(c0) = q; \
|
||||
(c1) = (q >> 64); \
|
||||
}
|
||||
|
||||
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *ac, const secp256k1_fe_t *bc) {
|
||||
|
||||
secp256k1_fe_t a = *ac, b = *bc;
|
||||
secp256k1_fe_reduce(&a);
|
||||
secp256k1_fe_reduce(&b);
|
||||
|
||||
#ifdef USE_FIELD_5X64_ASM
|
||||
secp256k1_fe_mul_inner((&a)->n,(&b)->n,r->n);
|
||||
#else
|
||||
uint64_t c1,c2,c3;
|
||||
c3=0;
|
||||
mul_c2(a.n[0], b.n[0], c1, c2);
|
||||
uint64_t r0 = c1; c1 = 0;
|
||||
muladd_c3(a.n[0], b.n[1], c2, c3, c1);
|
||||
muladd_c3(a.n[1], b.n[0], c2, c3, c1);
|
||||
uint64_t r1 = c2; c2 = 0;
|
||||
muladd_c3(a.n[2], b.n[0], c3, c1, c2);
|
||||
muladd_c3(a.n[1], b.n[1], c3, c1, c2);
|
||||
muladd_c3(a.n[0], b.n[2], c3, c1, c2);
|
||||
uint64_t r2 = c3; c3 = 0;
|
||||
muladd_c3(a.n[0], b.n[3], c1, c2, c3);
|
||||
muladd_c3(a.n[1], b.n[2], c1, c2, c3);
|
||||
muladd_c3(a.n[2], b.n[1], c1, c2, c3);
|
||||
muladd_c3(a.n[3], b.n[0], c1, c2, c3);
|
||||
uint64_t r3 = c1; c1 = 0;
|
||||
muladd_c3(a.n[3], b.n[1], c2, c3, c1);
|
||||
muladd_c3(a.n[2], b.n[2], c2, c3, c1);
|
||||
muladd_c3(a.n[1], b.n[3], c2, c3, c1);
|
||||
uint64_t r4 = c2; c2 = 0;
|
||||
muladd_c3(a.n[2], b.n[3], c3, c1, c2);
|
||||
muladd_c3(a.n[3], b.n[2], c3, c1, c2);
|
||||
uint64_t r5 = c3; c3 = 0;
|
||||
muladd_c3(a.n[3], b.n[3], c1, c2, c3);
|
||||
uint64_t r6 = c1;
|
||||
uint64_t r7 = c2;
|
||||
assert(c3 == 0);
|
||||
unsigned __int128 c = (unsigned __int128)r4 * COMP_LIMB + r0;
|
||||
r->n[0] = c;
|
||||
c = (unsigned __int128)r5 * COMP_LIMB + r1 + (c >> 64);
|
||||
r->n[1] = c;
|
||||
c = (unsigned __int128)r6 * COMP_LIMB + r2 + (c >> 64);
|
||||
r->n[2] = c;
|
||||
c = (unsigned __int128)r7 * COMP_LIMB + r3 + (c >> 64);
|
||||
r->n[3] = c;
|
||||
r->n[4] = c >> 64;
|
||||
#endif
|
||||
|
||||
#ifdef VERIFY
|
||||
r->normalized = 0;
|
||||
r->reduced = 0;
|
||||
#endif
|
||||
secp256k1_fe_reduce(r);
|
||||
}
|
||||
|
||||
/*void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
secp256k1_fe_mul(r, a, a);
|
||||
}*/
|
||||
|
||||
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *ac) {
|
||||
secp256k1_fe_t a = *ac;
|
||||
secp256k1_fe_reduce(&a);
|
||||
|
||||
#ifdef USE_FIELD_5X64_ASM
|
||||
secp256k1_fe_sqr_inner((&a)->n,r->n);
|
||||
#else
|
||||
uint64_t c1,c2,c3;
|
||||
c3=0;
|
||||
mul_c2(a.n[0], a.n[0], c1, c2);
|
||||
uint64_t r0 = c1; c1 = 0;
|
||||
muladd2_c3(a.n[0], a.n[1], c2, c3, c1);
|
||||
uint64_t r1 = c2; c2 = 0;
|
||||
muladd2_c3(a.n[2], a.n[0], c3, c1, c2);
|
||||
sqradd_c3(a.n[1], c3, c1, c2);
|
||||
uint64_t r2 = c3; c3 = 0;
|
||||
muladd2_c3(a.n[0], a.n[3], c1, c2, c3);
|
||||
muladd2_c3(a.n[1], a.n[2], c1, c2, c3);
|
||||
uint64_t r3 = c1; c1 = 0;
|
||||
muladd2_c3(a.n[3], a.n[1], c2, c3, c1);
|
||||
sqradd_c3(a.n[2], c2, c3, c1);
|
||||
uint64_t r4 = c2; c2 = 0;
|
||||
muladd2_c3(a.n[2], a.n[3], c3, c1, c2);
|
||||
uint64_t r5 = c3; c3 = 0;
|
||||
sqradd_c3(a.n[3], c1, c2, c3);
|
||||
uint64_t r6 = c1;
|
||||
uint64_t r7 = c2;
|
||||
assert(c3 == 0);
|
||||
unsigned __int128 c = (unsigned __int128)r4 * COMP_LIMB + r0;
|
||||
r->n[0] = c;
|
||||
c = (unsigned __int128)r5 * COMP_LIMB + r1 + (c >> 64);
|
||||
r->n[1] = c;
|
||||
c = (unsigned __int128)r6 * COMP_LIMB + r2 + (c >> 64);
|
||||
r->n[2] = c;
|
||||
c = (unsigned __int128)r7 * COMP_LIMB + r3 + (c >> 64);
|
||||
r->n[3] = c;
|
||||
r->n[4] = c >> 64;
|
||||
#endif
|
||||
|
||||
#ifdef VERIFY
|
||||
r->normalized = 0;
|
||||
r->reduced = 0;
|
||||
#endif
|
||||
secp256k1_fe_reduce(r);
|
||||
}
|
||||
|
||||
#endif
|
11
crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h
Normal file
11
crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
|
||||
void __attribute__ ((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r);
|
||||
void __attribute__ ((sysv_abi)) secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r);
|
||||
|
||||
#endif
|
155
crypto/secp256k1/secp256k1/src/impl/field_gmp.h
Normal file
155
crypto/secp256k1/secp256k1/src/impl/field_gmp.h
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "../num.h"
|
||||
#include "../field.h"
|
||||
|
||||
static mp_limb_t secp256k1_field_p[FIELD_LIMBS];
|
||||
static mp_limb_t secp256k1_field_pc[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS];
|
||||
|
||||
void static secp256k1_fe_inner_start(void) {
|
||||
for (int i=0; i<(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; i++)
|
||||
secp256k1_field_pc[i] = 0;
|
||||
secp256k1_field_pc[0] += 0x3D1UL;
|
||||
secp256k1_field_pc[32/GMP_NUMB_BITS] += (1UL << (32 % GMP_NUMB_BITS));
|
||||
for (int i=0; i<FIELD_LIMBS; i++) {
|
||||
secp256k1_field_p[i] = 0;
|
||||
}
|
||||
mpn_sub(secp256k1_field_p, secp256k1_field_p, FIELD_LIMBS, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_inner_stop(void) {
|
||||
}
|
||||
|
||||
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
|
||||
if (r->n[FIELD_LIMBS] != 0) {
|
||||
#if (GMP_NUMB_BITS >= 40)
|
||||
mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * r->n[FIELD_LIMBS]);
|
||||
mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * carry);
|
||||
#else
|
||||
mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * r->n[FIELD_LIMBS]) +
|
||||
mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), r->n[FIELD_LIMBS] << (32 % GMP_NUMB_BITS));
|
||||
mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * carry);
|
||||
mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), carry << (32%GMP_NUMB_BITS));
|
||||
#endif
|
||||
r->n[FIELD_LIMBS] = 0;
|
||||
}
|
||||
if (mpn_cmp(r->n, secp256k1_field_p, FIELD_LIMBS) >= 0)
|
||||
mpn_sub(r->n, r->n, FIELD_LIMBS, secp256k1_field_p, FIELD_LIMBS);
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
|
||||
r->n[0] = a;
|
||||
for (int i=1; i<FIELD_LIMBS+1; i++)
|
||||
r->n[i] = 0;
|
||||
}
|
||||
|
||||
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
|
||||
int ret = 1;
|
||||
for (int i=0; i<FIELD_LIMBS+1; i++)
|
||||
ret &= (a->n[i] == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
|
||||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
int ret = 1;
|
||||
for (int i=0; i<FIELD_LIMBS+1; i++)
|
||||
ret &= (a->n[i] == b->n[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
|
||||
for (int i=0; i<FIELD_LIMBS+1; i++)
|
||||
r->n[i] = 0;
|
||||
for (int i=0; i<256; i++) {
|
||||
int limb = i/GMP_NUMB_BITS;
|
||||
int shift = i%GMP_NUMB_BITS;
|
||||
r->n[limb] |= (mp_limb_t)((a[31-i/8] >> (i%8)) & 0x1) << shift;
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
|
||||
for (int i=0; i<32; i++) {
|
||||
int c = 0;
|
||||
for (int j=0; j<8; j++) {
|
||||
int limb = (8*i+j)/GMP_NUMB_BITS;
|
||||
int shift = (8*i+j)%GMP_NUMB_BITS;
|
||||
c |= ((a->n[limb] >> shift) & 0x1) << j;
|
||||
}
|
||||
r[31-i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
|
||||
*r = *a;
|
||||
secp256k1_fe_normalize(r);
|
||||
for (int i=0; i<FIELD_LIMBS; i++)
|
||||
r->n[i] = ~(r->n[i]);
|
||||
#if (GMP_NUMB_BITS >= 33)
|
||||
mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x1000003D0ULL);
|
||||
#else
|
||||
mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x3D0UL);
|
||||
mpn_sub_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS));
|
||||
#endif
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
|
||||
mpn_mul_1(r->n, r->n, FIELD_LIMBS+1, a);
|
||||
}
|
||||
|
||||
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
mpn_add(r->n, r->n, FIELD_LIMBS+1, a->n, FIELD_LIMBS+1);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_reduce(secp256k1_fe_t *r, mp_limb_t *tmp) {
|
||||
// <A1 A2 A3 A4> <B1 B2 B3 B4>
|
||||
// B1 B2 B3 B4
|
||||
// + C * A1 A2 A3 A4
|
||||
// + A1 A2 A3 A4
|
||||
|
||||
#if (GMP_NUMB_BITS >= 33)
|
||||
mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x1000003D1ULL);
|
||||
#else
|
||||
mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x3D1UL) +
|
||||
mpn_addmul_1(tmp+(32/GMP_NUMB_BITS), tmp+FIELD_LIMBS, FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS));
|
||||
#endif
|
||||
mp_limb_t q[1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS];
|
||||
q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] = mpn_mul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o);
|
||||
#if (GMP_NUMB_BITS <= 32)
|
||||
mp_limb_t o2 = tmp[2*FIELD_LIMBS-(32/GMP_NUMB_BITS)] << (32%GMP_NUMB_BITS);
|
||||
q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] += mpn_addmul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o2);
|
||||
#endif
|
||||
r->n[FIELD_LIMBS] = mpn_add(r->n, tmp, FIELD_LIMBS, q, 1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
secp256k1_fe_t ac = *a;
|
||||
secp256k1_fe_t bc = *b;
|
||||
secp256k1_fe_normalize(&ac);
|
||||
secp256k1_fe_normalize(&bc);
|
||||
mp_limb_t tmp[2*FIELD_LIMBS];
|
||||
mpn_mul_n(tmp, ac.n, bc.n, FIELD_LIMBS);
|
||||
secp256k1_fe_reduce(r, tmp);
|
||||
}
|
||||
|
||||
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
secp256k1_fe_t ac = *a;
|
||||
secp256k1_fe_normalize(&ac);
|
||||
mp_limb_t tmp[2*FIELD_LIMBS];
|
||||
mpn_sqr(tmp, ac.n, FIELD_LIMBS);
|
||||
secp256k1_fe_reduce(r, tmp);
|
||||
}
|
||||
|
||||
#endif
|
397
crypto/secp256k1/secp256k1/src/impl/group.h
Normal file
397
crypto/secp256k1/secp256k1/src/impl/group.h
Normal file
@ -0,0 +1,397 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_GROUP_IMPL_H_
|
||||
#define _SECP256K1_GROUP_IMPL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../num.h"
|
||||
#include "../field.h"
|
||||
#include "../group.h"
|
||||
|
||||
void static secp256k1_ge_set_infinity(secp256k1_ge_t *r) {
|
||||
r->infinity = 1;
|
||||
}
|
||||
|
||||
void static secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
|
||||
r->infinity = 0;
|
||||
r->x = *x;
|
||||
r->y = *y;
|
||||
}
|
||||
|
||||
int static secp256k1_ge_is_infinity(const secp256k1_ge_t *a) {
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
void static secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) {
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
secp256k1_fe_normalize(&r->y);
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
}
|
||||
|
||||
void static secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a) {
|
||||
char cx[65]; int lx=65;
|
||||
char cy[65]; int ly=65;
|
||||
secp256k1_fe_get_hex(cx, &lx, &a->x);
|
||||
secp256k1_fe_get_hex(cy, &ly, &a->y);
|
||||
lx = strlen(cx);
|
||||
ly = strlen(cy);
|
||||
int len = lx + ly + 3 + 1;
|
||||
if (*rlen < len) {
|
||||
*rlen = len;
|
||||
return;
|
||||
}
|
||||
*rlen = len;
|
||||
r[0] = '(';
|
||||
memcpy(r+1, cx, lx);
|
||||
r[1+lx] = ',';
|
||||
memcpy(r+2+lx, cy, ly);
|
||||
r[2+lx+ly] = ')';
|
||||
r[3+lx+ly] = 0;
|
||||
}
|
||||
|
||||
void static secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) {
|
||||
secp256k1_fe_inv_var(&a->z, &a->z);
|
||||
secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
|
||||
secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &a->z, &z2);
|
||||
secp256k1_fe_mul(&a->x, &a->x, &z2);
|
||||
secp256k1_fe_mul(&a->y, &a->y, &z3);
|
||||
secp256k1_fe_set_int(&a->z, 1);
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
}
|
||||
|
||||
void static secp256k1_gej_set_infinity(secp256k1_gej_t *r) {
|
||||
r->infinity = 1;
|
||||
}
|
||||
|
||||
void static secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
|
||||
r->infinity = 0;
|
||||
r->x = *x;
|
||||
r->y = *y;
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
}
|
||||
|
||||
void static secp256k1_ge_set_xo(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) {
|
||||
r->x = *x;
|
||||
secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, x);
|
||||
secp256k1_fe_t x3; secp256k1_fe_mul(&x3, x, &x2);
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
|
||||
secp256k1_fe_add(&c, &x3);
|
||||
secp256k1_fe_sqrt(&r->y, &c);
|
||||
secp256k1_fe_normalize(&r->y);
|
||||
if (secp256k1_fe_is_odd(&r->y) != odd)
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) {
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_get_x(secp256k1_fe_t *r, const secp256k1_gej_t *a) {
|
||||
secp256k1_fe_t zi2; secp256k1_fe_inv_var(&zi2, &a->z); secp256k1_fe_sqr(&zi2, &zi2);
|
||||
secp256k1_fe_mul(r, &a->x, &zi2);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
r->z = a->z;
|
||||
secp256k1_fe_normalize(&r->y);
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
}
|
||||
|
||||
int static secp256k1_gej_is_infinity(const secp256k1_gej_t *a) {
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
int static secp256k1_gej_is_valid(const secp256k1_gej_t *a) {
|
||||
if (a->infinity)
|
||||
return 0;
|
||||
// y^2 = x^3 + 7
|
||||
// (Y/Z^3)^2 = (X/Z^2)^3 + 7
|
||||
// Y^2 / Z^6 = X^3 / Z^6 + 7
|
||||
// Y^2 = X^3 + 7*Z^6
|
||||
secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y);
|
||||
secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||
secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
|
||||
secp256k1_fe_t z6; secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
|
||||
secp256k1_fe_mul_int(&z6, 7);
|
||||
secp256k1_fe_add(&x3, &z6);
|
||||
secp256k1_fe_normalize(&y2);
|
||||
secp256k1_fe_normalize(&x3);
|
||||
return secp256k1_fe_equal(&y2, &x3);
|
||||
}
|
||||
|
||||
int static secp256k1_ge_is_valid(const secp256k1_ge_t *a) {
|
||||
if (a->infinity)
|
||||
return 0;
|
||||
// y^2 = x^3 + 7
|
||||
secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y);
|
||||
secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||
secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
|
||||
secp256k1_fe_add(&x3, &c);
|
||||
secp256k1_fe_normalize(&y2);
|
||||
secp256k1_fe_normalize(&x3);
|
||||
return secp256k1_fe_equal(&y2, &x3);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_double(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
|
||||
secp256k1_fe_t t5 = a->y;
|
||||
secp256k1_fe_normalize(&t5);
|
||||
if (a->infinity || secp256k1_fe_is_zero(&t5)) {
|
||||
r->infinity = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
secp256k1_fe_t t1,t2,t3,t4;
|
||||
secp256k1_fe_mul(&r->z, &t5, &a->z);
|
||||
secp256k1_fe_mul_int(&r->z, 2); // Z' = 2*Y*Z (2)
|
||||
secp256k1_fe_sqr(&t1, &a->x);
|
||||
secp256k1_fe_mul_int(&t1, 3); // T1 = 3*X^2 (3)
|
||||
secp256k1_fe_sqr(&t2, &t1); // T2 = 9*X^4 (1)
|
||||
secp256k1_fe_sqr(&t3, &t5);
|
||||
secp256k1_fe_mul_int(&t3, 2); // T3 = 2*Y^2 (2)
|
||||
secp256k1_fe_sqr(&t4, &t3);
|
||||
secp256k1_fe_mul_int(&t4, 2); // T4 = 8*Y^4 (2)
|
||||
secp256k1_fe_mul(&t3, &a->x, &t3); // T3 = 2*X*Y^2 (1)
|
||||
r->x = t3;
|
||||
secp256k1_fe_mul_int(&r->x, 4); // X' = 8*X*Y^2 (4)
|
||||
secp256k1_fe_negate(&r->x, &r->x, 4); // X' = -8*X*Y^2 (5)
|
||||
secp256k1_fe_add(&r->x, &t2); // X' = 9*X^4 - 8*X*Y^2 (6)
|
||||
secp256k1_fe_negate(&t2, &t2, 1); // T2 = -9*X^4 (2)
|
||||
secp256k1_fe_mul_int(&t3, 6); // T3 = 12*X*Y^2 (6)
|
||||
secp256k1_fe_add(&t3, &t2); // T3 = 12*X*Y^2 - 9*X^4 (8)
|
||||
secp256k1_fe_mul(&r->y, &t1, &t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1)
|
||||
secp256k1_fe_negate(&t2, &t4, 2); // T2 = -8*Y^4 (3)
|
||||
secp256k1_fe_add(&r->y, &t2); // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4)
|
||||
r->infinity = 0;
|
||||
}
|
||||
|
||||
void static secp256k1_gej_add(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
|
||||
if (a->infinity) {
|
||||
*r = *b;
|
||||
return;
|
||||
}
|
||||
if (b->infinity) {
|
||||
*r = *a;
|
||||
return;
|
||||
}
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_t z22; secp256k1_fe_sqr(&z22, &b->z);
|
||||
secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z);
|
||||
secp256k1_fe_t u1; secp256k1_fe_mul(&u1, &a->x, &z22);
|
||||
secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||
secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);
|
||||
secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
|
||||
secp256k1_fe_normalize(&u1);
|
||||
secp256k1_fe_normalize(&u2);
|
||||
if (secp256k1_fe_equal(&u1, &u2)) {
|
||||
secp256k1_fe_normalize(&s1);
|
||||
secp256k1_fe_normalize(&s2);
|
||||
if (secp256k1_fe_equal(&s1, &s2)) {
|
||||
secp256k1_gej_double(r, a);
|
||||
} else {
|
||||
r->infinity = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
|
||||
secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i);
|
||||
secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
|
||||
secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
|
||||
secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h);
|
||||
secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
|
||||
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
|
||||
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
|
||||
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
|
||||
secp256k1_fe_add(&r->y, &h3);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
|
||||
if (a->infinity) {
|
||||
r->infinity = b->infinity;
|
||||
r->x = b->x;
|
||||
r->y = b->y;
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
return;
|
||||
}
|
||||
if (b->infinity) {
|
||||
*r = *a;
|
||||
return;
|
||||
}
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z);
|
||||
secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize(&u1);
|
||||
secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||
secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize(&s1);
|
||||
secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
|
||||
secp256k1_fe_normalize(&u1);
|
||||
secp256k1_fe_normalize(&u2);
|
||||
if (secp256k1_fe_equal(&u1, &u2)) {
|
||||
secp256k1_fe_normalize(&s1);
|
||||
secp256k1_fe_normalize(&s2);
|
||||
if (secp256k1_fe_equal(&s1, &s2)) {
|
||||
secp256k1_gej_double(r, a);
|
||||
} else {
|
||||
r->infinity = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
|
||||
secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i);
|
||||
secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
|
||||
secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
|
||||
r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h);
|
||||
secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
|
||||
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
|
||||
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
|
||||
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
|
||||
secp256k1_fe_add(&r->y, &h3);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a) {
|
||||
secp256k1_gej_t c = *a;
|
||||
secp256k1_ge_t t; secp256k1_ge_set_gej(&t, &c);
|
||||
secp256k1_ge_get_hex(r, rlen, &t);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
|
||||
const secp256k1_fe_t *beta = &secp256k1_ge_consts->beta;
|
||||
*r = *a;
|
||||
secp256k1_fe_mul(&r->x, &r->x, beta);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_split_exp(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a) {
|
||||
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
|
||||
secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2;
|
||||
|
||||
secp256k1_num_init(&bnc1);
|
||||
secp256k1_num_init(&bnc2);
|
||||
secp256k1_num_init(&bnt1);
|
||||
secp256k1_num_init(&bnt2);
|
||||
secp256k1_num_init(&bnn2);
|
||||
|
||||
secp256k1_num_copy(&bnn2, &c->order);
|
||||
secp256k1_num_shift(&bnn2, 1);
|
||||
|
||||
secp256k1_num_mul(&bnc1, a, &c->a1b2);
|
||||
secp256k1_num_add(&bnc1, &bnc1, &bnn2);
|
||||
secp256k1_num_div(&bnc1, &bnc1, &c->order);
|
||||
|
||||
secp256k1_num_mul(&bnc2, a, &c->b1);
|
||||
secp256k1_num_add(&bnc2, &bnc2, &bnn2);
|
||||
secp256k1_num_div(&bnc2, &bnc2, &c->order);
|
||||
|
||||
secp256k1_num_mul(&bnt1, &bnc1, &c->a1b2);
|
||||
secp256k1_num_mul(&bnt2, &bnc2, &c->a2);
|
||||
secp256k1_num_add(&bnt1, &bnt1, &bnt2);
|
||||
secp256k1_num_sub(r1, a, &bnt1);
|
||||
secp256k1_num_mul(&bnt1, &bnc1, &c->b1);
|
||||
secp256k1_num_mul(&bnt2, &bnc2, &c->a1b2);
|
||||
secp256k1_num_sub(r2, &bnt1, &bnt2);
|
||||
|
||||
secp256k1_num_free(&bnc1);
|
||||
secp256k1_num_free(&bnc2);
|
||||
secp256k1_num_free(&bnt1);
|
||||
secp256k1_num_free(&bnt2);
|
||||
secp256k1_num_free(&bnn2);
|
||||
}
|
||||
|
||||
|
||||
void static secp256k1_ge_start(void) {
|
||||
static const unsigned char secp256k1_ge_consts_order[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
|
||||
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
|
||||
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
|
||||
};
|
||||
static const unsigned char secp256k1_ge_consts_g_x[] = {
|
||||
0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,
|
||||
0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07,
|
||||
0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,
|
||||
0x59,0xF2,0x81,0x5B,0x16,0xF8,0x17,0x98
|
||||
};
|
||||
static const unsigned char secp256k1_ge_consts_g_y[] = {
|
||||
0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,
|
||||
0x5D,0xA4,0xFB,0xFC,0x0E,0x11,0x08,0xA8,
|
||||
0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,
|
||||
0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8
|
||||
};
|
||||
// properties of secp256k1's efficiently computable endomorphism
|
||||
static const unsigned char secp256k1_ge_consts_lambda[] = {
|
||||
0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,
|
||||
0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
|
||||
0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,
|
||||
0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72
|
||||
};
|
||||
static const unsigned char secp256k1_ge_consts_beta[] = {
|
||||
0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10,
|
||||
0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9,
|
||||
0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95,
|
||||
0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee
|
||||
};
|
||||
static const unsigned char secp256k1_ge_consts_a1b2[] = {
|
||||
0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
|
||||
0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15
|
||||
};
|
||||
static const unsigned char secp256k1_ge_consts_b1[] = {
|
||||
0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
|
||||
0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3
|
||||
};
|
||||
static const unsigned char secp256k1_ge_consts_a2[] = {
|
||||
0x01,
|
||||
0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
|
||||
0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8
|
||||
};
|
||||
if (secp256k1_ge_consts == NULL) {
|
||||
secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)malloc(sizeof(secp256k1_ge_consts_t));
|
||||
secp256k1_num_init(&ret->order);
|
||||
secp256k1_num_init(&ret->half_order);
|
||||
secp256k1_num_init(&ret->lambda);
|
||||
secp256k1_num_init(&ret->a1b2);
|
||||
secp256k1_num_init(&ret->a2);
|
||||
secp256k1_num_init(&ret->b1);
|
||||
secp256k1_num_set_bin(&ret->order, secp256k1_ge_consts_order, sizeof(secp256k1_ge_consts_order));
|
||||
secp256k1_num_set_bin(&ret->lambda, secp256k1_ge_consts_lambda, sizeof(secp256k1_ge_consts_lambda));
|
||||
secp256k1_num_set_bin(&ret->a1b2, secp256k1_ge_consts_a1b2, sizeof(secp256k1_ge_consts_a1b2));
|
||||
secp256k1_num_set_bin(&ret->a2, secp256k1_ge_consts_a2, sizeof(secp256k1_ge_consts_a2));
|
||||
secp256k1_num_set_bin(&ret->b1, secp256k1_ge_consts_b1, sizeof(secp256k1_ge_consts_b1));
|
||||
secp256k1_num_copy(&ret->half_order, &ret->order);
|
||||
secp256k1_num_shift(&ret->half_order, 1);
|
||||
secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta);
|
||||
secp256k1_fe_t g_x, g_y;
|
||||
secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x);
|
||||
secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y);
|
||||
secp256k1_ge_set_xy(&ret->g, &g_x, &g_y);
|
||||
secp256k1_ge_consts = ret;
|
||||
}
|
||||
}
|
||||
|
||||
void static secp256k1_ge_stop(void) {
|
||||
if (secp256k1_ge_consts != NULL) {
|
||||
secp256k1_ge_consts_t *c = (secp256k1_ge_consts_t*)secp256k1_ge_consts;
|
||||
secp256k1_num_free(&c->order);
|
||||
secp256k1_num_free(&c->half_order);
|
||||
secp256k1_num_free(&c->lambda);
|
||||
secp256k1_num_free(&c->a1b2);
|
||||
secp256k1_num_free(&c->a2);
|
||||
secp256k1_num_free(&c->b1);
|
||||
free((void*)c);
|
||||
secp256k1_ge_consts = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
18
crypto/secp256k1/secp256k1/src/impl/num.h
Normal file
18
crypto/secp256k1/secp256k1/src/impl/num.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_NUM_IMPL_H_
|
||||
#define _SECP256K1_NUM_IMPL_H_
|
||||
|
||||
#include "../num.h"
|
||||
|
||||
#if defined(USE_NUM_GMP)
|
||||
#include "num_gmp.h"
|
||||
#elif defined(USE_NUM_OPENSSL)
|
||||
#include "num_openssl.h"
|
||||
#else
|
||||
#error "Please select num implementation"
|
||||
#endif
|
||||
|
||||
#endif
|
346
crypto/secp256k1/secp256k1/src/impl/num_gmp.h
Normal file
346
crypto/secp256k1/secp256k1/src/impl/num_gmp.h
Normal file
@ -0,0 +1,346 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_NUM_REPR_IMPL_H_
|
||||
#define _SECP256K1_NUM_REPR_IMPL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "num.h"
|
||||
|
||||
#ifdef VERIFY
|
||||
void static secp256k1_num_sanity(const secp256k1_num_t *a) {
|
||||
assert(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0));
|
||||
}
|
||||
#else
|
||||
#define secp256k1_num_sanity(a) do { } while(0)
|
||||
#endif
|
||||
|
||||
void static secp256k1_num_init(secp256k1_num_t *r) {
|
||||
r->neg = 0;
|
||||
r->limbs = 1;
|
||||
r->data[0] = 0;
|
||||
}
|
||||
|
||||
void static secp256k1_num_free(secp256k1_num_t *r) {
|
||||
}
|
||||
|
||||
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
|
||||
*r = *a;
|
||||
}
|
||||
|
||||
int static secp256k1_num_bits(const secp256k1_num_t *a) {
|
||||
int ret=(a->limbs-1)*GMP_NUMB_BITS;
|
||||
mp_limb_t x=a->data[a->limbs-1];
|
||||
while (x) {
|
||||
x >>= 1;
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
|
||||
unsigned char tmp[65];
|
||||
int len = 0;
|
||||
if (a->limbs>1 || a->data[0] != 0) {
|
||||
len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);
|
||||
}
|
||||
int shift = 0;
|
||||
while (shift < len && tmp[shift] == 0) shift++;
|
||||
assert(len-shift <= rlen);
|
||||
memset(r, 0, rlen - len + shift);
|
||||
if (len > shift)
|
||||
memcpy(r + rlen - len + shift, tmp + shift, len - shift);
|
||||
}
|
||||
|
||||
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
|
||||
assert(alen > 0);
|
||||
assert(alen <= 64);
|
||||
int len = mpn_set_str(r->data, a, alen, 256);
|
||||
assert(len <= NUM_LIMBS*2);
|
||||
r->limbs = len;
|
||||
r->neg = 0;
|
||||
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
|
||||
}
|
||||
|
||||
void static secp256k1_num_set_int(secp256k1_num_t *r, int a) {
|
||||
r->limbs = 1;
|
||||
r->neg = (a < 0);
|
||||
r->data[0] = (a < 0) ? -a : a;
|
||||
}
|
||||
|
||||
void static secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
|
||||
r->limbs = a->limbs;
|
||||
if (c != 0) {
|
||||
assert(r->limbs < 2*NUM_LIMBS);
|
||||
r->data[r->limbs++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void static secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
|
||||
assert(c == 0);
|
||||
r->limbs = a->limbs;
|
||||
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
|
||||
}
|
||||
|
||||
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
|
||||
secp256k1_num_sanity(r);
|
||||
secp256k1_num_sanity(m);
|
||||
|
||||
if (r->limbs >= m->limbs) {
|
||||
mp_limb_t t[2*NUM_LIMBS];
|
||||
mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs);
|
||||
r->limbs = m->limbs;
|
||||
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
|
||||
}
|
||||
|
||||
if (r->neg && (r->limbs > 1 || r->data[0] != 0)) {
|
||||
secp256k1_num_sub_abs(r, m, r);
|
||||
r->neg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
|
||||
secp256k1_num_sanity(a);
|
||||
secp256k1_num_sanity(m);
|
||||
|
||||
// mpn_gcdext computes: (G,S) = gcdext(U,V), where
|
||||
// * G = gcd(U,V)
|
||||
// * G = U*S + V*T
|
||||
// * U has equal or more limbs than V, and V has no padding
|
||||
// If we set U to be (a padded version of) a, and V = m:
|
||||
// G = a*S + m*T
|
||||
// G = a*S mod m
|
||||
// Assuming G=1:
|
||||
// S = 1/a mod m
|
||||
assert(m->limbs <= NUM_LIMBS);
|
||||
assert(m->data[m->limbs-1] != 0);
|
||||
mp_limb_t g[NUM_LIMBS+1];
|
||||
mp_limb_t u[NUM_LIMBS+1];
|
||||
mp_limb_t v[NUM_LIMBS+1];
|
||||
for (int i=0; i < m->limbs; i++) {
|
||||
u[i] = (i < a->limbs) ? a->data[i] : 0;
|
||||
v[i] = m->data[i];
|
||||
}
|
||||
mp_size_t sn = NUM_LIMBS+1;
|
||||
mp_size_t gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
|
||||
assert(gn == 1);
|
||||
assert(g[0] == 1);
|
||||
r->neg = a->neg ^ m->neg;
|
||||
if (sn < 0) {
|
||||
mpn_sub(r->data, m->data, m->limbs, r->data, -sn);
|
||||
r->limbs = m->limbs;
|
||||
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
|
||||
} else {
|
||||
r->limbs = sn;
|
||||
}
|
||||
}
|
||||
|
||||
int static secp256k1_num_is_zero(const secp256k1_num_t *a) {
|
||||
return (a->limbs == 1 && a->data[0] == 0);
|
||||
}
|
||||
|
||||
int static secp256k1_num_is_odd(const secp256k1_num_t *a) {
|
||||
return a->data[0] & 1;
|
||||
}
|
||||
|
||||
int static secp256k1_num_is_neg(const secp256k1_num_t *a) {
|
||||
return (a->limbs > 1 || a->data[0] != 0) && a->neg;
|
||||
}
|
||||
|
||||
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
if (a->limbs > b->limbs) return 1;
|
||||
if (a->limbs < b->limbs) return -1;
|
||||
return mpn_cmp(a->data, b->data, a->limbs);
|
||||
}
|
||||
|
||||
void static secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) {
|
||||
if (!(b->neg ^ bneg ^ a->neg)) { // a and b have the same sign
|
||||
r->neg = a->neg;
|
||||
if (a->limbs >= b->limbs) {
|
||||
secp256k1_num_add_abs(r, a, b);
|
||||
} else {
|
||||
secp256k1_num_add_abs(r, b, a);
|
||||
}
|
||||
} else {
|
||||
if (secp256k1_num_cmp(a, b) > 0) {
|
||||
r->neg = a->neg;
|
||||
secp256k1_num_sub_abs(r, a, b);
|
||||
} else {
|
||||
r->neg = b->neg ^ bneg;
|
||||
secp256k1_num_sub_abs(r, b, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
secp256k1_num_sanity(a);
|
||||
secp256k1_num_sanity(b);
|
||||
secp256k1_num_subadd(r, a, b, 0);
|
||||
}
|
||||
|
||||
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
secp256k1_num_sanity(a);
|
||||
secp256k1_num_sanity(b);
|
||||
secp256k1_num_subadd(r, a, b, 1);
|
||||
}
|
||||
|
||||
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
secp256k1_num_sanity(a);
|
||||
secp256k1_num_sanity(b);
|
||||
|
||||
mp_limb_t tmp[2*NUM_LIMBS+1];
|
||||
assert(a->limbs + b->limbs <= 2*NUM_LIMBS+1);
|
||||
if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) {
|
||||
r->limbs = 1;
|
||||
r->neg = 0;
|
||||
r->data[0] = 0;
|
||||
return;
|
||||
}
|
||||
if (a->limbs >= b->limbs)
|
||||
mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs);
|
||||
else
|
||||
mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs);
|
||||
r->limbs = a->limbs + b->limbs;
|
||||
if (r->limbs > 1 && tmp[r->limbs - 1]==0) r->limbs--;
|
||||
assert(r->limbs <= 2*NUM_LIMBS);
|
||||
mpn_copyi(r->data, tmp, r->limbs);
|
||||
r->neg = a->neg ^ b->neg;
|
||||
}
|
||||
|
||||
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
secp256k1_num_sanity(a);
|
||||
secp256k1_num_sanity(b);
|
||||
if (b->limbs > a->limbs) {
|
||||
r->limbs = 1;
|
||||
r->data[0] = 0;
|
||||
r->neg = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mp_limb_t quo[2*NUM_LIMBS+1];
|
||||
mp_limb_t rem[2*NUM_LIMBS+1];
|
||||
mpn_tdiv_qr(quo, rem, 0, a->data, a->limbs, b->data, b->limbs);
|
||||
mpn_copyi(r->data, quo, a->limbs - b->limbs + 1);
|
||||
r->limbs = a->limbs - b->limbs + 1;
|
||||
while (r->limbs > 1 && r->data[r->limbs - 1]==0) r->limbs--;
|
||||
r->neg = a->neg ^ b->neg;
|
||||
}
|
||||
|
||||
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
|
||||
secp256k1_num_mul(r, a, b);
|
||||
secp256k1_num_mod(r, m);
|
||||
}
|
||||
|
||||
|
||||
int static secp256k1_num_shift(secp256k1_num_t *r, int bits) {
|
||||
assert(bits <= GMP_NUMB_BITS);
|
||||
mp_limb_t ret = mpn_rshift(r->data, r->data, r->limbs, bits);
|
||||
if (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
|
||||
ret >>= (GMP_NUMB_BITS - bits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
|
||||
return (a->limbs*GMP_NUMB_BITS > pos) && ((a->data[pos/GMP_NUMB_BITS] >> (pos % GMP_NUMB_BITS)) & 1);
|
||||
}
|
||||
|
||||
void static secp256k1_num_inc(secp256k1_num_t *r) {
|
||||
mp_limb_t ret = mpn_add_1(r->data, r->data, r->limbs, (mp_limb_t)1);
|
||||
if (ret) {
|
||||
assert(r->limbs < 2*NUM_LIMBS);
|
||||
r->data[r->limbs++] = ret;
|
||||
}
|
||||
}
|
||||
|
||||
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
|
||||
static const unsigned char cvt[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
|
||||
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
unsigned char num[257] = {};
|
||||
for (int i=0; i<alen; i++) {
|
||||
num[i] = cvt[a[i]];
|
||||
}
|
||||
r->limbs = mpn_set_str(r->data, num, alen, 16);
|
||||
while (r->limbs > 1 && r->data[r->limbs-1] == 0) r->limbs--;
|
||||
}
|
||||
|
||||
void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a) {
|
||||
static const unsigned char cvt[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
unsigned char *tmp = malloc(257);
|
||||
mp_size_t len = mpn_get_str(tmp, 16, (mp_limb_t*)a->data, a->limbs);
|
||||
assert(len <= rlen);
|
||||
for (int i=0; i<len; i++) {
|
||||
assert(rlen-len+i >= 0);
|
||||
assert(rlen-len+i < rlen);
|
||||
assert(tmp[i] >= 0);
|
||||
assert(tmp[i] < 16);
|
||||
r[rlen-len+i] = cvt[tmp[i]];
|
||||
}
|
||||
for (int i=0; i<rlen-len; i++) {
|
||||
assert(i >= 0);
|
||||
assert(i < rlen);
|
||||
r[i] = cvt[0];
|
||||
}
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
|
||||
assert(bits > 0);
|
||||
rh->neg = a->neg;
|
||||
if (bits >= a->limbs * GMP_NUMB_BITS) {
|
||||
*rl = *a;
|
||||
rh->limbs = 1;
|
||||
rh->data[0] = 0;
|
||||
return;
|
||||
}
|
||||
rl->limbs = 0;
|
||||
rl->neg = a->neg;
|
||||
int left = bits;
|
||||
while (left >= GMP_NUMB_BITS) {
|
||||
rl->data[rl->limbs] = a->data[rl->limbs];
|
||||
rl->limbs++;
|
||||
left -= GMP_NUMB_BITS;
|
||||
}
|
||||
if (left == 0) {
|
||||
mpn_copyi(rh->data, a->data + rl->limbs, a->limbs - rl->limbs);
|
||||
rh->limbs = a->limbs - rl->limbs;
|
||||
} else {
|
||||
mpn_rshift(rh->data, a->data + rl->limbs, a->limbs - rl->limbs, left);
|
||||
rh->limbs = a->limbs - rl->limbs;
|
||||
while (rh->limbs>1 && rh->data[rh->limbs-1]==0) rh->limbs--;
|
||||
}
|
||||
if (left > 0) {
|
||||
rl->data[rl->limbs] = a->data[rl->limbs] & ((((mp_limb_t)1) << left) - 1);
|
||||
rl->limbs++;
|
||||
}
|
||||
while (rl->limbs>1 && rl->data[rl->limbs-1]==0) rl->limbs--;
|
||||
}
|
||||
|
||||
void static secp256k1_num_negate(secp256k1_num_t *r) {
|
||||
r->neg ^= 1;
|
||||
}
|
||||
|
||||
#endif
|
145
crypto/secp256k1/secp256k1/src/impl/num_openssl.h
Normal file
145
crypto/secp256k1/secp256k1/src/impl/num_openssl.h
Normal file
@ -0,0 +1,145 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_NUM_REPR_IMPL_H_
|
||||
#define _SECP256K1_NUM_REPR_IMPL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "../num.h"
|
||||
|
||||
void static secp256k1_num_init(secp256k1_num_t *r) {
|
||||
BN_init(&r->bn);
|
||||
}
|
||||
|
||||
void static secp256k1_num_free(secp256k1_num_t *r) {
|
||||
BN_free(&r->bn);
|
||||
}
|
||||
|
||||
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
|
||||
BN_copy(&r->bn, &a->bn);
|
||||
}
|
||||
|
||||
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
|
||||
unsigned int size = BN_num_bytes(&a->bn);
|
||||
assert(size <= rlen);
|
||||
memset(r,0,rlen);
|
||||
BN_bn2bin(&a->bn, r + rlen - size);
|
||||
}
|
||||
|
||||
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
|
||||
BN_bin2bn(a, alen, &r->bn);
|
||||
}
|
||||
|
||||
void static secp256k1_num_set_int(secp256k1_num_t *r, int a) {
|
||||
BN_set_word(&r->bn, a < 0 ? -a : a);
|
||||
BN_set_negative(&r->bn, a < 0);
|
||||
}
|
||||
|
||||
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_mod_inverse(&r->bn, &a->bn, &m->bn, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_mod_mul(&r->bn, &a->bn, &b->bn, &m->bn, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
return BN_cmp(&a->bn, &b->bn);
|
||||
}
|
||||
|
||||
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
BN_add(&r->bn, &a->bn, &b->bn);
|
||||
}
|
||||
|
||||
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
BN_sub(&r->bn, &a->bn, &b->bn);
|
||||
}
|
||||
|
||||
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_mul(&r->bn, &a->bn, &b->bn, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_div(&r->bn, NULL, &a->bn, &b->bn, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_nnmod(&r->bn, &r->bn, &m->bn, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
int static secp256k1_num_bits(const secp256k1_num_t *a) {
|
||||
return BN_num_bits(&a->bn);
|
||||
}
|
||||
|
||||
int static secp256k1_num_shift(secp256k1_num_t *r, int bits) {
|
||||
int ret = BN_is_zero(&r->bn) ? 0 : r->bn.d[0] & ((1 << bits) - 1);
|
||||
BN_rshift(&r->bn, &r->bn, bits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int static secp256k1_num_is_zero(const secp256k1_num_t *a) {
|
||||
return BN_is_zero(&a->bn);
|
||||
}
|
||||
|
||||
int static secp256k1_num_is_odd(const secp256k1_num_t *a) {
|
||||
return BN_is_odd(&a->bn);
|
||||
}
|
||||
|
||||
int static secp256k1_num_is_neg(const secp256k1_num_t *a) {
|
||||
return BN_is_negative(&a->bn);
|
||||
}
|
||||
|
||||
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
|
||||
return BN_is_bit_set(&a->bn, pos);
|
||||
}
|
||||
|
||||
void static secp256k1_num_inc(secp256k1_num_t *r) {
|
||||
BN_add_word(&r->bn, 1);
|
||||
}
|
||||
|
||||
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
|
||||
char *str = (char*)malloc(alen+1);
|
||||
memcpy(str, a, alen);
|
||||
str[alen] = 0;
|
||||
BIGNUM *pbn = &r->bn;
|
||||
BN_hex2bn(&pbn, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a) {
|
||||
char *str = BN_bn2hex(&a->bn);
|
||||
int len = strlen(str);
|
||||
assert(rlen >= len);
|
||||
for (int i=0; i<rlen-len; i++)
|
||||
r[i] = '0';
|
||||
memcpy(r+rlen-len, str, len);
|
||||
OPENSSL_free(str);
|
||||
}
|
||||
|
||||
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
|
||||
BN_copy(&rl->bn, &a->bn);
|
||||
BN_rshift(&rh->bn, &a->bn, bits);
|
||||
BN_mask_bits(&rl->bn, bits);
|
||||
}
|
||||
|
||||
void static secp256k1_num_negate(secp256k1_num_t *r) {
|
||||
BN_set_negative(&r->bn, !BN_is_negative(&r->bn));
|
||||
}
|
||||
|
||||
#endif
|
45
crypto/secp256k1/secp256k1/src/impl/util.h
Normal file
45
crypto/secp256k1/secp256k1/src/impl/util.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_UTIL_IMPL_H_
|
||||
#define _SECP256K1_UTIL_IMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../util.h"
|
||||
|
||||
static inline uint32_t secp256k1_rand32(void) {
|
||||
static uint32_t Rz = 11, Rw = 11;
|
||||
Rz = 36969 * (Rz & 0xFFFF) + (Rz >> 16);
|
||||
Rw = 18000 * (Rw & 0xFFFF) + (Rw >> 16);
|
||||
return (Rw << 16) + (Rw >> 16) + Rz;
|
||||
}
|
||||
|
||||
static void secp256k1_rand256(unsigned char *b32) {
|
||||
for (int i=0; i<8; i++) {
|
||||
uint32_t r = secp256k1_rand32();
|
||||
b32[i*4 + 0] = (r >> 0) & 0xFF;
|
||||
b32[i*4 + 1] = (r >> 8) & 0xFF;
|
||||
b32[i*4 + 2] = (r >> 16) & 0xFF;
|
||||
b32[i*4 + 3] = (r >> 24) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_rand256_test(unsigned char *b32) {
|
||||
int bits=0;
|
||||
memset(b32, 0, 32);
|
||||
while (bits < 256) {
|
||||
uint32_t ent = secp256k1_rand32();
|
||||
int now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31;
|
||||
uint32_t val = 1 & (ent >> 11);
|
||||
while (now > 0 && bits < 256) {
|
||||
b32[bits / 8] |= val << (bits % 8);
|
||||
now--;
|
||||
bits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,60 @@
|
||||
package org.bitcoin;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
|
||||
/**
|
||||
* This class holds native methods to handle ECDSA verification.
|
||||
* You can find an example library that can be used for this at
|
||||
* https://github.com/sipa/secp256k1
|
||||
*/
|
||||
public class NativeSecp256k1 {
|
||||
public static final boolean enabled;
|
||||
static {
|
||||
boolean isEnabled = true;
|
||||
try {
|
||||
System.loadLibrary("javasecp256k1");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
isEnabled = false;
|
||||
}
|
||||
enabled = isEnabled;
|
||||
}
|
||||
|
||||
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
|
||||
/**
|
||||
* Verifies the given secp256k1 signature in native code.
|
||||
* Calling when enabled == false is undefined (probably library not loaded)
|
||||
*
|
||||
* @param data The data which was signed, must be exactly 32 bytes
|
||||
* @param signature The signature
|
||||
* @param pub The public key which did the signing
|
||||
*/
|
||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
|
||||
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.putInt(signature.length);
|
||||
byteBuff.putInt(pub.length);
|
||||
byteBuff.put(signature);
|
||||
byteBuff.put(pub);
|
||||
return secp256k1_ecdsa_verify(byteBuff) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byteBuff signature format is byte[32] data,
|
||||
* native-endian int signatureLength, native-endian int pubkeyLength,
|
||||
* byte[signatureLength] signature, byte[pubkeyLength] pub
|
||||
* @returns 1 for valid signature, anything else for invalid
|
||||
*/
|
||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#include "org_bitcoin_NativeSecp256k1.h"
|
||||
#include "include/secp256k1.h"
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject)
|
||||
{
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
int sigLen = *((int*)(data + 32));
|
||||
int pubLen = *((int*)(data + 32 + 4));
|
||||
|
||||
return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
|
||||
}
|
||||
|
||||
static void __javasecp256k1_attach(void) __attribute__((constructor));
|
||||
static void __javasecp256k1_detach(void) __attribute__((destructor));
|
||||
|
||||
static void __javasecp256k1_attach(void) {
|
||||
secp256k1_start();
|
||||
}
|
||||
|
||||
static void __javasecp256k1_detach(void) {
|
||||
secp256k1_stop();
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class org_bitcoin_NativeSecp256k1 */
|
||||
|
||||
#ifndef _Included_org_bitcoin_NativeSecp256k1
|
||||
#define _Included_org_bitcoin_NativeSecp256k1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdsa_verify
|
||||
* Signature: (Ljava/nio/ByteBuffer;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
93
crypto/secp256k1/secp256k1/src/num.h
Normal file
93
crypto/secp256k1/secp256k1/src/num.h
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_NUM_
|
||||
#define _SECP256K1_NUM_
|
||||
|
||||
#if defined(USE_NUM_GMP)
|
||||
#include "num_gmp.h"
|
||||
#elif defined(USE_NUM_OPENSSL)
|
||||
#include "num_openssl.h"
|
||||
#else
|
||||
#error "Please select num implementation"
|
||||
#endif
|
||||
|
||||
/** Initialize a number. */
|
||||
void static secp256k1_num_init(secp256k1_num_t *r);
|
||||
|
||||
/** Free a number. */
|
||||
void static secp256k1_num_free(secp256k1_num_t *r);
|
||||
|
||||
/** Copy a number. */
|
||||
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a);
|
||||
|
||||
/** Convert a number's absolute value to a binary big-endian string.
|
||||
* There must be enough place. */
|
||||
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a);
|
||||
|
||||
/** Set a number to the value of a binary big-endian string. */
|
||||
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen);
|
||||
|
||||
/** Set a number equal to a (signed) integer. */
|
||||
void static secp256k1_num_set_int(secp256k1_num_t *r, int a);
|
||||
|
||||
/** Compute a modular inverse. The input must be less than the modulus. */
|
||||
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m);
|
||||
|
||||
/** Multiply two numbers modulo another. */
|
||||
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m);
|
||||
|
||||
/** Compare the absolute value of two numbers. */
|
||||
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b);
|
||||
|
||||
/** Add two (signed) numbers. */
|
||||
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
|
||||
|
||||
/** Subtract two (signed) numbers. */
|
||||
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
|
||||
|
||||
/** Multiply two (signed) numbers. */
|
||||
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
|
||||
|
||||
/** Divide two (signed) numbers. */
|
||||
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
|
||||
|
||||
/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
|
||||
even if r was negative. */
|
||||
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m);
|
||||
|
||||
/** Calculate the number of bits in (the absolute value of) a number. */
|
||||
int static secp256k1_num_bits(const secp256k1_num_t *a);
|
||||
|
||||
/** Right-shift the passed number by bits bits, and return those bits. */
|
||||
int static secp256k1_num_shift(secp256k1_num_t *r, int bits);
|
||||
|
||||
/** Check whether a number is zero. */
|
||||
int static secp256k1_num_is_zero(const secp256k1_num_t *a);
|
||||
|
||||
/** Check whether a number is odd. */
|
||||
int static secp256k1_num_is_odd(const secp256k1_num_t *a);
|
||||
|
||||
/** Check whether a number is strictly negative. */
|
||||
int static secp256k1_num_is_neg(const secp256k1_num_t *a);
|
||||
|
||||
/** Check whether a particular bit is set in a number. */
|
||||
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos);
|
||||
|
||||
/** Increase a number by 1. */
|
||||
void static secp256k1_num_inc(secp256k1_num_t *r);
|
||||
|
||||
/** Set a number equal to the value of a hex string (unsigned). */
|
||||
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen);
|
||||
|
||||
/** Convert (the absolute value of) a number to a hexadecimal string. */
|
||||
void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a);
|
||||
|
||||
/** Split a number into a low and high part. */
|
||||
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits);
|
||||
|
||||
/** Change a number's sign. */
|
||||
void static secp256k1_num_negate(secp256k1_num_t *r);
|
||||
|
||||
#endif
|
18
crypto/secp256k1/secp256k1/src/num_gmp.h
Normal file
18
crypto/secp256k1/secp256k1/src/num_gmp.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_NUM_REPR_
|
||||
#define _SECP256K1_NUM_REPR_
|
||||
|
||||
#include <gmp.h>
|
||||
|
||||
#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS)
|
||||
|
||||
typedef struct {
|
||||
mp_limb_t data[2*NUM_LIMBS];
|
||||
int neg;
|
||||
int limbs;
|
||||
} secp256k1_num_t;
|
||||
|
||||
#endif
|
14
crypto/secp256k1/secp256k1/src/num_openssl.h
Normal file
14
crypto/secp256k1/secp256k1/src/num_openssl.h
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_NUM_REPR_
|
||||
#define _SECP256K1_NUM_REPR_
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
typedef struct {
|
||||
BIGNUM bn;
|
||||
} secp256k1_num_t;
|
||||
|
||||
#endif
|
269
crypto/secp256k1/secp256k1/src/secp256k1.c
Normal file
269
crypto/secp256k1/secp256k1/src/secp256k1.c
Normal file
@ -0,0 +1,269 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "impl/num.h"
|
||||
#include "impl/field.h"
|
||||
#include "impl/group.h"
|
||||
#include "impl/ecmult.h"
|
||||
#include "impl/ecdsa.h"
|
||||
|
||||
void secp256k1_start(void) {
|
||||
secp256k1_fe_start();
|
||||
secp256k1_ge_start();
|
||||
secp256k1_ecmult_start();
|
||||
}
|
||||
|
||||
void secp256k1_stop(void) {
|
||||
secp256k1_ecmult_stop();
|
||||
secp256k1_ge_stop();
|
||||
secp256k1_fe_stop();
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) {
|
||||
int ret = -3;
|
||||
secp256k1_num_t m;
|
||||
secp256k1_num_init(&m);
|
||||
secp256k1_ecdsa_sig_t s;
|
||||
secp256k1_ecdsa_sig_init(&s);
|
||||
secp256k1_ge_t q;
|
||||
secp256k1_num_set_bin(&m, msg, msglen);
|
||||
|
||||
if (!secp256k1_ecdsa_pubkey_parse(&q, pubkey, pubkeylen)) {
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
|
||||
ret = -2;
|
||||
goto end;
|
||||
}
|
||||
if (!secp256k1_ecdsa_sig_verify(&s, &q, &m)) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
secp256k1_ecdsa_sig_free(&s);
|
||||
secp256k1_num_free(&m);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_sign(const unsigned char *message, int messagelen, unsigned char *signature, int *signaturelen, const unsigned char *seckey, const unsigned char *nonce) {
|
||||
secp256k1_num_t sec, non, msg;
|
||||
secp256k1_num_init(&sec);
|
||||
secp256k1_num_init(&non);
|
||||
secp256k1_num_init(&msg);
|
||||
secp256k1_num_set_bin(&sec, seckey, 32);
|
||||
secp256k1_num_set_bin(&non, nonce, 32);
|
||||
secp256k1_num_set_bin(&msg, message, messagelen);
|
||||
secp256k1_ecdsa_sig_t sig;
|
||||
secp256k1_ecdsa_sig_init(&sig);
|
||||
int ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL);
|
||||
if (ret) {
|
||||
secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
|
||||
}
|
||||
secp256k1_ecdsa_sig_free(&sig);
|
||||
secp256k1_num_free(&msg);
|
||||
secp256k1_num_free(&non);
|
||||
secp256k1_num_free(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, unsigned char *sig64, const unsigned char *seckey, const unsigned char *nonce, int *recid) {
|
||||
secp256k1_num_t sec, non, msg;
|
||||
secp256k1_num_init(&sec);
|
||||
secp256k1_num_init(&non);
|
||||
secp256k1_num_init(&msg);
|
||||
secp256k1_num_set_bin(&sec, seckey, 32);
|
||||
secp256k1_num_set_bin(&non, nonce, 32);
|
||||
secp256k1_num_set_bin(&msg, message, messagelen);
|
||||
secp256k1_ecdsa_sig_t sig;
|
||||
secp256k1_ecdsa_sig_init(&sig);
|
||||
int ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid);
|
||||
if (ret) {
|
||||
secp256k1_num_get_bin(sig64, 32, &sig.r);
|
||||
secp256k1_num_get_bin(sig64 + 32, 32, &sig.s);
|
||||
}
|
||||
secp256k1_ecdsa_sig_free(&sig);
|
||||
secp256k1_num_free(&msg);
|
||||
secp256k1_num_free(&non);
|
||||
secp256k1_num_free(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) {
|
||||
int ret = 0;
|
||||
secp256k1_num_t m;
|
||||
secp256k1_num_init(&m);
|
||||
secp256k1_ecdsa_sig_t sig;
|
||||
secp256k1_ecdsa_sig_init(&sig);
|
||||
secp256k1_num_set_bin(&sig.r, sig64, 32);
|
||||
secp256k1_num_set_bin(&sig.s, sig64 + 32, 32);
|
||||
secp256k1_num_set_bin(&m, msg, msglen);
|
||||
|
||||
secp256k1_ge_t q;
|
||||
if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) {
|
||||
secp256k1_ecdsa_pubkey_serialize(&q, pubkey, pubkeylen, compressed);
|
||||
ret = 1;
|
||||
}
|
||||
secp256k1_ecdsa_sig_free(&sig);
|
||||
secp256k1_num_free(&m);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey) {
|
||||
secp256k1_num_t sec;
|
||||
secp256k1_num_init(&sec);
|
||||
secp256k1_num_set_bin(&sec, seckey, 32);
|
||||
int ret = !secp256k1_num_is_zero(&sec) &&
|
||||
(secp256k1_num_cmp(&sec, &secp256k1_ge_consts->order) < 0);
|
||||
secp256k1_num_free(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen) {
|
||||
secp256k1_ge_t q;
|
||||
return secp256k1_ecdsa_pubkey_parse(&q, pubkey, pubkeylen);
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) {
|
||||
secp256k1_num_t sec;
|
||||
secp256k1_num_init(&sec);
|
||||
secp256k1_num_set_bin(&sec, seckey, 32);
|
||||
secp256k1_gej_t pj;
|
||||
secp256k1_ecmult_gen(&pj, &sec);
|
||||
secp256k1_ge_t p;
|
||||
secp256k1_ge_set_gej(&p, &pj);
|
||||
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, pubkeylen, compressed);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_pubkey_decompress(unsigned char *pubkey, int *pubkeylen) {
|
||||
secp256k1_ge_t p;
|
||||
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, *pubkeylen))
|
||||
return 0;
|
||||
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, pubkeylen, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak) {
|
||||
int ret = 1;
|
||||
secp256k1_num_t term;
|
||||
secp256k1_num_init(&term);
|
||||
secp256k1_num_set_bin(&term, tweak, 32);
|
||||
if (secp256k1_num_cmp(&term, &secp256k1_ge_consts->order) >= 0)
|
||||
ret = 0;
|
||||
secp256k1_num_t sec;
|
||||
secp256k1_num_init(&sec);
|
||||
if (ret) {
|
||||
secp256k1_num_set_bin(&sec, seckey, 32);
|
||||
secp256k1_num_add(&sec, &sec, &term);
|
||||
secp256k1_num_mod(&sec, &secp256k1_ge_consts->order);
|
||||
if (secp256k1_num_is_zero(&sec))
|
||||
ret = 0;
|
||||
}
|
||||
if (ret)
|
||||
secp256k1_num_get_bin(seckey, 32, &sec);
|
||||
secp256k1_num_free(&sec);
|
||||
secp256k1_num_free(&term);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
|
||||
int ret = 1;
|
||||
secp256k1_num_t term;
|
||||
secp256k1_num_init(&term);
|
||||
secp256k1_num_set_bin(&term, tweak, 32);
|
||||
if (secp256k1_num_cmp(&term, &secp256k1_ge_consts->order) >= 0)
|
||||
ret = 0;
|
||||
secp256k1_ge_t p;
|
||||
if (ret) {
|
||||
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, pubkeylen))
|
||||
ret = 0;
|
||||
}
|
||||
if (ret) {
|
||||
secp256k1_gej_t pt;
|
||||
secp256k1_ecmult_gen(&pt, &term);
|
||||
secp256k1_gej_add_ge(&pt, &pt, &p);
|
||||
if (secp256k1_gej_is_infinity(&pt))
|
||||
ret = 0;
|
||||
secp256k1_ge_set_gej(&p, &pt);
|
||||
int oldlen = pubkeylen;
|
||||
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
|
||||
assert(pubkeylen == oldlen);
|
||||
}
|
||||
secp256k1_num_free(&term);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak) {
|
||||
int ret = 1;
|
||||
secp256k1_num_t factor;
|
||||
secp256k1_num_init(&factor);
|
||||
secp256k1_num_set_bin(&factor, tweak, 32);
|
||||
if (secp256k1_num_is_zero(&factor))
|
||||
ret = 0;
|
||||
if (secp256k1_num_cmp(&factor, &secp256k1_ge_consts->order) >= 0)
|
||||
ret = 0;
|
||||
secp256k1_num_t sec;
|
||||
secp256k1_num_init(&sec);
|
||||
if (ret) {
|
||||
secp256k1_num_set_bin(&sec, seckey, 32);
|
||||
secp256k1_num_mod_mul(&sec, &sec, &factor, &secp256k1_ge_consts->order);
|
||||
}
|
||||
if (ret)
|
||||
secp256k1_num_get_bin(seckey, 32, &sec);
|
||||
secp256k1_num_free(&sec);
|
||||
secp256k1_num_free(&factor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
|
||||
int ret = 1;
|
||||
secp256k1_num_t factor;
|
||||
secp256k1_num_init(&factor);
|
||||
secp256k1_num_set_bin(&factor, tweak, 32);
|
||||
if (secp256k1_num_is_zero(&factor))
|
||||
ret = 0;
|
||||
if (secp256k1_num_cmp(&factor, &secp256k1_ge_consts->order) >= 0)
|
||||
ret = 0;
|
||||
secp256k1_ge_t p;
|
||||
if (ret) {
|
||||
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, pubkeylen))
|
||||
ret = 0;
|
||||
}
|
||||
if (ret) {
|
||||
secp256k1_num_t zero;
|
||||
secp256k1_num_init(&zero);
|
||||
secp256k1_num_set_int(&zero, 0);
|
||||
secp256k1_gej_t pt;
|
||||
secp256k1_gej_set_ge(&pt, &p);
|
||||
secp256k1_ecmult(&pt, &pt, &factor, &zero);
|
||||
secp256k1_num_free(&zero);
|
||||
secp256k1_ge_set_gej(&p, &pt);
|
||||
int oldlen = pubkeylen;
|
||||
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
|
||||
assert(pubkeylen == oldlen);
|
||||
}
|
||||
secp256k1_num_free(&factor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_privkey_export(const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) {
|
||||
secp256k1_num_t key;
|
||||
secp256k1_num_init(&key);
|
||||
secp256k1_num_set_bin(&key, seckey, 32);
|
||||
int ret = secp256k1_ecdsa_privkey_serialize(privkey, privkeylen, &key, compressed);
|
||||
secp256k1_num_free(&key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_privkey_import(unsigned char *seckey, const unsigned char *privkey, int privkeylen) {
|
||||
secp256k1_num_t key;
|
||||
secp256k1_num_init(&key);
|
||||
int ret = secp256k1_ecdsa_privkey_parse(&key, privkey, privkeylen);
|
||||
if (ret)
|
||||
secp256k1_num_get_bin(seckey, 32, &key);
|
||||
secp256k1_num_free(&key);
|
||||
return ret;
|
||||
}
|
465
crypto/secp256k1/secp256k1/src/tests.c
Normal file
465
crypto/secp256k1/secp256k1/src/tests.c
Normal file
@ -0,0 +1,465 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "impl/num.h"
|
||||
#include "impl/field.h"
|
||||
#include "impl/group.h"
|
||||
#include "impl/ecmult.h"
|
||||
#include "impl/ecdsa.h"
|
||||
#include "impl/util.h"
|
||||
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
#include "openssl/bn.h"
|
||||
#include "openssl/ec.h"
|
||||
#include "openssl/ecdsa.h"
|
||||
#include "openssl/obj_mac.h"
|
||||
#endif
|
||||
|
||||
static int count = 100;
|
||||
|
||||
/***** NUM TESTS *****/
|
||||
|
||||
void random_num_negate(secp256k1_num_t *num) {
|
||||
if (secp256k1_rand32() & 1)
|
||||
secp256k1_num_negate(num);
|
||||
}
|
||||
|
||||
void random_num_order_test(secp256k1_num_t *num) {
|
||||
do {
|
||||
unsigned char b32[32];
|
||||
secp256k1_rand256_test(b32);
|
||||
secp256k1_num_set_bin(num, b32, 32);
|
||||
if (secp256k1_num_is_zero(num))
|
||||
continue;
|
||||
if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
|
||||
continue;
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
void random_num_order(secp256k1_num_t *num) {
|
||||
do {
|
||||
unsigned char b32[32];
|
||||
secp256k1_rand256(b32);
|
||||
secp256k1_num_set_bin(num, b32, 32);
|
||||
if (secp256k1_num_is_zero(num))
|
||||
continue;
|
||||
if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
|
||||
continue;
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
void test_num_copy_inc_cmp() {
|
||||
secp256k1_num_t n1,n2;
|
||||
secp256k1_num_init(&n1);
|
||||
secp256k1_num_init(&n2);
|
||||
random_num_order(&n1);
|
||||
secp256k1_num_copy(&n2, &n1);
|
||||
assert(secp256k1_num_cmp(&n1, &n2) == 0);
|
||||
assert(secp256k1_num_cmp(&n2, &n1) == 0);
|
||||
secp256k1_num_inc(&n2);
|
||||
assert(secp256k1_num_cmp(&n1, &n2) != 0);
|
||||
assert(secp256k1_num_cmp(&n2, &n1) != 0);
|
||||
secp256k1_num_free(&n1);
|
||||
secp256k1_num_free(&n2);
|
||||
}
|
||||
|
||||
|
||||
void test_num_get_set_hex() {
|
||||
secp256k1_num_t n1,n2;
|
||||
secp256k1_num_init(&n1);
|
||||
secp256k1_num_init(&n2);
|
||||
random_num_order_test(&n1);
|
||||
char c[64];
|
||||
secp256k1_num_get_hex(c, 64, &n1);
|
||||
secp256k1_num_set_hex(&n2, c, 64);
|
||||
assert(secp256k1_num_cmp(&n1, &n2) == 0);
|
||||
for (int i=0; i<64; i++) {
|
||||
// check whether the lower 4 bits correspond to the last hex character
|
||||
int low1 = secp256k1_num_shift(&n1, 4);
|
||||
int lowh = c[63];
|
||||
int low2 = (lowh>>6)*9+(lowh-'0')&15;
|
||||
assert(low1 == low2);
|
||||
// shift bits off the hex representation, and compare
|
||||
memmove(c+1, c, 63);
|
||||
c[0] = '0';
|
||||
secp256k1_num_set_hex(&n2, c, 64);
|
||||
assert(secp256k1_num_cmp(&n1, &n2) == 0);
|
||||
}
|
||||
secp256k1_num_free(&n2);
|
||||
secp256k1_num_free(&n1);
|
||||
}
|
||||
|
||||
void test_num_get_set_bin() {
|
||||
secp256k1_num_t n1,n2;
|
||||
secp256k1_num_init(&n1);
|
||||
secp256k1_num_init(&n2);
|
||||
random_num_order_test(&n1);
|
||||
unsigned char c[32];
|
||||
secp256k1_num_get_bin(c, 32, &n1);
|
||||
secp256k1_num_set_bin(&n2, c, 32);
|
||||
assert(secp256k1_num_cmp(&n1, &n2) == 0);
|
||||
for (int i=0; i<32; i++) {
|
||||
// check whether the lower 8 bits correspond to the last byte
|
||||
int low1 = secp256k1_num_shift(&n1, 8);
|
||||
int low2 = c[31];
|
||||
assert(low1 == low2);
|
||||
// shift bits off the byte representation, and compare
|
||||
memmove(c+1, c, 31);
|
||||
c[0] = 0;
|
||||
secp256k1_num_set_bin(&n2, c, 32);
|
||||
assert(secp256k1_num_cmp(&n1, &n2) == 0);
|
||||
}
|
||||
secp256k1_num_free(&n2);
|
||||
secp256k1_num_free(&n1);
|
||||
}
|
||||
|
||||
void run_num_int() {
|
||||
secp256k1_num_t n1;
|
||||
secp256k1_num_init(&n1);
|
||||
for (int i=-255; i<256; i++) {
|
||||
unsigned char c1[3] = {};
|
||||
c1[2] = abs(i);
|
||||
unsigned char c2[3] = {0x11,0x22,0x33};
|
||||
secp256k1_num_set_int(&n1, i);
|
||||
secp256k1_num_get_bin(c2, 3, &n1);
|
||||
assert(memcmp(c1, c2, 3) == 0);
|
||||
}
|
||||
secp256k1_num_free(&n1);
|
||||
}
|
||||
|
||||
void test_num_negate() {
|
||||
secp256k1_num_t n1;
|
||||
secp256k1_num_t n2;
|
||||
secp256k1_num_init(&n1);
|
||||
secp256k1_num_init(&n2);
|
||||
random_num_order_test(&n1); // n1 = R
|
||||
random_num_negate(&n1);
|
||||
secp256k1_num_copy(&n2, &n1); // n2 = R
|
||||
secp256k1_num_sub(&n1, &n2, &n1); // n1 = n2-n1 = 0
|
||||
assert(secp256k1_num_is_zero(&n1));
|
||||
secp256k1_num_copy(&n1, &n2); // n1 = R
|
||||
secp256k1_num_negate(&n1); // n1 = -R
|
||||
assert(!secp256k1_num_is_zero(&n1));
|
||||
secp256k1_num_add(&n1, &n2, &n1); // n1 = n2+n1 = 0
|
||||
assert(secp256k1_num_is_zero(&n1));
|
||||
secp256k1_num_copy(&n1, &n2); // n1 = R
|
||||
secp256k1_num_negate(&n1); // n1 = -R
|
||||
assert(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2));
|
||||
secp256k1_num_negate(&n1); // n1 = R
|
||||
assert(secp256k1_num_cmp(&n1, &n2) == 0);
|
||||
assert(secp256k1_num_is_neg(&n1) == secp256k1_num_is_neg(&n2));
|
||||
secp256k1_num_free(&n2);
|
||||
secp256k1_num_free(&n1);
|
||||
}
|
||||
|
||||
void test_num_add_sub() {
|
||||
secp256k1_num_t n1;
|
||||
secp256k1_num_t n2;
|
||||
secp256k1_num_init(&n1);
|
||||
secp256k1_num_init(&n2);
|
||||
random_num_order_test(&n1); // n1 = R1
|
||||
random_num_negate(&n1);
|
||||
random_num_order_test(&n2); // n2 = R2
|
||||
random_num_negate(&n2);
|
||||
secp256k1_num_t n1p2, n2p1, n1m2, n2m1;
|
||||
secp256k1_num_init(&n1p2);
|
||||
secp256k1_num_init(&n2p1);
|
||||
secp256k1_num_init(&n1m2);
|
||||
secp256k1_num_init(&n2m1);
|
||||
secp256k1_num_add(&n1p2, &n1, &n2); // n1p2 = R1 + R2
|
||||
secp256k1_num_add(&n2p1, &n2, &n1); // n2p1 = R2 + R1
|
||||
secp256k1_num_sub(&n1m2, &n1, &n2); // n1m2 = R1 - R2
|
||||
secp256k1_num_sub(&n2m1, &n2, &n1); // n2m1 = R2 - R1
|
||||
assert(secp256k1_num_cmp(&n1p2, &n2p1) == 0);
|
||||
assert(secp256k1_num_cmp(&n1p2, &n1m2) != 0);
|
||||
secp256k1_num_negate(&n2m1); // n2m1 = -R2 + R1
|
||||
assert(secp256k1_num_cmp(&n2m1, &n1m2) == 0);
|
||||
assert(secp256k1_num_cmp(&n2m1, &n1) != 0);
|
||||
secp256k1_num_add(&n2m1, &n2m1, &n2); // n2m1 = -R2 + R1 + R2 = R1
|
||||
assert(secp256k1_num_cmp(&n2m1, &n1) == 0);
|
||||
assert(secp256k1_num_cmp(&n2p1, &n1) != 0);
|
||||
secp256k1_num_sub(&n2p1, &n2p1, &n2); // n2p1 = R2 + R1 - R2 = R1
|
||||
assert(secp256k1_num_cmp(&n2p1, &n1) == 0);
|
||||
secp256k1_num_free(&n2m1);
|
||||
secp256k1_num_free(&n1m2);
|
||||
secp256k1_num_free(&n2p1);
|
||||
secp256k1_num_free(&n1p2);
|
||||
secp256k1_num_free(&n2);
|
||||
secp256k1_num_free(&n1);
|
||||
}
|
||||
|
||||
void run_num_smalltests() {
|
||||
for (int i=0; i<100*count; i++) {
|
||||
test_num_copy_inc_cmp();
|
||||
test_num_get_set_hex();
|
||||
test_num_get_set_bin();
|
||||
test_num_negate();
|
||||
test_num_add_sub();
|
||||
}
|
||||
run_num_int();
|
||||
}
|
||||
|
||||
void run_ecmult_chain() {
|
||||
// random starting point A (on the curve)
|
||||
secp256k1_fe_t ax; secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64);
|
||||
secp256k1_fe_t ay; secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
|
||||
secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay);
|
||||
// two random initial factors xn and gn
|
||||
secp256k1_num_t xn;
|
||||
secp256k1_num_init(&xn);
|
||||
secp256k1_num_set_hex(&xn, "84cc5452f7fde1edb4d38a8ce9b1b84ccef31f146e569be9705d357a42985407", 64);
|
||||
secp256k1_num_t gn;
|
||||
secp256k1_num_init(&gn);
|
||||
secp256k1_num_set_hex(&gn, "a1e58d22553dcd42b23980625d4c57a96e9323d42b3152e5ca2c3990edc7c9de", 64);
|
||||
// two small multipliers to be applied to xn and gn in every iteration:
|
||||
secp256k1_num_t xf;
|
||||
secp256k1_num_init(&xf);
|
||||
secp256k1_num_set_hex(&xf, "1337", 4);
|
||||
secp256k1_num_t gf;
|
||||
secp256k1_num_init(&gf);
|
||||
secp256k1_num_set_hex(&gf, "7113", 4);
|
||||
// accumulators with the resulting coefficients to A and G
|
||||
secp256k1_num_t ae;
|
||||
secp256k1_num_init(&ae);
|
||||
secp256k1_num_set_int(&ae, 1);
|
||||
secp256k1_num_t ge;
|
||||
secp256k1_num_init(&ge);
|
||||
secp256k1_num_set_int(&ge, 0);
|
||||
// the point being computed
|
||||
secp256k1_gej_t x = a;
|
||||
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
|
||||
for (int i=0; i<200*count; i++) {
|
||||
// in each iteration, compute X = xn*X + gn*G;
|
||||
secp256k1_ecmult(&x, &x, &xn, &gn);
|
||||
// also compute ae and ge: the actual accumulated factors for A and G
|
||||
// if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G)
|
||||
secp256k1_num_mod_mul(&ae, &ae, &xn, order);
|
||||
secp256k1_num_mod_mul(&ge, &ge, &xn, order);
|
||||
secp256k1_num_add(&ge, &ge, &gn);
|
||||
secp256k1_num_mod(&ge, order);
|
||||
// modify xn and gn
|
||||
secp256k1_num_mod_mul(&xn, &xn, &xf, order);
|
||||
secp256k1_num_mod_mul(&gn, &gn, &gf, order);
|
||||
|
||||
// verify
|
||||
if (i == 19999) {
|
||||
char res[132]; int resl = 132;
|
||||
secp256k1_gej_get_hex(res, &resl, &x);
|
||||
assert(strcmp(res, "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)") == 0);
|
||||
}
|
||||
}
|
||||
// redo the computation, but directly with the resulting ae and ge coefficients:
|
||||
secp256k1_gej_t x2; secp256k1_ecmult(&x2, &a, &ae, &ge);
|
||||
char res[132]; int resl = 132;
|
||||
char res2[132]; int resl2 = 132;
|
||||
secp256k1_gej_get_hex(res, &resl, &x);
|
||||
secp256k1_gej_get_hex(res2, &resl2, &x2);
|
||||
assert(strcmp(res, res2) == 0);
|
||||
assert(strlen(res) == 131);
|
||||
secp256k1_num_free(&xn);
|
||||
secp256k1_num_free(&gn);
|
||||
secp256k1_num_free(&xf);
|
||||
secp256k1_num_free(&gf);
|
||||
secp256k1_num_free(&ae);
|
||||
secp256k1_num_free(&ge);
|
||||
}
|
||||
|
||||
void test_point_times_order(const secp256k1_gej_t *point) {
|
||||
// either the point is not on the curve, or multiplying it by the order results in O
|
||||
if (!secp256k1_gej_is_valid(point))
|
||||
return;
|
||||
|
||||
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
|
||||
secp256k1_num_t zero;
|
||||
secp256k1_num_init(&zero);
|
||||
secp256k1_num_set_int(&zero, 0);
|
||||
secp256k1_gej_t res;
|
||||
secp256k1_ecmult(&res, point, order, order); // calc res = order * point + order * G;
|
||||
assert(secp256k1_gej_is_infinity(&res));
|
||||
secp256k1_num_free(&zero);
|
||||
}
|
||||
|
||||
void run_point_times_order() {
|
||||
secp256k1_fe_t x; secp256k1_fe_set_hex(&x, "02", 2);
|
||||
for (int i=0; i<500; i++) {
|
||||
secp256k1_ge_t p; secp256k1_ge_set_xo(&p, &x, 1);
|
||||
secp256k1_gej_t j; secp256k1_gej_set_ge(&j, &p);
|
||||
test_point_times_order(&j);
|
||||
secp256k1_fe_sqr(&x, &x);
|
||||
}
|
||||
char c[65]; int cl=65;
|
||||
secp256k1_fe_get_hex(c, &cl, &x);
|
||||
assert(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0);
|
||||
}
|
||||
|
||||
void test_wnaf(const secp256k1_num_t *number, int w) {
|
||||
secp256k1_num_t x, two, t;
|
||||
secp256k1_num_init(&x);
|
||||
secp256k1_num_init(&two);
|
||||
secp256k1_num_init(&t);
|
||||
secp256k1_num_set_int(&x, 0);
|
||||
secp256k1_num_set_int(&two, 2);
|
||||
int wnaf[257];
|
||||
int bits = secp256k1_ecmult_wnaf(wnaf, number, w);
|
||||
int zeroes = -1;
|
||||
for (int i=bits-1; i>=0; i--) {
|
||||
secp256k1_num_mul(&x, &x, &two);
|
||||
int v = wnaf[i];
|
||||
if (v) {
|
||||
assert(zeroes == -1 || zeroes >= w-1); // check that distance between non-zero elements is at least w-1
|
||||
zeroes=0;
|
||||
assert((v & 1) == 1); // check non-zero elements are odd
|
||||
assert(v <= (1 << (w-1)) - 1); // check range below
|
||||
assert(v >= -(1 << (w-1)) - 1); // check range above
|
||||
} else {
|
||||
assert(zeroes != -1); // check that no unnecessary zero padding exists
|
||||
zeroes++;
|
||||
}
|
||||
secp256k1_num_set_int(&t, v);
|
||||
secp256k1_num_add(&x, &x, &t);
|
||||
}
|
||||
assert(secp256k1_num_cmp(&x, number) == 0); // check that wnaf represents number
|
||||
secp256k1_num_free(&x);
|
||||
secp256k1_num_free(&two);
|
||||
secp256k1_num_free(&t);
|
||||
}
|
||||
|
||||
void run_wnaf() {
|
||||
secp256k1_num_t n;
|
||||
secp256k1_num_init(&n);
|
||||
for (int i=0; i<count; i++) {
|
||||
random_num_order(&n);
|
||||
if (i % 1)
|
||||
secp256k1_num_negate(&n);
|
||||
test_wnaf(&n, 4+(i%10));
|
||||
}
|
||||
secp256k1_num_free(&n);
|
||||
}
|
||||
|
||||
void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *key, const secp256k1_num_t *msg, int *recid) {
|
||||
secp256k1_num_t nonce;
|
||||
secp256k1_num_init(&nonce);
|
||||
do {
|
||||
random_num_order_test(&nonce);
|
||||
} while(!secp256k1_ecdsa_sig_sign(sig, key, msg, &nonce, recid));
|
||||
secp256k1_num_free(&nonce);
|
||||
}
|
||||
|
||||
void test_ecdsa_sign_verify() {
|
||||
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
|
||||
secp256k1_num_t msg, key;
|
||||
secp256k1_num_init(&msg);
|
||||
random_num_order_test(&msg);
|
||||
secp256k1_num_init(&key);
|
||||
random_num_order_test(&key);
|
||||
secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key);
|
||||
secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj);
|
||||
secp256k1_ecdsa_sig_t sig;
|
||||
secp256k1_ecdsa_sig_init(&sig);
|
||||
random_sign(&sig, &key, &msg, NULL);
|
||||
assert(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
|
||||
secp256k1_num_inc(&msg);
|
||||
assert(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
|
||||
secp256k1_ecdsa_sig_free(&sig);
|
||||
secp256k1_num_free(&msg);
|
||||
secp256k1_num_free(&key);
|
||||
}
|
||||
|
||||
void run_ecdsa_sign_verify() {
|
||||
for (int i=0; i<10*count; i++) {
|
||||
test_ecdsa_sign_verify();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
EC_KEY *get_openssl_key(const secp256k1_num_t *key) {
|
||||
unsigned char privkey[300];
|
||||
int privkeylen;
|
||||
int compr = secp256k1_rand32() & 1;
|
||||
const unsigned char* pbegin = privkey;
|
||||
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
assert(secp256k1_ecdsa_privkey_serialize(privkey, &privkeylen, key, compr));
|
||||
assert(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
|
||||
assert(EC_KEY_check_key(ec_key));
|
||||
return ec_key;
|
||||
}
|
||||
|
||||
void test_ecdsa_openssl() {
|
||||
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
|
||||
secp256k1_num_t key, msg;
|
||||
secp256k1_num_init(&msg);
|
||||
unsigned char message[32];
|
||||
secp256k1_rand256_test(message);
|
||||
secp256k1_num_set_bin(&msg, message, 32);
|
||||
secp256k1_num_init(&key);
|
||||
random_num_order_test(&key);
|
||||
secp256k1_gej_t qj;
|
||||
secp256k1_ecmult_gen(&qj, &key);
|
||||
secp256k1_ge_t q;
|
||||
secp256k1_ge_set_gej(&q, &qj);
|
||||
EC_KEY *ec_key = get_openssl_key(&key);
|
||||
assert(ec_key);
|
||||
unsigned char signature[80];
|
||||
int sigsize = 80;
|
||||
assert(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));
|
||||
secp256k1_ecdsa_sig_t sig;
|
||||
secp256k1_ecdsa_sig_init(&sig);
|
||||
assert(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize));
|
||||
assert(secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
|
||||
secp256k1_num_inc(&sig.r);
|
||||
assert(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
|
||||
|
||||
random_sign(&sig, &key, &msg, NULL);
|
||||
sigsize = 80;
|
||||
assert(secp256k1_ecdsa_sig_serialize(signature, &sigsize, &sig));
|
||||
assert(ECDSA_verify(0, message, sizeof(message), signature, sigsize, ec_key) == 1);
|
||||
|
||||
secp256k1_ecdsa_sig_free(&sig);
|
||||
EC_KEY_free(ec_key);
|
||||
secp256k1_num_free(&key);
|
||||
secp256k1_num_free(&msg);
|
||||
}
|
||||
|
||||
void run_ecdsa_openssl() {
|
||||
for (int i=0; i<10*count; i++) {
|
||||
test_ecdsa_openssl();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc > 1)
|
||||
count = strtol(argv[1], NULL, 0)*47;
|
||||
|
||||
printf("test count = %i\n", count);
|
||||
|
||||
// initialize
|
||||
secp256k1_fe_start();
|
||||
secp256k1_ge_start();
|
||||
secp256k1_ecmult_start();
|
||||
|
||||
// num tests
|
||||
run_num_smalltests();
|
||||
|
||||
// ecmult tests
|
||||
run_wnaf();
|
||||
run_point_times_order();
|
||||
run_ecmult_chain();
|
||||
|
||||
// ecdsa tests
|
||||
run_ecdsa_sign_verify();
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
run_ecdsa_openssl();
|
||||
#endif
|
||||
|
||||
// shutdown
|
||||
secp256k1_ecmult_stop();
|
||||
secp256k1_ge_stop();
|
||||
secp256k1_fe_stop();
|
||||
return 0;
|
||||
}
|
19
crypto/secp256k1/secp256k1/src/util.h
Normal file
19
crypto/secp256k1/secp256k1/src/util.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2013 Pieter Wuille
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef _SECP256K1_UTIL_H_
|
||||
#define _SECP256K1_UTIL_H_
|
||||
|
||||
/** Generate a pseudorandom 32-bit number. */
|
||||
static uint32_t secp256k1_rand32(void);
|
||||
|
||||
/** Generate a pseudorandom 32-byte array. */
|
||||
static void secp256k1_rand256(unsigned char *b32);
|
||||
|
||||
/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */
|
||||
static void secp256k1_rand256_test(unsigned char *b32);
|
||||
|
||||
#include "impl/util.h"
|
||||
|
||||
#endif
|
171
crypto/sha3/keccakf.go
Normal file
171
crypto/sha3/keccakf.go
Normal file
@ -0,0 +1,171 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sha3
|
||||
|
||||
// This file implements the core Keccak permutation function necessary for computing SHA3.
|
||||
// This is implemented in a separate file to allow for replacement by an optimized implementation.
|
||||
// Nothing in this package is exported.
|
||||
// For the detailed specification, refer to the Keccak web site (http://keccak.noekeon.org/).
|
||||
|
||||
// rc stores the round constants for use in the ι step.
|
||||
var rc = [...]uint64{
|
||||
0x0000000000000001,
|
||||
0x0000000000008082,
|
||||
0x800000000000808A,
|
||||
0x8000000080008000,
|
||||
0x000000000000808B,
|
||||
0x0000000080000001,
|
||||
0x8000000080008081,
|
||||
0x8000000000008009,
|
||||
0x000000000000008A,
|
||||
0x0000000000000088,
|
||||
0x0000000080008009,
|
||||
0x000000008000000A,
|
||||
0x000000008000808B,
|
||||
0x800000000000008B,
|
||||
0x8000000000008089,
|
||||
0x8000000000008003,
|
||||
0x8000000000008002,
|
||||
0x8000000000000080,
|
||||
0x000000000000800A,
|
||||
0x800000008000000A,
|
||||
0x8000000080008081,
|
||||
0x8000000000008080,
|
||||
0x0000000080000001,
|
||||
0x8000000080008008,
|
||||
}
|
||||
|
||||
// ro_xx represent the rotation offsets for use in the χ step.
|
||||
// Defining them as const instead of in an array allows the compiler to insert constant shifts.
|
||||
const (
|
||||
ro_00 = 0
|
||||
ro_01 = 36
|
||||
ro_02 = 3
|
||||
ro_03 = 41
|
||||
ro_04 = 18
|
||||
ro_05 = 1
|
||||
ro_06 = 44
|
||||
ro_07 = 10
|
||||
ro_08 = 45
|
||||
ro_09 = 2
|
||||
ro_10 = 62
|
||||
ro_11 = 6
|
||||
ro_12 = 43
|
||||
ro_13 = 15
|
||||
ro_14 = 61
|
||||
ro_15 = 28
|
||||
ro_16 = 55
|
||||
ro_17 = 25
|
||||
ro_18 = 21
|
||||
ro_19 = 56
|
||||
ro_20 = 27
|
||||
ro_21 = 20
|
||||
ro_22 = 39
|
||||
ro_23 = 8
|
||||
ro_24 = 14
|
||||
)
|
||||
|
||||
// keccakF computes the complete Keccak-f function consisting of 24 rounds with a different
|
||||
// constant (rc) in each round. This implementation fully unrolls the round function to avoid
|
||||
// inner loops, as well as pre-calculating shift offsets.
|
||||
func (d *digest) keccakF() {
|
||||
for _, roundConstant := range rc {
|
||||
// θ step
|
||||
d.c[0] = d.a[0] ^ d.a[5] ^ d.a[10] ^ d.a[15] ^ d.a[20]
|
||||
d.c[1] = d.a[1] ^ d.a[6] ^ d.a[11] ^ d.a[16] ^ d.a[21]
|
||||
d.c[2] = d.a[2] ^ d.a[7] ^ d.a[12] ^ d.a[17] ^ d.a[22]
|
||||
d.c[3] = d.a[3] ^ d.a[8] ^ d.a[13] ^ d.a[18] ^ d.a[23]
|
||||
d.c[4] = d.a[4] ^ d.a[9] ^ d.a[14] ^ d.a[19] ^ d.a[24]
|
||||
|
||||
d.d[0] = d.c[4] ^ (d.c[1]<<1 ^ d.c[1]>>63)
|
||||
d.d[1] = d.c[0] ^ (d.c[2]<<1 ^ d.c[2]>>63)
|
||||
d.d[2] = d.c[1] ^ (d.c[3]<<1 ^ d.c[3]>>63)
|
||||
d.d[3] = d.c[2] ^ (d.c[4]<<1 ^ d.c[4]>>63)
|
||||
d.d[4] = d.c[3] ^ (d.c[0]<<1 ^ d.c[0]>>63)
|
||||
|
||||
d.a[0] ^= d.d[0]
|
||||
d.a[1] ^= d.d[1]
|
||||
d.a[2] ^= d.d[2]
|
||||
d.a[3] ^= d.d[3]
|
||||
d.a[4] ^= d.d[4]
|
||||
d.a[5] ^= d.d[0]
|
||||
d.a[6] ^= d.d[1]
|
||||
d.a[7] ^= d.d[2]
|
||||
d.a[8] ^= d.d[3]
|
||||
d.a[9] ^= d.d[4]
|
||||
d.a[10] ^= d.d[0]
|
||||
d.a[11] ^= d.d[1]
|
||||
d.a[12] ^= d.d[2]
|
||||
d.a[13] ^= d.d[3]
|
||||
d.a[14] ^= d.d[4]
|
||||
d.a[15] ^= d.d[0]
|
||||
d.a[16] ^= d.d[1]
|
||||
d.a[17] ^= d.d[2]
|
||||
d.a[18] ^= d.d[3]
|
||||
d.a[19] ^= d.d[4]
|
||||
d.a[20] ^= d.d[0]
|
||||
d.a[21] ^= d.d[1]
|
||||
d.a[22] ^= d.d[2]
|
||||
d.a[23] ^= d.d[3]
|
||||
d.a[24] ^= d.d[4]
|
||||
|
||||
// ρ and π steps
|
||||
d.b[0] = d.a[0]
|
||||
d.b[1] = d.a[6]<<ro_06 ^ d.a[6]>>(64-ro_06)
|
||||
d.b[2] = d.a[12]<<ro_12 ^ d.a[12]>>(64-ro_12)
|
||||
d.b[3] = d.a[18]<<ro_18 ^ d.a[18]>>(64-ro_18)
|
||||
d.b[4] = d.a[24]<<ro_24 ^ d.a[24]>>(64-ro_24)
|
||||
d.b[5] = d.a[3]<<ro_15 ^ d.a[3]>>(64-ro_15)
|
||||
d.b[6] = d.a[9]<<ro_21 ^ d.a[9]>>(64-ro_21)
|
||||
d.b[7] = d.a[10]<<ro_02 ^ d.a[10]>>(64-ro_02)
|
||||
d.b[8] = d.a[16]<<ro_08 ^ d.a[16]>>(64-ro_08)
|
||||
d.b[9] = d.a[22]<<ro_14 ^ d.a[22]>>(64-ro_14)
|
||||
d.b[10] = d.a[1]<<ro_05 ^ d.a[1]>>(64-ro_05)
|
||||
d.b[11] = d.a[7]<<ro_11 ^ d.a[7]>>(64-ro_11)
|
||||
d.b[12] = d.a[13]<<ro_17 ^ d.a[13]>>(64-ro_17)
|
||||
d.b[13] = d.a[19]<<ro_23 ^ d.a[19]>>(64-ro_23)
|
||||
d.b[14] = d.a[20]<<ro_04 ^ d.a[20]>>(64-ro_04)
|
||||
d.b[15] = d.a[4]<<ro_20 ^ d.a[4]>>(64-ro_20)
|
||||
d.b[16] = d.a[5]<<ro_01 ^ d.a[5]>>(64-ro_01)
|
||||
d.b[17] = d.a[11]<<ro_07 ^ d.a[11]>>(64-ro_07)
|
||||
d.b[18] = d.a[17]<<ro_13 ^ d.a[17]>>(64-ro_13)
|
||||
d.b[19] = d.a[23]<<ro_19 ^ d.a[23]>>(64-ro_19)
|
||||
d.b[20] = d.a[2]<<ro_10 ^ d.a[2]>>(64-ro_10)
|
||||
d.b[21] = d.a[8]<<ro_16 ^ d.a[8]>>(64-ro_16)
|
||||
d.b[22] = d.a[14]<<ro_22 ^ d.a[14]>>(64-ro_22)
|
||||
d.b[23] = d.a[15]<<ro_03 ^ d.a[15]>>(64-ro_03)
|
||||
d.b[24] = d.a[21]<<ro_09 ^ d.a[21]>>(64-ro_09)
|
||||
|
||||
// χ step
|
||||
d.a[0] = d.b[0] ^ (^d.b[1] & d.b[2])
|
||||
d.a[1] = d.b[1] ^ (^d.b[2] & d.b[3])
|
||||
d.a[2] = d.b[2] ^ (^d.b[3] & d.b[4])
|
||||
d.a[3] = d.b[3] ^ (^d.b[4] & d.b[0])
|
||||
d.a[4] = d.b[4] ^ (^d.b[0] & d.b[1])
|
||||
d.a[5] = d.b[5] ^ (^d.b[6] & d.b[7])
|
||||
d.a[6] = d.b[6] ^ (^d.b[7] & d.b[8])
|
||||
d.a[7] = d.b[7] ^ (^d.b[8] & d.b[9])
|
||||
d.a[8] = d.b[8] ^ (^d.b[9] & d.b[5])
|
||||
d.a[9] = d.b[9] ^ (^d.b[5] & d.b[6])
|
||||
d.a[10] = d.b[10] ^ (^d.b[11] & d.b[12])
|
||||
d.a[11] = d.b[11] ^ (^d.b[12] & d.b[13])
|
||||
d.a[12] = d.b[12] ^ (^d.b[13] & d.b[14])
|
||||
d.a[13] = d.b[13] ^ (^d.b[14] & d.b[10])
|
||||
d.a[14] = d.b[14] ^ (^d.b[10] & d.b[11])
|
||||
d.a[15] = d.b[15] ^ (^d.b[16] & d.b[17])
|
||||
d.a[16] = d.b[16] ^ (^d.b[17] & d.b[18])
|
||||
d.a[17] = d.b[17] ^ (^d.b[18] & d.b[19])
|
||||
d.a[18] = d.b[18] ^ (^d.b[19] & d.b[15])
|
||||
d.a[19] = d.b[19] ^ (^d.b[15] & d.b[16])
|
||||
d.a[20] = d.b[20] ^ (^d.b[21] & d.b[22])
|
||||
d.a[21] = d.b[21] ^ (^d.b[22] & d.b[23])
|
||||
d.a[22] = d.b[22] ^ (^d.b[23] & d.b[24])
|
||||
d.a[23] = d.b[23] ^ (^d.b[24] & d.b[20])
|
||||
d.a[24] = d.b[24] ^ (^d.b[20] & d.b[21])
|
||||
|
||||
// ι step
|
||||
d.a[0] ^= roundConstant
|
||||
}
|
||||
}
|
216
crypto/sha3/sha3.go
Normal file
216
crypto/sha3/sha3.go
Normal file
@ -0,0 +1,216 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package sha3 implements the SHA3 hash algorithm (formerly called Keccak) chosen by NIST in 2012.
|
||||
// This file provides a SHA3 implementation which implements the standard hash.Hash interface.
|
||||
// Writing input data, including padding, and reading output data are computed in this file.
|
||||
// Note that the current implementation can compute the hash of an integral number of bytes only.
|
||||
// This is a consequence of the hash interface in which a buffer of bytes is passed in.
|
||||
// The internals of the Keccak-f function are computed in keccakf.go.
|
||||
// For the detailed specification, refer to the Keccak web site (http://keccak.noekeon.org/).
|
||||
package sha3
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// laneSize is the size in bytes of each "lane" of the internal state of SHA3 (5 * 5 * 8).
|
||||
// Note that changing this size would requires using a type other than uint64 to store each lane.
|
||||
const laneSize = 8
|
||||
|
||||
// sliceSize represents the dimensions of the internal state, a square matrix of
|
||||
// sliceSize ** 2 lanes. This is the size of both the "rows" and "columns" dimensions in the
|
||||
// terminology of the SHA3 specification.
|
||||
const sliceSize = 5
|
||||
|
||||
// numLanes represents the total number of lanes in the state.
|
||||
const numLanes = sliceSize * sliceSize
|
||||
|
||||
// stateSize is the size in bytes of the internal state of SHA3 (5 * 5 * WSize).
|
||||
const stateSize = laneSize * numLanes
|
||||
|
||||
// digest represents the partial evaluation of a checksum.
|
||||
// Note that capacity, and not outputSize, is the critical security parameter, as SHA3 can output
|
||||
// an arbitrary number of bytes for any given capacity. The Keccak proposal recommends that
|
||||
// capacity = 2*outputSize to ensure that finding a collision of size outputSize requires
|
||||
// O(2^{outputSize/2}) computations (the birthday lower bound). Future standards may modify the
|
||||
// capacity/outputSize ratio to allow for more output with lower cryptographic security.
|
||||
type digest struct {
|
||||
a [numLanes]uint64 // main state of the hash
|
||||
b [numLanes]uint64 // intermediate states
|
||||
c [sliceSize]uint64 // intermediate states
|
||||
d [sliceSize]uint64 // intermediate states
|
||||
outputSize int // desired output size in bytes
|
||||
capacity int // number of bytes to leave untouched during squeeze/absorb
|
||||
absorbed int // number of bytes absorbed thus far
|
||||
}
|
||||
|
||||
// minInt returns the lesser of two integer arguments, to simplify the absorption routine.
|
||||
func minInt(v1, v2 int) int {
|
||||
if v1 <= v2 {
|
||||
return v1
|
||||
}
|
||||
return v2
|
||||
}
|
||||
|
||||
// rate returns the number of bytes of the internal state which can be absorbed or squeezed
|
||||
// in between calls to the permutation function.
|
||||
func (d *digest) rate() int {
|
||||
return stateSize - d.capacity
|
||||
}
|
||||
|
||||
// Reset clears the internal state by zeroing bytes in the state buffer.
|
||||
// This can be skipped for a newly-created hash state; the default zero-allocated state is correct.
|
||||
func (d *digest) Reset() {
|
||||
d.absorbed = 0
|
||||
for i := range d.a {
|
||||
d.a[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// BlockSize, required by the hash.Hash interface, does not have a standard intepretation
|
||||
// for a sponge-based construction like SHA3. We return the data rate: the number of bytes which
|
||||
// can be absorbed per invocation of the permutation function. For Merkle-Damgård based hashes
|
||||
// (ie SHA1, SHA2, MD5) the output size of the internal compression function is returned.
|
||||
// We consider this to be roughly equivalent because it represents the number of bytes of output
|
||||
// produced per cryptographic operation.
|
||||
func (d *digest) BlockSize() int { return d.rate() }
|
||||
|
||||
// Size returns the output size of the hash function in bytes.
|
||||
func (d *digest) Size() int {
|
||||
return d.outputSize
|
||||
}
|
||||
|
||||
// unalignedAbsorb is a helper function for Write, which absorbs data that isn't aligned with an
|
||||
// 8-byte lane. This requires shifting the individual bytes into position in a uint64.
|
||||
func (d *digest) unalignedAbsorb(p []byte) {
|
||||
var t uint64
|
||||
for i := len(p) - 1; i >= 0; i-- {
|
||||
t <<= 8
|
||||
t |= uint64(p[i])
|
||||
}
|
||||
offset := (d.absorbed) % d.rate()
|
||||
t <<= 8 * uint(offset%laneSize)
|
||||
d.a[offset/laneSize] ^= t
|
||||
d.absorbed += len(p)
|
||||
}
|
||||
|
||||
// Write "absorbs" bytes into the state of the SHA3 hash, updating as needed when the sponge
|
||||
// "fills up" with rate() bytes. Since lanes are stored internally as type uint64, this requires
|
||||
// converting the incoming bytes into uint64s using a little endian interpretation. This
|
||||
// implementation is optimized for large, aligned writes of multiples of 8 bytes (laneSize).
|
||||
// Non-aligned or uneven numbers of bytes require shifting and are slower.
|
||||
func (d *digest) Write(p []byte) (int, error) {
|
||||
// An initial offset is needed if the we aren't absorbing to the first lane initially.
|
||||
offset := d.absorbed % d.rate()
|
||||
toWrite := len(p)
|
||||
|
||||
// The first lane may need to absorb unaligned and/or incomplete data.
|
||||
if (offset%laneSize != 0 || len(p) < 8) && len(p) > 0 {
|
||||
toAbsorb := minInt(laneSize-(offset%laneSize), len(p))
|
||||
d.unalignedAbsorb(p[:toAbsorb])
|
||||
p = p[toAbsorb:]
|
||||
offset = (d.absorbed) % d.rate()
|
||||
|
||||
// For every rate() bytes absorbed, the state must be permuted via the F Function.
|
||||
if (d.absorbed)%d.rate() == 0 {
|
||||
d.keccakF()
|
||||
}
|
||||
}
|
||||
|
||||
// This loop should absorb the bulk of the data into full, aligned lanes.
|
||||
// It will call the update function as necessary.
|
||||
for len(p) > 7 {
|
||||
firstLane := offset / laneSize
|
||||
lastLane := minInt(d.rate()/laneSize, firstLane+len(p)/laneSize)
|
||||
|
||||
// This inner loop absorbs input bytes into the state in groups of 8, converted to uint64s.
|
||||
for lane := firstLane; lane < lastLane; lane++ {
|
||||
d.a[lane] ^= binary.LittleEndian.Uint64(p[:laneSize])
|
||||
p = p[laneSize:]
|
||||
}
|
||||
d.absorbed += (lastLane - firstLane) * laneSize
|
||||
// For every rate() bytes absorbed, the state must be permuted via the F Function.
|
||||
if (d.absorbed)%d.rate() == 0 {
|
||||
d.keccakF()
|
||||
}
|
||||
|
||||
offset = 0
|
||||
}
|
||||
|
||||
// If there are insufficient bytes to fill the final lane, an unaligned absorption.
|
||||
// This should always start at a correct lane boundary though, or else it would be caught
|
||||
// by the uneven opening lane case above.
|
||||
if len(p) > 0 {
|
||||
d.unalignedAbsorb(p)
|
||||
}
|
||||
|
||||
return toWrite, nil
|
||||
}
|
||||
|
||||
// pad computes the SHA3 padding scheme based on the number of bytes absorbed.
|
||||
// The padding is a 1 bit, followed by an arbitrary number of 0s and then a final 1 bit, such that
|
||||
// the input bits plus padding bits are a multiple of rate(). Adding the padding simply requires
|
||||
// xoring an opening and closing bit into the appropriate lanes.
|
||||
func (d *digest) pad() {
|
||||
offset := d.absorbed % d.rate()
|
||||
// The opening pad bit must be shifted into position based on the number of bytes absorbed
|
||||
padOpenLane := offset / laneSize
|
||||
d.a[padOpenLane] ^= 0x0000000000000001 << uint(8*(offset%laneSize))
|
||||
// The closing padding bit is always in the last position
|
||||
padCloseLane := (d.rate() / laneSize) - 1
|
||||
d.a[padCloseLane] ^= 0x8000000000000000
|
||||
}
|
||||
|
||||
// finalize prepares the hash to output data by padding and one final permutation of the state.
|
||||
func (d *digest) finalize() {
|
||||
d.pad()
|
||||
d.keccakF()
|
||||
}
|
||||
|
||||
// squeeze outputs an arbitrary number of bytes from the hash state.
|
||||
// Squeezing can require multiple calls to the F function (one per rate() bytes squeezed),
|
||||
// although this is not the case for standard SHA3 parameters. This implementation only supports
|
||||
// squeezing a single time, subsequent squeezes may lose alignment. Future implementations
|
||||
// may wish to support multiple squeeze calls, for example to support use as a PRNG.
|
||||
func (d *digest) squeeze(in []byte, toSqueeze int) []byte {
|
||||
// Because we read in blocks of laneSize, we need enough room to read
|
||||
// an integral number of lanes
|
||||
needed := toSqueeze + (laneSize-toSqueeze%laneSize)%laneSize
|
||||
if cap(in)-len(in) < needed {
|
||||
newIn := make([]byte, len(in), len(in)+needed)
|
||||
copy(newIn, in)
|
||||
in = newIn
|
||||
}
|
||||
out := in[len(in) : len(in)+needed]
|
||||
|
||||
for len(out) > 0 {
|
||||
for i := 0; i < d.rate() && len(out) > 0; i += laneSize {
|
||||
binary.LittleEndian.PutUint64(out[:], d.a[i/laneSize])
|
||||
out = out[laneSize:]
|
||||
}
|
||||
if len(out) > 0 {
|
||||
d.keccakF()
|
||||
}
|
||||
}
|
||||
return in[:len(in)+toSqueeze] // Re-slice in case we wrote extra data.
|
||||
}
|
||||
|
||||
// Sum applies padding to the hash state and then squeezes out the desired nubmer of output bytes.
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
// Make a copy of the original hash so that caller can keep writing and summing.
|
||||
dup := *d
|
||||
dup.finalize()
|
||||
return dup.squeeze(in, dup.outputSize)
|
||||
}
|
||||
|
||||
// The NewKeccakX constructors enable initializing a hash in any of the four recommend sizes
|
||||
// from the Keccak specification, all of which set capacity=2*outputSize. Note that the final
|
||||
// NIST standard for SHA3 may specify different input/output lengths.
|
||||
// The output size is indicated in bits but converted into bytes internally.
|
||||
func NewKeccak224() hash.Hash { return &digest{outputSize: 224 / 8, capacity: 2 * 224 / 8} }
|
||||
func NewKeccak256() hash.Hash { return &digest{outputSize: 256 / 8, capacity: 2 * 256 / 8} }
|
||||
func NewKeccak384() hash.Hash { return &digest{outputSize: 384 / 8, capacity: 2 * 384 / 8} }
|
||||
func NewKeccak512() hash.Hash { return &digest{outputSize: 512 / 8, capacity: 2 * 512 / 8} }
|
@ -8,9 +8,9 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/obscuren/secp256k1-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -6,9 +6,9 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/ethutil"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/obscuren/sha3"
|
||||
)
|
||||
|
||||
var powlogger = logger.NewLogger("POW")
|
||||
|
@ -6,10 +6,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/ethutil"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/pow"
|
||||
"github.com/obscuren/sha3"
|
||||
)
|
||||
|
||||
var powlogger = logger.NewLogger("POW")
|
||||
|
4
tests/files/.gitignore
vendored
Normal file
4
tests/files/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
venv/
|
||||
*~
|
||||
*.swp
|
||||
.vagrant/
|
53
tests/files/VMTests/RandomTests/201501151106PYTHON.json
Normal file
53
tests/files/VMTests/RandomTests/201501151106PYTHON.json
Normal file
@ -0,0 +1,53 @@
|
||||
{
|
||||
"randomVMtest" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "300",
|
||||
"currentTimestamp" : "2",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x4142414131424043923a58f2",
|
||||
"data" : "0x",
|
||||
"gas" : "10000",
|
||||
"gasPrice" : "100000000000000",
|
||||
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "1000000000000000000"
|
||||
},
|
||||
"gas" : "9940",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "1000000000000000000",
|
||||
"code" : "0x4142414131424043923a58f2",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0",
|
||||
"code" : "0x",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "1000000000000000000",
|
||||
"code" : "0x4142414131424043923a58f2",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
tests/files/VMTests/RandomTests/201501191458PYTHON.json
Normal file
31
tests/files/VMTests/RandomTests/201501191458PYTHON.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"randomVMtest" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "300",
|
||||
"currentTimestamp" : "2",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x4243434440448143f2a231f1",
|
||||
"data" : "0x",
|
||||
"gas" : "10000",
|
||||
"gasPrice" : "100000000000000",
|
||||
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "1000000000000000000"
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "1000000000000000000",
|
||||
"code" : "0x4243434440448143f2a231f1",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
tests/files/VMTests/RandomTests/201501191859PYTHON.json
Normal file
31
tests/files/VMTests/RandomTests/201501191859PYTHON.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"randomVMtest" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "300",
|
||||
"currentTimestamp" : "2",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x4243434244444340f201186211907055",
|
||||
"data" : "0x",
|
||||
"gas" : "10000",
|
||||
"gasPrice" : "100000000000000",
|
||||
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "1000000000000000000"
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "1000000000000000000",
|
||||
"code" : "0x4243434244444340f201186211907055",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
tests/files/VMTests/RandomTests/201501191953PYTHON.json
Normal file
31
tests/files/VMTests/RandomTests/201501191953PYTHON.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"randomVMtest" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "300",
|
||||
"currentTimestamp" : "2",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x434342444041454545045bf2f23a55",
|
||||
"data" : "0x",
|
||||
"gas" : "10000",
|
||||
"gasPrice" : "100000000000000",
|
||||
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "1000000000000000000"
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "1000000000000000000",
|
||||
"code" : "0x434342444041454545045bf2f23a55",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -249,5 +249,63 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sha3_bigOffset" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "256",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "0",
|
||||
"currentTimestamp" : "1",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x60027e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
|
||||
"data" : "0x",
|
||||
"gas" : "1099511627776",
|
||||
"gasPrice" : "1",
|
||||
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "115792089237316195423570985008687907853269984665640564039457584007913129639935"
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
||||
"code" : "0x60027e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sha3_bigSize" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "256",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "0",
|
||||
"currentTimestamp" : "1",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
|
||||
"data" : "0x",
|
||||
"gas" : "1099511627776",
|
||||
"gasPrice" : "1",
|
||||
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "115792089237316195423570985008687907853269984665640564039457584007913129639935"
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
||||
"code" : "0x7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
tests/files/ansible/README.md
Normal file
5
tests/files/ansible/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Automatic deployment of the random test generator
|
||||
|
||||
Testing is done in a Vagrant virtual machine
|
||||
|
||||
install vagrant, virtualbox, ansible, then do `vagrant up`. It should provison a basic machine. `vagrant ssh` to verify the machine is working as expected. `vagrant terminate` to reset machine to clean state.
|
78
tests/files/ansible/Vagrantfile
vendored
Normal file
78
tests/files/ansible/Vagrantfile
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
||||
VAGRANTFILE_API_VERSION ||= "2"
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
# All Vagrant configuration is done here. The most common configuration
|
||||
# options are documented and commented below. For a complete reference,
|
||||
# please see the online documentation at vagrantup.com.
|
||||
|
||||
# Every Vagrant virtual environment requires a box to build off of.
|
||||
config.vm.box = "ubuntu/trusty64"
|
||||
config.vm.define "random-test"
|
||||
|
||||
# Disable automatic box update checking. If you disable this, then
|
||||
# boxes will only be checked for updates when the user runs
|
||||
# `vagrant box outdated`. This is not recommended.
|
||||
# config.vm.box_check_update = false
|
||||
|
||||
# Create a forwarded port mapping which allows access to a specific port
|
||||
# within the machine from a port on the host machine. In the example below,
|
||||
# accessing "localhost:8080" will access port 80 on the guest machine.
|
||||
# config.vm.network "forwarded_port", guest: 80, host: 8080
|
||||
|
||||
# Create a private network, which allows host-only access to the machine
|
||||
# using a specific IP.
|
||||
# config.vm.network "private_network", ip: "192.168.33.10"
|
||||
|
||||
# Create a public network, which generally matched to bridged network.
|
||||
# Bridged networks make the machine appear as another physical device on
|
||||
# your network.
|
||||
# config.vm.network "public_network"
|
||||
|
||||
# If true, then any SSH connections made will enable agent forwarding.
|
||||
# Default value: false
|
||||
# config.ssh.forward_agent = true
|
||||
|
||||
# Share an additional folder to the guest VM. The first argument is
|
||||
# the path on the host to the actual folder. The second argument is
|
||||
# the path on the guest to mount the folder. And the optional third
|
||||
# argument is a set of non-required options.
|
||||
# config.vm.synced_folder "../data", "/vagrant_data"
|
||||
|
||||
# Provider-specific configuration so you can fine-tune various
|
||||
# backing providers for Vagrant. These expose provider-specific options.
|
||||
# Example for VirtualBox:
|
||||
#
|
||||
# config.vm.provider "virtualbox" do |vb|
|
||||
# # Don't boot with headless mode
|
||||
# vb.gui = true
|
||||
#
|
||||
# # Use VBoxManage to customize the VM. For example to change memory:
|
||||
# vb.customize ["modifyvm", :id, "--memory", "1024"]
|
||||
# end
|
||||
|
||||
|
||||
config.vm.provider "virtualbox" do |vb|
|
||||
# Ubuntu / Virtualbox workaround.
|
||||
# see http://askubuntu.com/questions/238040/how-do-i-fix-name-service-for-vagrant-client
|
||||
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
|
||||
|
||||
# cpp client needs a lot of RAM to build
|
||||
vb.customize ["modifyvm", :id, "--memory", "2048"]
|
||||
end
|
||||
|
||||
#
|
||||
# View the documentation for the provider you're using for more
|
||||
# information on available options.
|
||||
|
||||
|
||||
# Ansible
|
||||
config.vm.provision "ansible" do |ansible|
|
||||
ansible.playbook = "site.yml"
|
||||
end
|
||||
|
||||
end
|
||||
|
8
tests/files/ansible/host-config.yml
Normal file
8
tests/files/ansible/host-config.yml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Provision the operation system for tests
|
||||
# testing
|
||||
hosts: all
|
||||
# live
|
||||
# hosts: TDB
|
||||
roles:
|
||||
- common
|
28
tests/files/ansible/roles/common/tasks/main.yml
Normal file
28
tests/files/ansible/roles/common/tasks/main.yml
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
- name: install docker
|
||||
sudo: true
|
||||
# install script from https://docs.docker.com/installation/ubuntulinux/
|
||||
shell: curl -sSL https://get.docker.com/ubuntu/ | sudo sh
|
||||
|
||||
- name: install package dependencies
|
||||
sudo: true
|
||||
apt: name={{ item }}
|
||||
with_items:
|
||||
- python-pip
|
||||
- htop
|
||||
|
||||
- name: install python dependencies
|
||||
sudo: true
|
||||
pip: name=docker-py
|
||||
|
||||
|
||||
- name: enable docker for standard user
|
||||
sudo: true
|
||||
# todo: how to logout after this command, otherwise won't be effective in this play
|
||||
user: name=vagrant groups=docker append=yes
|
||||
|
||||
- name: checkout test repo
|
||||
git:
|
||||
repo: https://github.com/sveneh/tests.git
|
||||
version: develop
|
||||
dest: git
|
18
tests/files/ansible/roles/testrunner/tasks/main.yml
Normal file
18
tests/files/ansible/roles/testrunner/tasks/main.yml
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
- name: update C++ client
|
||||
sudo: true
|
||||
docker_image:
|
||||
path: git/ansible/test-files/docker-cpp
|
||||
name: cpp
|
||||
state: build
|
||||
|
||||
- name: update Go client
|
||||
sudo: true
|
||||
docker_image:
|
||||
path: git/ansible/test-files/docker-go
|
||||
name: go
|
||||
state: build
|
||||
|
||||
- name: Run infinite tests (press ^C to stop)
|
||||
sudo: true
|
||||
shell: git/ansible/test-files/testrunner.sh
|
3
tests/files/ansible/site.yml
Normal file
3
tests/files/ansible/site.yml
Normal file
@ -0,0 +1,3 @@
|
||||
---
|
||||
- include: host-config.yml
|
||||
- include: testrunner-config.yml
|
32
tests/files/ansible/test-files/docker-cpp/Dockerfile
Normal file
32
tests/files/ansible/test-files/docker-cpp/Dockerfile
Normal file
@ -0,0 +1,32 @@
|
||||
# adjusted from https://github.com/ethereum/cpp-ethereum/blob/develop/docker/Dockerfile
|
||||
FROM ubuntu:14.04
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get upgrade -y
|
||||
|
||||
# Ethereum dependencies
|
||||
RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget
|
||||
RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
|
||||
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
|
||||
|
||||
# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 )
|
||||
RUN apt-get install -qy libncurses5-dev
|
||||
|
||||
# Qt-based GUI
|
||||
# RUN apt-get install -qy qtbase5-dev qt5-default qtdeclarative5-dev libqt5webkit5-dev
|
||||
|
||||
# Ethereum PPA
|
||||
RUN apt-get install -qy software-properties-common
|
||||
RUN add-apt-repository ppa:ethereum/ethereum
|
||||
RUN apt-get update
|
||||
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev
|
||||
|
||||
# Build Ethereum (HEADLESS)
|
||||
RUN git clone --depth=1 --branch develop https://github.com/ethereum/cpp-ethereum
|
||||
RUN mkdir -p cpp-ethereum/build
|
||||
RUN cd cpp-ethereum/build && cmake .. -DCMAKE_BUILD_TYPE=Release -DHEADLESS=1 && make -j $(cat /proc/cpuinfo | grep processor | wc -l) && make install
|
||||
RUN ldconfig
|
||||
|
||||
ENTRYPOINT ["/cpp-ethereum/build/test/createRandomTest"]
|
||||
|
46
tests/files/ansible/test-files/docker-go/Dockerfile
Normal file
46
tests/files/ansible/test-files/docker-go/Dockerfile
Normal file
@ -0,0 +1,46 @@
|
||||
# Adjusted from https://github.com/ethereum/go-ethereum/blob/develop/Dockerfile
|
||||
FROM ubuntu:14.04
|
||||
|
||||
## Environment setup
|
||||
ENV HOME /root
|
||||
ENV GOPATH /root/go
|
||||
ENV PATH /go/bin:/root/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
|
||||
|
||||
RUN mkdir -p /root/go
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
## Install base dependencies
|
||||
RUN apt-get update && apt-get upgrade -y
|
||||
RUN apt-get install -y git mercurial build-essential software-properties-common pkg-config libgmp3-dev libreadline6-dev libpcre3-dev libpcre++-dev
|
||||
|
||||
## Build and install Go
|
||||
RUN hg clone -u release https://code.google.com/p/go
|
||||
RUN cd go && hg update go1.4
|
||||
RUN cd go/src && ./make.bash && go version
|
||||
|
||||
## Install GUI dependencies
|
||||
RUN add-apt-repository ppa:ubuntu-sdk-team/ppa -y
|
||||
RUN apt-get update -y
|
||||
RUN apt-get install -y qtbase5-private-dev qtdeclarative5-private-dev libqt5opengl5-dev
|
||||
|
||||
## Fetch and install serpent-go
|
||||
RUN go get -v -d github.com/ethereum/serpent-go
|
||||
WORKDIR $GOPATH/src/github.com/ethereum/serpent-go
|
||||
# RUN git checkout master
|
||||
RUN git submodule update --init
|
||||
RUN go install -v
|
||||
|
||||
# Fetch and install go-ethereum
|
||||
RUN go get -v -d github.com/ethereum/go-ethereum/...
|
||||
WORKDIR $GOPATH/src/github.com/ethereum/go-ethereum
|
||||
|
||||
RUN git checkout develop
|
||||
|
||||
RUN git pull
|
||||
RUN ETH_DEPS=$(go list -f '{{.Imports}} {{.TestImports}} {{.XTestImports}}' github.com/ethereum/go-ethereum/... | sed -e 's/\[//g' | sed -e 's/\]//g' | sed -e 's/C //g'); if [ "$ETH_DEPS" ]; then go get $ETH_DEPS; fi
|
||||
RUN go install -v ./cmd/ethtest
|
||||
|
||||
# Run JSON RPC
|
||||
ENTRYPOINT ["ethtest"]
|
||||
EXPOSE 8080
|
||||
|
56
tests/files/ansible/test-files/testrunner.sh
Executable file
56
tests/files/ansible/test-files/testrunner.sh
Executable file
@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# create random virtual machine test
|
||||
#cd ~/software/Ethereum/pyethereum (python has local dependencies so only works from within the directory)
|
||||
while [ 1 ]
|
||||
do
|
||||
TEST="$(docker run --rm cpp)"
|
||||
# echo "$TEST"
|
||||
|
||||
# test pyethereum
|
||||
|
||||
#OUTPUT_PYTHON="$(python ./tests/test_vm.py "$TEST")"
|
||||
#RESULT_PYTHON=$?
|
||||
|
||||
# test go
|
||||
OUTPUT_GO="$(docker run --rm go "$TEST")"
|
||||
RESULT_GO=$?
|
||||
|
||||
# test cpp-jit
|
||||
#OUTPUT_CPPJIT="$(~/software/Ethereum/cpp-ethereum/build/test/checkRandomTest "$TEST")"
|
||||
#RESULT_CPPJIT=$?
|
||||
|
||||
# go fails
|
||||
if [ "$RESULT_GO" -ne 0 ]; then
|
||||
echo Failed:
|
||||
echo Output_GO:
|
||||
echo $OUTPUT_GO
|
||||
echo Test:
|
||||
echo "$TEST"
|
||||
echo "$TEST" > FailedTest.json
|
||||
mv FailedTest.json $(date -d "today" +"%Y%m%d%H%M")GO.json # replace with scp to central server
|
||||
fi
|
||||
|
||||
# python fails
|
||||
#if [ "$RESULT_PYTHON" -ne 0 ]; then
|
||||
# echo Failed:
|
||||
# echo Output_PYTHON:
|
||||
# echo $OUTPUT_PYTHON
|
||||
# echo Test:
|
||||
# echo "$TEST"
|
||||
# echo "$TEST" > FailedTest.json
|
||||
# mv FailedTest.json $(date -d "today" +"%Y%m%d%H%M")PYTHON.json
|
||||
#fi
|
||||
|
||||
# cppjit fails
|
||||
#if [ "$RESULT_CPPJIT" -ne 0 ]; then
|
||||
# echo Failed:
|
||||
# echo Output_CPPJIT:
|
||||
# echo $OUTPUT_CPPJIT
|
||||
# echo Test:
|
||||
# echo "$TEST"
|
||||
# echo "$TEST" > FailedTest.json
|
||||
# mv FailedTest.json $(date -d "today" +"%Y%m%d%H%M")CPPJIT.json
|
||||
#fi
|
||||
done
|
||||
|
12
tests/files/ansible/testrunner-config.yml
Normal file
12
tests/files/ansible/testrunner-config.yml
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: preparing and running tests
|
||||
# testing
|
||||
hosts: all
|
||||
# live
|
||||
# hosts: TBD
|
||||
|
||||
# TODO use the right user for configuring, until credentials set, stay with default vagrant user
|
||||
# remote_user: ubuntu
|
||||
|
||||
roles:
|
||||
- testrunner
|
@ -1,36 +1,6 @@
|
||||
module.exports = {
|
||||
blockgenesis: require('./BasicTests/blockgenesistest'),
|
||||
genesishashes: require('./BasicTests/genesishashestest'),
|
||||
hexencode: require('./BasicTests/hexencodetest'),
|
||||
keyaddrtests: require('./BasicTests/keyaddrtest'),
|
||||
rlptest: require('./BasicTests/rlptest'),
|
||||
trieTests: {
|
||||
trietest: require('./TrieTests/trietest'),
|
||||
trietestnextprev: require('./TrieTests/trietestnextprev'),
|
||||
trieanyorder: require('./TrieTests/trieanyorder')
|
||||
},
|
||||
txtest: require('./BasicTests/txtest'),
|
||||
StateTests: {
|
||||
stExample: require('./StateTests/stExample.json'),
|
||||
stInitCodeTest: require('./StateTests/stInitCodeTest.json'),
|
||||
stLogTests: require('./StateTests/stLogTests.json'),
|
||||
stPreCompiledContracts: require('./StateTests/stPreCompiledContracts'),
|
||||
stRecursiveCreate: require('./StateTests/stRecursiveCreate'),
|
||||
stRefundTest: require('./StateTests/stRefundTest'),
|
||||
stSpecial: require('./StateTests/stSpecialTest'),
|
||||
stSystemOperationsTest: require('./StateTests/stSystemOperationsTest'),
|
||||
stTransactionTest: require('./StateTests/stTransactionTest')
|
||||
},
|
||||
VMTests: {
|
||||
vmRandom: require('./VMTests/RandomTests/randomTest'),
|
||||
vmArithmeticTest: require('./VMTests/vmArithmeticTest'),
|
||||
vmBitwiseLogicOperationTest: require('./VMTests/vmBitwiseLogicOperationTest'),
|
||||
vmBlockInfoTest: require('./VMTests/vmBlockInfoTest'),
|
||||
vmEnvironmentalInfoTest: require('./VMTests/vmEnvironmentalInfoTest'),
|
||||
vmIOandFlowOperationsTest: require('./VMTests/vmIOandFlowOperationsTest'),
|
||||
vmLogTest: require('./VMTests/vmLogTest'),
|
||||
vmPushDupSwapTest: require('./VMTests/vmPushDupSwapTest'),
|
||||
vmSha3Test: require('./VMTests/vmSha3Test'),
|
||||
vmtests: require('./VMTests/vmtests')
|
||||
}
|
||||
basicTests: require('require-all')(__dirname + '/BasicTests/'),
|
||||
trieTests: require('require-all')(__dirname + '/TrieTests/'),
|
||||
stateTests: require('require-all')(__dirname + '/StateTests/'),
|
||||
vmTests: require('require-all')(__dirname + '/VMTests')
|
||||
};
|
||||
|
@ -19,5 +19,8 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/ethereum/tests/issues"
|
||||
},
|
||||
"homepage": "https://github.com/ethereum/tests"
|
||||
"homepage": "https://github.com/ethereum/tests",
|
||||
"dependencies": {
|
||||
"require-all": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/whisper"
|
||||
"github.com/obscuren/secp256k1-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -81,7 +81,7 @@ func (self *peer) broadcast(envelopes []*Envelope) error {
|
||||
if err := self.ws.WriteMsg(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
self.peer.Infoln("broadcasted", i, "message(s)")
|
||||
self.peer.DebugDetailln("broadcasted", i, "message(s)")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
Loading…
Reference in New Issue
Block a user