Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/wally.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,12 @@ inline int bip340_tagged_hash(const BYTES& bytes, const TAG& tag, BYTES_OUT& byt
return detail::check_ret(__FUNCTION__, ret);
}

template <class BYTES>
inline bool bip341_control_block_verify(const BYTES& bytes) {
int ret = ::wally_bip341_control_block_verify(bytes.data(), bytes.size());
return ret == WALLY_OK;
}

template <class BYTES>
inline int bzero(BYTES& bytes) {
int ret = ::wally_bzero(bytes.data(), bytes.size());
Expand Down
10 changes: 10 additions & 0 deletions include/wally_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,16 @@ WALLY_CORE_API int wally_merkle_path_xonly_public_key_verify(
const unsigned char *val,
size_t val_len);

/**
* Verify a taproot control block as specified in BIP-0341.
*
* :param bytes: Control block bytes.
* :param bytes_len: Length of ``bytes`` in bytes. Must be at least `EC_XONLY_PUBLIC_KEY_LEN` + 1.
*/
WALLY_CORE_API int wally_bip341_control_block_verify(
const unsigned char *bytes,
size_t bytes_len);

/**
* Allocate and initialize a new BIP32 keypath map.
*
Expand Down
15 changes: 13 additions & 2 deletions src/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,11 +667,22 @@ int wally_merkle_path_xonly_public_key_verify(const unsigned char *key, size_t k

if (key_len != EC_XONLY_PUBLIC_KEY_LEN ||
keypath_key_verify(key, key_len, &extkey) != WALLY_OK ||
extkey.version || BYTES_INVALID(val, val_len) || val_len % SHA256_LEN != 0)
extkey.version || BYTES_INVALID(val, val_len))
return WALLY_EINVAL;
if (val_len && (val_len % SHA256_LEN || val_len % SHA256_LEN > 128u))
return WALLY_EINVAL;
return WALLY_OK;
}

int wally_bip341_control_block_verify(const unsigned char *bytes, size_t bytes_len)
{
const size_t min_len = 1 + EC_XONLY_PUBLIC_KEY_LEN;
if (bytes_len < min_len)
return WALLY_EINVAL; /* Missing parity byte and/or x-only pubkey */
return wally_merkle_path_xonly_public_key_verify(bytes + 1, EC_XONLY_PUBLIC_KEY_LEN,
bytes_len == min_len ? NULL : bytes + min_len, bytes_len - min_len);
}

int wally_map_keypath_bip32_init_alloc(size_t allocation_len, struct wally_map **output)
{
return wally_map_init_alloc(allocation_len, wally_keypath_bip32_verify, output);
Expand Down Expand Up @@ -727,7 +738,7 @@ int wally_map_merkle_path_add(struct wally_map *map_in,

/* Add map for tap leaves */
return map_add(map_in, pub_key, pub_key_len,
merkle_hashes, merkle_hashes_len, false, false);
merkle_hashes, merkle_hashes_len, false, true);
}

int wally_keypath_get_fingerprint(const unsigned char *val, size_t val_len,
Expand Down
16 changes: 5 additions & 11 deletions src/psbt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ static int psbt_init(uint32_t version, size_t num_inputs, size_t num_outputs,
wally_free(psbt_out->inputs);
wally_free(psbt_out->outputs);
wally_map_clear(&psbt_out->unknowns);
wally_clear(psbt_out, sizeof(psbt_out));
wally_clear(psbt_out, sizeof(*psbt_out));
return ret != WALLY_OK ? ret : WALLY_ENOMEM;
}

Expand Down Expand Up @@ -2217,22 +2217,15 @@ static int pull_taproot_leaf_signature(const unsigned char **cursor, size_t *max
return map_add(leaf_sigs, xonly_hash, 64u, val, val_len, false, false);
}

static bool is_valid_control_block_len(size_t ctrl_len)
{
return ctrl_len >= 33u && ctrl_len <= 33u + 128u * 32u &&
((ctrl_len - 33u) % 32u) == 0;
}

static int pull_taproot_leaf_script(const unsigned char **cursor, size_t *max,
const unsigned char **key, size_t *key_len,
struct wally_map *leaf_scripts)
{
/* TODO: use taproot constants here */
const unsigned char *ctrl, *val;
size_t ctrl_len = *key_len, val_len;

ctrl = pull_skip(key, key_len, ctrl_len);
if (!ctrl || !is_valid_control_block_len(ctrl_len))
if (wally_bip341_control_block_verify(ctrl, ctrl_len) != WALLY_OK)
return WALLY_EINVAL;
subfield_nomore_end(cursor, max, *key, *key_len);

Expand Down Expand Up @@ -2987,7 +2980,8 @@ static int push_taproot_leaf_scripts(unsigned char **cursor, size_t *max, size_t
for (i = 0; i < leaf_scripts->num_items; ++i) {
const struct wally_map_item *item = leaf_scripts->items + i;

if (!is_valid_control_block_len(item->key_len) || !item->value_len)
if (wally_bip341_control_block_verify(item->key, item->key_len) != WALLY_OK ||
!item->value_len)
return WALLY_EINVAL;

push_key(cursor, max, ft, false, item->key, item->key_len);
Expand Down Expand Up @@ -3961,7 +3955,7 @@ static int psbt_build_input(const struct wally_psbt_input *src,
BUILD_ITEM(inflation_keys_rangeproof, PSET_IN_ISSUANCE_INFLATION_KEYS_RANGEPROOF);
struct wally_map_item issuance_amount_item = { NULL, 0, issuance_amount, sizeof(issuance_amount) };
struct wally_map_item inflation_keys_item = { NULL, 0, inflation_keys, sizeof(inflation_keys) };
int src_index = src->index;
uint32_t src_index = src->index;

if (src->issuance_amount || src->inflation_keys || issuance_amount_commitment || inflation_keys_commitment)
src_index |= WALLY_TX_ISSUANCE_FLAG;
Expand Down
2 changes: 1 addition & 1 deletion src/sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ int wally_ec_sig_from_bytes_aux(const unsigned char *priv_key, size_t priv_key_l
ret = WALLY_EINVAL;
else if (!secp256k1_schnorrsig_sign32(ctx, bytes_out, bytes, &keypair, aux_rand))
ret = WALLY_ERROR;
wally_clear(&keypair, sizeof(&keypair));
wally_clear(&keypair, sizeof(keypair));
return ret;
} else {
unsigned char extra_entropy[32] = {0}, *entropy_p = (unsigned char *)aux_rand;
Expand Down
1 change: 1 addition & 0 deletions src/swig_java/swig.i
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ static jobjectArray create_jstringArray(JNIEnv *jenv, char **p, size_t len) {
%returns_string(wally_bip32_key_to_address);
%returns_string(wally_bip32_key_to_addr_segwit);
%returns_array_(wally_bip340_tagged_hash, 4, 5, SHA256_LEN);
%returns_void__(wally_bip341_control_block_verify)
%returns_size_t(wally_coinselect_assets);
%returns_string(wally_confidential_addr_to_addr);
%returns_array_(wally_confidential_addr_to_ec_public_key, 3, 4, EC_PUBLIC_KEY_LEN);
Expand Down
18 changes: 18 additions & 0 deletions src/swig_python/contrib/psbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,23 @@ def check_keypath(self, keypaths, master, derived, pubkey, fingerprint, path):
key = map_keypath_get_bip32_key_from(keypaths, 0, master)
self.assertEqual(bip32_key_serialize(key, 0), bip32_key_serialize(derived, 0))

def check_taproot_keypath(self):
# TODO: add in-situ checks on the PSBT fields
# BIP-0341 control block
parity = hex_to_bytes('55')
xonly = hex_to_bytes('22' * 32)
bad_xonly = hex_to_bytes('04' + '22' * 32)
path_elem = hex_to_bytes('00' * 32)
bip341_control_block_verify(parity + xonly) # No path, OK
bip341_control_block_verify(parity + xonly + path_elem) # 1 path element, OK
for args in [
None, # Null control block
parity + bad_xonly + path_elem, # Bad x-only pubkey
parity + bad_xonly + path_elem[:-1], # Path length not modulo 32
parity + bad_xonly + path_elem * 129, # Path length too long
]:
self.assertRaises(ValueError, lambda: bip341_control_block_verify(args))

def check_txout(self, lhs, rhs):
self.assertEqual(tx_output_get_satoshi(lhs), tx_output_get_satoshi(rhs))
self.assertEqual(tx_output_get_script(lhs), tx_output_get_script(rhs))
Expand Down Expand Up @@ -350,6 +367,7 @@ def test_psbt(self):
map_keypath_add(dummy_keypaths, dummy_pubkey, dummy_fingerprint, dummy_path)
self.check_keypath(dummy_keypaths, master, derived,
dummy_pubkey, dummy_fingerprint, dummy_path)
self.check_taproot_keypath()

empty_signatures = map_init(0, None)
dummy_signatures = map_init(0, None) # TODO: pubkey to sig map init
Expand Down
1 change: 1 addition & 0 deletions src/test/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ class wally_psbt(Structure):
('wally_bip32_key_to_addr_segwit', c_int, [POINTER(ext_key), c_char_p, c_uint32, c_char_p_p]),
('wally_bip32_key_to_address', c_int, [POINTER(ext_key), c_uint32, c_uint32, c_char_p_p]),
('wally_bip340_tagged_hash', c_int, [c_void_p, c_size_t, c_char_p, c_void_p, c_size_t]),
('wally_bip341_control_block_verify', c_int, [c_void_p, c_size_t]),
('wally_bzero', c_int, [c_void_p, c_size_t]),
('wally_cleanup', c_int, [c_uint32]),
('wally_coinselect_assets', c_int, [POINTER(c_uint64), c_size_t, c_uint64, c_uint64, c_uint32, POINTER(c_uint32), c_size_t, c_size_t_p]),
Expand Down
1 change: 1 addition & 0 deletions src/wasm_package/src/functions.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/wasm_package/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export function bip32_path_from_str_n_len(path_str: string, path_str_len: number
export function bip32_path_str_get_features(path_str: string): number;
export function bip32_path_str_n_get_features(path_str: string, path_str_len: number): number;
export function bip340_tagged_hash(bytes: Buffer|Uint8Array, tag: string): Buffer;
export function bip341_control_block_verify(bytes: Buffer|Uint8Array): void;
export function bip38_get_flags(bip38: string): number;
export function bip38_raw_get_flags(bytes: Buffer|Uint8Array): number;
export function bip39_get_languages(): string;
Expand Down
1 change: 1 addition & 0 deletions tools/wasm_exports.sh
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ EXPORTED_FUNCTIONS="['_malloc','_free','_bip32_key_free' \
,'_wally_bip32_key_to_addr_segwit' \
,'_wally_bip32_key_to_address' \
,'_wally_bip340_tagged_hash' \
,'_wally_bip341_control_block_verify' \
,'_wally_bzero' \
,'_wally_cleanup' \
,'_wally_descriptor_canonicalize' \
Expand Down
Loading