psbt: avoid aborting on invalid MuSig2 derivations

`SignMuSig2()` derives MuSig2 aggregate keys from metadata supplied by a PSBT.
A hardened child cannot be publicly derived, and a path that produces another key does not identify the aggregate being signed.

Check each child index as `uint32_t` immediately before deriving that child, preserving the hardened bit without an implementation-defined conversion to `int`.
Return failure if a child index is hardened, and skip a path if it derives to a different key so another aggregate can still be tried.
The descriptor parser enforces the same requirement for MuSig2 aggregate derivations.

Co-authored-by: Anthropic Security <security-cvd@anthropic.com>
Co-authored-by: Evan Sultanik <evan.sultanik@trailofbits.com>
Co-authored-by: Ava Chow <github@achow101.com>
This commit is contained in:
Lőrinc
2026-08-06 14:16:08 -07:00
parent e3d1e75a51
commit 73a94b4545
2 changed files with 5 additions and 7 deletions

View File

@@ -57,7 +57,6 @@ from test_framework.util import (
assert_equal,
assert_greater_than,
assert_greater_than_or_equal,
assert_raises,
assert_raises_rpc_error,
find_vout_for_address,
wallet_importprivkey,
@@ -320,10 +319,8 @@ class PSBTTest(BitcoinTestFramework):
PSBT_IN_TAP_INTERNAL_KEY: script_pubkey,
bytes([PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS]) + aggregate_pubkey: [participant_pubkey],
}).to_base64()
assert_raises(Exception, node.analyzepsbt, psbt) # TODO: Unexpected derivation metadata should not abort the node
self.start_node(0)
assert_raises(Exception, node.finalizepsbt, psbt) # TODO: Unexpected derivation metadata should not abort the node
self.start_node(0)
assert_equal(node.analyzepsbt(psbt)["inputs"][0]["is_final"], False)
assert_equal(node.finalizepsbt(psbt)["complete"], False)
def test_combinepsbt_preserves_proprietary_fields(self):
self.log.info("Test that combining PSBTs preserves proprietary fields")