diff --git a/bip32.c b/bip32.c index 8ecfc6f73..d9bda71af 100644 --- a/bip32.c +++ b/bip32.c @@ -264,6 +264,45 @@ 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) +{ + uint8_t data[1 + 32 + 4]; + uint8_t I[32 + 32]; + uint8_t public_key[33]; + curve_point b; + bignum256 c; + + if (i & 0x80000000) { // private derivation + return 0; + } + memcpy(data, in->public_key, 33); + write_be(data + 33, i); + + while (true) { + bool failed = false; + hmac_sha512(in->chain_code, 32, data, sizeof(data), I); + bn_read_be(I, &c); + if (!bn_is_less(&c, &in->curve->params->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 + 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); + break; + } + data[0] = 1; + memcpy(data + 1, I + 32, 32); + } + ecdsa_get_address(public_key, version, addr, addrsize); + return 1; +} + #if USE_BIP32_CACHE static bool private_ckd_cache_root_set = false; diff --git a/bip32.h b/bip32.h index 2f7dca3e1..ed45498bb 100644 --- a/bip32.h +++ b/bip32.h @@ -56,6 +56,8 @@ 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); + #if USE_BIP32_CACHE int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count); diff --git a/test_speed.c b/test_speed.c index 0541ef246..75ccb4d8b 100644 --- a/test_speed.c +++ b/test_speed.c @@ -6,6 +6,7 @@ #include "curves.h" #include "ecdsa.h" #include "secp256k1.h" +#include "nist256p1.h" #include "ed25519.h" uint8_t msg[32]; @@ -34,6 +35,23 @@ void bench_secp256k1(void) { printf("SECP256k1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); } +void bench_nist256p1(void) { + uint8_t sig[64], pub[33], priv[32], pby; + + const ecdsa_curve *curve = &nist256p1; + + memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); + ecdsa_get_public_key33(curve, priv, pub); + ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby); + + clock_t t = clock(); + for (int i = 0 ; i < 500; i++) { + int res = ecdsa_verify(curve, pub, sig, msg, sizeof(msg)); + assert(res == 0); + } + printf("NIST256p1 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} + void bench_ed25519(void) { ed25519_public_key pk; ed25519_secret_key sk; @@ -49,12 +67,58 @@ void bench_ed25519(void) { assert(res == 0); } printf("Ed25519 verifying speed: %0.2f sig/s\n", 500.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); - } -int main(void) { +void test_verify_speed(void) { prepare_msg(); bench_secp256k1(); + bench_nist256p1(); bench_ed25519(); +} + +HDNode root; + +void prepare_node(void) +{ + hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); +} + +void bench_ckd_normal(void) { + char addr[40]; + clock_t t = clock(); + for (int i = 0; i < 1000; i++) { + HDNode node = root; + hdnode_public_ckd(&node, i); + ecdsa_get_address(node.public_key, 0, addr, 40); + if (i == 0) { + printf("address = %s\n", addr); + } + } + printf("CKD normal speed: %0.2f iter/s\n", 1000.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} + +void bench_ckd_optimized(void) { + char addr[40]; + curve_point pub; + ecdsa_read_pubkey(root.curve->params, 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); + if (i == 0) { + printf("address = %s\n", addr); + } + } + printf("CKD optim speed: %0.2f iter/s\n", 1000.0f / ((float)(clock() - t) / CLOCKS_PER_SEC)); +} + +void test_ckd_speed(void) { + prepare_node(); + bench_ckd_normal(); + bench_ckd_optimized(); +} + +int main(void) { + test_verify_speed(); + test_ckd_speed(); return 0; }