You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
678 lines
23 KiB
678 lines
23 KiB
#include "internal.h"
|
|
#include "hmac.h"
|
|
#include "ccan/ccan/crypto/ripemd160/ripemd160.h"
|
|
#include "ccan/ccan/crypto/sha256/sha256.h"
|
|
#include "ccan/ccan/crypto/sha512/sha512.h"
|
|
#include "ccan/ccan/endian/endian.h"
|
|
#include "ccan/ccan/build_assert/build_assert.h"
|
|
#include <include/wally_bip32.h>
|
|
#include <include/wally_crypto.h>
|
|
#include "bip32_int.h"
|
|
#include <stdbool.h>
|
|
|
|
#define BIP32_ALL_DEFINED_FLAGS (BIP32_FLAG_KEY_PRIVATE | BIP32_FLAG_KEY_PUBLIC | BIP32_FLAG_SKIP_HASH)
|
|
|
|
static const unsigned char SEED[] = {
|
|
'B', 'i', 't', 'c', 'o', 'i', 'n', ' ', 's', 'e', 'e', 'd'
|
|
};
|
|
|
|
/* LCOV_EXCL_START */
|
|
/* Check assumptions we expect to hold true */
|
|
static void assert_assumptions(void)
|
|
{
|
|
#define key_off(member) offsetof(struct ext_key, member)
|
|
#define key_size(member) sizeof(((struct ext_key *)0)->member)
|
|
|
|
/* Our ripend buffers must be uint32_t aligned and the correct size */
|
|
BUILD_ASSERT(key_off(parent160) % sizeof(uint32_t) == 0);
|
|
BUILD_ASSERT(key_off(hash160) % sizeof(uint32_t) == 0);
|
|
BUILD_ASSERT(key_size(parent160) == sizeof(struct ripemd160));
|
|
BUILD_ASSERT(key_size(hash160) == sizeof(struct ripemd160));
|
|
BUILD_ASSERT(key_size(priv_key) == EC_PRIVATE_KEY_LEN + 1);
|
|
|
|
/* Our keys following the parity byte must be uint64_t aligned */
|
|
BUILD_ASSERT((key_off(priv_key) + 1) % sizeof(uint64_t) == 0);
|
|
BUILD_ASSERT((key_off(pub_key) + 1) % sizeof(uint64_t) == 0);
|
|
|
|
/* child_num must be contigous after priv_key */
|
|
BUILD_ASSERT((key_off(priv_key) + key_size(priv_key)) == key_off(child_num));
|
|
|
|
/* We use priv_key[0] to determine if this extended key is public or
|
|
* private, If priv_key[0] is BIP32_FLAG_KEY_PRIVATE then this key is private
|
|
* with a computed public key present. If set to BIP32_FLAG_KEY_PUBLIC then
|
|
* this is a public key with no private key (A BIP32 'neutered' key).
|
|
*
|
|
* For this to work BIP32_FLAG_KEY_PRIVATE must be zero so the whole 33 byte
|
|
* private key is valid when serialized, and BIP32_FLAG_KEY_PUBLIC cannot be
|
|
* 2 or 3 as they are valid parity bytes for public keys.
|
|
*/
|
|
BUILD_ASSERT(BIP32_FLAG_KEY_PRIVATE == 0);
|
|
BUILD_ASSERT(BIP32_FLAG_KEY_PUBLIC != BIP32_FLAG_KEY_PRIVATE &&
|
|
BIP32_FLAG_KEY_PUBLIC != 2u &&
|
|
BIP32_FLAG_KEY_PUBLIC != 3u);
|
|
}
|
|
/* LCOV_EXCL_STOP */
|
|
|
|
static bool mem_is_zero(const void *mem, size_t len)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < len; ++i)
|
|
if (((const unsigned char *)mem)[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static bool child_is_hardened(uint32_t child_num)
|
|
{
|
|
return child_num >= BIP32_INITIAL_HARDENED_CHILD;
|
|
}
|
|
|
|
static bool version_is_valid(uint32_t ver, uint32_t flags)
|
|
{
|
|
if (ver == BIP32_VER_MAIN_PRIVATE || ver == BIP32_VER_TEST_PRIVATE)
|
|
return true;
|
|
|
|
return flags == BIP32_FLAG_KEY_PUBLIC &&
|
|
(ver == BIP32_VER_MAIN_PUBLIC || ver == BIP32_VER_TEST_PUBLIC);
|
|
}
|
|
|
|
static bool version_is_mainnet(uint32_t ver)
|
|
{
|
|
return ver == BIP32_VER_MAIN_PRIVATE || ver == BIP32_VER_MAIN_PUBLIC;
|
|
}
|
|
|
|
static bool key_is_private(const struct ext_key *key_in)
|
|
{
|
|
return key_in->priv_key[0] == BIP32_FLAG_KEY_PRIVATE;
|
|
}
|
|
|
|
static void key_strip_private_key(struct ext_key *key_out)
|
|
{
|
|
key_out->priv_key[0] = BIP32_FLAG_KEY_PUBLIC;
|
|
clear(key_out->priv_key + 1, sizeof(key_out->priv_key) - 1);
|
|
}
|
|
|
|
/* Compute a public key from a private key */
|
|
static int key_compute_pub_key(struct ext_key *key_out)
|
|
{
|
|
return wally_ec_public_key_from_private_key(key_out->priv_key + 1,
|
|
EC_PRIVATE_KEY_LEN,
|
|
key_out->pub_key,
|
|
sizeof(key_out->pub_key));
|
|
}
|
|
|
|
static void key_compute_hash160(struct ext_key *key_out)
|
|
{
|
|
wally_hash160(key_out->pub_key, sizeof(key_out->pub_key),
|
|
key_out->hash160, sizeof(key_out->hash160));
|
|
}
|
|
|
|
int bip32_key_free(const struct ext_key *key_in)
|
|
{
|
|
if (!key_in)
|
|
return WALLY_EINVAL;
|
|
wally_free((void *)key_in);
|
|
return WALLY_OK;
|
|
}
|
|
|
|
static bool is_valid_seed_len(size_t len) {
|
|
return len == BIP32_ENTROPY_LEN_512 || len == BIP32_ENTROPY_LEN_256 ||
|
|
len == BIP32_ENTROPY_LEN_128;
|
|
}
|
|
|
|
int bip32_key_from_seed(const unsigned char *bytes_in, size_t len_in,
|
|
uint32_t version, uint32_t flags,
|
|
struct ext_key *key_out)
|
|
{
|
|
const secp256k1_context *ctx;
|
|
struct sha512 sha;
|
|
|
|
if (!bytes_in || !is_valid_seed_len(len_in) ||
|
|
!version_is_valid(version, BIP32_FLAG_KEY_PRIVATE) ||
|
|
(flags & ~BIP32_FLAG_SKIP_HASH) || !key_out)
|
|
return WALLY_EINVAL;
|
|
|
|
clear(key_out, sizeof(*key_out));
|
|
key_out->version = version;
|
|
|
|
if (!(ctx = secp_ctx()))
|
|
return WALLY_ENOMEM;
|
|
|
|
/* Generate private key and chain code */
|
|
hmac_sha512(&sha, SEED, sizeof(SEED), bytes_in, len_in);
|
|
|
|
/* Check that the generated private key is valid */
|
|
if (!secp256k1_ec_seckey_verify(ctx, sha.u.u8)) {
|
|
clear(&sha, sizeof(sha));
|
|
return WALLY_ERROR; /* Invalid private key */
|
|
}
|
|
|
|
/* Copy the private key and set its prefix */
|
|
key_out->priv_key[0] = BIP32_FLAG_KEY_PRIVATE;
|
|
memcpy(key_out->priv_key + 1, sha.u.u8, sizeof(sha) / 2);
|
|
if (key_compute_pub_key(key_out) != WALLY_OK) {
|
|
clear_n(2, &sha, sizeof(sha), key_out, sizeof(*key_out));
|
|
return WALLY_EINVAL;
|
|
}
|
|
|
|
/* Copy the chain code */
|
|
memcpy(key_out->chain_code, sha.u.u8 + sizeof(sha) / 2, sizeof(sha) / 2);
|
|
|
|
key_out->depth = 0; /* Master key, depth 0 */
|
|
key_out->child_num = 0;
|
|
if (!(flags & BIP32_FLAG_SKIP_HASH))
|
|
key_compute_hash160(key_out);
|
|
clear(&sha, sizeof(sha));
|
|
return WALLY_OK;
|
|
}
|
|
|
|
#define ALLOC_KEY() \
|
|
if (!output) \
|
|
return WALLY_EINVAL; \
|
|
*output = wally_malloc(sizeof(struct ext_key)); \
|
|
if (!*output) \
|
|
return WALLY_ENOMEM; \
|
|
clear((void *)*output, sizeof(struct ext_key))
|
|
|
|
int bip32_key_from_seed_alloc(const unsigned char *bytes_in, size_t len_in,
|
|
uint32_t version, uint32_t flags,
|
|
const struct ext_key **output)
|
|
{
|
|
int ret;
|
|
|
|
ALLOC_KEY();
|
|
ret = bip32_key_from_seed(bytes_in, len_in, version, flags,
|
|
(struct ext_key *)*output);
|
|
if (ret != WALLY_OK) {
|
|
wally_free((void *)*output);
|
|
*output = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static unsigned char *copy_out(unsigned char *dest,
|
|
const void *src, size_t len)
|
|
{
|
|
memcpy(dest, src, len);
|
|
return dest + len;
|
|
}
|
|
|
|
static bool key_is_valid(const struct ext_key *key_in)
|
|
{
|
|
bool is_private = key_is_private(key_in);
|
|
bool is_master = !key_in->depth;
|
|
uint8_t ver_flags = is_private ? BIP32_FLAG_KEY_PRIVATE : BIP32_FLAG_KEY_PUBLIC;
|
|
|
|
if (!version_is_valid(key_in->version, ver_flags))
|
|
return false;
|
|
|
|
if (mem_is_zero(key_in->chain_code, sizeof(key_in->chain_code)) ||
|
|
(key_in->pub_key[0] != 0x2 && key_in->pub_key[0] != 0x3) ||
|
|
mem_is_zero(key_in->pub_key + 1, sizeof(key_in->pub_key) - 1))
|
|
return false;
|
|
|
|
if (key_in->priv_key[0] != BIP32_FLAG_KEY_PUBLIC &&
|
|
key_in->priv_key[0] != BIP32_FLAG_KEY_PRIVATE)
|
|
return false;
|
|
|
|
if (is_private &&
|
|
mem_is_zero(key_in->priv_key + 1, sizeof(key_in->priv_key) - 1))
|
|
return false;
|
|
|
|
if (is_master && !is_private)
|
|
return false;
|
|
|
|
if (is_master &&
|
|
!mem_is_zero(key_in->parent160, sizeof(key_in->parent160)))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int bip32_key_serialize(const struct ext_key *key_in, uint32_t flags,
|
|
unsigned char *bytes_out, size_t len)
|
|
{
|
|
const bool serialize_private = !(flags & BIP32_FLAG_KEY_PUBLIC);
|
|
unsigned char *out = bytes_out;
|
|
uint32_t tmp32;
|
|
beint32_t tmp32_be;
|
|
|
|
if (flags & ~BIP32_FLAG_KEY_PUBLIC)
|
|
return WALLY_EINVAL; /* Only this flag makes sense here */
|
|
|
|
/* Validate our arguments and then the input key */
|
|
if (!key_in ||
|
|
(serialize_private && !key_is_private(key_in)) ||
|
|
!key_is_valid(key_in) ||
|
|
!bytes_out || len != BIP32_SERIALIZED_LEN)
|
|
return WALLY_EINVAL;
|
|
|
|
tmp32 = key_in->version;
|
|
if (!serialize_private) {
|
|
/* Change version if serialising the public part of a private key */
|
|
if (tmp32 == BIP32_VER_MAIN_PRIVATE)
|
|
tmp32 = BIP32_VER_MAIN_PUBLIC;
|
|
else if (tmp32 == BIP32_VER_TEST_PRIVATE)
|
|
tmp32 = BIP32_VER_TEST_PUBLIC;
|
|
}
|
|
tmp32_be = cpu_to_be32(tmp32);
|
|
out = copy_out(out, &tmp32_be, sizeof(tmp32_be));
|
|
|
|
*out++ = key_in->depth;
|
|
|
|
/* Save the first 32 bits of the parent key (aka fingerprint) only */
|
|
out = copy_out(out, key_in->parent160, sizeof(uint32_t));
|
|
|
|
tmp32_be = cpu_to_be32(key_in->child_num);
|
|
out = copy_out(out, &tmp32_be, sizeof(tmp32_be));
|
|
|
|
out = copy_out(out, key_in->chain_code, sizeof(key_in->chain_code));
|
|
|
|
if (serialize_private)
|
|
copy_out(out, key_in->priv_key, sizeof(key_in->priv_key));
|
|
else
|
|
copy_out(out, key_in->pub_key, sizeof(key_in->pub_key));
|
|
|
|
return WALLY_OK;
|
|
}
|
|
|
|
static const unsigned char *copy_in(void *dest,
|
|
const unsigned char *src, size_t len)
|
|
{
|
|
memcpy(dest, src, len);
|
|
return src + len;
|
|
}
|
|
|
|
/* Wipe a key and return failure for the caller to propigate */
|
|
static int wipe_key_fail(struct ext_key *key_out)
|
|
{
|
|
clear(key_out, sizeof(*key_out));
|
|
return WALLY_EINVAL;
|
|
}
|
|
|
|
int bip32_key_unserialize(const unsigned char *bytes_in, size_t len_in,
|
|
struct ext_key *key_out)
|
|
{
|
|
if (!bytes_in || len_in != BIP32_SERIALIZED_LEN || !key_out)
|
|
return WALLY_EINVAL;
|
|
|
|
clear(key_out, sizeof(*key_out));
|
|
|
|
bytes_in = copy_in(&key_out->version, bytes_in, sizeof(key_out->version));
|
|
key_out->version = be32_to_cpu(key_out->version);
|
|
if (!version_is_valid(key_out->version, BIP32_FLAG_KEY_PUBLIC))
|
|
return wipe_key_fail(key_out);
|
|
|
|
bytes_in = copy_in(&key_out->depth, bytes_in, sizeof(key_out->depth));
|
|
|
|
/* We only have a partial fingerprint available. Copy it, but the
|
|
* user will need to call bip32_key_set_parent() (FIXME: Implement)
|
|
* later if they want it to be fully populated.
|
|
*/
|
|
bytes_in = copy_in(key_out->parent160, bytes_in, sizeof(uint32_t));
|
|
bytes_in = copy_in(&key_out->child_num, bytes_in, sizeof(key_out->child_num));
|
|
key_out->child_num = be32_to_cpu(key_out->child_num);
|
|
bytes_in = copy_in(key_out->chain_code, bytes_in, sizeof(key_out->chain_code));
|
|
|
|
if (bytes_in[0] == BIP32_FLAG_KEY_PRIVATE) {
|
|
if (key_out->version == BIP32_VER_MAIN_PUBLIC ||
|
|
key_out->version == BIP32_VER_TEST_PUBLIC)
|
|
return wipe_key_fail(key_out); /* Private key data in public key */
|
|
|
|
copy_in(key_out->priv_key, bytes_in, sizeof(key_out->priv_key));
|
|
if (key_compute_pub_key(key_out) != WALLY_OK)
|
|
return wipe_key_fail(key_out);
|
|
} else {
|
|
if (key_out->version == BIP32_VER_MAIN_PRIVATE ||
|
|
key_out->version == BIP32_VER_TEST_PRIVATE)
|
|
return wipe_key_fail(key_out); /* Public key data in private key */
|
|
|
|
copy_in(key_out->pub_key, bytes_in, sizeof(key_out->pub_key));
|
|
key_strip_private_key(key_out);
|
|
}
|
|
|
|
key_compute_hash160(key_out);
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int bip32_key_unserialize_alloc(const unsigned char *bytes_in, size_t len_in,
|
|
const struct ext_key **output)
|
|
{
|
|
int ret;
|
|
|
|
ALLOC_KEY();
|
|
ret = bip32_key_unserialize(bytes_in, len_in, (struct ext_key *)*output);
|
|
if (ret) {
|
|
wally_free((void *)*output);
|
|
*output = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* BIP32: Child Key Derivations
|
|
*
|
|
* The spec doesn't have a simple table of derivations, its:
|
|
*
|
|
* Parent Child Hardened Status Path In Spec
|
|
* private private no OK m/n Y
|
|
* private private yes OK m/nH Y
|
|
* private public no OK - N
|
|
* private public yes OK - N
|
|
* public private no FAIL (N/A) (N/A)
|
|
* public private yes FAIL (N/A) (N/A)
|
|
* public public no OK M/n N
|
|
* public public yes FAIL M/nH (N/A)
|
|
*
|
|
* The spec path nomenclature only expresses derivations where the parent
|
|
* and desired child type match. For private->public the derivation is
|
|
* described in terms of private-private and public->public, but there are
|
|
* no test vectors or paths describing these values to validate against.
|
|
* Further, there are no public-public vectors in the BIP32 spec either.
|
|
*/
|
|
int bip32_key_from_parent(const struct ext_key *key_in, uint32_t child_num,
|
|
uint32_t flags, struct ext_key *key_out)
|
|
{
|
|
struct sha512 sha;
|
|
const secp256k1_context *ctx;
|
|
const bool we_are_private = key_in && key_is_private(key_in);
|
|
const bool derive_private = !(flags & BIP32_FLAG_KEY_PUBLIC);
|
|
const bool hardened = child_is_hardened(child_num);
|
|
|
|
if (flags & ~BIP32_ALL_DEFINED_FLAGS)
|
|
return WALLY_EINVAL; /* These flags are not defined yet */
|
|
|
|
if (!key_in || !key_out)
|
|
return WALLY_EINVAL;
|
|
|
|
if (!(ctx = secp_ctx()))
|
|
return WALLY_ENOMEM;
|
|
|
|
if (!we_are_private && (derive_private || hardened))
|
|
return wipe_key_fail(key_out); /* Unsupported derivation */
|
|
|
|
if (key_in->depth == 0xff)
|
|
return wipe_key_fail(key_out); /* Maximum depth reached */
|
|
|
|
/*
|
|
* Private parent -> private child:
|
|
* CKDpriv((kpar, cpar), i) -> (ki, ci)
|
|
*
|
|
* Private parent -> public child:
|
|
* N(CKDpriv((kpar, cpar), i) -> (ki, ci))
|
|
* As we always calculate the public key, we can derive a public
|
|
* child by deriving a private one and stripping its private key.
|
|
*
|
|
* Public parent -> non hardened public child
|
|
* CKDpub((Kpar, cpar), i) -> (Ki, ci)
|
|
*/
|
|
|
|
/* NB: We use the key_outs' priv_key+child_num to hold 'Data' here */
|
|
if (hardened) {
|
|
/* Hardened: Data = 0x00 || ser256(kpar) || ser32(i)) */
|
|
memcpy(key_out->priv_key, key_in->priv_key, sizeof(key_in->priv_key));
|
|
} else {
|
|
/* Non Hardened Private: Data = serP(point(kpar)) || ser32(i)
|
|
* Non Hardened Public : Data = serP(kpar) || ser32(i)
|
|
* point(kpar) when par is private is the public key.
|
|
*/
|
|
memcpy(key_out->priv_key, key_in->pub_key, sizeof(key_in->pub_key));
|
|
}
|
|
|
|
/* This is the '|| ser32(i)' part of the above */
|
|
key_out->child_num = cpu_to_be32(child_num);
|
|
|
|
/* I = HMAC-SHA512(Key = cpar, Data) */
|
|
hmac_sha512(&sha, key_in->chain_code, sizeof(key_in->chain_code),
|
|
key_out->priv_key,
|
|
sizeof(key_out->priv_key) + sizeof(key_out->child_num));
|
|
|
|
/* Split I into two 32-byte sequences, IL and IR
|
|
* The returned chain code ci is IR (i.e. the 2nd half of our hmac sha512)
|
|
*/
|
|
memcpy(key_out->chain_code, sha.u.u8 + sizeof(sha) / 2,
|
|
sizeof(key_out->chain_code));
|
|
|
|
if (we_are_private) {
|
|
/* The returned child key ki is parse256(IL) + kpar (mod n)
|
|
* In case parse256(IL) ≥ n or ki = 0, the resulting key is invalid
|
|
* (NOTE: privkey_tweak_add checks both conditions)
|
|
*/
|
|
memcpy(key_out->priv_key, key_in->priv_key, sizeof(key_in->priv_key));
|
|
if (!privkey_tweak_add(ctx, key_out->priv_key + 1, sha.u.u8)) {
|
|
clear(&sha, sizeof(sha));
|
|
return wipe_key_fail(key_out); /* Out of bounds FIXME: Iterate to the next? */
|
|
}
|
|
|
|
if (key_compute_pub_key(key_out) != WALLY_OK) {
|
|
clear(&sha, sizeof(sha));
|
|
return wipe_key_fail(key_out);
|
|
}
|
|
} else {
|
|
/* The returned child key ki is point(parse256(IL) + kpar)
|
|
* In case parse256(IL) ≥ n or Ki is the point at infinity, the
|
|
* resulting key is invalid (NOTE: pubkey_tweak_add checks both
|
|
* conditions)
|
|
*/
|
|
secp256k1_pubkey pub_key;
|
|
size_t len = sizeof(key_out->pub_key);
|
|
|
|
/* FIXME: Out of bounds on pubkey_tweak_add */
|
|
if (!pubkey_parse(ctx, &pub_key, key_in->pub_key,
|
|
sizeof(key_in->pub_key)) ||
|
|
!pubkey_tweak_add(ctx, &pub_key, sha.u.u8) ||
|
|
!pubkey_serialize(ctx, key_out->pub_key, &len, &pub_key,
|
|
PUBKEY_COMPRESSED) ||
|
|
len != sizeof(key_out->pub_key)) {
|
|
clear(&sha, sizeof(sha));
|
|
return wipe_key_fail(key_out);
|
|
}
|
|
}
|
|
|
|
if (derive_private) {
|
|
if (version_is_mainnet(key_in->version))
|
|
key_out->version = BIP32_VER_MAIN_PRIVATE;
|
|
else
|
|
key_out->version = BIP32_VER_TEST_PRIVATE;
|
|
|
|
} else {
|
|
if (version_is_mainnet(key_in->version))
|
|
key_out->version = BIP32_VER_MAIN_PUBLIC;
|
|
else
|
|
key_out->version = BIP32_VER_TEST_PUBLIC;
|
|
|
|
key_strip_private_key(key_out);
|
|
}
|
|
|
|
key_out->depth = key_in->depth + 1;
|
|
key_out->child_num = child_num;
|
|
if (flags & BIP32_FLAG_SKIP_HASH)
|
|
clear_n(2, &key_out->parent160, sizeof(key_out->parent160),
|
|
&key_out->hash160, sizeof(key_out->hash160));
|
|
else {
|
|
memcpy(key_out->parent160, key_in->hash160, sizeof(key_in->hash160));
|
|
key_compute_hash160(key_out);
|
|
}
|
|
clear(&sha, sizeof(sha));
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int bip32_key_from_parent_alloc(const struct ext_key *key_in,
|
|
uint32_t child_num, uint32_t flags,
|
|
const struct ext_key **output)
|
|
{
|
|
int ret;
|
|
|
|
ALLOC_KEY();
|
|
ret = bip32_key_from_parent(key_in, child_num, flags, (struct ext_key *)*output);
|
|
if (ret) {
|
|
wally_free((void *)*output);
|
|
*output = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int bip32_key_from_parent_path(const struct ext_key *key_in,
|
|
const uint32_t *child_num_in, size_t child_num_len,
|
|
uint32_t flags, struct ext_key *key_out)
|
|
{
|
|
/* Optimization: We can skip hash calculations for internal nodes */
|
|
uint32_t derivation_flags = flags | BIP32_FLAG_SKIP_HASH;
|
|
struct ext_key tmp[2];
|
|
size_t i, tmp_idx = 0;
|
|
int ret;
|
|
|
|
if (flags & ~BIP32_ALL_DEFINED_FLAGS)
|
|
return WALLY_EINVAL; /* These flags are not defined yet */
|
|
|
|
if (!key_in || !child_num_in || !child_num_len || !key_out)
|
|
return WALLY_EINVAL;
|
|
|
|
for (i = 0; i < child_num_len; ++i) {
|
|
struct ext_key *derived = &tmp[tmp_idx];
|
|
if (i + 2 >= child_num_len)
|
|
derivation_flags = flags; /* Use callers flags for the final derivations */
|
|
ret = bip32_key_from_parent(key_in, child_num_in[i], derivation_flags, derived);
|
|
if (ret != WALLY_OK)
|
|
break;
|
|
key_in = derived; /* Derived becomes next parent */
|
|
tmp_idx = !tmp_idx; /* Use free slot in tmp for next derived */
|
|
}
|
|
|
|
if (ret == WALLY_OK)
|
|
memcpy(key_out, key_in, sizeof(*key_out));
|
|
|
|
clear(tmp, sizeof(tmp));
|
|
return ret;
|
|
}
|
|
|
|
int bip32_key_from_parent_path_alloc(const struct ext_key *key_in,
|
|
const uint32_t *child_num_in, size_t child_num_len,
|
|
uint32_t flags,
|
|
const struct ext_key **output)
|
|
{
|
|
int ret;
|
|
|
|
ALLOC_KEY();
|
|
ret = bip32_key_from_parent_path(key_in, child_num_in, child_num_len,
|
|
flags, (struct ext_key *)*output);
|
|
if (ret) {
|
|
wally_free((void *)*output);
|
|
*output = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int bip32_key_init_alloc(uint32_t version, uint32_t depth, uint32_t child_num,
|
|
const unsigned char *chain_code, size_t chain_code_len,
|
|
const unsigned char *pub_key, size_t pub_key_len,
|
|
const unsigned char *priv_key, size_t priv_key_len,
|
|
const unsigned char *hash160, size_t hash160_len,
|
|
const unsigned char *parent160, size_t parent160_len,
|
|
const struct ext_key **output)
|
|
{
|
|
struct ext_key *key_out;
|
|
|
|
if (!output)
|
|
return WALLY_EINVAL;
|
|
*output = NULL;
|
|
|
|
switch (version) {
|
|
case BIP32_VER_MAIN_PRIVATE:
|
|
case BIP32_VER_TEST_PRIVATE:
|
|
if (!priv_key || priv_key_len != key_size(priv_key) - 1)
|
|
return WALLY_EINVAL;
|
|
break;
|
|
case BIP32_VER_MAIN_PUBLIC:
|
|
case BIP32_VER_TEST_PUBLIC:
|
|
if (!pub_key || pub_key_len != key_size(pub_key))
|
|
return WALLY_EINVAL;
|
|
break;
|
|
}
|
|
|
|
if (!chain_code || chain_code_len != key_size(chain_code))
|
|
return WALLY_EINVAL;
|
|
|
|
if ((priv_key && priv_key_len != key_size(priv_key) - 1) || (!priv_key && priv_key_len) ||
|
|
(pub_key && pub_key_len != key_size(pub_key)) || (!pub_key && pub_key_len) ||
|
|
(hash160 && hash160_len != key_size(hash160)) || (!hash160 && hash160_len) ||
|
|
(parent160 && parent160_len != key_size(parent160)))
|
|
return WALLY_EINVAL;
|
|
|
|
ALLOC_KEY();
|
|
|
|
key_out = (struct ext_key *)*output;
|
|
key_out->version = version;
|
|
key_out->depth = depth;
|
|
key_out->child_num = child_num;
|
|
|
|
if (chain_code)
|
|
memcpy(key_out->chain_code, chain_code, key_size(chain_code));
|
|
if (priv_key && version != BIP32_VER_MAIN_PUBLIC && version != BIP32_VER_TEST_PUBLIC)
|
|
memcpy(key_out->priv_key + 1, priv_key, key_size(priv_key) - 1);
|
|
else
|
|
key_out->priv_key[0] = BIP32_FLAG_KEY_PUBLIC;
|
|
if (pub_key)
|
|
memcpy(key_out->pub_key, pub_key, key_size(pub_key));
|
|
else if (version == BIP32_VER_MAIN_PRIVATE || version == BIP32_VER_TEST_PRIVATE) {
|
|
/* Compute the public key if not given */
|
|
int ret = key_compute_pub_key(key_out);
|
|
if (ret != WALLY_OK) {
|
|
clear(key_out, sizeof(*key_out));
|
|
wally_free(key_out);
|
|
*output = 0;
|
|
return ret;
|
|
}
|
|
}
|
|
if (hash160)
|
|
memcpy(key_out->hash160, hash160, key_size(hash160));
|
|
else
|
|
key_compute_hash160(key_out);
|
|
if (parent160)
|
|
memcpy(key_out->parent160, parent160, key_size(parent160));
|
|
|
|
return WALLY_OK;
|
|
}
|
|
|
|
|
|
#if defined (SWIG_JAVA_BUILD) || defined (SWIG_PYTHON_BUILD)
|
|
|
|
/* Getters for ext_key values */
|
|
|
|
static int getb_impl(const struct ext_key *key_in,
|
|
const unsigned char *src, size_t src_len,
|
|
unsigned char *bytes_out, size_t len)
|
|
{
|
|
if (!key_in || !bytes_out || len != src_len)
|
|
return WALLY_EINVAL;
|
|
memcpy(bytes_out, src, len);
|
|
return WALLY_OK;
|
|
}
|
|
|
|
#define GET_B(name) \
|
|
int bip32_key_get_ ## name(const struct ext_key *key_in, unsigned char *bytes_out, size_t len) { \
|
|
return getb_impl(key_in, key_in->name, sizeof(key_in->name), bytes_out, len); \
|
|
}
|
|
|
|
GET_B(chain_code)
|
|
GET_B(parent160)
|
|
GET_B(hash160)
|
|
GET_B(pub_key)
|
|
|
|
int bip32_key_get_priv_key(const struct ext_key *key_in, unsigned char *bytes_out, size_t len) {
|
|
return getb_impl(key_in, key_in->priv_key + 1, sizeof(key_in->priv_key) - 1, bytes_out, len);
|
|
}
|
|
|
|
|
|
#define GET_I(name) \
|
|
int bip32_key_get_ ## name(const struct ext_key *key_in, size_t *output) { \
|
|
if (output) *output = 0; \
|
|
if (!key_in || !output) return WALLY_EINVAL; \
|
|
*output = key_in->name; \
|
|
return WALLY_OK; \
|
|
}
|
|
|
|
GET_I(depth)
|
|
GET_I(child_num)
|
|
GET_I(version)
|
|
|
|
#endif /* SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD */
|
|
|