Skip to content

feat: add Pay-to-Merkle-Root (P2MR) support per BIP 360#2312

Open
jasonandjay wants to merge 4 commits intobitcoinjs:masterfrom
jasonandjay:feat/p2mr-bip360
Open

feat: add Pay-to-Merkle-Root (P2MR) support per BIP 360#2312
jasonandjay wants to merge 4 commits intobitcoinjs:masterfrom
jasonandjay:feat/p2mr-bip360

Conversation

@jasonandjay
Copy link
Copy Markdown
Member

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:

  • Add p2mr payment module (ts_src/payments/p2mr.ts) — address encoding (bc1z), scriptPubKey (OP_2), witness construction, and validation
  • Add rootHashFromP2MRPath to bip341 utilities for P2MR control blocks (no internal pubkey, Merkle path starts at byte offset 1)
  • Update address.ts to support SegWit v2 encoding/decoding
  • Extend PSBT bip371.ts to recognize P2MR inputs/outputs via isTaprootInput/isTaprootOutput
  • Add isP2MR detection to psbtutils.ts

Key differences from P2TR:

P2TR (BIP 341) P2MR (BIP 360)
Witness version v1 (OP_1) v2 (OP_2)
Address prefix bc1p bc1z
Internal pubkey Required None
Key-path spend Yes No (script-path only)
Control block [ctrl_byte][32B pubkey][path...] [ctrl_byte][path...]

Tests:

  • 22 unit tests covering all 6 official BIP 360 valid test vectors (address, scriptPubKey, merkleRoot) + 12 witness/controlBlock tests for every leaf in each tree topology + 6 negative tests
  • 9 integration tests covering full PSBT workflow (sign → finalize → extract), multi-leaf trees, PSBT serialization roundtrip, key-path rejection, and P2MR vs P2TR comparison

Notes

  • The official BIP 360 test vector for p2mr_different_version_leaves has a known bug: control byte 0xC1 instead of the correct 0xFB for leaf version 250. Our tests use the correct value.
  • P2MR transactions cannot be broadcast until BIP 360 activates on mainnet, so integration tests verify the full PSBT workflow locally.
  • PSBT signing/finalization reuses existing P2TR script-path code paths — P2MR inputs naturally lack tapInternalKey and tapKeySig, so the existing logic correctly falls into script-path-only execution.

Test plan

  • All 2695 existing unit tests pass
  • 22 new P2MR unit tests pass (BIP 360 test vectors)
  • 9 new P2MR integration tests pass
  • No regressions in address, PSBT, or P2TR tests

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Add P2MR (Pay-to-Merkle-Root) support (BIP 360)

1 participant