#36122 BIP460: CISA for Taproot key path spends

full analysis

https://github.com/bitcoin/bitcoin/pull/36122 · fjahr · +11288/-488 in 133 files, 22 commits · labels: Needs rebase · draft

Goal

  • Cut transaction fees and witness size by aggregating signatures across multiple inputs.
  • Encourage collaborative transactions like Payjoin and CoinJoin by removing per-input signature overhead.

This pull request provides a reference implementation of BIP460 Cross-Input Signature Aggregation (CISA) for Taproot key path spends. It introduces witness version 2 outputs supporting BIP458 half-aggregation and BIP459 full-aggregation alongside consensus validation in the script engine and check queue. In addition to consensus rules and mempool standardness, it provides draft companion implementations for cisa() descriptors, PSBT extension fields, and wallet signing RPCs.

Problem: Currently, every Taproot key path spend must provide an individual 64-byte Schnorr signature, increasing witness weight linearly with the number of inputs and discouraging collaborative transactions like Payjoin or CoinJoin. BIP460 solves this by allowing multiple inputs within a transaction to share aggregated signatures, significantly reducing witness size and fees.

Category: Mempool and policy (#4 of 10)

P3 · new feature

  • P3 because standardness rules allow relaying aggregated transactions on test networks
  • The policy changes are limited to defining standardness constraints for witness version 2 spends

Updates policy standardness rules (IsWitnessStandard) to permit witness version 2 spends with Taproot-equivalent constraints, enabling test network relay of aggregated transactions.

Membership: Modifies policy.cpp and policy.h to define standardness rules and verification flags for witness version 2.

Factors: security/stability 0, bug 0, performance 1, user value 1, leverage 1

Category: Validation (#12 of 48)

P2 · new feature

  • P2 because cross-input signature aggregation offers substantial block space savings across transactions
  • Consensus rule changes require extensive scrutiny to ensure batch verification and validation safety

Implementing a proposed soft fork represents substantial, strategic work within validation. CISA offers significant block space savings and efficiency gains across multi-input transactions. Consensus rule additions require extensive and deliberate review to ensure validation invariants, batch verification safety, and resource limits are sound.

Membership: Implements witness version 2 consensus validation rules, interpreter checks, checkqueue aggregation, and versionbits deployment.

Factors: security/stability 1, bug 0, performance 2, user value 2, leverage 2

Category: Wallet (#66 of 84)

P3 · new feature

  • P3 because descriptor and PSBT tooling enables prototyping multi-party aggregated transactions
  • Tooling remains speculative until consensus rules are finalized

Provides practical tooling for descriptor wallets and PSBT coordinators to construct and sign aggregated transactions. While valuable for testing and multi-party protocol prototyping, the draft BIPs and wallet support are speculative ahead of consensus finalization.

Membership: Implements cisa() descriptors, PSBT aggregation roles, reservecisanonce RPC, and transaction signing for witness v2.

Factors: security/stability 0, bug 0, performance 1, user value 2, leverage 1

Reviewability: Stale: Needs rebase

  • Wait for a rebase to resolve merge conflicts.
  • Author noted this is a draft reference implementation not yet intended for upstream merge.

The PR has merge conflicts with the base branch and is marked dirty with the 'Needs rebase' label. In addition, the author stated that this is a draft reference implementation accompanying the BIPs and not yet intended for upstream merge.

Author status: silent since 2026-09-08 (9 days), waiting on author response to BarneyChambers review comments for 2 days

Open concerns:

  • Dummy member witness signatures cause signrawtransactionwithwallet to prematurely report complete=true because script verification succeeds on per-input marker parsing alone (BarneyChambers)
  • combinepsbt silently keeps the first half-aggregation signature instead of detecting conflicts or incompatible inputs (BarneyChambers)
  • FinalizeCISAInputs skips already-signed inputs, which can partition inputs of the same mode into invalid duplicate groups that fail consensus (BarneyChambers)

Agreement: Mild

  • Commended consensus and policy test coverage after running local tests (BarneyChambers)
  • Reported three bugs in wallet signing and PSBT aggregation that break completion states (BarneyChambers)
  • Author has not yet replied to the reported wallet issues

Mild: BarneyChambers tested the branch and found three bugs in wallet signing and PSBT handling; author has not yet replied.

BarneyChambers gave positive feedback on the consensus and policy test coverage after running local tests, but reported three concrete bugs in the wallet and PSBT aggregation handling that produce invalid transactions or incorrect completion states. The author has not yet addressed these findings.

  • BarneyChambers noted that both feature_cisa.py and wallet_cisa.py passed and consensus/policy coverage looks great, but filed three inline issues regarding PSBT and wallet behavior.
  • BarneyChambers demonstrated that VerifyScript returning success on markers causes signrawtransactionwithwallet to report complete=true for incomplete spends.
  • BarneyChambers showed combinepsbt silently keeps the first half-agg signature even when inputs conflict, unlike full-agg.
  • BarneyChambers demonstrated FinalizeCISAInputs produces consensus-invalid duplicate groups when inputs are signed incrementally.

Review verdicts (DrahtBot): 0

Files

3523 lines under test/bench/ci.

  • src/secp256k1/src/modules/schnorrsig_halfagg/vectors.h +1162/-0
  • src/secp256k1/src/modules/fullagg/main_impl.h +1043/-0
  • src/test/data/cisa_consensus_vectors.json +950/-0
  • src/secp256k1/src/modules/fullagg/vectors.h +702/-0
  • src/secp256k1/src/modules/fullagg/tests_impl.h +586/-0
  • src/test/data/cisa_descriptor_vectors.json +496/-0
  • test/functional/feature_cisa.py +484/-0
  • src/secp256k1/include/secp256k1_fullagg.h +448/-0
  • src/test/cisa_tests.cpp +353/-0
  • src/secp256k1/src/modules/schnorrsig_halfagg/tests_impl.h +329/-0
  • src/test/data/cisa_psbt_vectors.json +310/-0
  • test/functional/wallet_cisa.py +257/-0
  • src/secp256k1/tools/test_vectors_halfagg_generate.py +237/-0
  • src/test/data/cisa_wallet_vectors.json +222/-0
  • src/secp256k1/src/modules/schnorrsig_halfagg/main_impl.h +219/-0
  • src/secp256k1/tools/test_vectors_fullagg_generate.py +214/-0
  • src/secp256k1/examples/fullagg.c +208/-0
  • src/script/interpreter.cpp +173/-12
  • src/cisa.cpp +177/-0
  • src/test/psbt_tests.cpp +169/-0
  • src/script/sign.cpp +131/-21
  • src/secp256k1/src/modules/musig/session_impl.h +26/-118
  • src/psbt.cpp +129/-5
  • src/secp256k1/src/modules/nonce_common_impl.h +121/-0
  • src/secp256k1/examples/halfagg.c +115/-0
  • src/secp256k1/include/secp256k1_schnorrsig_halfagg.h +112/-0
  • src/secp256k1/src/modules/fullagg/bench_impl.h +106/-0
  • test/functional/test_framework/cisa.py +106/-0
  • src/secp256k1/src/tests.c +51/-38
  • src/secp256k1/configure.ac +59/-25
  • src/script/descriptor.cpp +44/-35
  • src/test/descriptor_tests.cpp +75/-0
  • src/secp256k1/src/modules/schnorrsig_halfagg/bench_impl.h +74/-0
  • src/wallet/rpc/spend.cpp +70/-4
  • src/psbt.h +70/-0
  • src/secp256k1/.github/workflows/ci.yml +54/-15
  • src/cisa.h +66/-0
  • src/secp256k1/src/ecmult_gen_impl.h +33/-33
  • src/secp256k1/src/group_impl.h +61/-0
  • src/validation.cpp +56/-4
  • src/secp256k1/src/ctime_tests.c +55/-0
  • src/secp256k1/doc/fullagg.md +54/-0
  • src/secp256k1/src/bench.c +52/-2
  • src/secp256k1/src/modules/nonce_common.h +52/-0
  • src/pubkey.cpp +51/-0
  • src/script/interpreter.h +43/-4
  • src/validation.h +44/-3
  • src/secp256k1/src/eckey_impl.h +2/-41
  • src/secp256k1/src/secp256k1.c +23/-16
  • src/script/signingprovider.cpp +38/-0
  • src/secp256k1/Makefile.am +35/-1
  • src/secp256k1/src/modules/ellswift/main_impl.h +16/-17
  • doc/psbt.md +27/-0
  • src/rpc/rawtransaction.cpp +21/-4
  • src/script/sign.h +25/-0
  • src/secp256k1/doc/halfagg.md +22/-0
  • src/rpc/util.cpp +21/-0
  • src/secp256k1/src/CMakeLists.txt +21/-0
  • src/secp256k1/src/modules/silentpayments/main_impl.h +10/-10
  • src/core_io.cpp +19/-0
  • src/wallet/scriptpubkeyman.cpp +16/-2
  • src/secp256k1/src/group.h +17/-0
  • src/test/transaction_tests.cpp +11/-4
  • test/functional/rpc_blockchain.py +14/-1
  • test/functional/rpc_deriveaddresses.py +15/-0
  • src/key_io.cpp +14/-0
  • src/secp256k1/src/modules/ecdh/main_impl.h +6/-8
  • src/wallet/wallet.cpp +12/-0
  • src/addresstype.cpp +11/-0
  • src/script/signingprovider.h +11/-0
  • src/test/script_standard_tests.cpp +8/-3
  • src/secp256k1/src/eckey.h +2/-8
  • src/secp256k1/src/ecmult_gen.h +5/-5
  • src/secp256k1/src/scratch_impl.h +8/-2
  • src/test/txvalidationcache_tests.cpp +5/-5
  • src/addresstype.h +8/-1
  • test/functional/p2p_segwit.py +5/-4
  • src/script/script_error.cpp +8/-0
  • src/secp256k1/examples/CMakeLists.txt +8/-0
  • src/secp256k1/src/modules/musig/keyagg_impl.h +4/-4
  • src/secp256k1/src/modules/schnorrsig/main_impl.h +4/-4
  • src/kernel/chainparams.cpp +7/-0
  • src/script/script.cpp +7/-0
  • src/secp256k1/CMakeLists.txt +7/-0
  • src/wallet/wallet.h +7/-0
  • src/common/types.h +6/-0
  • src/key.cpp +6/-0
  • src/policy/policy.h +4/-2
  • src/pubkey.h +6/-0
  • src/script/script_error.h +6/-0
  • src/secp256k1/src/bench_internal.c +3/-3
  • src/wallet/scriptpubkeyman.h +6/-0
  • src/policy/policy.cpp +3/-2
  • src/script/solver.cpp +5/-0
  • src/secp256k1/src/modules/fullagg/Makefile.am.include +5/-0
  • src/secp256k1/src/modules/schnorrsig_halfagg/Makefile.am.include +5/-0
  • src/test/CMakeLists.txt +5/-0
  • src/test/fuzz/util.cpp +4/-1
  • doc/descriptors.md +3/-1
  • src/deploymentinfo.cpp +4/-0
  • src/key.h +4/-0
  • src/secp256k1/README.md +4/-0
  • src/secp256k1/ci/ci.sh +3/-1
  • src/secp256k1/src/bench_ecmult.c +2/-2
  • src/secp256k1/src/ecdsa_impl.h +2/-2
  • src/secp256k1/src/field.h +2/-2
  • src/secp256k1/src/modules/ecdh/tests_impl.h +2/-2
  • src/secp256k1/src/modules/musig/tests_impl.h +2/-2
  • src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h +2/-2
  • src/secp256k1/src/modules/schnorrsig/tests_impl.h +2/-2
  • src/test/versionbits_tests.cpp +4/-0
  • test/functional/feature_taproot.py +4/-0
  • test/functional/test_framework/psbt.py +4/-0
  • cmake/secp256k1.cmake +3/-0
  • src/node/psbt.cpp +2/-1
  • src/rpc/blockchain.cpp +3/-0
  • src/rpc/client.cpp +3/-0
  • src/core_io.h +2/-0
  • src/secp256k1/.gitignore +2/-0
  • src/secp256k1/src/ecdsa.h +1/-1
  • src/secp256k1/src/modules/ellswift/tests_impl.h +1/-1
  • src/secp256k1/src/testrand_impl.h +1/-1
  • src/wallet/rpc/wallet.cpp +2/-0
  • test/functional/mining_basic.py +1/-1
  • test/functional/test_runner.py +2/-0
  • src/CMakeLists.txt +1/-0
  • src/consensus/params.h +1/-0
  • src/outputtype.cpp +1/-0
  • src/rpc/util.h +1/-0
  • src/script/script.h +1/-0
  • src/script/solver.h +1/-0
  • src/wallet/feebumper.h +1/-0
  • src/wallet/rpc/addresses.cpp +1/-0

Card

Fabian Jahr implements a reference implementation of BIP460 Cross-Input Signature Aggregation (CISA) for Taproot key path spends, introducing witness version 2 outputs that support BIP458 half-aggregation and BIP459 full-aggregation. The PR includes consensus validation rules in the script engine and check queue, mempool standardness, wallet descriptors, PSBT fields, and signing infrastructure. The PR was explicitly opened as an experimental draft to accompany the BIP proposals rather than for immediate upstream merge, but soft fork proposals require deliberate review to evaluate consensus invariants and verification performance. The branch currently needs a rebase against master and awaits author response to three wallet and PSBT bugs identified during review by Barney Chambers.

Data

dossier JSON · extract JSON · model openrouter/google/gemini-3.8-flash, generated 2026-09-17T15:58, confidence high, input hash 65504dee64d85c37