bip360: fix leafHashes order and a control byte in the pqc test vectors - #2220
Merged
Merged
Conversation
In p2mr_pqc_construction.json, the three-leaf vectors (p2mr_three_leaf_complex, p2mr_three_leaf_alternative) listed intermediary.leafHashes with entries 0 and 2 swapped relative to the depth-first order of the script tree, while the merkle root, scriptPubKey, address and control blocks all follow depth-first order (as do the same trees in p2mr_construction.json). In p2mr_different_version_leaves, scriptPathControlBlocks[1] started with byte 0xc1 although the leaf it commits to has leafVersion 0xfa; the control byte carries the leaf version in its upper 7 bits with the low bit set, so it must be 0xfb. The vector's leafHashes[1] and merkle root already correspond to the 0xfa leaf.
jeanpablojp
added a commit
to jeanpablojp/bitcoin
that referenced
this pull request
Jul 27, 2026
Check the official BIP 360 construction vectors, vendored from bitcoin/bips at commit 0fdf6ffdbb394a73c80978ae647322ceda8b9337, in the style of the existing BIP 341 vector tests. For each vector the harness rebuilds the script tree with the consensus hashing functions and compares leaf hashes, Merkle root, scriptPubKey, bech32m address and control blocks against the published values, then walks each control block back through ComputeP2MRMerkleRoot() to tie the vectors to the code that validates blocks. All nine vectors in p2mr_construction.json pass. Two vectors in p2mr_pqc_construction.json carry bugs (swapped leaf hashes in the three-leaf trees, and a control byte that does not match its leaf version); the fix is bitcoin/bips#2220. Until it lands, the harness asserts those divergences still reproduce, so the exceptions cannot outlive the pinned vectors.
jeanpablojp
added a commit
to jeanpablojp/bitcoin-p2mr
that referenced
this pull request
Jul 27, 2026
All nine vectors in p2mr_construction.json pass; the two bugs found in the pqc file went upstream as bitcoin/bips#2220, and the doc-side problems as #2221. Keep the issue drafts out of the repo now that they are PRs.
jonatack
reviewed
Jul 28, 2026
jonatack
left a comment
Member
There was a problem hiding this comment.
Fixes LGTM (thanks!) pinging @cryptoquick @EthanHeilman for feedback or sign-off.
cryptoquick
reviewed
Aug 1, 2026
cryptoquick
left a comment
Contributor
There was a problem hiding this comment.
Good changes. I'll make sure they're also reflected in our bindings vectors with this PR:
jeanpablojp
added a commit
to jeanpablojp/bitcoin
that referenced
this pull request
Aug 1, 2026
The pqc vector fix (bitcoin/bips#2220) was merged upstream as commit b31410ca587c. Replace the vendored p2mr_pqc_construction.json with the fixed file, remove the KnownVectorBug exceptions that asserted the divergence at the old pin, and update the pin references. All 16 vectors now pass as ordinary cases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two fixes in bip-0360/ref-impl/common/tests/data/p2mr_pqc_construction.json, found while implementing BIP 360 against the published vectors.
First, the three-leaf vectors (p2mr_three_leaf_complex and p2mr_three_leaf_alternative) list intermediary.leafHashes with entries 0 and 2 swapped relative to the depth-first order of the script tree. The merkle root, scriptPubKey, address and control blocks in those same vectors all follow depth-first order, as do the equivalent trees in p2mr_construction.json. This looks like a leftover from the ordering problem that #2202 fixed for the control blocks.
Check against the spec formulas:
Before this change that prints "0 False / 1 True / 2 False", i.e. entries 0 and 2 hold each other's values. Same for p2mr_three_leaf_alternative.
Second, in p2mr_different_version_leaves the second leaf has "leafVersion": 250 (0xfa), but scriptPathControlBlocks[1] started with c1. The control byte carries the leaf version in its upper 7 bits with the low bit set, so it should be fb. The vector's leafHashes[1] and merkle root already correspond to the leaf hashed under 0xfa and the path bytes are correct, so only the first byte was wrong. As published, a spender using that control block would recompute the leaf hash under 0xc0 and fail the merkle check.
After both fixes every success vector in the file passes a full recomputation from the spec formulas: leaf hashes, merkle root, scriptPubKey, bech32m address, control blocks, and walking each control block path back to the root.