diff --git a/bip32.c b/bip32.c index d9bda71af4..a9fc2e7f53 100644 --- a/bip32.c +++ b/bip32.c @@ -264,42 +264,42 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) return 1; } -int hdnode_public_ckd_address_optimized(const HDNode *in, const curve_point *pub, uint32_t i, uint8_t version, char *addr, int addrsize) +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint8_t version, char *addr, int addrsize) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; - uint8_t public_key[33]; + uint8_t child_pubkey[33]; curve_point b; bignum256 c; if (i & 0x80000000) { // private derivation return 0; } - memcpy(data, in->public_key, 33); + memcpy(data, public_key, 33); write_be(data + 33, i); while (true) { bool failed = false; - hmac_sha512(in->chain_code, 32, data, sizeof(data), I); + hmac_sha512(chain_code, 32, data, sizeof(data), I); bn_read_be(I, &c); - if (!bn_is_less(&c, &in->curve->params->order)) { // >= order + if (!bn_is_less(&c, &secp256k1.order)) { // >= order failed = true; } else { - scalar_multiply(in->curve->params, &c, &b); // b = c * G - point_add(in->curve->params, pub, &b); // b = a + b + scalar_multiply(&secp256k1, &c, &b); // b = c * G + point_add(&secp256k1, pub, &b); // b = a + b if (point_is_infinity(&b)) { failed = true; } } if (!failed) { - public_key[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, public_key + 1); + child_pubkey[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, child_pubkey + 1); break; } data[0] = 1; memcpy(data + 1, I + 32, 32); } - ecdsa_get_address(public_key, version, addr, addrsize); + ecdsa_get_address(child_pubkey, version, addr, addrsize); return 1; } diff --git a/bip32.h b/bip32.h index ed45498bb2..ddabf1869a 100644 --- a/bip32.h +++ b/bip32.h @@ -56,7 +56,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i); int hdnode_public_ckd(HDNode *inout, uint32_t i); -int hdnode_public_ckd_address_optimized(const HDNode *in, const curve_point *pub, uint32_t i, uint8_t version, char *addr, int addrsize); +int hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *public_key, const uint8_t *chain_code, uint32_t i, uint8_t version, char *addr, int addrsize); #if USE_BIP32_CACHE diff --git a/ecdsa.c b/ecdsa.c index bb465a2f49..9cbd928498 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -35,6 +35,7 @@ #include "ecdsa.h" #include "base58.h" #include "macros.h" +#include "secp256k1.h" // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) @@ -878,6 +879,9 @@ void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub) { + if (!curve) { + curve = &secp256k1; + } if (pub_key[0] == 0x04) { bn_read_be(pub_key + 1, &(pub->x)); bn_read_be(pub_key + 33, &(pub->y)); diff --git a/emscripten/Makefile b/emscripten/Makefile index 66e1bf4923..0424c23b71 100644 --- a/emscripten/Makefile +++ b/emscripten/Makefile @@ -2,7 +2,8 @@ EMFLAGS = \ -Os --closure 1 \ --memory-init-file 0 \ --pre-js pre.js --post-js post.js \ - -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd", "_ecdsa_get_address"]' + -I ../ed25519-donna \ + -s EXPORTED_FUNCTIONS='["_hdnode_public_ckd_address_optimized", "_ecdsa_read_pubkey"]' SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \ ../base58.c ../ripemd160.c ../sha2.c ../rand.c @@ -22,3 +23,6 @@ node_modules: clean: rm -f trezor-crypto.js test-browserify.js + +docker: + docker run --rm -i -v $(shell pwd)/..:/src -t apiaryio/emcc /bin/bash diff --git a/emscripten/post.js b/emscripten/post.js index c42c941c1e..29942893a7 100644 --- a/emscripten/post.js +++ b/emscripten/post.js @@ -11,13 +11,17 @@ var HEAPU8 = Module['HEAPU8']; var _malloc = Module['_malloc']; -var _hdnode_public_ckd = Module['_hdnode_public_ckd']; -var _ecdsa_get_address = Module['_ecdsa_get_address']; +var _hdnode_public_ckd_address_optimized = Module['_hdnode_public_ckd_address_optimized']; +var _ecdsa_read_pubkey = Module['_ecdsa_read_pubkey']; var Pointer_stringify = Module['Pointer_stringify']; -// HDNode struct global -var HDNODE_SIZE = 4 + 4 + 4 + 32 + 32 + 33; -var _hdnode = _malloc(HDNODE_SIZE); +// HDNode structs global +var PUBPOINT_SIZE = 2 * 9 * 4; // (2 * bignum256 (= 9 * uint32_t)) +var _pubpoint = _malloc(PUBPOINT_SIZE); +var PUBKEY_SIZE = 33; +var _pubkey = _malloc(PUBKEY_SIZE); +var CHAINCODE_SIZE = 32; +var _chaincode = _malloc(CHAINCODE_SIZE); // address string global var ADDRESS_SIZE = 40; // maximum size @@ -29,33 +33,26 @@ var _address = _malloc(ADDRESS_SIZE); /** * @param {HDNode} node HDNode struct, see the definition above - * @return {Uint8Array} */ function serializeNode(node) { - var b = new ArrayBuffer(HDNODE_SIZE); + var u8_pubkey = new Uint8Array(33); + u8_pubkey.set(node['public_key'], 0); + HEAPU8.set(u8_pubkey, _pubkey); - var u32 = new Uint32Array(b, 0, 12); - u32[0] = node['depth']; - u32[1] = node['fingerprint']; - u32[2] = node['child_num']; + var u8_chaincode = new Uint8Array(32); + u8_chaincode.set(node['chain_code'], 0); + HEAPU8.set(u8_chaincode, _chaincode); - var u8 = new Uint8Array(b, 0, HDNODE_SIZE); - u8.set(node['chain_code'], 12); - u8.set(node['public_key'], 12 + 32 + 32); - - return u8; + _ecdsa_read_pubkey(0, _pubkey, _pubpoint); } /** - * @param {Uint8Array} sn serialized node, see `serializeNode` * @param {Number} index BIP32 index of the address * @param {Number} version address version byte * @return {String} */ -function deriveAddress(sn, index, version) { - HEAPU8.set(sn, _hdnode); - _hdnode_public_ckd(_hdnode, index); - _ecdsa_get_address(_hdnode + 12 + 32 + 32, version, _address, ADDRESS_SIZE); +function deriveAddress(index, version) { + _hdnode_public_ckd_address_optimized(_pubpoint, _pubkey, _chaincode, index, version, _address, ADDRESS_SIZE); return Pointer_stringify(_address); } @@ -68,10 +65,10 @@ function deriveAddress(sn, index, version) { */ function deriveAddressRange(node, firstIndex, lastIndex, version) { var addresses = []; - var sn = serializeNode(node); + serializeNode(node); var i; for (i = firstIndex; i <= lastIndex; i++) { - addresses.push(deriveAddress(sn, i, version)); + addresses.push(deriveAddress(i, version)); } return addresses; } diff --git a/emscripten/test.js b/emscripten/test.js index acaeb600c2..ed7ed8cfc4 100644 --- a/emscripten/test.js +++ b/emscripten/test.js @@ -13,7 +13,6 @@ var nodeStruct = { chain_code: node.chainCode, public_key: node.keyPair.getPublicKeyBuffer() }; -var nodeSerialized = crypto.serializeNode(nodeStruct); var suite; var worker; @@ -60,8 +59,9 @@ function benchBitcoinJS(ops, fn) { function benchBrowserify(ops, fn) { var i; + crypto.serializeNode(nodeStruct); for (i = 0; i < ops; i++) { - crypto.deriveAddress(nodeSerialized, i, 0); + crypto.deriveAddress(i, 0); } fn(); } diff --git a/test_speed.c b/test_speed.c index 75ccb4d8b6..0378692ef1 100644 --- a/test_speed.c +++ b/test_speed.c @@ -100,10 +100,10 @@ void bench_ckd_normal(void) { void bench_ckd_optimized(void) { char addr[40]; curve_point pub; - ecdsa_read_pubkey(root.curve->params, root.public_key, &pub); + ecdsa_read_pubkey(0, root.public_key, &pub); clock_t t = clock(); for (int i = 0; i < 1000; i++) { - hdnode_public_ckd_address_optimized(&root, &pub, i, 0, addr, 40); + hdnode_public_ckd_address_optimized(&pub, root.public_key, root.chain_code, i, 0, addr, 40); if (i == 0) { printf("address = %s\n", addr); }