From 1f8290ca44df31cc4c4b68b30eef412476ed24e0 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Tue, 20 Jan 2015 23:55:13 +0100 Subject: [PATCH 01/10] Add ImportPreSaleKey * ImportPreSaleKey takes a KeyStore, a presale key JSON (e.g. file content) and a password string. It stores the key in the given key store. * Refactored common AES decryption and moved some functions to crypto.go --- crypto/crypto.go | 104 +++++++++++++++++++++++++++++++++ crypto/key.go | 9 +-- crypto/key_store_passphrase.go | 46 +-------------- crypto/key_store_test.go | 13 +++++ 4 files changed, 123 insertions(+), 49 deletions(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index ac84c6204..066d23dcb 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -1,12 +1,19 @@ package crypto import ( + "crypto/aes" + "crypto/cipher" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" + "errors" + "code.google.com/p/go-uuid/uuid" + "code.google.com/p/go.crypto/pbkdf2" "code.google.com/p/go.crypto/ripemd160" + "encoding/hex" + "encoding/json" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/ethutil" @@ -113,3 +120,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 := aes_cbc_decrypt(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 aes_cbc_decrypt(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)] +} diff --git a/crypto/key.go b/crypto/key.go index d371ad4dc..ca29b691f 100644 --- a/crypto/key.go +++ b/crypto/key.go @@ -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 } diff --git a/crypto/key_store_passphrase.go b/crypto/key_store_passphrase.go index e30a0a785..913b68498 100644 --- a/crypto/key_store_passphrase.go +++ b/crypto/key_store_passphrase.go @@ -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 := aes_cbc_decrypt(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)] -} diff --git a/crypto/key_store_test.go b/crypto/key_store_test.go index 16c0e476d..54efc739a 100644 --- a/crypto/key_store_test.go +++ b/crypto/key_store_test.go @@ -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) + } +} From 8af42d42da1d428025622d3b76982798ec9436bd Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Wed, 21 Jan 2015 19:08:05 +0100 Subject: [PATCH 02/10] CamelCase aesCBCDecrypt --- crypto/crypto.go | 4 ++-- crypto/key_store_passphrase.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index 066d23dcb..55d6f47e7 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -156,7 +156,7 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error */ passBytes := []byte(password) derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New) - plainText, err := aes_cbc_decrypt(derivedKey, cipherText, iv) + plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv) ethPriv := Sha3(plainText) ecKey := ToECDSA(ethPriv) key = &Key{ @@ -171,7 +171,7 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error return key, err } -func aes_cbc_decrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte, err error) { +func aesCBCDecrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte, err error) { aesBlock, err := aes.NewCipher(key) if err != nil { return plainText, err diff --git a/crypto/key_store_passphrase.go b/crypto/key_store_passphrase.go index 913b68498..80bf49d68 100644 --- a/crypto/key_store_passphrase.go +++ b/crypto/key_store_passphrase.go @@ -178,7 +178,7 @@ func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes if err != nil { return nil, err } - plainText, err := aes_cbc_decrypt(derivedKey, cipherText, iv) + plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv) if err != nil { return nil, err } From 465b0a79d8fa2550e6104d0d86e357b123f74a39 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 Jan 2015 00:24:20 +0100 Subject: [PATCH 03/10] Updated browser & pass view to callback function --- cmd/mist/assets/qml/browser.qml | 587 ++++++++++++++++---------------- cmd/mist/ui_lib.go | 5 +- 2 files changed, 303 insertions(+), 289 deletions(-) diff --git a/cmd/mist/assets/qml/browser.qml b/cmd/mist/assets/qml/browser.qml index a89c3c97d..c8f291e22 100644 --- a/cmd/mist/assets/qml/browser.qml +++ b/cmd/mist/assets/qml/browser.qml @@ -9,9 +9,9 @@ import Ethereum 1.0 Rectangle { id: window - objectName: "browserView" - anchors.fill: parent - color: "#00000000" + objectName: "browserView" + anchors.fill: parent + color: "#00000000" property var title: "Browser" property var iconSource: "../browser.png" @@ -139,311 +139,324 @@ 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 injectJs(js) { + webview.experimental.navigatorQtObjectEnabled = true; + webview.experimental.evaluateJavaScript(js) + webview.experimental.javascriptEnabled = true; + } - Instantiator { - model: selectorModel.items - delegate: MenuItem { - text: model.text - onTriggered: { - selectorModel.accept(index) - } - } - onObjectAdded: itemSelector.insertItem(index, object) - onObjectRemoved: itemSelector.removeItem(object) - } + function sendMessage(data) { + webview.experimental.postMessage(JSON.stringify(data)) } Component.onCompleted: { - itemSelector.popup() - } - } - 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; + for (var i in experimental.preferences) { + console.log(i) } - } catch(e) { - console.log(data.call + ": " + e) - - postData(data._id, null); } - } + 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" - function post(seed, data) { - postData(data._id, data) - } + experimental.itemSelector: MouseArea { + // To avoid conflicting with ListView.model when inside Initiator context. + property QtObject selectorModel: model + anchors.fill: parent + onClicked: selectorModel.reject() - function require(args, num) { - if(args.length < num) { - throw("required argument count of "+num+" got "+args.length); + 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) + } + } + + Component.onCompleted: { + itemSelector.popup() + } } - } - 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})) - } + 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) - function onWatchedCb(data, id) { - var messages = JSON.parse(data) - postEvent("watched:"+id, messages) - } + try { + switch(data.call) { + case "eth_compile": + postData(data._id, eth.compile(data.args[0])) + break - 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]) + 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; + } + } 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]) + } } } diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go index c88c4dab6..596f8442a 100644 --- a/cmd/mist/ui_lib.go +++ b/cmd/mist/ui_lib.go @@ -312,10 +312,11 @@ 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) + //self.win.Root().Call("invokeFilterCallback", xeth.ToJSMessages(messages), id) } id = self.filterManager.InstallFilter(filter) return id From 0045ce4cde69af0dd4b2f77871f893b091250489 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 Jan 2015 00:24:30 +0100 Subject: [PATCH 04/10] Future blocks not allowed --- core/block_processor.go | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index aa8fcc9e7..37acc4f72 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -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)) From 6eaa404187953777e8dc866e4e3db089e4ad0501 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 Jan 2015 00:25:00 +0100 Subject: [PATCH 05/10] Moved sha3 from `obscuren` --- crypto/crypto.go | 2 +- crypto/sha3/keccakf.go | 171 ++++++++++++++++++++++++++++++++ crypto/sha3/sha3.go | 216 +++++++++++++++++++++++++++++++++++++++++ pow/dagger/dagger.go | 2 +- pow/ezp/pow.go | 2 +- 5 files changed, 390 insertions(+), 3 deletions(-) create mode 100644 crypto/sha3/keccakf.go create mode 100644 crypto/sha3/sha3.go diff --git a/crypto/crypto.go b/crypto/crypto.go index b8fd78fa2..2c5f30905 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -7,10 +7,10 @@ import ( "crypto/sha256" "code.google.com/p/go.crypto/ripemd160" + "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() { diff --git a/crypto/sha3/keccakf.go b/crypto/sha3/keccakf.go new file mode 100644 index 000000000..3baf13ba3 --- /dev/null +++ b/crypto/sha3/keccakf.go @@ -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]<>(64-ro_06) + d.b[2] = d.a[12]<>(64-ro_12) + d.b[3] = d.a[18]<>(64-ro_18) + d.b[4] = d.a[24]<>(64-ro_24) + d.b[5] = d.a[3]<>(64-ro_15) + d.b[6] = d.a[9]<>(64-ro_21) + d.b[7] = d.a[10]<>(64-ro_02) + d.b[8] = d.a[16]<>(64-ro_08) + d.b[9] = d.a[22]<>(64-ro_14) + d.b[10] = d.a[1]<>(64-ro_05) + d.b[11] = d.a[7]<>(64-ro_11) + d.b[12] = d.a[13]<>(64-ro_17) + d.b[13] = d.a[19]<>(64-ro_23) + d.b[14] = d.a[20]<>(64-ro_04) + d.b[15] = d.a[4]<>(64-ro_20) + d.b[16] = d.a[5]<>(64-ro_01) + d.b[17] = d.a[11]<>(64-ro_07) + d.b[18] = d.a[17]<>(64-ro_13) + d.b[19] = d.a[23]<>(64-ro_19) + d.b[20] = d.a[2]<>(64-ro_10) + d.b[21] = d.a[8]<>(64-ro_16) + d.b[22] = d.a[14]<>(64-ro_22) + d.b[23] = d.a[15]<>(64-ro_03) + d.b[24] = 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 + } +} diff --git a/crypto/sha3/sha3.go b/crypto/sha3/sha3.go new file mode 100644 index 000000000..22df0ef11 --- /dev/null +++ b/crypto/sha3/sha3.go @@ -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} } diff --git a/pow/dagger/dagger.go b/pow/dagger/dagger.go index 9ac000443..310f8abdd 100644 --- a/pow/dagger/dagger.go +++ b/pow/dagger/dagger.go @@ -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") diff --git a/pow/ezp/pow.go b/pow/ezp/pow.go index 8c164798a..5abe6950e 100644 --- a/pow/ezp/pow.go +++ b/pow/ezp/pow.go @@ -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") From 67f9783e6a0fa5613a031e05549b92adbee57399 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 Jan 2015 00:35:00 +0100 Subject: [PATCH 06/10] Moved `obscuren` secp256k1-go --- core/types/transaction.go | 2 +- crypto/crypto.go | 2 +- crypto/crypto_test.go | 2 +- crypto/keypair.go | 2 +- crypto/secp256k1/.gitignore | 24 + crypto/secp256k1/README.md | 22 + crypto/secp256k1/notes.go | 192 +++++++ crypto/secp256k1/secp256.go | 304 +++++++++++ crypto/secp256k1/secp256_rand.go | 96 ++++ crypto/secp256k1/secp256_test.go | 228 ++++++++ crypto/secp256k1/secp256k1/COPYING | 19 + crypto/secp256k1/secp256k1/Makefile | 55 ++ crypto/secp256k1/secp256k1/TODO | 3 + crypto/secp256k1/secp256k1/config.mk | 9 + crypto/secp256k1/secp256k1/configure | 175 +++++++ .../secp256k1/secp256k1/include/secp256k1.h | 121 +++++ crypto/secp256k1/secp256k1/src/bench.c | 64 +++ crypto/secp256k1/secp256k1/src/ecdsa.h | 28 + crypto/secp256k1/secp256k1/src/ecmult.h | 19 + crypto/secp256k1/secp256k1/src/field.h | 101 ++++ crypto/secp256k1/secp256k1/src/field_10x26.h | 19 + crypto/secp256k1/secp256k1/src/field_5x52.h | 19 + .../secp256k1/src/field_5x52_asm.asm | 463 +++++++++++++++++ crypto/secp256k1/secp256k1/src/field_5x64.h | 19 + .../secp256k1/src/field_5x64_asm.asm | 332 ++++++++++++ crypto/secp256k1/secp256k1/src/field_gmp.h | 16 + crypto/secp256k1/secp256k1/src/group.h | 108 ++++ crypto/secp256k1/secp256k1/src/impl/ecdsa.h | 309 +++++++++++ crypto/secp256k1/secp256k1/src/impl/ecmult.h | 238 +++++++++ crypto/secp256k1/secp256k1/src/impl/field.h | 175 +++++++ .../secp256k1/src/impl/field_10x26.h | 487 ++++++++++++++++++ .../secp256k1/secp256k1/src/impl/field_5x52.h | 196 +++++++ .../secp256k1/src/impl/field_5x52_asm.h | 11 + .../secp256k1/src/impl/field_5x52_int128.h | 105 ++++ .../secp256k1/secp256k1/src/impl/field_5x64.h | 371 +++++++++++++ .../secp256k1/src/impl/field_5x64_asm.h | 11 + .../secp256k1/secp256k1/src/impl/field_gmp.h | 155 ++++++ crypto/secp256k1/secp256k1/src/impl/group.h | 397 ++++++++++++++ crypto/secp256k1/secp256k1/src/impl/num.h | 18 + crypto/secp256k1/secp256k1/src/impl/num_gmp.h | 346 +++++++++++++ .../secp256k1/src/impl/num_openssl.h | 145 ++++++ crypto/secp256k1/secp256k1/src/impl/util.h | 45 ++ .../src/java/org/bitcoin/NativeSecp256k1.java | 60 +++ .../src/java/org_bitcoin_NativeSecp256k1.c | 23 + .../src/java/org_bitcoin_NativeSecp256k1.h | 21 + crypto/secp256k1/secp256k1/src/num.h | 93 ++++ crypto/secp256k1/secp256k1/src/num_gmp.h | 18 + crypto/secp256k1/secp256k1/src/num_openssl.h | 14 + crypto/secp256k1/secp256k1/src/secp256k1.c | 269 ++++++++++ crypto/secp256k1/secp256k1/src/tests.c | 465 +++++++++++++++++ crypto/secp256k1/secp256k1/src/util.h | 19 + p2p/testpoc7.go | 2 +- whisper/main.go | 2 +- 53 files changed, 6433 insertions(+), 6 deletions(-) create mode 100644 crypto/secp256k1/.gitignore create mode 100644 crypto/secp256k1/README.md create mode 100644 crypto/secp256k1/notes.go create mode 100644 crypto/secp256k1/secp256.go create mode 100644 crypto/secp256k1/secp256_rand.go create mode 100644 crypto/secp256k1/secp256_test.go create mode 100644 crypto/secp256k1/secp256k1/COPYING create mode 100644 crypto/secp256k1/secp256k1/Makefile create mode 100644 crypto/secp256k1/secp256k1/TODO create mode 100644 crypto/secp256k1/secp256k1/config.mk create mode 100755 crypto/secp256k1/secp256k1/configure create mode 100644 crypto/secp256k1/secp256k1/include/secp256k1.h create mode 100644 crypto/secp256k1/secp256k1/src/bench.c create mode 100644 crypto/secp256k1/secp256k1/src/ecdsa.h create mode 100644 crypto/secp256k1/secp256k1/src/ecmult.h create mode 100644 crypto/secp256k1/secp256k1/src/field.h create mode 100644 crypto/secp256k1/secp256k1/src/field_10x26.h create mode 100644 crypto/secp256k1/secp256k1/src/field_5x52.h create mode 100644 crypto/secp256k1/secp256k1/src/field_5x52_asm.asm create mode 100644 crypto/secp256k1/secp256k1/src/field_5x64.h create mode 100644 crypto/secp256k1/secp256k1/src/field_5x64_asm.asm create mode 100644 crypto/secp256k1/secp256k1/src/field_gmp.h create mode 100644 crypto/secp256k1/secp256k1/src/group.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/ecdsa.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/ecmult.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/field.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/field_10x26.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/field_5x52.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/field_5x64.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/field_gmp.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/group.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/num.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/num_gmp.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/num_openssl.h create mode 100644 crypto/secp256k1/secp256k1/src/impl/util.h create mode 100644 crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java create mode 100644 crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c create mode 100644 crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h create mode 100644 crypto/secp256k1/secp256k1/src/num.h create mode 100644 crypto/secp256k1/secp256k1/src/num_gmp.h create mode 100644 crypto/secp256k1/secp256k1/src/num_openssl.h create mode 100644 crypto/secp256k1/secp256k1/src/secp256k1.c create mode 100644 crypto/secp256k1/secp256k1/src/tests.c create mode 100644 crypto/secp256k1/secp256k1/src/util.h diff --git a/core/types/transaction.go b/core/types/transaction.go index 83d76648f..7a1d6104e 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -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 { diff --git a/crypto/crypto.go b/crypto/crypto.go index 2c5f30905..ac84c6204 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -7,10 +7,10 @@ import ( "crypto/sha256" "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" ) func init() { diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 41c05a242..349bc31ae 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -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. diff --git a/crypto/keypair.go b/crypto/keypair.go index d02875ded..da5788437 100644 --- a/crypto/keypair.go +++ b/crypto/keypair.go @@ -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 { diff --git a/crypto/secp256k1/.gitignore b/crypto/secp256k1/.gitignore new file mode 100644 index 000000000..802b6744a --- /dev/null +++ b/crypto/secp256k1/.gitignore @@ -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 + +*~ diff --git a/crypto/secp256k1/README.md b/crypto/secp256k1/README.md new file mode 100644 index 000000000..79cdccb38 --- /dev/null +++ b/crypto/secp256k1/README.md @@ -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 +``` \ No newline at end of file diff --git a/crypto/secp256k1/notes.go b/crypto/secp256k1/notes.go new file mode 100644 index 000000000..7ed16caab --- /dev/null +++ b/crypto/secp256k1/notes.go @@ -0,0 +1,192 @@ +package secp256k1 + +/* + sipa, int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed); + is that how i generate private/public keys? + HaltingState: you pass in a random 32-byte string as seckey + HaltingState: if it is valid, the corresponding pubkey is put in pubkey + and true is returned + otherwise, false is returned + around 1 in 2^128 32-byte strings are invalid, so the odds of even ever seeing one is extremely rare + + private keys are mathematically numbers + each has a corresponding point on the curve as public key + a private key is just a number + a public key is a point with x/y coordinates + almost every 256-bit number is a valid private key (one with a point on the curve corresponding to it) + HaltingState: ok? + + more than half of random points are not on the curve + and actually, it is less than the square root, not less than half, sorry :) +!!! + a private key is a NUMBER + a public key is a POINT + half the x,y values in the field are not on the curve, a private key is an integer. + + 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 + that's the reason ECDH works + multiplication is associative and commutativ +*/ + +/* + 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 + because i know they can do that for the normal 72 byte signatures that openssl was putting out + HaltingState: if you don't enforce non-malleability, yes + HaltingState: if you force the highest bit of t + + it _creates_ signatures that already satisfy that condition + but it will accept ones that don't + maybe i should change that, and be strict + yes; i want some way to know signature is valid but fails malleability + well if the highest bit of S is 1, you can take its complement + and end up with a valid signature + that is canonical +*/ + +/* + + sipa, I am signing messages and highest bit of the compact signature is 1!!! + if (b & 0x80) == 0x80 { + log.Panic("b= %v b2= %v \n", b, b&0x80) + } + what bit? +* Pengoo has quit (Ping timeout: 272 seconds) + the highest bit of the first byte of signature + it's the highest bit of S + so the 32nd byte + 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 +*/ + +/* + one thing I dont get about armory for instance, +is how the hot-wallet can generate new addresses without +knowing the master key +*/ + +/* + 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 + ... + + You know that the *r curves are selected via an undisclosed +secret process, right? + 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); +*/ diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go new file mode 100644 index 000000000..53ad9b477 --- /dev/null +++ b/crypto/secp256k1/secp256.go @@ -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") +} diff --git a/crypto/secp256k1/secp256_rand.go b/crypto/secp256k1/secp256_rand.go new file mode 100644 index 000000000..5e8035e0f --- /dev/null +++ b/crypto/secp256k1/secp256_rand.go @@ -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 +} diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go new file mode 100644 index 000000000..468c50db9 --- /dev/null +++ b/crypto/secp256k1/secp256_test.go @@ -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) + } +} diff --git a/crypto/secp256k1/secp256k1/COPYING b/crypto/secp256k1/secp256k1/COPYING new file mode 100644 index 000000000..4522a5990 --- /dev/null +++ b/crypto/secp256k1/secp256k1/COPYING @@ -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. diff --git a/crypto/secp256k1/secp256k1/Makefile b/crypto/secp256k1/secp256k1/Makefile new file mode 100644 index 000000000..21628f308 --- /dev/null +++ b/crypto/secp256k1/secp256k1/Makefile @@ -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 diff --git a/crypto/secp256k1/secp256k1/TODO b/crypto/secp256k1/secp256k1/TODO new file mode 100644 index 000000000..a300e1c5e --- /dev/null +++ b/crypto/secp256k1/secp256k1/TODO @@ -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 diff --git a/crypto/secp256k1/secp256k1/config.mk b/crypto/secp256k1/secp256k1/config.mk new file mode 100644 index 000000000..3386b7bcb --- /dev/null +++ b/crypto/secp256k1/secp256k1/config.mk @@ -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 diff --git a/crypto/secp256k1/secp256k1/configure b/crypto/secp256k1/secp256k1/configure new file mode 100755 index 000000000..cb69239b7 --- /dev/null +++ b/crypto/secp256k1/secp256k1/configure @@ -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 - </dev/null </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 < +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 < +#include +#include +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 < +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 < +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 diff --git a/crypto/secp256k1/secp256k1/include/secp256k1.h b/crypto/secp256k1/secp256k1/include/secp256k1.h new file mode 100644 index 000000000..fd6d6b1f4 --- /dev/null +++ b/crypto/secp256k1/secp256k1/include/secp256k1.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/bench.c b/crypto/secp256k1/secp256k1/src/bench.c new file mode 100644 index 000000000..eeb71343f --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/bench.c @@ -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 + +#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; +} diff --git a/crypto/secp256k1/secp256k1/src/ecdsa.h b/crypto/secp256k1/secp256k1/src/ecdsa.h new file mode 100644 index 000000000..d9faaa3e8 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/ecdsa.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/ecmult.h b/crypto/secp256k1/secp256k1/src/ecmult.h new file mode 100644 index 000000000..856bd284f --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/ecmult.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/field.h b/crypto/secp256k1/secp256k1/src/field.h new file mode 100644 index 000000000..4e0f26179 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/field.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/field_10x26.h b/crypto/secp256k1/secp256k1/src/field_10x26.h new file mode 100644 index 000000000..d544139e8 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/field_10x26.h @@ -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 + +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 diff --git a/crypto/secp256k1/secp256k1/src/field_5x52.h b/crypto/secp256k1/secp256k1/src/field_5x52.h new file mode 100644 index 000000000..9d5de2cc4 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/field_5x52.h @@ -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 + +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 diff --git a/crypto/secp256k1/secp256k1/src/field_5x52_asm.asm b/crypto/secp256k1/secp256k1/src/field_5x52_asm.asm new file mode 100644 index 000000000..9237b3687 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/field_5x52_asm.asm @@ -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 + + diff --git a/crypto/secp256k1/secp256k1/src/field_5x64.h b/crypto/secp256k1/secp256k1/src/field_5x64.h new file mode 100644 index 000000000..f3d47f547 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/field_5x64.h @@ -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 + +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 diff --git a/crypto/secp256k1/secp256k1/src/field_5x64_asm.asm b/crypto/secp256k1/secp256k1/src/field_5x64_asm.asm new file mode 100644 index 000000000..d449185c7 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/field_5x64_asm.asm @@ -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 + + diff --git a/crypto/secp256k1/secp256k1/src/field_gmp.h b/crypto/secp256k1/secp256k1/src/field_gmp.h new file mode 100644 index 000000000..d51dea0af --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/field_gmp.h @@ -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 + +#define FIELD_LIMBS ((256 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS) + +typedef struct { + mp_limb_t n[FIELD_LIMBS+1]; +} secp256k1_fe_t; + +#endif diff --git a/crypto/secp256k1/secp256k1/src/group.h b/crypto/secp256k1/secp256k1/src/group.h new file mode 100644 index 000000000..ae291c6ca --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/group.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/impl/ecdsa.h b/crypto/secp256k1/secp256k1/src/impl/ecdsa.h new file mode 100644 index 000000000..dd26cfd11 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/ecdsa.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/impl/ecmult.h b/crypto/secp256k1/secp256k1/src/impl/ecmult.h new file mode 100644 index 000000000..6acb4c408 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/ecmult.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/impl/field.h b/crypto/secp256k1/secp256k1/src/impl/field.h new file mode 100644 index 000000000..edb2acadc --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/field.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/impl/field_10x26.h b/crypto/secp256k1/secp256k1/src/impl/field_10x26.h new file mode 100644 index 000000000..449769254 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/field_10x26.h @@ -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 +#include +#include +#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 diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x52.h b/crypto/secp256k1/secp256k1/src/impl/field_5x52.h new file mode 100644 index 000000000..5347189f1 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/field_5x52.h @@ -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 +#include +#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 diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h b/crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h new file mode 100644 index 000000000..93c6ab6b5 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h b/crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h new file mode 100644 index 000000000..23cb13462 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h @@ -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 + +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 diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x64.h b/crypto/secp256k1/secp256k1/src/impl/field_5x64.h new file mode 100644 index 000000000..1e645cddb --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/field_5x64.h @@ -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 +#include +#include "../num.h" +#include "../field.h" + +#include +#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> 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 diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h b/crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h new file mode 100644 index 000000000..93c6ab6b5 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/impl/field_gmp.h b/crypto/secp256k1/secp256k1/src/impl/field_gmp.h new file mode 100644 index 000000000..6172ef48e --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/field_gmp.h @@ -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 +#include +#include +#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; in[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; in[i] = 0; +} + +int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) { + int ret = 1; + for (int i=0; in[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; in[i] == b->n[i]); + return ret; +} + +void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { + for (int i=0; in[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; in[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) { + // + // 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 diff --git a/crypto/secp256k1/secp256k1/src/impl/group.h b/crypto/secp256k1/secp256k1/src/impl/group.h new file mode 100644 index 000000000..ce8d7b204 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/group.h @@ -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 + +#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 diff --git a/crypto/secp256k1/secp256k1/src/impl/num.h b/crypto/secp256k1/secp256k1/src/impl/num.h new file mode 100644 index 000000000..fc6d05c3d --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/num.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/impl/num_gmp.h b/crypto/secp256k1/secp256k1/src/impl/num_gmp.h new file mode 100644 index 000000000..067c15180 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/num_gmp.h @@ -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 +#include +#include +#include + +#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; ilimbs = 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= 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= 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 diff --git a/crypto/secp256k1/secp256k1/src/impl/num_openssl.h b/crypto/secp256k1/secp256k1/src/impl/num_openssl.h new file mode 100644 index 000000000..0a54689ac --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/num_openssl.h @@ -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 +#include +#include +#include +#include + +#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; ibn, &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 diff --git a/crypto/secp256k1/secp256k1/src/impl/util.h b/crypto/secp256k1/secp256k1/src/impl/util.h new file mode 100644 index 000000000..a59a00cac --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/impl/util.h @@ -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 +#include + +#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 diff --git a/crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java new file mode 100644 index 000000000..90a498eaa --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java @@ -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 nativeECDSABuffer = new ThreadLocal(); + /** + * 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); +} diff --git a/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c new file mode 100644 index 000000000..ed65cccf6 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -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(); +} diff --git a/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h new file mode 100644 index 000000000..d7fb004fa --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* 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 diff --git a/crypto/secp256k1/secp256k1/src/num.h b/crypto/secp256k1/secp256k1/src/num.h new file mode 100644 index 000000000..b2e7462bc --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/num.h @@ -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 diff --git a/crypto/secp256k1/secp256k1/src/num_gmp.h b/crypto/secp256k1/secp256k1/src/num_gmp.h new file mode 100644 index 000000000..960df8605 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/num_gmp.h @@ -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 + +#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 diff --git a/crypto/secp256k1/secp256k1/src/num_openssl.h b/crypto/secp256k1/secp256k1/src/num_openssl.h new file mode 100644 index 000000000..7d03757f6 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/num_openssl.h @@ -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 + +typedef struct { + BIGNUM bn; +} secp256k1_num_t; + +#endif diff --git a/crypto/secp256k1/secp256k1/src/secp256k1.c b/crypto/secp256k1/secp256k1/src/secp256k1.c new file mode 100644 index 000000000..ed8bf2e95 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/secp256k1.c @@ -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; +} diff --git a/crypto/secp256k1/secp256k1/src/tests.c b/crypto/secp256k1/secp256k1/src/tests.c new file mode 100644 index 000000000..af7bbaad0 --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/tests.c @@ -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 + +#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 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; +} diff --git a/crypto/secp256k1/secp256k1/src/util.h b/crypto/secp256k1/secp256k1/src/util.h new file mode 100644 index 000000000..357c7e06b --- /dev/null +++ b/crypto/secp256k1/secp256k1/src/util.h @@ -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 diff --git a/p2p/testpoc7.go b/p2p/testpoc7.go index c0cc5c544..63b996f79 100644 --- a/p2p/testpoc7.go +++ b/p2p/testpoc7.go @@ -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() { diff --git a/whisper/main.go b/whisper/main.go index edd5f7004..9f35dbb8d 100644 --- a/whisper/main.go +++ b/whisper/main.go @@ -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() { From 4df2e1ef5c20ebd7004a595de7e6a032699106ad Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 Jan 2015 00:37:58 +0100 Subject: [PATCH 07/10] updated tests --- tests/files/.gitignore | 4 + .../RandomTests/201501151106PYTHON.json | 53 +++++++++++++ .../RandomTests/201501191458PYTHON.json | 31 ++++++++ .../RandomTests/201501191859PYTHON.json | 31 ++++++++ .../RandomTests/201501191953PYTHON.json | 31 ++++++++ tests/files/VMTests/vmSha3Test.json | 58 ++++++++++++++ tests/files/ansible/README.md | 5 ++ tests/files/ansible/Vagrantfile | 78 +++++++++++++++++++ tests/files/ansible/host-config.yml | 8 ++ .../files/ansible/roles/common/tasks/main.yml | 28 +++++++ .../ansible/roles/testrunner/tasks/main.yml | 18 +++++ tests/files/ansible/site.yml | 3 + .../ansible/test-files/docker-cpp/Dockerfile | 32 ++++++++ .../ansible/test-files/docker-go/Dockerfile | 46 +++++++++++ tests/files/ansible/test-files/testrunner.sh | 56 +++++++++++++ tests/files/ansible/testrunner-config.yml | 12 +++ tests/files/index.js | 38 +-------- tests/files/package.json | 5 +- 18 files changed, 502 insertions(+), 35 deletions(-) create mode 100644 tests/files/.gitignore create mode 100644 tests/files/VMTests/RandomTests/201501151106PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201501191458PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201501191859PYTHON.json create mode 100644 tests/files/VMTests/RandomTests/201501191953PYTHON.json create mode 100644 tests/files/ansible/README.md create mode 100644 tests/files/ansible/Vagrantfile create mode 100644 tests/files/ansible/host-config.yml create mode 100644 tests/files/ansible/roles/common/tasks/main.yml create mode 100644 tests/files/ansible/roles/testrunner/tasks/main.yml create mode 100644 tests/files/ansible/site.yml create mode 100644 tests/files/ansible/test-files/docker-cpp/Dockerfile create mode 100644 tests/files/ansible/test-files/docker-go/Dockerfile create mode 100755 tests/files/ansible/test-files/testrunner.sh create mode 100644 tests/files/ansible/testrunner-config.yml diff --git a/tests/files/.gitignore b/tests/files/.gitignore new file mode 100644 index 000000000..cdf615a0f --- /dev/null +++ b/tests/files/.gitignore @@ -0,0 +1,4 @@ +venv/ +*~ +*.swp +.vagrant/ diff --git a/tests/files/VMTests/RandomTests/201501151106PYTHON.json b/tests/files/VMTests/RandomTests/201501151106PYTHON.json new file mode 100644 index 000000000..b2b82c46b --- /dev/null +++ b/tests/files/VMTests/RandomTests/201501151106PYTHON.json @@ -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" : { + } + } + } + } +} diff --git a/tests/files/VMTests/RandomTests/201501191458PYTHON.json b/tests/files/VMTests/RandomTests/201501191458PYTHON.json new file mode 100644 index 000000000..add1fbff5 --- /dev/null +++ b/tests/files/VMTests/RandomTests/201501191458PYTHON.json @@ -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" : { + } + } + } + } +} diff --git a/tests/files/VMTests/RandomTests/201501191859PYTHON.json b/tests/files/VMTests/RandomTests/201501191859PYTHON.json new file mode 100644 index 000000000..53a0d2da9 --- /dev/null +++ b/tests/files/VMTests/RandomTests/201501191859PYTHON.json @@ -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" : { + } + } + } + } +} diff --git a/tests/files/VMTests/RandomTests/201501191953PYTHON.json b/tests/files/VMTests/RandomTests/201501191953PYTHON.json new file mode 100644 index 000000000..2ca16c9ea --- /dev/null +++ b/tests/files/VMTests/RandomTests/201501191953PYTHON.json @@ -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" : { + } + } + } + } +} diff --git a/tests/files/VMTests/vmSha3Test.json b/tests/files/VMTests/vmSha3Test.json index b9e6b46a1..d9d3c640b 100644 --- a/tests/files/VMTests/vmSha3Test.json +++ b/tests/files/VMTests/vmSha3Test.json @@ -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" : { + } + } + } } } \ No newline at end of file diff --git a/tests/files/ansible/README.md b/tests/files/ansible/README.md new file mode 100644 index 000000000..cef407986 --- /dev/null +++ b/tests/files/ansible/README.md @@ -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. diff --git a/tests/files/ansible/Vagrantfile b/tests/files/ansible/Vagrantfile new file mode 100644 index 000000000..ce6ac3dde --- /dev/null +++ b/tests/files/ansible/Vagrantfile @@ -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 + diff --git a/tests/files/ansible/host-config.yml b/tests/files/ansible/host-config.yml new file mode 100644 index 000000000..571cc141e --- /dev/null +++ b/tests/files/ansible/host-config.yml @@ -0,0 +1,8 @@ +--- +- name: Provision the operation system for tests + # testing + hosts: all + # live + # hosts: TDB + roles: + - common diff --git a/tests/files/ansible/roles/common/tasks/main.yml b/tests/files/ansible/roles/common/tasks/main.yml new file mode 100644 index 000000000..3c483ce13 --- /dev/null +++ b/tests/files/ansible/roles/common/tasks/main.yml @@ -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 diff --git a/tests/files/ansible/roles/testrunner/tasks/main.yml b/tests/files/ansible/roles/testrunner/tasks/main.yml new file mode 100644 index 000000000..ce7fd8efa --- /dev/null +++ b/tests/files/ansible/roles/testrunner/tasks/main.yml @@ -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 diff --git a/tests/files/ansible/site.yml b/tests/files/ansible/site.yml new file mode 100644 index 000000000..cc04daa94 --- /dev/null +++ b/tests/files/ansible/site.yml @@ -0,0 +1,3 @@ +--- +- include: host-config.yml +- include: testrunner-config.yml diff --git a/tests/files/ansible/test-files/docker-cpp/Dockerfile b/tests/files/ansible/test-files/docker-cpp/Dockerfile new file mode 100644 index 000000000..a3b0e4ca6 --- /dev/null +++ b/tests/files/ansible/test-files/docker-cpp/Dockerfile @@ -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"] + diff --git a/tests/files/ansible/test-files/docker-go/Dockerfile b/tests/files/ansible/test-files/docker-go/Dockerfile new file mode 100644 index 000000000..2302518f3 --- /dev/null +++ b/tests/files/ansible/test-files/docker-go/Dockerfile @@ -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 + diff --git a/tests/files/ansible/test-files/testrunner.sh b/tests/files/ansible/test-files/testrunner.sh new file mode 100755 index 000000000..2c9608dd4 --- /dev/null +++ b/tests/files/ansible/test-files/testrunner.sh @@ -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 + diff --git a/tests/files/ansible/testrunner-config.yml b/tests/files/ansible/testrunner-config.yml new file mode 100644 index 000000000..0304883f1 --- /dev/null +++ b/tests/files/ansible/testrunner-config.yml @@ -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 diff --git a/tests/files/index.js b/tests/files/index.js index 99c19aa13..6db56cc55 100644 --- a/tests/files/index.js +++ b/tests/files/index.js @@ -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') }; diff --git a/tests/files/package.json b/tests/files/package.json index eb0841450..c066bd1b5 100644 --- a/tests/files/package.json +++ b/tests/files/package.json @@ -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" + } } From b777d6aa3f0e771ca8465924820db1848bc47402 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 Jan 2015 12:35:31 +0100 Subject: [PATCH 08/10] UI Updates * Browser now has tabs * Fixed a callback issue --- cmd/mist/assets/qml/browser.qml | 32 +++----------- cmd/mist/assets/qml/main.qml | 63 +++++++++++++-------------- cmd/mist/assets/qml/views/whisper.qml | 1 - cmd/mist/ui_lib.go | 9 +--- whisper/peer.go | 2 +- 5 files changed, 40 insertions(+), 67 deletions(-) diff --git a/cmd/mist/assets/qml/browser.qml b/cmd/mist/assets/qml/browser.qml index c8f291e22..7056dbbf3 100644 --- a/cmd/mist/assets/qml/browser.qml +++ b/cmd/mist/assets/qml/browser.qml @@ -9,15 +9,16 @@ import Ethereum 1.0 Rectangle { id: window - objectName: "browserView" 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); @@ -164,22 +164,10 @@ Rectangle { id: webview anchors.fill: parent - function injectJs(js) { - webview.experimental.navigatorQtObjectEnabled = true; - webview.experimental.evaluateJavaScript(js) - webview.experimental.javascriptEnabled = true; - } - function sendMessage(data) { webview.experimental.postMessage(JSON.stringify(data)) } - Component.onCompleted: { - for (var i in experimental.preferences) { - console.log(i) - } - } - experimental.preferences.javascriptEnabled: true experimental.preferences.webAudioEnabled: true experimental.preferences.pluginsEnabled: true @@ -219,8 +207,7 @@ Rectangle { } 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 + //console.log("[onMessageReceived]: ", message.data) var data = JSON.parse(message.data) try { @@ -350,13 +337,13 @@ Rectangle { case "eth_newFilterString": require(1) - var id = eth.newFilterString(data.args[0]) + 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]) + var id = eth.newFilter(data.args[0], window) postData(data._id, id); break; @@ -425,11 +412,9 @@ Rectangle { } } - 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); @@ -441,12 +426,10 @@ Rectangle { 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) } @@ -460,7 +443,6 @@ Rectangle { } } - Rectangle { id: sizeGrip color: "gray" diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index 7b207cbcc..c6b524549 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -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"}) } diff --git a/cmd/mist/assets/qml/views/whisper.qml b/cmd/mist/assets/qml/views/whisper.qml index 029376c45..dc097b806 100644 --- a/cmd/mist/assets/qml/views/whisper.qml +++ b/cmd/mist/assets/qml/views/whisper.qml @@ -18,7 +18,6 @@ Rectangle { property var identity: "" Component.onCompleted: { identity = shh.newIdentity() - console.log("New identity:", identity) var t = shh.watch({}, root) } diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go index 596f8442a..e0321f6dd 100644 --- a/cmd/mist/ui_lib.go +++ b/cmd/mist/ui_lib.go @@ -316,20 +316,15 @@ func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (i filter := qt.NewFilterFromMap(object, self.eth) filter.MessageCallback = func(messages state.Messages) { view.Call("messages", xeth.ToJSMessages(messages), id) - //self.win.Root().Call("invokeFilterCallback", 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 diff --git a/whisper/peer.go b/whisper/peer.go index f82cc6e3e..332ddd22a 100644 --- a/whisper/peer.go +++ b/whisper/peer.go @@ -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 From d4cc2d3503ce7497ef0cb39456a332b25e0999b9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 Jan 2015 18:12:05 +0100 Subject: [PATCH 09/10] Pad private key when signing & length check for hashes in sign --- crypto/crypto.go | 7 ++++++- crypto/crypto_test.go | 14 +++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index ac84c6204..3da69ea94 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -5,6 +5,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/sha256" + "fmt" "code.google.com/p/go.crypto/ripemd160" "github.com/ethereum/go-ethereum/crypto/secp256k1" @@ -101,7 +102,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(), 32)) return } diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 349bc31ae..441733f93 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -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") + } +} From 0dfe5113709d2981ef2ec8885d831a38cf2e4f91 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 Jan 2015 18:15:11 +0100 Subject: [PATCH 10/10] Use curve params instead of hardcoded 32 bytes --- crypto/crypto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index 3da69ea94..93453b91c 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -106,7 +106,7 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { 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(), 32)) + sig, err = secp256k1.Sign(hash, ethutil.LeftPadBytes(prv.D.Bytes(), prv.Params().BitSize/8)) return }