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

implement BIP32 cache

This commit is contained in:
Pavol Rusnak 2015-01-26 19:09:00 +01:00
parent 40b023b1f4
commit f4e6010e18
4 changed files with 130 additions and 0 deletions

68
bip32.c
View File

@ -22,6 +22,7 @@
*/
#include <string.h>
#include <stdbool.h>
#include "bignum.h"
#include "hmac.h"
@ -176,6 +177,73 @@ int hdnode_public_ckd(HDNode *inout, uint32_t i)
return 1;
}
#if USE_BIP32_CACHE
static bool private_ckd_cache_root_set = false;
static HDNode private_ckd_cache_root;
static int private_ckd_cache_index = 0;
static struct {
bool set;
size_t depth;
uint32_t i[BIP32_CACHE_MAXDEPTH];
HDNode node;
} private_ckd_cache[BIP32_CACHE_SIZE];
int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count)
{
if (i_count == 0) {
return 1;
}
if (i_count == 1) {
if (hdnode_private_ckd(inout, i[0]) == 0) return 0;
return 1;
}
bool found = false;
// if root is not set or not the same
if (!private_ckd_cache_root_set || memcmp(&private_ckd_cache_root, inout, sizeof(HDNode)) != 0) {
// clear the cache
private_ckd_cache_index = 0;
memset(private_ckd_cache, 0, sizeof(private_ckd_cache));
// setup new root
memcpy(&private_ckd_cache_root, inout, sizeof(HDNode));
private_ckd_cache_root_set = true;
} else {
// try to find parent
int j;
for (j = 0; j < BIP32_CACHE_SIZE; j++) {
if (private_ckd_cache[j].set &&
private_ckd_cache[j].depth == i_count - 1 &&
memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0) {
memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode));
found = true;
break;
}
}
}
// else derive parent
if (!found) {
size_t k;
for (k = 0; k < i_count - 1; k++) {
if (hdnode_private_ckd(inout, i[k]) == 0) return 0;
}
// and save it
private_ckd_cache[private_ckd_cache_index].set = true;
private_ckd_cache[private_ckd_cache_index].depth = i_count - 1;
memcpy(private_ckd_cache[private_ckd_cache_index].i, i, (i_count - 1) * sizeof(uint32_t));
memcpy(&(private_ckd_cache[private_ckd_cache_index].node), inout, sizeof(HDNode));
private_ckd_cache_index = (private_ckd_cache_index + 1) % BIP32_CACHE_SIZE;
}
if (hdnode_private_ckd(inout, i[i_count - 1]) == 0) return 0;
return 1;
}
#endif
void hdnode_fill_public_key(HDNode *node)
{
ecdsa_get_public_key33(node->private_key, node->public_key);

View File

@ -25,6 +25,7 @@
#define __BIP32_H__
#include <stdint.h>
#include "options.h"
typedef struct {
uint32_t depth;
@ -47,6 +48,12 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i);
int hdnode_public_ckd(HDNode *inout, uint32_t i);
#if USE_BIP32_CACHE
int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count);
#endif
void hdnode_fill_public_key(HDNode *node);
void hdnode_serialize_public(const HDNode *node, char *str, int strsize);

View File

@ -53,4 +53,11 @@
#define USE_PUBKEY_VALIDATE 1
#endif
// implement BIP32 caching
#ifndef USE_BIP32_CACHE
#define USE_BIP32_CACHE 1
#define BIP32_CACHE_SIZE 10
#define BIP32_CACHE_MAXDEPTH 8
#endif
#endif

48
tests.c
View File

@ -427,6 +427,52 @@ START_TEST(test_bip32_compare)
}
END_TEST
START_TEST(test_bip32_cache)
{
HDNode node1, node2;
int r;
// test 1 .. 8
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1);
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2);
uint32_t i;
for (i = 1; i < 8; i++) {
r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1);
}
r = hdnode_private_ckd(&node1, 8); ck_assert_int_eq(r, 1);
uint32_t ii[] = {1, 2, 3, 4, 5, 6, 7, 8};
r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1);
ck_assert_mem_eq(&node1, &node2, sizeof(HDNode));
// test 1 .. 7, 20
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1);
hdnode_from_seed(fromhex("301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2);
for (i = 1; i < 8; i++) {
r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1);
}
r = hdnode_private_ckd(&node1, 20); ck_assert_int_eq(r, 1);
ii[7] = 20;
r = hdnode_private_ckd_cached(&node2, ii, 8); ck_assert_int_eq(r, 1);
ck_assert_mem_eq(&node1, &node2, sizeof(HDNode));
// test different root node
hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node1);
hdnode_from_seed(fromhex("000000002ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, &node2);
for (i = 1; i < 8; i++) {
r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1);
}
r = hdnode_private_ckd(&node1, 20); 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));
}
END_TEST
#define test_deterministic(KEY, MSG, K) do { \
sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \
res = generate_k_rfc6979(&k, fromhex(KEY), buf); \
@ -1139,6 +1185,7 @@ Suite *test_suite(void)
Suite *s = suite_create("trezor-crypto");
TCase *tc;
tc = tcase_create("base58");
tcase_add_test(tc, test_base58);
suite_add_tcase(s, tc);
@ -1147,6 +1194,7 @@ Suite *test_suite(void)
tcase_add_test(tc, test_bip32_vector_1);
tcase_add_test(tc, test_bip32_vector_2);
tcase_add_test(tc, test_bip32_compare);
tcase_add_test(tc, test_bip32_cache);
suite_add_tcase(s, tc);
tc = tcase_create("rfc6979");