Skip to content

bip360: add spend-path test vectors - #2232

Open
jeanpablojp wants to merge 1 commit into
bitcoin:masterfrom
jeanpablojp:bip360-spend-vectors
Open

bip360: add spend-path test vectors#2232
jeanpablojp wants to merge 1 commit into
bitcoin:masterfrom
jeanpablojp:bip360-spend-vectors

Conversation

@jeanpablojp

@jeanpablojp jeanpablojp commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

The existing test vectors are construction-only: script tree in; leaf
hashes, Merkle root, scriptPubKey, address and control blocks out. There
are no spending transactions or signatures, unlike BIP 341's
wallet-test-vectors.json, so everyone implementing consensus has to
invent their own spend coverage. This PR adds the spend-path vectors
offered in the Delving write-up
(https://delvingbitcoin.org/t/bip-360-p2mr-implemented-in-bitcoin-core-on-regtest-vector-results-measurements-spec-feedback/2751).
I generated them from the regtest implementation discussed there.

The schema mirrors bip-0341/wallet-test-vectors.json, adapted to an
output type whose only spend path is the script path. One transaction
with six inputs covers the valid cases, with per-input
given/intermediary/expected and the BIP 341 sighash midstate
pieces at the group level. A separate invalidSpending array has nine
self-contained transactions that must fail validation. The error
field uses short spec-level descriptions; implementations map them
onto their own error codes (several deliberately collapse onto one code
in ours). For inputs spent without a signature,
privkey/hashType/annex/sigMsg/sigHash are null rather than absent.

Valid cases:

  • depth-1 leaf, SIGHASH_DEFAULT
  • depth-2 leaf of a three-leaf tree, SIGHASH_ALL (65-byte signature)
  • annex present, covered by the signature
  • p2mr_single_leaf_script_tree (from p2mr_construction.json) spent at
    depth 0 with no signature: demonstrates the v0.12.0 anyone-can-spend
    rule on a published tree
  • p2mr_different_version_leaves (also from p2mr_construction.json)
    spent through its 0xfa leaf: unknown leaf versions are unencumbered
  • a depth-128 leaf whose control block is exactly the 4097-byte
    maximum, pinning the accepting side of the depth limit

Invalid cases: bit-flipped signature, tampered Merkle path, control
byte with the low bit unset, single-element witness, two-element
witness ending in an annex, empty witness, and control blocks of 0, 34
and 1+32*129 bytes. That covers all three clauses of the control block
size rule.

Everything can be regenerated from scratch: private keys are
sha256("p2mr_spending/key/<n>"), prevout txids
sha256("p2mr_spending/prevout/<n>"), and signing is BIP 340 with an
all-zero aux. The two reused trees are asserted to reproduce their
published construction vectors, so the two files cross-check each
other.

One case bakes in an interpretation the spec text leaves implicit:
p2mr_spend_control_byte_low_bit_zero expects failure when the control
byte's low bit is 0. Script Validation says the bit "is unused and must
be 1" and the footnote describes it catching deserialization bugs "with
an immediate error", but the validation steps have no explicit "Fail
if" clause for it, unlike every other rule in that section. If the
intended reading is non-enforcement, this vector should be dropped and
the footnote reworded; either way the text could make it explicit.

Verified against a Bitcoin Core implementation of the BIP: every valid
input passes VerifyScript and every invalid case fails with the
expected script error
(https://github.com/jeanpablojp/bitcoin/tree/p2mr-regtest,
src/test/p2mr_vector_tests.cpp). The generator is
test/functional/tool_p2mr_spend_vectors.py on the same branch.

@jonatack jonatack added Proposed BIP modification PR by non-owner to update BIP content Pending acceptance This BIP modification requires sign-off by the champion of the BIP being modified labels Aug 2, 2026
@murchandamus

Copy link
Copy Markdown
Member

cc: @cryptoquick

The existing vectors are construction-only, so implementations have to
invent their own spend coverage. This adds a spending file in the shape
of bip-0341/wallet-test-vectors.json, adapted to an output type whose
only spend path is the script path.

One transaction with six inputs covers the valid cases, with the five
shared BIP 341 sighash hashes at the group level and per-input given,
intermediary and expected fields. A separate invalidSpending array has
nine self-contained transactions that must fail validation, with the
reason in a short spec-level error string.

Private keys are sha256("p2mr_spending/key/<n>"), prevout txids are
sha256("p2mr_spending/prevout/<n>") in internal byte order, and signing
is BIP 340 with an all-zero aux, so the signatures can be re-derived
rather than trusted. Two of the inputs reuse trees from
p2mr_construction.json, which makes the two files cross-check each
other.
@jeanpablojp
jeanpablojp force-pushed the bip360-spend-vectors branch from 92cb0b1 to adbc31f Compare August 15, 2026 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Pending acceptance This BIP modification requires sign-off by the champion of the BIP being modified Proposed BIP modification PR by non-owner to update BIP content

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants