Summary
- Detect invalid signatures in
analyzepsbtby checking for the case whereSignPSBTInputreturns incomplete, nomissing_*fields are populated, yet signature data exists — meaning the signature is present but cryptographically invalid - Report a clear error (
"PSBT is not valid. Input N has an invalid signature") instead of the confusing"next": "updater"fallback - Add functional test covering the exact scenario from #33320 (corrupted taproot key path signature)
Problem
When a PSBT input has an invalid taproot_key_path_sig (e.g. a script path sig mistakenly placed in the key path field by external software like HWI), analyzepsbt returns "next": "updater" with no error message.
This happens because SignTaproot in ProduceSignature finds the existing signature data and returns solved = true, but VerifyScript (with the real MutableTransactionSignatureChecker) fails the cryptographic check, setting sigdata.complete = false. Back in AnalyzePSBT, the missing_* fields
are all empty — taproot signing never populates them — so the code falls through to the UPDATER fallback.
Approach
Rather than adding a separate signature verification step, this relies on the verification that already happens inside ProduceSignature → VerifyScript. When AnalyzePSBT calls SignPSBTInput with real PrecomputedTransactionData, the signature is verified against the actual transaction via
libsecp256k1. If that fails but nothing is missing, the signature must be invalid.
The check also covers m_tap_script_sigs and partial_sigs for completeness, though the primary motivation is the taproot key path case from #33320.
Note: a previous attempt at this fix (#33360) was closed because it used DUMMY_SIGNATURE_CREATOR/DUMMY_CHECKER which accept any non-empty signature, and its hand-crafted test PSBT was malformed.
Test plan
-
python3 test/functional/rpc_psbt.py— includes new test for corrupted taproot key path sig -
build/bin/test_bitcoin -t psbt_wallet_tests— no regressions in C++ unit tests
Fixes #33320