mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-21 23:18:13 +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:
parent
de30ffbf9a
commit
698f40f385
177
bip32.c
177
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;
|
||||
}
|
||||
|
9
bip32.h
9
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
|
||||
|
17
ecdsa.c
17
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;
|
||||
}
|
||||
|
2
ecdsa.h
2
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);
|
||||
|
11
nist256p1.c
11
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
|
||||
};
|
||||
|
@ -27,8 +27,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ecdsa.h"
|
||||
#include "bip32.h"
|
||||
|
||||
extern const char NIST256P1_NAME[];
|
||||
extern const ecdsa_curve nist256p1;
|
||||
extern const curve_info nist256p1_info;
|
||||
|
||||
#endif
|
||||
|
11
secp256k1.c
11
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
|
||||
};
|
||||
|
@ -27,8 +27,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ecdsa.h"
|
||||
#include "bip32.h"
|
||||
|
||||
extern const char SECP256K1_NAME[];
|
||||
extern const ecdsa_curve secp256k1;
|
||||
extern const curve_info secp256k1_info;
|
||||
|
||||
#endif
|
||||
|
15
tests.c
15
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");
|
||||
|
Loading…
Reference in New Issue
Block a user