1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 07:28:10 +00:00

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
This commit is contained in:
Jochen Hoenicke 2016-04-22 14:48:24 +02:00
parent de30ffbf9a
commit 698f40f385
No known key found for this signature in database
GPG Key ID: EB17C6B5E51193F5
9 changed files with 142 additions and 104 deletions

177
bip32.c
View File

@ -1,6 +1,7 @@
/** /**
* Copyright (c) 2013-2014 Tomas Dzetkulic * Copyright (c) 2013-2016 Tomas Dzetkulic
* Copyright (c) 2013-2014 Pavol Rusnak * Copyright (c) 2013-2016 Pavol Rusnak
* Copyright (c) 2015-2016 Jochen Hoenicke
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"), * a copy of this software and associated documentation files (the "Software"),
@ -33,17 +34,18 @@
#include "base58.h" #include "base58.h"
#include "macros.h" #include "macros.h"
#include "secp256k1.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) 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); const curve_info *info = get_curve_by_name(curve);
if (curve_info == 0) { if (info == 0) {
return 0; return 0;
} }
if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey if (public_key[0] != 0x02 && public_key[0] != 0x03) { // invalid pubkey
return 0; return 0;
} }
out->curve = curve_info; out->curve = info;
out->depth = depth; out->depth = depth;
out->fingerprint = fingerprint; out->fingerprint = fingerprint;
out->child_num = child_num; 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) 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; bool failed = false;
const ecdsa_curve *curve_info = get_curve_by_name(curve); const curve_info *info = get_curve_by_name(curve);
if (curve_info == 0) { if (info == 0) {
failed = true;
} else if (bn_is_zero(&a)) { // == 0
failed = true; failed = true;
} else { } 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; failed = true;
} else {
if (!bn_is_less(&a, &info->params->order)) { // >= order
failed = true;
}
} }
MEMSET_BZERO(&a, sizeof(a)); 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; return 0;
} }
out->curve = curve_info; out->curve = info;
out->depth = depth; out->depth = depth;
out->fingerprint = fingerprint; out->fingerprint = fingerprint;
out->child_num = child_num; 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, hmac_sha512((const uint8_t*) out->curve->bip32_name,
strlen(out->curve->bip32_name), seed, seed_len, I); 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 (out->curve->params) {
if (bn_is_zero(&a)) { // == 0 bignum256 a;
failed = true; while (true) {
} else { bn_read_be(I, &a);
if (!bn_is_less(&a, &out->curve->order)) { // >= order if (!bn_is_zero(&a) // != 0
failed = true; && 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)); MEMSET_BZERO(&a, sizeof(a));
} }
memcpy(out->private_key, I, 32);
if (!failed) { memcpy(out->chain_code, I + 32, 32);
memcpy(out->chain_code, I + 32, 32); hdnode_fill_public_key(out);
hdnode_fill_public_key(out);
}
MEMSET_BZERO(I, sizeof(I)); MEMSET_BZERO(I, sizeof(I));
return failed ? 0 : 1; return 1;
} }
int hdnode_private_ckd(HDNode *inout, uint32_t i) 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; data[0] = 0;
memcpy(data + 1, inout->private_key, 32); memcpy(data + 1, inout->private_key, 32);
} else { // public derivation } else { // public derivation
if (!inout->curve->params) {
return 0;
}
memcpy(data, inout->public_key, 33); memcpy(data, inout->public_key, 33);
} }
write_be(data + 33, i); 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); bn_read_be(inout->private_key, &a);
hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); hmac_sha512(inout->chain_code, 32, data, sizeof(data), I);
memcpy(inout->chain_code, I + 32, 32); if (inout->curve->params) {
memcpy(inout->private_key, I, 32); 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); data[0] = 1;
memcpy(data + 1, I + 32, 32);
bool failed = false; hmac_sha512(inout->chain_code, 32, data, sizeof(data), I);
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;
} }
} else {
memcpy(inout->private_key, I, 32);
} }
if (!failed) {
inout->depth++; memcpy(inout->chain_code, I + 32, 32);
inout->child_num = i; inout->depth++;
bn_write_be(&a, inout->private_key); inout->child_num = i;
hdnode_fill_public_key(inout); hdnode_fill_public_key(inout);
}
// making sure to wipe our memory // making sure to wipe our memory
MEMSET_BZERO(&a, sizeof(a)); 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(I, sizeof(I));
MEMSET_BZERO(fingerprint, sizeof(fingerprint)); MEMSET_BZERO(fingerprint, sizeof(fingerprint));
MEMSET_BZERO(data, sizeof(data)); MEMSET_BZERO(data, sizeof(data));
return failed ? 0 : 1; return 1;
} }
int hdnode_public_ckd(HDNode *inout, uint32_t i) 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 if (i & 0x80000000) { // private derivation
return 0; return 0;
} else { // public derivation } else { // public derivation
if (!inout->curve->params) {
return 0;
}
memcpy(data, inout->public_key, 33); memcpy(data, inout->public_key, 33);
} }
write_be(data + 33, i); write_be(data + 33, i);
@ -197,34 +214,37 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i)
memset(inout->private_key, 0, 32); memset(inout->private_key, 0, 32);
bool failed = false; if (!ecdsa_read_pubkey(inout->curve->params, inout->public_key, &a)) {
if (!ecdsa_read_pubkey(inout->curve, inout->public_key, &a)) { return 0;
failed = true;
} }
if (!failed) { while (true) {
bool failed = false;
hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); hmac_sha512(inout->chain_code, 32, data, sizeof(data), I);
memcpy(inout->chain_code, I + 32, 32);
bn_read_be(I, &c); 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; 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) { inout->depth++;
scalar_multiply(inout->curve, &c, &b); // b = c * G inout->child_num = i;
point_add(inout->curve, &a, &b); // b = a + b memcpy(inout->chain_code, I + 32, 32);
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;
}
// Wipe all stack data. // Wipe all stack data.
MEMSET_BZERO(data, sizeof(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(&b, sizeof(b));
MEMSET_BZERO(&c, sizeof(c)); MEMSET_BZERO(&c, sizeof(c));
return failed ? 0 : 1; return 1;
} }
#if USE_BIP32_CACHE #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) 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) 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); memcpy(node->chain_code, node_data + 13, 32);
return 0; 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;
}

View File

@ -29,6 +29,11 @@
#include "ecdsa.h" #include "ecdsa.h"
#include "options.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 { typedef struct {
uint32_t depth; uint32_t depth;
uint32_t fingerprint; uint32_t fingerprint;
@ -36,7 +41,7 @@ typedef struct {
uint8_t chain_code[32]; uint8_t chain_code[32];
uint8_t private_key[32]; uint8_t private_key[32];
uint8_t public_key[33]; uint8_t public_key[33];
const ecdsa_curve *curve; const curve_info *curve;
} HDNode; } 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); 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 // Private
void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize); 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 #endif

17
ecdsa.c
View File

@ -36,9 +36,6 @@
#include "base58.h" #include "base58.h"
#include "macros.h" #include "macros.h"
#include "secp256k1.h"
#include "nist256p1.h"
// Set cp2 = cp1 // Set cp2 = cp1
void point_copy(const curve_point *cp1, curve_point *cp2) 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; *len = *len1 + *len2 + 4;
return *len + 2; 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;
}

View File

@ -41,7 +41,6 @@ typedef struct {
bignum256 order_half; // order of G divided by 2 bignum256 order_half; // order of G divided by 2
int a; // coefficient 'a' of the elliptic curve int a; // coefficient 'a' of the elliptic curve
bignum256 b; // coefficient 'b' 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 #if USE_PRECOMPUTED_CP
const curve_point cp[64][8]; 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_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_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); int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der);
const ecdsa_curve *get_curve_by_name(const char *curve_name);
// Private // Private
int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash); int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash);

View File

@ -46,10 +46,7 @@ const ecdsa_curve nist256p1 = {
/* b */ { /* b */ {
/*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6} /*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6}
}, }
/* bip32_name */
"Nist256p1 seed"
#if USE_PRECOMPUTED_CP #if USE_PRECOMPUTED_CP
, ,
@ -58,3 +55,9 @@ const ecdsa_curve nist256p1 = {
} }
#endif #endif
}; };
const curve_info nist256p1_info = {
/* bip32_name */
"Nist256p1 seed",
&nist256p1
};

View File

@ -27,8 +27,10 @@
#include <stdint.h> #include <stdint.h>
#include "ecdsa.h" #include "ecdsa.h"
#include "bip32.h"
extern const char NIST256P1_NAME[]; extern const char NIST256P1_NAME[];
extern const ecdsa_curve nist256p1; extern const ecdsa_curve nist256p1;
extern const curve_info nist256p1_info;
#endif #endif

View File

@ -47,10 +47,7 @@ const ecdsa_curve secp256k1 = {
/* b */ { /* b */ {
/*.val =*/{7} /*.val =*/{7}
}, }
/* bip32_name */
"Bitcoin seed"
#if USE_PRECOMPUTED_CP #if USE_PRECOMPUTED_CP
, ,
@ -59,3 +56,9 @@ const ecdsa_curve secp256k1 = {
} }
#endif #endif
}; };
const curve_info secp256k1_info = {
/* bip32_name */
"Bitcoin seed",
&secp256k1
};

View File

@ -27,8 +27,10 @@
#include <stdint.h> #include <stdint.h>
#include "ecdsa.h" #include "ecdsa.h"
#include "bip32.h"
extern const char SECP256K1_NAME[]; extern const char SECP256K1_NAME[];
extern const ecdsa_curve secp256k1; extern const ecdsa_curve secp256k1;
extern const curve_info secp256k1_info;
#endif #endif

15
tests.c
View File

@ -648,7 +648,7 @@ START_TEST(test_bip32_nist_compare)
} }
END_TEST END_TEST
START_TEST(test_bip32_nist_invalid) START_TEST(test_bip32_nist_repeat)
{ {
HDNode node, node2; HDNode node, node2;
int r; int r;
@ -666,12 +666,19 @@ START_TEST(test_bip32_nist_invalid)
memcpy(&node2, &node, sizeof(HDNode)); memcpy(&node2, &node, sizeof(HDNode));
r = hdnode_private_ckd(&node2, 33941); 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)); memcpy(&node2, &node, sizeof(HDNode));
memset(&node2.private_key, 0, 32); memset(&node2.private_key, 0, 32);
r = hdnode_public_ckd(&node2, 33941); 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 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_1);
tcase_add_test(tc, test_bip32_nist_vector_2); tcase_add_test(tc, test_bip32_nist_vector_2);
tcase_add_test(tc, test_bip32_nist_compare); 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); suite_add_tcase(s, tc);
tc = tcase_create("rfc6979"); tc = tcase_create("rfc6979");