1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 04:18:10 +00:00

Merge pull request #52 from jhoenicke/multicurve

Multicurve
This commit is contained in:
Pavol Rusnak 2016-04-20 16:52:47 +02:00
commit bf34b4269c
10 changed files with 212 additions and 41 deletions

View File

@ -371,7 +371,7 @@ void bn_sqrt(bignum256 *x, const bignum256 *prime)
bn_zero(&res); res.val[0] = 1; bn_zero(&res); res.val[0] = 1;
// compute p = (prime+1)/4 // compute p = (prime+1)/4
memcpy(&p, prime, sizeof(bignum256)); memcpy(&p, prime, sizeof(bignum256));
p.val[0] += 1; bn_addi(&p, 1);
bn_rshift(&p); bn_rshift(&p);
bn_rshift(&p); bn_rshift(&p);
for (i = 0; i < 9; i++) { for (i = 0; i < 9; i++) {

40
bip32.c
View File

@ -34,9 +34,7 @@
#include "macros.h" #include "macros.h"
#include "secp256k1.h" #include "secp256k1.h"
static const ecdsa_curve *default_curve = &secp256k1; 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, HDNode *out)
{ {
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;
@ -47,19 +45,21 @@ int hdnode_from_xpub(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c
memcpy(out->chain_code, chain_code, 32); memcpy(out->chain_code, chain_code, 32);
MEMSET_BZERO(out->private_key, 32); MEMSET_BZERO(out->private_key, 32);
memcpy(out->public_key, public_key, 33); memcpy(out->public_key, public_key, 33);
out->curve = get_curve_by_name(curve);
return 1; return 1;
} }
int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, 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; bignum256 a;
bn_read_be(private_key, &a); bn_read_be(private_key, &a);
out->curve = get_curve_by_name(curve);
bool failed = false; bool failed = false;
if (bn_is_zero(&a)) { // == 0 if (bn_is_zero(&a)) { // == 0
failed = true; failed = true;
} else { } else {
if (!bn_is_less(&a, &default_curve->order)) { // >= order if (!bn_is_less(&a, &out->curve->order)) { // >= order
failed = true; failed = true;
} }
MEMSET_BZERO(&a, sizeof(a)); MEMSET_BZERO(&a, sizeof(a));
@ -78,14 +78,16 @@ int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, c
return 1; return 1;
} }
int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) int hdnode_from_seed(const uint8_t *seed, int seed_len, const char* curve, HDNode *out)
{ {
uint8_t I[32 + 32]; uint8_t I[32 + 32];
memset(out, 0, sizeof(HDNode)); memset(out, 0, sizeof(HDNode));
out->depth = 0; out->depth = 0;
out->fingerprint = 0x00000000; out->fingerprint = 0x00000000;
out->child_num = 0; out->child_num = 0;
hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, I); out->curve = get_curve_by_name(curve);
hmac_sha512((const uint8_t*) out->curve->bip32_name,
strlen(out->curve->bip32_name), seed, seed_len, I);
memcpy(out->private_key, I, 32); memcpy(out->private_key, I, 32);
bignum256 a; bignum256 a;
bn_read_be(out->private_key, &a); bn_read_be(out->private_key, &a);
@ -94,7 +96,7 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out)
if (bn_is_zero(&a)) { // == 0 if (bn_is_zero(&a)) { // == 0
failed = true; failed = true;
} else { } else {
if (!bn_is_less(&a, &default_curve->order)) { // >= order if (!bn_is_less(&a, &out->curve->order)) { // >= order
failed = true; failed = true;
} }
MEMSET_BZERO(&a, sizeof(a)); MEMSET_BZERO(&a, sizeof(a));
@ -138,12 +140,12 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i)
bool failed = false; bool failed = false;
if (!bn_is_less(&b, &default_curve->order)) { // >= order if (!bn_is_less(&b, &inout->curve->order)) { // >= order
failed = true; failed = true;
} }
if (!failed) { if (!failed) {
bn_addmod(&a, &b, &default_curve->order); bn_addmod(&a, &b, &inout->curve->order);
bn_mod(&a, &default_curve->order); bn_mod(&a, &inout->curve->order);
if (bn_is_zero(&a)) { if (bn_is_zero(&a)) {
failed = true; failed = true;
} }
@ -186,7 +188,7 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i)
memset(inout->private_key, 0, 32); memset(inout->private_key, 0, 32);
bool failed = false; bool failed = false;
if (!ecdsa_read_pubkey(default_curve, inout->public_key, &a)) { if (!ecdsa_read_pubkey(inout->curve, inout->public_key, &a)) {
failed = true; failed = true;
} }
@ -194,15 +196,15 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i)
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); memcpy(inout->chain_code, I + 32, 32);
bn_read_be(I, &c); bn_read_be(I, &c);
if (!bn_is_less(&c, &default_curve->order)) { // >= order if (!bn_is_less(&c, &inout->curve->order)) { // >= order
failed = true; failed = true;
} }
} }
if (!failed) { if (!failed) {
scalar_multiply(default_curve, &c, &b); // b = c * G scalar_multiply(inout->curve, &c, &b); // b = c * G
point_add(default_curve, &a, &b); // b = a + b point_add(inout->curve, &a, &b); // b = a + b
if (!ecdsa_validate_pubkey(default_curve, &b)) { if (!ecdsa_validate_pubkey(inout->curve, &b)) {
failed = true; failed = true;
} }
} }
@ -263,7 +265,8 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count)
for (j = 0; j < BIP32_CACHE_SIZE; j++) { for (j = 0; j < BIP32_CACHE_SIZE; j++) {
if (private_ckd_cache[j].set && if (private_ckd_cache[j].set &&
private_ckd_cache[j].depth == i_count - 1 && private_ckd_cache[j].depth == i_count - 1 &&
memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0) { memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 &&
private_ckd_cache[j].node.curve == inout->curve) {
memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode)); memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode));
found = true; found = true;
break; break;
@ -295,7 +298,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(default_curve, node->private_key, node->public_key); ecdsa_get_public_key33(node->curve, 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)
@ -335,6 +338,7 @@ int hdnode_deserialize(const char *str, HDNode *node)
if (!base58_decode_check(str, node_data, sizeof(node_data))) { if (!base58_decode_check(str, node_data, sizeof(node_data))) {
return -1; return -1;
} }
node->curve = get_curve_by_name(SECP256K1_NAME);
uint32_t version = read_be(node_data); uint32_t version = read_be(node_data);
if (version == 0x0488B21E) { // public node if (version == 0x0488B21E) { // public node
memcpy(node->public_key, node_data + 45, 33); memcpy(node->public_key, node_data + 45, 33);

View File

@ -36,13 +36,14 @@ 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;
} 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, 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);
int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, 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);
int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out); int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out);
#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000))

View File

@ -862,7 +862,7 @@ int ecdsa_address_decode(const char *addr, uint8_t *out)
void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y) void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y)
{ {
// y^2 = x^3 + 0*x + 7 // y^2 = x^3 + a*x + b
memcpy(y, x, sizeof(bignum256)); // y is x memcpy(y, x, sizeof(bignum256)); // y is x
bn_multiply(x, y, &curve->prime); // y is x^2 bn_multiply(x, y, &curve->prime); // y is x^2
bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a bn_subi(y, -curve->a, &curve->prime); // y is x^2 + a
@ -1050,10 +1050,10 @@ const ecdsa_curve *get_curve_by_name(const char *curve_name) {
if (curve_name == 0) { if (curve_name == 0) {
return 0; return 0;
} }
if (strcmp(curve_name, "secp256k1") == 0) { if (strcmp(curve_name, SECP256K1_NAME) == 0) {
return &secp256k1; return &secp256k1;
} }
if (strcmp(curve_name, "nist256p1") == 0) { if (strcmp(curve_name, NIST256P1_NAME) == 0) {
return &nist256p1; return &nist256p1;
} }
return 0; return 0;

View File

@ -41,6 +41,7 @@ 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];

View File

@ -23,6 +23,7 @@
#include "nist256p1.h" #include "nist256p1.h"
const char NIST256P1_NAME[] = "nist256p1";
const ecdsa_curve nist256p1 = { const ecdsa_curve nist256p1 = {
/* .prime */ { /* .prime */ {
/*.val =*/ {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff} /*.val =*/ {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff}
@ -45,7 +46,11 @@ 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
, ,
/* cp */ { /* cp */ {

View File

@ -28,6 +28,7 @@
#include "ecdsa.h" #include "ecdsa.h"
extern const char NIST256P1_NAME[];
extern const ecdsa_curve nist256p1; extern const ecdsa_curve nist256p1;
#endif #endif

View File

@ -23,6 +23,8 @@
#include "secp256k1.h" #include "secp256k1.h"
const char SECP256K1_NAME[] = "secp256k1";
const ecdsa_curve secp256k1 = { const ecdsa_curve secp256k1 = {
/* .prime */ { /* .prime */ {
/*.val =*/ {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff} /*.val =*/ {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}
@ -45,7 +47,11 @@ const ecdsa_curve secp256k1 = {
/* b */ { /* b */ {
/*.val =*/{7} /*.val =*/{7}
} },
/* bip32_name */
"Bitcoin seed"
#if USE_PRECOMPUTED_CP #if USE_PRECOMPUTED_CP
, ,
/* cp */ { /* cp */ {

View File

@ -28,6 +28,7 @@
#include "ecdsa.h" #include "ecdsa.h"
extern const char SECP256K1_NAME[];
extern const ecdsa_curve secp256k1; extern const ecdsa_curve secp256k1;
#endif #endif

180
tests.c
View File

@ -25,6 +25,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <time.h> #include <time.h>
#include "aes.h" #include "aes.h"
@ -168,7 +169,7 @@ START_TEST(test_bip32_vector_1)
int r; int r;
// init m // init m
hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, &node); hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, SECP256K1_NAME, &node);
// [Chain m] // [Chain m]
ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_int_eq(node.fingerprint, 0x00000000);
@ -281,7 +282,7 @@ START_TEST(test_bip32_vector_2)
int r; int r;
// init m // init m
hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node);
// [Chain m] // [Chain m]
ck_assert_int_eq(node.fingerprint, 0x00000000); ck_assert_int_eq(node.fingerprint, 0x00000000);
@ -390,7 +391,7 @@ START_TEST(test_bip32_vector_2)
ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode));
// init m // init m
hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, &node); hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, SECP256K1_NAME, &node);
// test public derivation // test public derivation
// [Chain m/0] // [Chain m/0]
@ -407,8 +408,8 @@ START_TEST(test_bip32_compare)
{ {
HDNode node1, node2, node3; HDNode node1, node2, node3;
int i, r; int i, r;
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1);
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2);
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
memcpy(&node3, &node1, sizeof(HDNode)); memcpy(&node3, &node1, sizeof(HDNode));
r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1);
@ -436,8 +437,8 @@ START_TEST(test_bip32_cache_1)
int i, r; int i, r;
// test 1 .. 8 // test 1 .. 8
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1);
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2);
uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008}; uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008};
@ -447,8 +448,8 @@ START_TEST(test_bip32_cache_1)
r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1); r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1);
ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode));
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1);
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2);
// test 1 .. 7, 20 // test 1 .. 7, 20
ii[7] = 20; ii[7] = 20;
@ -459,8 +460,8 @@ START_TEST(test_bip32_cache_1)
ck_assert_mem_eq(&node1, &node2, sizeof(HDNode)); ck_assert_mem_eq(&node1, &node2, sizeof(HDNode));
// test different root node // test different root node
hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1); hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node1);
hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2); hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1); r = hdnode_private_ckd(&node1, ii[i]); ck_assert_int_eq(r, 1);
@ -476,8 +477,8 @@ START_TEST(test_bip32_cache_2)
int i, j, r; int i, j, r;
for (j = 0; j < 9; j++) { for (j = 0; j < 9; j++) {
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &(nodea[j])); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &(nodea[j]));
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &(nodeb[j])); hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &(nodeb[j]));
} }
uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008}; uint32_t ii[] = {0x80000001, 0x80000002, 0x80000003, 0x80000004, 0x80000005, 0x80000006, 0x80000007, 0x80000008};
@ -502,7 +503,152 @@ START_TEST(test_bip32_cache_2)
} }
END_TEST END_TEST
#define test_deterministic(KEY, MSG, K) do { \ START_TEST(test_bip32_nist_vector_1)
{
HDNode node;
// init m
hdnode_from_seed(fromhex("000102030405060708090a0b0c0d0e0f"), 16, NIST256P1_NAME, &node);
// [Chain m]
ck_assert_int_eq(node.fingerprint, 0x00000000);
ck_assert_mem_eq(node.chain_code, fromhex("beeb672fe4621673f722f38529c07392fecaa61015c80c34f29ce8b41b3cb6ea"), 32);
ck_assert_mem_eq(node.private_key, fromhex("612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), 32);
ck_assert_mem_eq(node.public_key, fromhex("0266874dc6ade47b3ecd096745ca09bcd29638dd52c2c12117b11ed3e458cfa9e8"), 33);
// [Chain m/0']
hdnode_private_ckd_prime(&node, 0);
ck_assert_int_eq(node.fingerprint, 0xbe6105b5);
ck_assert_mem_eq(node.chain_code, fromhex("3460cea53e6a6bb5fb391eeef3237ffd8724bf0a40e94943c98b83825342ee11"), 32);
ck_assert_mem_eq(node.private_key, fromhex("6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), 32);
ck_assert_mem_eq(node.public_key, fromhex("0384610f5ecffe8fda089363a41f56a5c7ffc1d81b59a612d0d649b2d22355590c"), 33);
// [Chain m/0'/1]
hdnode_private_ckd(&node, 1);
ck_assert_int_eq(node.fingerprint, 0x9b02312f);
ck_assert_mem_eq(node.chain_code, fromhex("4187afff1aafa8445010097fb99d23aee9f599450c7bd140b6826ac22ba21d0c"), 32);
ck_assert_mem_eq(node.private_key, fromhex("284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), 32);
ck_assert_mem_eq(node.public_key, fromhex("03526c63f8d0b4bbbf9c80df553fe66742df4676b241dabefdef67733e070f6844"), 33);
// [Chain m/0'/1/2']
hdnode_private_ckd_prime(&node, 2);
ck_assert_int_eq(node.fingerprint, 0xb98005c1);
ck_assert_mem_eq(node.chain_code, fromhex("98c7514f562e64e74170cc3cf304ee1ce54d6b6da4f880f313e8204c2a185318"), 32);
ck_assert_mem_eq(node.private_key, fromhex("694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), 32);
ck_assert_mem_eq(node.public_key, fromhex("0359cf160040778a4b14c5f4d7b76e327ccc8c4a6086dd9451b7482b5a4972dda0"), 33);
// [Chain m/0'/1/2'/2]
hdnode_private_ckd(&node, 2);
ck_assert_int_eq(node.fingerprint, 0x0e9f3274);
ck_assert_mem_eq(node.chain_code, fromhex("ba96f776a5c3907d7fd48bde5620ee374d4acfd540378476019eab70790c63a0"), 32);
ck_assert_mem_eq(node.private_key, fromhex("5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), 32);
ck_assert_mem_eq(node.public_key, fromhex("029f871f4cb9e1c97f9f4de9ccd0d4a2f2a171110c61178f84430062230833ff20"), 33);
// [Chain m/0'/1/2'/2/1000000000]
hdnode_private_ckd(&node, 1000000000);
ck_assert_int_eq(node.fingerprint, 0x8b2b5c4b);
ck_assert_mem_eq(node.chain_code, fromhex("b9b7b82d326bb9cb5b5b121066feea4eb93d5241103c9e7a18aad40f1dde8059"), 32);
ck_assert_mem_eq(node.private_key, fromhex("21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119"), 32);
ck_assert_mem_eq(node.public_key, fromhex("02216cd26d31147f72427a453c443ed2cde8a1e53c9cc44e5ddf739725413fe3f4"), 33);
}
END_TEST
START_TEST(test_bip32_nist_vector_2)
{
HDNode node;
int r;
// init m
hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, NIST256P1_NAME, &node);
// [Chain m]
ck_assert_int_eq(node.fingerprint, 0x00000000);
ck_assert_mem_eq(node.chain_code, fromhex("96cd4465a9644e31528eda3592aa35eb39a9527769ce1855beafc1b81055e75d"), 32);
ck_assert_mem_eq(node.private_key, fromhex("eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), 32);
ck_assert_mem_eq(node.public_key, fromhex("02c9e16154474b3ed5b38218bb0463e008f89ee03e62d22fdcc8014beab25b48fa"), 33);
// [Chain m/0]
r = hdnode_private_ckd(&node, 0);
ck_assert_int_eq(r, 1);
ck_assert_int_eq(node.fingerprint, 0x607f628f);
ck_assert_mem_eq(node.chain_code, fromhex("84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), 32);
ck_assert_mem_eq(node.private_key, fromhex("d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), 32);
ck_assert_mem_eq(node.public_key, fromhex("039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), 33);
// [Chain m/0/2147483647']
r = hdnode_private_ckd_prime(&node, 2147483647);
ck_assert_int_eq(r, 1);
ck_assert_int_eq(node.fingerprint, 0x946d2a54);
ck_assert_mem_eq(node.chain_code, fromhex("f235b2bc5c04606ca9c30027a84f353acf4e4683edbd11f635d0dcc1cd106ea6"), 32);
ck_assert_mem_eq(node.private_key, fromhex("96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), 32);
ck_assert_mem_eq(node.public_key, fromhex("02f89c5deb1cae4fedc9905f98ae6cbf6cbab120d8cb85d5bd9a91a72f4c068c76"), 33);
// [Chain m/0/2147483647'/1]
r = hdnode_private_ckd(&node, 1);
ck_assert_int_eq(r, 1);
ck_assert_int_eq(node.fingerprint, 0x218182d8);
ck_assert_mem_eq(node.chain_code, fromhex("7c0b833106235e452eba79d2bdd58d4086e663bc8cc55e9773d2b5eeda313f3b"), 32);
ck_assert_mem_eq(node.private_key, fromhex("974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc"), 32);
ck_assert_mem_eq(node.public_key, fromhex("03abe0ad54c97c1d654c1852dfdc32d6d3e487e75fa16f0fd6304b9ceae4220c64"), 33);
// [Chain m/0/2147483647'/1/2147483646']
r = hdnode_private_ckd_prime(&node, 2147483646);
ck_assert_int_eq(r, 1);
ck_assert_int_eq(node.fingerprint, 0x931223e4);
ck_assert_mem_eq(node.chain_code, fromhex("5794e616eadaf33413aa309318a26ee0fd5163b70466de7a4512fd4b1a5c9e6a"), 32);
ck_assert_mem_eq(node.private_key, fromhex("da29649bbfaff095cd43819eda9a7be74236539a29094cd8336b07ed8d4eff63"), 32);
ck_assert_mem_eq(node.public_key, fromhex("03cb8cb067d248691808cd6b5a5a06b48e34ebac4d965cba33e6dc46fe13d9b933"), 33);
// [Chain m/0/2147483647'/1/2147483646'/2]
r = hdnode_private_ckd(&node, 2);
ck_assert_int_eq(r, 1);
ck_assert_int_eq(node.fingerprint, 0x956c4629);
ck_assert_mem_eq(node.chain_code, fromhex("3bfb29ee8ac4484f09db09c2079b520ea5616df7820f071a20320366fbe226a7"), 32);
ck_assert_mem_eq(node.private_key, fromhex("bb0a77ba01cc31d77205d51d08bd313b979a71ef4de9b062f8958297e746bd67"), 32);
ck_assert_mem_eq(node.public_key, fromhex("020ee02e18967237cf62672983b253ee62fa4dd431f8243bfeccdf39dbe181387f"), 33);
// init m
hdnode_from_seed(fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"), 64, NIST256P1_NAME, &node);
// test public derivation
// [Chain m/0]
r = hdnode_public_ckd(&node, 0);
ck_assert_int_eq(r, 1);
ck_assert_int_eq(node.fingerprint, 0x607f628f);
ck_assert_mem_eq(node.chain_code, fromhex("84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a"), 32);
ck_assert_mem_eq(node.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32);
ck_assert_mem_eq(node.public_key, fromhex("039b6df4bece7b6c81e2adfeea4bcf5c8c8a6e40ea7ffa3cf6e8494c61a1fc82cc"), 33);
}
END_TEST
START_TEST(test_bip32_nist_compare)
{
HDNode node1, node2, node3;
int i, r;
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node1);
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node2);
for (i = 0; i < 100; i++) {
memcpy(&node3, &node1, sizeof(HDNode));
r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1);
r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1);
r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1);
ck_assert_int_eq(node1.depth, node2.depth);
ck_assert_int_eq(node1.depth, node3.depth);
ck_assert_int_eq(node1.fingerprint, node2.fingerprint);
ck_assert_int_eq(node1.fingerprint, node3.fingerprint);
ck_assert_int_eq(node1.child_num, node2.child_num);
ck_assert_int_eq(node1.child_num, node3.child_num);
ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32);
ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32);
ck_assert_mem_eq(node2.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32);
ck_assert_mem_eq(node3.private_key, fromhex("0000000000000000000000000000000000000000000000000000000000000000"), 32);
ck_assert_mem_eq(node1.public_key, node2.public_key, 33);
ck_assert_mem_eq(node1.public_key, node3.public_key, 33);
}
}
END_TEST
#define test_deterministic(KEY, MSG, K) do { \
sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \
res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \ res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \
ck_assert_int_eq(res, 0); \ ck_assert_int_eq(res, 0); \
@ -1419,6 +1565,12 @@ Suite *test_suite(void)
tcase_add_test(tc, test_bip32_cache_2); tcase_add_test(tc, test_bip32_cache_2);
suite_add_tcase(s, tc); suite_add_tcase(s, tc);
tc = tcase_create("bip32-nist");
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);
suite_add_tcase(s, tc);
tc = tcase_create("rfc6979"); tc = tcase_create("rfc6979");
tcase_add_test(tc, test_rfc6979); tcase_add_test(tc, test_rfc6979);
suite_add_tcase(s, tc); suite_add_tcase(s, tc);