psbt: use control block verification call internally
What changed, and why it matters
This commit replaces a simple length check on Taproot control blocks with a dedicated verification function. The change is likely a hardening or correctness improvement rather than a clear-cut security fix. The old check only ensured the control block had a valid-looking size; the new function may also validate internal structure, such as the parity bit and merkle proof path. Without the implementation of the new verification function, we cannot confirm whether it closes a real vulnerability or just reduces duplicated logic.
Review the implementation of wally_bip341_control_block_verify to confirm it enforces all BIP341 control-block rules (valid parity byte, valid internal public key, valid merkle path). If the function only repeats the length check, this is a refactor; if it adds missing validation, consider whether a CVE or advisory is warranted. No immediate action is required solely from this diff.
Security signals we found
Replaced length-only validation with a dedicated BIP341 control-block verification routine
Removed duplicated inline length check in favor of a centralized validation call
Parsing and serialization paths for Taproot leaf scripts now share the same validation logic
Evidence from the diff
In src/psbt.c, the local helper is_valid_control_block_len() was removed. Two call sites now use wally_bip341_control_block_verify() instead: pull_taproot_leaf_script() when parsing PSBT key data, and push_taproot_leaf_scripts() when serializing. The old helper accepted any byte length of the form 33 + 32*k for k=0..128. The new function presumably performs additional BIP341-specific validation. The diff alone does not show the new function’s body, so the exact security difference is unverified.
Changed components
src/psbt.cPSBT Taproot leaf script parsing (pull_taproot_leaf_script)PSBT Taproot leaf script serialization (push_taproot_leaf_scripts)Inspect captured patch +3 / −9
diff --git a/src/psbt.c b/src/psbt.c
index 5f47472..74b46a5 100644
--- a/src/psbt.c
+++ b/src/psbt.c
@@ -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);
@@ -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);
Why this scored 35/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.