psbt: clear Taproot and MuSig2 signatures when joining #36352

pull FlashWayne wants to merge 1 commits into bitcoin:master from FlashWayne:fix-joinpsbts-clear-taproot-sigs changing 2 files +18 −0
  1. FlashWayne commented at 10:35 PM on September 26, 2026: none

    joinpsbts builds a new transaction from the inputs and outputs of the given PSBTs, so any existing signatures are no longer valid for it. PartiallySignedTransaction::AddInput handles that by clearing partial_sigs and the final scriptSig/witness (psbt.cpp:180), but that code predates Taproot and was never extended to the Taproot and MuSig2 fields.

    So a Taproot input that was signed before the join keeps its old taproot_key_path_sig. SignTaproot (sign.cpp:608) doesn't produce a new key path signature when one is already present, so the input can't be completed afterwards:

    • a bech32 (P2WPKH) input: after joinpsbts, walletprocesspsbt re-signs and returns complete: true
    • a bech32m (P2TR) input: taproot_key_path_sig is still there after the join, and walletprocesspsbt / finalizepsbt return complete: false. utxoupdatepsbt, descriptorprocesspsbt and signing again don't help, so the only way out is editing the PSBT by hand.

    Script path signatures (taproot_script_path_sigs) behave the same. For MuSig2 the old public nonce is kept, but the secret nonce is looked up by a session id that includes the old sighash, so no new partial signature is made either.

    This also clears m_tap_key_sig, m_tap_script_sigs, m_musig2_pubnonces and m_musig2_partial_sigs in the v0 branch of AddInput. Participant pubkeys are key data, not signatures, so they're kept. The v2 branch is unchanged: there, adding inputs is governed by the BIP370 modifiable flags.

    The new check in rpc_psbt.py signs a v0 PSBT with a P2TR input, joins it with another one, and checks that the key path signature is gone and the joined PSBT can be signed. It fails on master and passes with the fix. wallet_musig.py still passes.

  2. psbt: clear Taproot and MuSig2 signatures when joining
    joinpsbts builds a new transaction, so signatures made for the original
    ones are no longer valid. PartiallySignedTransaction::AddInput clears
    partial_sigs and the final scriptSig/witness for that reason, but it was
    never updated for the Taproot and MuSig2 fields.
    
    The stale Taproot signature is then kept. SignTaproot only signs when no
    key path signature is present, so the input can't be completed anymore:
    walletprocesspsbt and finalizepsbt keep returning complete=false. Script
    path signatures and MuSig2 partial signatures/nonces have the same
    problem.
    
    Clear m_tap_key_sig, m_tap_script_sigs, m_musig2_pubnonces and
    m_musig2_partial_sigs as well.
    e1aa0baa14
  3. DrahtBot added the label PSBT on Sep 26, 2026
  4. DrahtBot commented at 10:35 PM on September 26, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/36352.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process. A summary of reviews will appear here.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

Contributors
Labels

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-09-28 10:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me