Skip to content

feat: add P2MR fixed-script wallet integration#247

Merged
lcovar merged 4 commits intomasterfrom
BTC-3241-bip360-p2mr-fixed-script
Apr 14, 2026
Merged

feat: add P2MR fixed-script wallet integration#247
lcovar merged 4 commits intomasterfrom
BTC-3241-bip360-p2mr-fixed-script

Conversation

@lcovar
Copy link
Copy Markdown
Contributor

@lcovar lcovar commented Apr 7, 2026

Add P2MR (BIP-360) address encoding and fixed-script wallet integration
to wasm-utxo.

Address encoding:

  • Generic bech32 segwit::encode() for all witness versions (v0-v2+)
  • P2MR script detection (34 bytes, witness v2, OP_PUSHBYTES_32)
  • OutputScriptSupport.p2mr flag on all Bitcoin networks
  • P2MR address test vectors (bc1z mainnet, tb1z testnet)

Fixed-script wallet:

  • OutputScriptType::P2mr with chain values 360/361
  • ScriptP2mr: 3-leaf tree (user+bitgo, user+backup, backup+bitgo)
    using same 2-of-2 checksigverify scripts as P2TR
  • InputScriptType::P2mr with proper witness size calculation
    (1 + 32*depth control blocks, no 32-byte internal key)
  • PSBT output metadata (tap_tree, tap_key_origins) reusing taproot
    fields (tested with rust-bitcoin, bitcoinjs-lib, utxo-lib)
  • PSBT input signing stub (returns "not yet supported")
  • Fixture tests for output scripts, control blocks, chain values
  • P2MR chain codes (360/361) added to TypeScript chainCodes array,
    skipped in utxo-lib comparison tests (wasm-only)

BTC-3241

@lcovar lcovar requested a review from a team as a code owner April 7, 2026 23:17
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-fixed-script branch from 8ed1ed5 to 1698651 Compare April 8, 2026 04:51
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-support branch from 5a099bf to 3bf0bc7 Compare April 8, 2026 19:24
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-fixed-script branch from 1698651 to 3363c32 Compare April 8, 2026 19:24
@lcovar lcovar requested a review from OttoAllmendinger April 8, 2026 19:31
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-support branch from 3bf0bc7 to b19bd0e Compare April 9, 2026 16:11
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-fixed-script branch 2 times, most recently from 91d8d19 to 415affc Compare April 9, 2026 16:38
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-support branch from b19bd0e to eeae358 Compare April 9, 2026 16:38
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-fixed-script branch from 415affc to 6064a34 Compare April 9, 2026 18:36
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-support branch 2 times, most recently from ac5e692 to 7a36520 Compare April 13, 2026 20:06
Base automatically changed from BTC-3241-bip360-p2mr-support to master April 13, 2026 20:16
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-fixed-script branch from 6064a34 to da43899 Compare April 13, 2026 20:25
lcovar added 2 commits April 13, 2026 13:26
Add witness v2 (P2MR) support to the address encoding layer:
- Generic bech32 segwit::encode() for all witness versions (v0-v2+)
- P2MR script detection (34 bytes, witness v2, OP_PUSHBYTES_32)
- OutputScriptSupport.p2mr flag on all Bitcoin networks
- P2MR address test vectors (bc1z mainnet, tb1z testnet) validated
  against BIP-360 spec fixtures

BTC-3241
Add P2MR as a new script type in the fixed-script wallet system,
mirroring P2TR legacy but without internal key or tweak.

- OutputScriptType::P2mr with chain values 360/361
- ScriptP2mr: 3-leaf tree (user+bitgo, user+backup, backup+bitgo)
  using same 2-of-2 checksigverify scripts as P2TR
- InputScriptType::P2mr with proper witness size calculation
  (1 + 32*depth control blocks, no 32-byte internal key)
- PSBT output metadata (tap_tree, tap_key_origins) reusing taproot
  fields (tested with rust-bitcoin, bitcoinjs-lib, utxo-lib)
- PSBT input signing stub (returns "not yet supported")
- Fixture tests for output scripts, control blocks, chain values

BTC-3241
@lcovar lcovar force-pushed the BTC-3241-bip360-p2mr-fixed-script branch from da43899 to 73de89f Compare April 13, 2026 20:26
Add chain codes 360/361 to the TypeScript chainCodes array so the WASM
chain_code_table() entries for P2MR don't crash at module load time.
Skip P2MR in utxo-lib comparison tests since utxo-lib won't add P2MR
support. Restore the bitcoinBitGoSignet -> bitcoinPublicSignet fixture
mapping that was incorrectly removed.

Ticket: BTC-3241
@lcovar lcovar requested a review from OttoAllmendinger April 13, 2026 21:26
inner_psbt.inputs[input_index].witness_script = Some(script.witness_script.clone());
}
WalletScripts::P2mr(_) => {
return Err("BIP-322 signing for P2MR is not yet supported".to_string());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add it in this PR

Add P2MR (BIP-360) input construction to add_bip322_input. P2MR uses
the same sighash as P2TR (BIP-342 common signature message) and the
same 2-of-2 checksigverify leaf scripts. The key difference is that
P2MR has no internal key (quantum resistance), so tap_scripts cannot
be populated (rust-bitcoin's ControlBlock requires an internal key).
Instead, we use precomputed leaf hashes from ScriptP2mr and set only
tap_key_origins, which is sufficient for signing.

Also adds P2MR support to build_output_script_from_pubkeys for
BIP-322 verification with pubkeys.

Ticket: BTC-3241
@lcovar lcovar merged commit 3f59e99 into master Apr 14, 2026
16 checks passed
@lcovar lcovar deleted the BTC-3241-bip360-p2mr-fixed-script branch April 14, 2026 19:52
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.

2 participants