static void test_extended_key() { printf("TEST: test_extended_key\n"); // Check we get sensible results when parsing some test vector data struct hd_extended_key pub; assert(hd_extended_key_init(&pub)); { cstring *tv1data = base58_decode(s_tv1_m_xpub); assert(hd_extended_key_deser(&pub, tv1data->str, tv1data->len)); cstr_free(tv1data, true); } struct hd_extended_key priv; assert(hd_extended_key_init(&priv)); { cstring *tv1data = base58_decode(s_tv1_m_xprv); assert(hd_extended_key_deser(&priv, tv1data->str, tv1data->len)); cstr_free(tv1data, true); } printf("PUB:\n"); print_ek_public(&pub); printf("PRV:\n"); print_ek_public(&priv); // Check we get the same codechains assert(0 == memcmp(pub.chaincode.data, priv.chaincode.data, 32)); hd_extended_key_free(&priv); hd_extended_key_free(&pub); }
static void wallet_free_hdkey(void *p) { struct hd_extended_key *hdkey = p; if (!hdkey) return; hd_extended_key_free(hdkey); memset(hdkey, 0, sizeof(*hdkey)); free(hdkey); }
cstring *wallet_new_address(struct wallet *wlt) { struct hd_path_seg hdpath[] = { { 44, true }, // BIP 44 { 0, true }, // chain: BTC { 0, true }, // acct# { 0, false }, // change? { 0, false }, // key index }; struct wallet_account *acct = account_byname(wlt, wlt->def_acct->str); if (!acct) return NULL; // patch HD path based on account settings hdpath[2].index = acct->acct_idx; hdpath[4].index = acct->next_key_idx; assert(wlt->hdmaster && (wlt->hdmaster->len > 0)); struct hd_extended_key *master = parr_idx(wlt->hdmaster, 0); assert(master != NULL); struct hd_extended_key child; hd_extended_key_init(&child); if (!hd_derive(&child, master, hdpath, ARRAY_SIZE(hdpath))) { hd_extended_key_free(&child); return NULL; } acct->next_key_idx++; cstring *rs = bp_pubkey_get_address(&child.key,wlt->chain->addr_pubkey); hd_extended_key_free(&child); return rs; }
static void test_vector_2() { struct hd_extended_key_serialized tv2_m_xpub; read_ek_ser_from_base58(s_tv2_m_xpub, &tv2_m_xpub); struct hd_extended_key_serialized tv2_m_xprv; read_ek_ser_from_base58(s_tv2_m_xprv, &tv2_m_xprv); struct hd_extended_key_serialized tv2_m_0_xpub; read_ek_ser_from_base58(s_tv2_m_0_xpub, &tv2_m_0_xpub); struct hd_extended_key_serialized tv2_m_0_xprv; read_ek_ser_from_base58(s_tv2_m_0_xprv, &tv2_m_0_xprv); struct hd_extended_key_serialized tv2_m_0_2147483647H_xpub; read_ek_ser_from_base58(s_tv2_m_0_2147483647H_xpub, &tv2_m_0_2147483647H_xpub); struct hd_extended_key_serialized tv2_m_0_2147483647H_xprv; read_ek_ser_from_base58(s_tv2_m_0_2147483647H_xprv, &tv2_m_0_2147483647H_xprv); struct hd_extended_key_serialized tv2_m_0_2147483647H_1_xpub; read_ek_ser_from_base58(s_tv2_m_0_2147483647H_1_xpub, &tv2_m_0_2147483647H_1_xpub); struct hd_extended_key_serialized tv2_m_0_2147483647H_1_xprv; read_ek_ser_from_base58(s_tv2_m_0_2147483647H_1_xprv, &tv2_m_0_2147483647H_1_xprv); struct hd_extended_key_serialized tv2_m_0_2147483647H_1_2147483646H_xpub; read_ek_ser_from_base58(s_tv2_m_0_2147483647H_1_2147483646H_xpub, &tv2_m_0_2147483647H_1_2147483646H_xpub); struct hd_extended_key_serialized tv2_m_0_2147483647H_1_2147483646H_xprv; read_ek_ser_from_base58(s_tv2_m_0_2147483647H_1_2147483646H_xprv, &tv2_m_0_2147483647H_1_2147483646H_xprv); struct hd_extended_key_serialized tv2_m_0_2147483647H_1_2147483646H_2_xpub; read_ek_ser_from_base58(s_tv2_m_0_2147483647H_1_2147483646H_2_xpub, &tv2_m_0_2147483647H_1_2147483646H_2_xpub); struct hd_extended_key_serialized tv2_m_0_2147483647H_1_2147483646H_2_xprv; read_ek_ser_from_base58(s_tv2_m_0_2147483647H_1_2147483646H_2_xprv, &tv2_m_0_2147483647H_1_2147483646H_2_xprv); printf("TEST: test_vector_2\n"); // Chain m struct hd_extended_key m; assert(hd_extended_key_init(&m)); assert(hd_extended_key_generate_master(&m, s_tv2_seed, sizeof(s_tv2_seed))); assert(compare_serialized_pub(&m, &tv2_m_xpub)); assert(compare_serialized_prv(&m, &tv2_m_xprv)); // Chain m/0 struct hd_extended_key m_0; assert(hd_extended_key_init(&m_0)); assert(hd_extended_key_generate_child(&m, 0x0, &m_0)); assert(compare_serialized_pub(&m_0, &tv2_m_0_xpub)); assert(compare_serialized_prv(&m_0, &tv2_m_0_xprv)); // Chain m/0/2147483647H struct hd_extended_key m_0_2147483647H; assert(hd_extended_key_init(&m_0_2147483647H)); assert(hd_extended_key_generate_child(&m_0, 0x80000000 | 2147483647, &m_0_2147483647H)); assert(compare_serialized_pub(&m_0_2147483647H, &tv2_m_0_2147483647H_xpub)); assert(compare_serialized_prv(&m_0_2147483647H, &tv2_m_0_2147483647H_xprv)); // Chain m/0/2147483647H/1 struct hd_extended_key m_0_2147483647H_1; assert(hd_extended_key_init(&m_0_2147483647H_1)); assert(hd_extended_key_generate_child(&m_0_2147483647H, 1, &m_0_2147483647H_1)); assert(compare_serialized_pub(&m_0_2147483647H_1, &tv2_m_0_2147483647H_1_xpub)); assert(compare_serialized_prv(&m_0_2147483647H_1, &tv2_m_0_2147483647H_1_xprv)); // Chain m/0/2147483647H/1/2147483646H struct hd_extended_key m_0_2147483647H_1_2147483646H; assert(hd_extended_key_init(&m_0_2147483647H_1_2147483646H)); assert(hd_extended_key_generate_child(&m_0_2147483647H_1, 0x80000000 | 2147483646, &m_0_2147483647H_1_2147483646H)); assert(compare_serialized_pub(&m_0_2147483647H_1_2147483646H, &tv2_m_0_2147483647H_1_2147483646H_xpub)); assert(compare_serialized_prv(&m_0_2147483647H_1_2147483646H, &tv2_m_0_2147483647H_1_2147483646H_xprv)); // Chain m/0/2147483647H/1/2147483646H/2 struct hd_extended_key m_0_2147483647H_1_2147483646H_2; assert(hd_extended_key_init(&m_0_2147483647H_1_2147483646H_2)); assert(hd_extended_key_generate_child(&m_0_2147483647H_1_2147483646H, 2, &m_0_2147483647H_1_2147483646H_2)); assert(compare_serialized_pub(&m_0_2147483647H_1_2147483646H_2, &tv2_m_0_2147483647H_1_2147483646H_2_xpub)); assert(compare_serialized_prv(&m_0_2147483647H_1_2147483646H_2, &tv2_m_0_2147483647H_1_2147483646H_2_xprv)); hd_extended_key_free(&m_0_2147483647H_1_2147483646H_2); hd_extended_key_free(&m_0_2147483647H_1_2147483646H); hd_extended_key_free(&m_0_2147483647H_1); hd_extended_key_free(&m_0_2147483647H); hd_extended_key_free(&m_0); hd_extended_key_free(&m); }
static void test_vector_1() { struct hd_extended_key_serialized tv1_m_xpub; read_ek_ser_from_base58(s_tv1_m_xpub, &tv1_m_xpub); struct hd_extended_key_serialized tv1_m_xprv; read_ek_ser_from_base58(s_tv1_m_xprv, &tv1_m_xprv); struct hd_extended_key_serialized tv1_m_0H_xpub; read_ek_ser_from_base58(s_tv1_m_0H_xpub, &tv1_m_0H_xpub); struct hd_extended_key_serialized tv1_m_0H_xprv; read_ek_ser_from_base58(s_tv1_m_0H_xprv, &tv1_m_0H_xprv); struct hd_extended_key_serialized tv1_m_0H_1_xpub; read_ek_ser_from_base58(s_tv1_m_0H_1_xpub, &tv1_m_0H_1_xpub); struct hd_extended_key_serialized tv1_m_0H_1_xprv; read_ek_ser_from_base58(s_tv1_m_0H_1_xprv, &tv1_m_0H_1_xprv); struct hd_extended_key_serialized tv1_m_0H_1_2H_xpub; read_ek_ser_from_base58(s_tv1_m_0H_1_2H_xpub, &tv1_m_0H_1_2H_xpub); struct hd_extended_key_serialized tv1_m_0H_1_2H_xprv; read_ek_ser_from_base58(s_tv1_m_0H_1_2H_xprv, &tv1_m_0H_1_2H_xprv); struct hd_extended_key_serialized tv1_m_0H_1_2H_2_xpub; read_ek_ser_from_base58(s_tv1_m_0H_1_2H_2_xpub, &tv1_m_0H_1_2H_2_xpub); struct hd_extended_key_serialized tv1_m_0H_1_2H_2_xprv; read_ek_ser_from_base58(s_tv1_m_0H_1_2H_2_xprv, &tv1_m_0H_1_2H_2_xprv); struct hd_extended_key_serialized tv1_m_0H_1_2H_2_1000000000_xpub; read_ek_ser_from_base58(s_tv1_m_0H_1_2H_2_1000000000_xpub, &tv1_m_0H_1_2H_2_1000000000_xpub); struct hd_extended_key_serialized tv1_m_0H_1_2H_2_1000000000_xprv; read_ek_ser_from_base58(s_tv1_m_0H_1_2H_2_1000000000_xprv, &tv1_m_0H_1_2H_2_1000000000_xprv); printf("TEST: test_vector_1\n"); // Chain m struct hd_extended_key m; assert(hd_extended_key_init(&m)); assert(hd_extended_key_generate_master(&m, s_tv1_seed, sizeof(s_tv1_seed))); assert(compare_serialized_pub(&m, &tv1_m_xpub)); assert(compare_serialized_prv(&m, &tv1_m_xprv)); // Chain m/0H struct hd_extended_key m_0H; assert(hd_extended_key_init(&m_0H)); assert(hd_extended_key_generate_child(&m, 0x80000000, &m_0H)); assert(compare_serialized_pub(&m_0H, &tv1_m_0H_xpub)); assert(compare_serialized_prv(&m_0H, &tv1_m_0H_xprv)); // Chain m/0H/1 struct hd_extended_key m_0H_1; assert(hd_extended_key_init(&m_0H_1)); assert(hd_extended_key_generate_child(&m_0H, 0x00000001, &m_0H_1)); assert(compare_serialized_pub(&m_0H_1, &tv1_m_0H_1_xpub)); assert(compare_serialized_prv(&m_0H_1, &tv1_m_0H_1_xprv)); // Chain m/0H/1/2H struct hd_extended_key m_0H_1_2H; assert(hd_extended_key_init(&m_0H_1_2H)); assert(hd_extended_key_generate_child(&m_0H_1, 0x80000002, &m_0H_1_2H)); assert(compare_serialized_pub(&m_0H_1_2H, &tv1_m_0H_1_2H_xpub)); assert(compare_serialized_prv(&m_0H_1_2H, &tv1_m_0H_1_2H_xprv)); // Chain m/0H/1/2H/2 struct hd_extended_key m_0H_1_2H_2; assert(hd_extended_key_init(&m_0H_1_2H_2)); assert(hd_extended_key_generate_child(&m_0H_1_2H, 0x00000002, &m_0H_1_2H_2)); assert(compare_serialized_pub(&m_0H_1_2H_2, &tv1_m_0H_1_2H_2_xpub)); assert(compare_serialized_prv(&m_0H_1_2H_2, &tv1_m_0H_1_2H_2_xprv)); // Chain m/0H/1/2H/2/1000000000 struct hd_extended_key m_0H_1_2H_2_1000000000; assert(hd_extended_key_init(&m_0H_1_2H_2_1000000000)); assert(hd_extended_key_generate_child(&m_0H_1_2H_2, 1000000000, &m_0H_1_2H_2_1000000000)); assert(compare_serialized_pub(&m_0H_1_2H_2_1000000000, &tv1_m_0H_1_2H_2_1000000000_xpub)); assert(compare_serialized_prv(&m_0H_1_2H_2_1000000000, &tv1_m_0H_1_2H_2_1000000000_xprv)); hd_extended_key_free(&m_0H_1_2H_2_1000000000); hd_extended_key_free(&m_0H_1_2H_2); hd_extended_key_free(&m_0H_1_2H); hd_extended_key_free(&m_0H_1); hd_extended_key_free(&m_0H); hd_extended_key_free(&m); }
static void test_serialize() { printf("TEST: test_serialize\n"); const char seed[] = "picocoin test seed"; struct hd_extended_key m; struct hd_extended_key_serialized m_xpub; struct hd_extended_key_serialized m_xprv; { assert(hd_extended_key_init(&m)); assert(hd_extended_key_generate_master(&m, seed, sizeof(seed))); assert(0 == m.depth); assert(0 == m.index); assert(write_ek_ser_pub(&m_xpub, &m)); assert(write_ek_ser_prv(&m_xprv, &m)); } // Check that there are no gaps in serialized data { struct hd_extended_key_serialized m_xpub_A; struct hd_extended_key_serialized m_xpub_B; memset(m_xpub_A.data, 0xff, sizeof(m_xpub_A.data)); assert(write_ek_ser_pub(&m_xpub_A, &m)); memset(m_xpub_B.data, 0x00, sizeof(m_xpub_B.data)); assert(write_ek_ser_pub(&m_xpub_B, &m)); assert(0 == memcmp(m_xpub_A.data, m_xpub_B.data, sizeof(m_xpub_B.data))); } { struct hd_extended_key_serialized m_xprv_A; struct hd_extended_key_serialized m_xprv_B; memset(m_xprv_A.data, 0xff, sizeof(m_xprv_A.data)); assert(write_ek_ser_prv(&m_xprv_A, &m)); memset(m_xprv_B.data, 0x00, sizeof(m_xprv_B.data)); assert(write_ek_ser_prv(&m_xprv_B, &m)); assert(0 == memcmp(m_xprv_A.data, m_xprv_B.data, sizeof(m_xprv_B.data))); } // generate child keys 1 and 2H, keep serialized version for // comparison struct hd_extended_key m_1; struct hd_extended_key_serialized m_1_xpub; struct hd_extended_key_serialized m_1_xprv; struct hd_extended_key m_2H; struct hd_extended_key_serialized m_2H_xpub; struct hd_extended_key_serialized m_2H_xprv; { assert(hd_extended_key_init(&m_1)); assert(hd_extended_key_generate_child(&m, 1, &m_1)); assert(write_ek_ser_pub(&m_1_xpub, &m_1)); assert(write_ek_ser_prv(&m_1_xprv, &m_1)); assert(hd_extended_key_init(&m_2H)); assert(hd_extended_key_generate_child(&m, 0x80000002, &m_2H)); assert(write_ek_ser_pub(&m_2H_xpub, &m_2H)); assert(write_ek_ser_prv(&m_2H_xprv, &m_2H)); } // read back in, re-serialize and check the memory { struct hd_extended_key m_1_; struct hd_extended_key_serialized m_1_xpub_; struct hd_extended_key_serialized m_1_xprv_; assert(hd_extended_key_init(&m_1_)); assert(hd_extended_key_deser(&m_1_, m_1_xprv.data, sizeof(m_1_xprv))); assert(write_ek_ser_pub(&m_1_xpub_, &m_1_)); assert(write_ek_ser_prv(&m_1_xprv_, &m_1_)); assert(0 == memcmp(&m_1_xpub, &m_1_xpub_, sizeof(m_1_xpub_))); assert(0 == memcmp(&m_1_xprv, &m_1_xprv_, sizeof(m_1_xprv_))); hd_extended_key_free(&m_1_); } { struct hd_extended_key m_2H_; struct hd_extended_key_serialized m_2H_xpub_; struct hd_extended_key_serialized m_2H_xprv_; assert(hd_extended_key_init(&m_2H_)); assert(hd_extended_key_deser(&m_2H_, m_2H_xprv.data, sizeof(m_2H_xprv))); assert(write_ek_ser_pub(&m_2H_xpub_, &m_2H_)); assert(write_ek_ser_prv(&m_2H_xprv_, &m_2H_)); assert(0 == memcmp(&m_2H_xpub, &m_2H_xpub_, sizeof(m_2H_xpub_))); assert(0 == memcmp(&m_2H_xprv, &m_2H_xprv_, sizeof(m_2H_xprv_))); hd_extended_key_free(&m_2H_); } // read back master, generate child, check prv and pub { struct hd_extended_key m_; struct hd_extended_key m_1_; struct hd_extended_key m_2H_; assert(hd_extended_key_init(&m_)); assert(hd_extended_key_deser(&m_, m_xprv.data, sizeof(m_xprv))); assert(hd_extended_key_init(&m_1_)); assert(hd_extended_key_generate_child(&m_, 1, &m_1_)); assert(check_keys_match(&m_1, &m_1_)); assert(hd_extended_key_init(&m_2H_)); assert(hd_extended_key_generate_child(&m_, 0x80000002, &m_2H_)); assert(check_keys_match(&m_2H, &m_2H_)); hd_extended_key_free(&m_2H_); hd_extended_key_free(&m_1_); hd_extended_key_free(&m_); } // read back master from xpub and generate child. ensure prv keys // can't be retrieved but public keys match. { struct hd_extended_key m_; struct hd_extended_key m_1_; uint8_t priv[32]; assert(hd_extended_key_init(&m_)); assert(hd_extended_key_deser(&m_, m_xpub.data, sizeof(m_xpub))); assert(!bp_key_secret_get(&priv[0], sizeof(priv), &m_.key)); assert(hd_extended_key_init(&m_1_)); assert(hd_extended_key_generate_child(&m_, 1, &m_1_)); assert(!bp_key_secret_get(&priv[0], sizeof(priv), &m_1_.key)); assert(check_keys_match(&m_1, &m_1_)); hd_extended_key_free(&m_1_); hd_extended_key_free(&m_); } // read back child from xpub. ensure no hardened children can be // generated. { struct hd_extended_key m_2H_; struct hd_extended_key m_2H_3H_; assert(hd_extended_key_init(&m_2H_)); assert(hd_extended_key_deser(&m_2H_, m_2H_xpub.data, sizeof(m_2H_xpub))); assert(hd_extended_key_init(&m_2H_3H_)); assert(!hd_extended_key_generate_child(&m_2H_, 0x80000003, &m_2H_)); hd_extended_key_free(&m_2H_3H_); hd_extended_key_free(&m_2H_); } hd_extended_key_free(&m_2H); hd_extended_key_free(&m_1); hd_extended_key_free(&m); }