Skip to content

feat: add BIP-360 P2MR address encoding and Merkle tree support#246

Draft
lcovar wants to merge 3 commits intomasterfrom
BTC-3241-bip360-p2mr-support
Draft

feat: add BIP-360 P2MR address encoding and Merkle tree support#246
lcovar wants to merge 3 commits intomasterfrom
BTC-3241-bip360-p2mr-support

Conversation

@lcovar
Copy link
Copy Markdown
Contributor

@lcovar lcovar commented Apr 7, 2026

Add Pay-to-Merkle-Root (BIP-360) support to wasm-utxo covering address
encoding/decoding (witness v2, bech32m bc1z/tb1z) and script tree
construction with control block generation.

Address encoding (commit 1):

  • Generic bech32 segwit::encode() for all witness versions (v0-v2+)
  • P2MR script detection (34 bytes, witness v2, OP_PUSHBYTES_32)
  • OutputScriptSupport.p2mr flag, enabled only on BitGo Signet
  • Separate bitcoinBitGoSignet.json fixture file with P2MR test vectors

Merkle tree + WASM bindings (commit 2):

  • Core p2mr module: tagged hashes, tree building, control block generation/verification
  • P2mrNamespace WASM bindings using TryIntoJsValue/get_field pattern
  • TypeScript wrapper (js/p2mr.ts) with full types
  • Fixture-driven tests against all 8 BIP-360 construction vectors

BTC-3241

@lcovar lcovar requested a review from a team as a code owner April 7, 2026 21:43
lcovar added 3 commits April 7, 2026 15:19
Add witness v2 (P2MR) support to the address encoding layer:
- Switch bech32 encoding from version-specific to generic
  segwit::encode() supporting all witness versions (v0-v2+)
- Add P2MR script detection (34 bytes, witness v2, OP_PUSHBYTES_32)
- Add OutputScriptSupport.p2mr flag, enabled only on BitGo Signet
- Create separate bitcoinBitGoSignet.json fixture file with P2MR
  address test vectors (tb1z prefix)
- Filter P2MR from utxolib compat test path (not supported there)

BTC-3241
Add core P2MR tree construction module with WASM bindings and
comprehensive tests against BIP-360 specification test vectors.

Rust core (src/p2mr/mod.rs):
- Tagged hash computation (TapLeaf, TapBranch per BIP-341)
- Script tree building with DFS traversal and per-leaf control blocks
- Control block generation (leaf_version | 0x01 parity) and verification
- Merkle proof verification against expected root

WASM bindings (src/wasm/p2mr.rs):
- P2mrNamespace with computeLeafHash, computeBranchHash, buildTree,
  buildScriptPubkey, verifyControlBlock
- Uses wasm-utxo TryIntoJsValue/get_field pattern (not serde_wasm_bindgen)
- Tree deserialization: leaf = {script, leafVersion?}, branch = [left, right]

TypeScript (js/p2mr.ts):
- Typed wrapper with ScriptTreeNode, P2mrLeafInfo, P2mrTreeInfo types

Tests:
- Fixture-driven tests against all 8 BIP-360 p2mr_construction vectors

BTC-3241
- Export p2mr namespace from js/index.ts
- Fix clippy unnecessary_unwrap in bitgo_psbt test code (use if-let)

BTC-3241
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-support branch from 95389bd to 5a099bf Compare April 7, 2026 22:20
@lcovar lcovar marked this pull request as draft April 7, 2026 22:32
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.

1 participant