#36122 BIP460: CISA for Taproot key path spends

ReviewabilityReviewsAgreementSize
#36122 fjahr BIP460: CISA for Taproot key path spendsWaiting on author0Strong7,680 + 3,565 tests
  • Allow cross-input signature aggregation for Taproot key path spends to reduce transaction size and fees
  • Lower fee overhead for multi-party collaborative transactions like CoinJoin and Payjoin
  • Worth reviewing now, but check if CI failures are caused by this PR before a deep review
  • No review verdicts recorded
  • Substantive support after testing consensus logic against BIP460 vectors and edge cases (fametrano)
  • Objections regarding wallet signing and PSBT input grouping were addressed in code (BarneyChambers)
  • Open suggestion to update vendored consensus test vectors to match the latest BIP copy (fametrano)
  • 7,680 lines added or modified outside tests
  • 3,565 lines added or modified in tests
  • 219 lines removed in total
  • 111 files, 22 commits
Mempool and policy#13 of 14
P3 · new feature
  • P3 because it establishes standardness rules for witness version 2 spends
  • It provides a clear relay specification to test cross-input aggregation before activation
Utilities (logging, arguments, libraries)#46 of 59
P3 · new feature
  • P3 because it vendors experimental half- and full-aggregation modules from libsecp256k1
  • It provides the cryptographic primitives necessary to test the proposed aggregation BIPs
  • Ranking pass: Moved down: an explicitly draft reference implementation accompanying unmerged BIPs and unmerged secp256k1 modules.
Validation#23 of 53
P2 · new feature
  • P2 because it supplies the consensus reference implementation for BIP460 soft-fork validation
  • Evaluating consensus rules and validation safety is critical for the long-term consensus roadmap
Wallet#80 of 92
P4 · new feature
  • P4 after comparing with the other PRs here (assessed alone as P3): Lowered from P3: explicitly a draft accompanying unaccepted BIPs and vendoring unmerged libsecp256k1 work; wallet value is speculative until consensus work lands.
  • P3 because it introduces descriptor and PSBT support for aggregated Taproot spends
  • It allows wallet users to construct and test multi-party collaborative transactions end to end
Reviewability: ReadyStalePaused
Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets
Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs.
Size: lines added or modified outside tests, then in tests; greener = smaller.

Goal

Implements a reference implementation of BIP460 Cross-Input Signature Aggregation (CISA) for Taproot key path spends using witness version 2 outputs. Includes consensus script verification, check queue validation, mempool standardness, descriptor support (`cisa()`), PSBT fields, and wallet signing using BIP458 half-aggregation and BIP459 full-aggregation from an updated secp256k1 subtree.

Problem: Every Taproot key path spend requires an individual 64-byte Schnorr signature, increasing transaction size and fees linearly with the number of inputs and disincentivizing multi-party collaborative transactions like CoinJoin or Payjoin.

Evidence of importance:

Scope: Contains a large libsecp256k1 subtree update (+11k lines) bringing in experimental halfagg and fullagg modules, consensus changes for witness v2 script validation, and activation restricted to regtest only.

Risk of a mistake: high (consensus, validation, mempool_policy, wallet, rpc_api, build, tests). Introduces new consensus validation rules and script verification logic that, if flawed or inconsistent across nodes, would cause consensus splits.

Changed since the previous assessment: Added commits decoupling full aggregation nonces from the signed message, introducing the `reservecisanonce` wallet RPC to pre-share BIP459 nonces, and adding corresponding unit and functional tests.

Reviewability

Paused · Waiting on author

Open objection from fametrano with no author reply for 7 days; review would repeat what has been asked.

Waiting on (from the thread read):

  • author: response to suggestion to update vendored cisa_consensus_vectors.json 2026-10-25
  • reviewer: BarneyChambers to check the fixes for wallet and PSBT handling 2026-09-21
  • author: update vendored cisa_consensus_vectors.json from BIP repo 2026-10-25
  • reviewer: BarneyChambers to check fixes for wallet and PSBT handling 2026-09-21

Agreement

Strong

substantive support, no open objection (fametrano)

Thread notes: Added fametrano's testing support and suggestion to update vendored test vectors. Updated BarneyChambers' code defects to fixed with clears_with=change following the pushed fixes. / Updated existing claims under current schema: rc:4015169298 and rc:4015234807 were fixed in code by the author, so their clears_with is set to change and status to fixed. Added fametrano's Tested ACK and their suggestion to update the vendored test vectors.

Objections, suggestions, and questions:

ReviewerTypeHarm, request, or questionStatusMust beAuthor repliedQuote
BarneyChambers (none)objection, correctnesssignrawtransactionwithwallet prematurely reports complete=true on incomplete spends with dummy member witnesses because per-input script verification succeeds on markersfixed · fix pushed · author added tx-level VerifyCISATransaction check in SignTransaction and a wallet testchangedyes2026-09-15: 'ProduceSignature and DataFromTransaction then treat that success as complete, so a dummy member looks fully signed.'
Status from: 2026-09-21: fjahr: 'SignTransaction now runs VerifyCISATransaction once all inputs are processed and reports the error on the aggregated inputs'
BarneyChambers (none)objection, correctnesscombinepsbt silently keeps the first half-aggregation signature instead of detecting conflicting signatures across inputsanswered · author explained keeping first is intended per BIP 174/371 and added test showing invalid sigs fail finalizationansweredyes2026-09-15: 'Half-agg signatures do not get checked the same way. Merge keeps the first m_cisa_halfagg_sig it sees.'
Status from: 2026-09-21: fjahr: 'This is intended, halfagg has no signing session so two different signatures for the same input can both be valid and either one aggregates fine.'
BarneyChambers (none)objection, correctnessFinalizeCISAInputs skipping already-signed inputs can partition inputs into duplicate groups of the same mode that fail consensusfixed · fix pushed · author updated FinalizeCISAInputs to close group once an input has a final witnesschangedyes2026-09-15: 'This skip on already-signed inputs can leave you with two separate groups of the same mode. Consensus then fails the tx with SCRIPT_ERR_CISA_GROUP_INVALID'
Status from: 2026-09-21: fjahr: 'The finalizer should treat a group as closed once any input of that mode has a final witness and I have changed FinalizeCISAInputs to do that'
fametrano (contributor)suggestion, maintenanceupdate vendored cisa_consensus_vectors.json to match the updated BIP copyopenansweredno2026-10-25: 'The vendored cisa_consensus_vectors.json is older than the BIP's copy. Its marker-undefined case is optout-sighash-undefined there, with the same transaction, now an opted-out signature with an undefined sighash type, which is how the BIP text reads 0xbb. Copying the BIP's file over fixes it.'

Support:

  • fametrano (contributor) (2026-10-25) [both: cisa_consensus_vectors.json, cisa_tests, consensus code, feature_cisa.py, wallet vectors, wallet_cisa.py]: the consensus code agrees with BIP460's vectors and with 35 extra edge cases, checked against maintained libraries

Participants:

  • BarneyChambers (none, objection, 4 statements 2026-09-15 to 2026-09-15): tested functional tests and raised three wallet and PSBT issues, which the author addressed
  • fametrano (contributor, support, 1 statements 2026-10-25 to 2026-10-25): tested against BIP460 vectors and 35 edge cases; suggested updating vendored test vectors

Files

3584 lines under test/bench/ci.

  • src/secp256k1/src/modules/schnorrsig_halfagg/vectors.h +1162/-0
  • src/secp256k1/src/modules/fullagg/main_impl.h +1144/-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 +618/-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 +371/-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 +300/-0
  • src/secp256k1/tools/test_vectors_halfagg_generate.py +237/-0
  • src/test/data/cisa_wallet_vectors.json +222/-0
  • src/secp256k1/tools/test_vectors_fullagg_generate.py +214/-0
  • src/secp256k1/src/modules/schnorrsig_halfagg/main_impl.h +211/-0
  • src/secp256k1/examples/fullagg.c +208/-0
  • src/cisa.cpp +192/-0
  • src/script/interpreter.cpp +173/-12
  • src/test/psbt_tests.cpp +169/-0
  • src/script/sign.cpp +138/-21
  • src/secp256k1/src/tests.c +108/-46
  • src/psbt.cpp +134/-5
  • 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/ctime_tests.c +96/-0
  • src/secp256k1/configure.ac +59/-24
  • 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/cisa.h +71/-0
  • src/psbt.h +70/-0
  • src/secp256k1/.github/workflows/ci.yml +47/-15
  • src/validation.cpp +56/-4
  • src/secp256k1/doc/fullagg.md +54/-0
  • src/secp256k1/src/bench.c +52/-1
  • src/pubkey.cpp +51/-0
  • src/script/interpreter.h +43/-4
  • src/validation.h +44/-3
  • src/secp256k1/src/group_impl.h +34/-6
  • src/script/signingprovider.cpp +38/-0
  • src/secp256k1/Makefile.am +33/-1
  • 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/core_io.cpp +19/-0
  • src/wallet/scriptpubkeyman.cpp +16/-2
  • src/secp256k1/src/secp256k1.c +15/-1
  • 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/wallet/wallet.cpp +12/-0
  • src/addresstype.cpp +11/-0
  • src/script/signingprovider.h +11/-0
  • src/secp256k1/src/group.h +9/-2
  • src/test/script_standard_tests.cpp +8/-3
  • 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/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/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/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/modules/musig/session_impl.h +1/-1
  • src/secp256k1/src/modules/silentpayments/main_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

The short text the ranking pass compares across PRs.

This PR provides a draft reference implementation of BIP460 Cross-Input Signature Aggregation (CISA) for Taproot key path spends as witness version 2 outputs. It addresses linear witness byte bloat across multi-input transactions by allowing inputs to aggregate Schnorr signatures using BIP458 half-aggregation or BIP459 full-aggregation. It includes consensus rules, check queue integration, mempool policy, descriptors, PSBT handling, and wallet signing. The author explicitly notes this is a draft to accompany BIP proposals and not intended for immediate merge, and it vendors unmerged experimental libsecp256k1 PRs.

Data

dossier JSON · extract JSON · model ledger, generated 2026-10-26T01:22, confidence high, input hash fd0717ddd402b329
thread read through 2026-10-25 (9 statements), head 07addd3748
labels: Needs rebase, CI failed · draft

Categories

Mempool and policy

P3 · new feature

Defines policy standardness rules for witness v2 transactions to support cross-input signature aggregation safely before full activation. Policy rules for experimental soft fork proposals provide a clear specification for transaction relay and acceptance.

Membership: Implements mempool standardness and policy rules for witness version 2 CISA spends in src/policy/policy.cpp.

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

Utilities (logging, arguments, libraries)

P3 · new feature (ranking pass: Moved down: an explicitly draft reference implementation accompanying unmerged BIPs and unmerged secp256k1 modules.)

Vendors unmerged upstream libsecp256k1 modules (bitcoin-core/secp256k1#1566 and #1754) to provide signature aggregation primitives. Subtree updates for prospective cryptographic standards are worthwhile for testing and specification validation.

Membership: Updates the vendored libsecp256k1 subtree with experimental BIP458 half-aggregation and BIP459 full-aggregation modules.

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

Validation

P2 · new feature

Provides the consensus reference implementation for BIP460 Cross-Input Signature Aggregation. As a proposed soft fork, evaluating its consensus rules and validation security is strategically important for the project's consensus roadmap.

Membership: Implements consensus script verification for witness version 2 outputs and check-queue batching in src/script/interpreter.cpp and src/validation.cpp.

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

Wallet

P4 · new feature (assessed alone as P3; Lowered from P3: explicitly a draft accompanying unaccepted BIPs and vendoring unmerged libsecp256k1 work; wallet value is speculative until consensus work lands.)

Adds wallet descriptor and PSBT support for Taproot key path spends with aggregated signatures to enable multi-party transaction construction. It demonstrates and exercises end-to-end wallet signing for collaborative transactions under BIP460.

Membership: Adds `cisa()` descriptor parsing and wallet signing integration using half- and full-aggregation across src/wallet/ and src/psbt.cpp.

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