From 698f40f38509a4cce1d64fbca559d6205869fa82 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 22 Apr 2016 14:48:24 +0200 Subject: [PATCH] BIP-32 without gaps, prepare non-ecdsa curves * Split ecdsa_curve into curve_info and ecdsa_curve to support bip32 on curves that don't have a ecdsa_curve. * Don't fail in key derivation but retry with a new hash. * Adapted test case accordingly --- bip32.c | 177 +++++++++++++++++++++++++++++++--------------------- bip32.h | 9 ++- ecdsa.c | 17 ----- ecdsa.h | 2 - nist256p1.c | 11 ++-- nist256p1.h | 2 + secp256k1.c | 11 ++-- secp256k1.h | 2 + tests.c | 15 +++-- 9 files changed, 142 insertions(+), 104 deletions(-) diff --git a/bip32.c b/bip32.c index dc1f2264d..d6ee70df1 100644 --- a/bip32.c +++ b/bip32.c @@ -1,6 +1,7 @@ /** - * Copyright (c) 2013-2014 Tomas Dzetkulic - * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2013-2016 Tomas Dzetkulic + * Copyright (c) 2013-2016 Pavol Rusnak + * Copyright (c) 2015-2016 Jochen Hoenicke * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -33,17 +34,18 @@ #include "base58.h" #include "macros.h" #include "secp256k1.h" +#include "nist256p1.h" int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char* curve, HDNode *out) { - const ecdsa_curve *curve_info = get_curve_by_name(curve); - if (curve_info == 0) { + const curve_info *info = get_curve_by_name(curve); + if (info == 0) { return 0; } if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey return 0; } - out->curve = curve_info; + out->curve = info; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -55,18 +57,19 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char* curve, HDNode *out) { - bignum256 a; - bn_read_be(private_key, &a); - bool failed = false; - const ecdsa_curve *curve_info = get_curve_by_name(curve); - if (curve_info == 0) { - failed = true; - } else if (bn_is_zero(&a)) { // == 0 + const curve_info *info = get_curve_by_name(curve); + if (info == 0) { failed = true; } else { - if (!bn_is_less(&a, &out->curve->order)) { // >= order + bignum256 a; + bn_read_be(private_key, &a); + if (bn_is_zero(&a)) { // == 0 failed = true; + } else { + if (!bn_is_less(&a, &info->params->order)) { // >= order + failed = true; + } } MEMSET_BZERO(&a, sizeof(a)); } @@ -75,7 +78,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c return 0; } - out->curve = curve_info; + out->curve = info; out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; @@ -98,27 +101,27 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNod } hmac_sha512((const uint8_t*) out->curve->bip32_name, strlen(out->curve->bip32_name), seed, seed_len, I); - memcpy(out->private_key, I, 32); - bignum256 a; - bn_read_be(out->private_key, &a); - bool failed = false; - if (bn_is_zero(&a)) { // == 0 - failed = true; - } else { - if (!bn_is_less(&a, &out->curve->order)) { // >= order - failed = true; + if (out->curve->params) { + bignum256 a; + while (true) { + bn_read_be(I, &a); + if (!bn_is_zero(&a) // != 0 + && bn_is_less(&a, &out->curve->params->order)) { // < order + + break; + } + hmac_sha512((const uint8_t*) out->curve->bip32_name, + strlen(out->curve->bip32_name), I, sizeof(I), I); } MEMSET_BZERO(&a, sizeof(a)); } - - if (!failed) { - memcpy(out->chain_code, I + 32, 32); - hdnode_fill_public_key(out); - } + memcpy(out->private_key, I, 32); + memcpy(out->chain_code, I + 32, 32); + hdnode_fill_public_key(out); MEMSET_BZERO(I, sizeof(I)); - return failed ? 0 : 1; + return 1; } int hdnode_private_ckd(HDNode *inout, uint32_t i) @@ -132,6 +135,9 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) data[0] = 0; memcpy(data + 1, inout->private_key, 32); } else { // public derivation + if (!inout->curve->params) { + return 0; + } memcpy(data, inout->public_key, 33); } write_be(data + 33, i); @@ -143,29 +149,37 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) bn_read_be(inout->private_key, &a); hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); - memcpy(inout->chain_code, I + 32, 32); - memcpy(inout->private_key, I, 32); + if (inout->curve->params) { + while (true) { + bool failed = false; + bn_read_be(I, &b); + if (!bn_is_less(&b, &inout->curve->params->order)) { // >= order + failed = true; + } else { + bn_addmod(&b, &a, &inout->curve->params->order); + bn_mod(&b, &inout->curve->params->order); + if (bn_is_zero(&b)) { + failed = true; + } + } + + if (!failed) { + bn_write_be(&b, inout->private_key); + break; + } - bn_read_be(inout->private_key, &b); - - bool failed = false; - - if (!bn_is_less(&b, &inout->curve->order)) { // >= order - failed = true; - } - if (!failed) { - bn_addmod(&a, &b, &inout->curve->order); - bn_mod(&a, &inout->curve->order); - if (bn_is_zero(&a)) { - failed = true; + data[0] = 1; + memcpy(data + 1, I + 32, 32); + hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); } + } else { + memcpy(inout->private_key, I, 32); } - if (!failed) { - inout->depth++; - inout->child_num = i; - bn_write_be(&a, inout->private_key); - hdnode_fill_public_key(inout); - } + + memcpy(inout->chain_code, I + 32, 32); + inout->depth++; + inout->child_num = i; + hdnode_fill_public_key(inout); // making sure to wipe our memory MEMSET_BZERO(&a, sizeof(a)); @@ -173,7 +187,7 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) MEMSET_BZERO(I, sizeof(I)); MEMSET_BZERO(fingerprint, sizeof(fingerprint)); MEMSET_BZERO(data, sizeof(data)); - return failed ? 0 : 1; + return 1; } int hdnode_public_ckd(HDNode *inout, uint32_t i) @@ -187,6 +201,9 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) if (i & 0x80000000) { // private derivation return 0; } else { // public derivation + if (!inout->curve->params) { + return 0; + } memcpy(data, inout->public_key, 33); } write_be(data + 33, i); @@ -197,34 +214,37 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) memset(inout->private_key, 0, 32); - bool failed = false; - if (!ecdsa_read_pubkey(inout->curve, inout->public_key, &a)) { - failed = true; + if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &a)) { + return 0; } - if (!failed) { + while (true) { + bool failed = false; hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); - memcpy(inout->chain_code, I + 32, 32); bn_read_be(I, &c); - if (!bn_is_less(&c, &inout->curve->order)) { // >= order + if (!bn_is_less(&c, &inout->curve->params->order)) { // >= order failed = true; + } else { + scalar_multiply(inout->curve->params, &c, &b); // b = c * G + point_add(inout->curve->params, &a, &b); // b = a + b + if (point_is_infinity(&b)) { + failed = true; + } } + + if (!failed) { + inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); + bn_write_be(&b.x, inout->public_key + 1); + break; + } + + data[0] = 1; + memcpy(data + 1, I + 32, 32); } - if (!failed) { - scalar_multiply(inout->curve, &c, &b); // b = c * G - point_add(inout->curve, &a, &b); // b = a + b - if (!ecdsa_validate_pubkey(inout->curve, &b)) { - failed = true; - } - } - - if (!failed) { - inout->public_key[0] = 0x02 | (b.y.val[0] & 0x01); - bn_write_be(&b.x, inout->public_key + 1); - inout->depth++; - inout->child_num = i; - } + inout->depth++; + inout->child_num = i; + memcpy(inout->chain_code, I + 32, 32); // Wipe all stack data. MEMSET_BZERO(data, sizeof(data)); @@ -234,7 +254,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i) MEMSET_BZERO(&b, sizeof(b)); MEMSET_BZERO(&c, sizeof(c)); - return failed ? 0 : 1; + return 1; } #if USE_BIP32_CACHE @@ -308,7 +328,7 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count) void hdnode_fill_public_key(HDNode *node) { - ecdsa_get_public_key33(node->curve, node->private_key, node->public_key); + ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key); } void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize) @@ -367,3 +387,16 @@ int hdnode_deserialize(const char *str, HDNode *node) memcpy(node->chain_code, node_data + 13, 32); return 0; } + +const curve_info *get_curve_by_name(const char *curve_name) { + if (curve_name == 0) { + return 0; + } + if (strcmp(curve_name, SECP256K1_NAME) == 0) { + return &secp256k1_info; + } + if (strcmp(curve_name, NIST256P1_NAME) == 0) { + return &nist256p1_info; + } + return 0; +} diff --git a/bip32.h b/bip32.h index 2d2e46b6f..f8e864d7e 100644 --- a/bip32.h +++ b/bip32.h @@ -29,6 +29,11 @@ #include "ecdsa.h" #include "options.h" +typedef struct { + const char *bip32_name; // string for generating BIP32 xprv from seed + const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 +} curve_info; + typedef struct { uint32_t depth; uint32_t fingerprint; @@ -36,7 +41,7 @@ typedef struct { uint8_t chain_code[32]; uint8_t private_key[32]; uint8_t public_key[33]; - const ecdsa_curve *curve; + const curve_info *curve; } HDNode; int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out); @@ -68,4 +73,6 @@ int hdnode_deserialize(const char *str, HDNode *node); // Private void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize); +const curve_info *get_curve_by_name(const char *curve_name); + #endif diff --git a/ecdsa.c b/ecdsa.c index 14637da15..0a46190b7 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -36,9 +36,6 @@ #include "base58.h" #include "macros.h" -#include "secp256k1.h" -#include "nist256p1.h" - // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) { @@ -1044,17 +1041,3 @@ int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) *len = *len1 + *len2 + 4; return *len + 2; } - - -const ecdsa_curve *get_curve_by_name(const char *curve_name) { - if (curve_name == 0) { - return 0; - } - if (strcmp(curve_name, SECP256K1_NAME) == 0) { - return &secp256k1; - } - if (strcmp(curve_name, NIST256P1_NAME) == 0) { - return &nist256p1; - } - return 0; -} diff --git a/ecdsa.h b/ecdsa.h index 85b6cd058..2a6edde65 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -41,7 +41,6 @@ typedef struct { bignum256 order_half; // order of G divided by 2 int a; // coefficient 'a' of the elliptic curve bignum256 b; // coefficient 'b' of the elliptic curve - const char *bip32_name;// string used for generating BIP32 xprv from seed #if USE_PRECOMPUTED_CP const curve_point cp[64][8]; @@ -77,7 +76,6 @@ int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); -const ecdsa_curve *get_curve_by_name(const char *curve_name); // Private int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); diff --git a/nist256p1.c b/nist256p1.c index 5ec461776..166fda801 100644 --- a/nist256p1.c +++ b/nist256p1.c @@ -46,10 +46,7 @@ const ecdsa_curve nist256p1 = { /* b */ { /*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6} - }, - - /* bip32_name */ - "Nist256p1 seed" + } #if USE_PRECOMPUTED_CP , @@ -58,3 +55,9 @@ const ecdsa_curve nist256p1 = { } #endif }; + +const curve_info nist256p1_info = { + /* bip32_name */ + "Nist256p1 seed", + &nist256p1 +}; diff --git a/nist256p1.h b/nist256p1.h index 22bd895b8..347fe86dc 100644 --- a/nist256p1.h +++ b/nist256p1.h @@ -27,8 +27,10 @@ #include #include "ecdsa.h" +#include "bip32.h" extern const char NIST256P1_NAME[]; extern const ecdsa_curve nist256p1; +extern const curve_info nist256p1_info; #endif diff --git a/secp256k1.c b/secp256k1.c index 804837697..a5f4507f1 100644 --- a/secp256k1.c +++ b/secp256k1.c @@ -47,10 +47,7 @@ const ecdsa_curve secp256k1 = { /* b */ { /*.val =*/{7} - }, - - /* bip32_name */ - "Bitcoin seed" + } #if USE_PRECOMPUTED_CP , @@ -59,3 +56,9 @@ const ecdsa_curve secp256k1 = { } #endif }; + +const curve_info secp256k1_info = { + /* bip32_name */ + "Bitcoin seed", + &secp256k1 +}; diff --git a/secp256k1.h b/secp256k1.h index c07a2823e..e7ef6bf4a 100644 --- a/secp256k1.h +++ b/secp256k1.h @@ -27,8 +27,10 @@ #include #include "ecdsa.h" +#include "bip32.h" extern const char SECP256K1_NAME[]; extern const ecdsa_curve secp256k1; +extern const curve_info secp256k1_info; #endif diff --git a/tests.c b/tests.c index 0694fcc2a..264882377 100644 --- a/tests.c +++ b/tests.c @@ -648,7 +648,7 @@ START_TEST(test_bip32_nist_compare) } END_TEST -START_TEST(test_bip32_nist_invalid) +START_TEST(test_bip32_nist_repeat) { HDNode node, node2; int r; @@ -666,12 +666,19 @@ START_TEST(test_bip32_nist_invalid) memcpy(&node2, &node, sizeof(HDNode)); r = hdnode_private_ckd(&node2, 33941); - ck_assert_int_eq(r, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node2.fingerprint, 0x3e2b7bc6); + ck_assert_mem_eq(node2.chain_code, fromhex("9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); + ck_assert_mem_eq(node2.private_key, fromhex("092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a"), 32); + ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); memcpy(&node2, &node, sizeof(HDNode)); memset(&node2.private_key, 0, 32); r = hdnode_public_ckd(&node2, 33941); - ck_assert_int_eq(r, 0); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(node2.fingerprint, 0x3e2b7bc6); + ck_assert_mem_eq(node2.chain_code, fromhex("9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); + ck_assert_mem_eq(node2.public_key, fromhex("0235bfee614c0d5b2cae260000bb1d0d84b270099ad790022c1ae0b2e782efe120"), 33); } END_TEST @@ -1596,7 +1603,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bip32_nist_vector_1); tcase_add_test(tc, test_bip32_nist_vector_2); tcase_add_test(tc, test_bip32_nist_compare); - tcase_add_test(tc, test_bip32_nist_invalid); + tcase_add_test(tc, test_bip32_nist_repeat); suite_add_tcase(s, tc); tc = tcase_create("rfc6979");