feat: add Pay-to-Merkle-Root (P2MR) support per BIP 360#2312
Open
jasonandjay wants to merge 4 commits intobitcoinjs:masterfrom
Open
feat: add Pay-to-Merkle-Root (P2MR) support per BIP 360#2312jasonandjay wants to merge 4 commits intobitcoinjs:masterfrom
jasonandjay wants to merge 4 commits intobitcoinjs:masterfrom
Conversation
Implement SegWit v2 P2MR output type that commits directly to a script tree Merkle root without an internal public key, supporting script-path spending only. This provides resistance to long-exposure quantum attacks by removing the key-path spend vector present in P2TR. - Add p2mr payment module (ts_src/payments/p2mr.ts) - Add rootHashFromP2MRPath to bip341 utilities for P2MR control blocks - Export p2mr from payments index - Update address encoding/decoding for SegWit v2 (bc1z prefix) - Extend PSBT bip371 to recognize P2MR inputs/outputs - Add isP2MR detection to psbtutils
Cover all 6 official BIP 360 valid test vectors for address, scriptPubKey, and Merkle root derivation. Add 12 witness/controlBlock tests verifying script-path spending for every leaf in each tree topology (single leaf, two-leaf same/different version, lightning contract, three-leaf complex and alternative). Include 6 negative tests for error handling. Note: the official BIP 360 test vector for p2mr_different_version_leaves has a known bug (control byte 0xC1 instead of correct 0xFB for leaf version 250). Our test uses the correct value.
Add 9 integration tests covering the complete P2MR pipeline: - Address generation and validation (mainnet bc1z, regtest bcrt1z) - Address ↔ output script roundtrip via bitcoin.address - Single-leaf script-path spend (OP_CHECKSIG) with PSBT sign/finalize - Two-leaf tree spending each leaf independently (+ wrong-key rejection) - Three-leaf tree spending a depth-2 leaf - PSBT serialization/deserialization roundtrip - Key-path spend rejection enforcement - P2MR vs P2TR structural comparison (no internalPubkey) Note: P2MR transactions cannot be broadcast until BIP 360 activates, so these tests verify the full PSBT workflow locally without regtest.
Link to the P2MR integration tests from the Examples section, following the existing pattern used for Taproot examples.
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.
Summary
Implements BIP 360 Pay-to-Merkle-Root (P2MR) payment type support. P2MR is a SegWit version 2 output type that commits directly to a script tree's Merkle root without an internal public key, supporting script-path spending only. This provides resistance to long-exposure quantum attacks by removing the key-path spend vector present in P2TR.
Closes #2311
Changes
Core implementation:
p2mrpayment module (ts_src/payments/p2mr.ts) — address encoding (bc1z), scriptPubKey (OP_2), witness construction, and validationrootHashFromP2MRPathto bip341 utilities for P2MR control blocks (no internal pubkey, Merkle path starts at byte offset 1)address.tsto support SegWit v2 encoding/decodingbip371.tsto recognize P2MR inputs/outputs viaisTaprootInput/isTaprootOutputisP2MRdetection topsbtutils.tsKey differences from P2TR:
OP_1)OP_2)bc1pbc1z[ctrl_byte][32B pubkey][path...][ctrl_byte][path...]Tests:
Notes
p2mr_different_version_leaveshas a known bug: control byte0xC1instead of the correct0xFBfor leaf version 250. Our tests use the correct value.tapInternalKeyandtapKeySig, so the existing logic correctly falls into script-path-only execution.Test plan