1
0
mirror of https://github.com/bitcoin/bips.git synced 2026-03-02 15:43:53 +00:00
Files
bips/bip-0360/ref-impl/rust/docs/development_notes.adoc
Hunter Beast eae7d9fc57 BIP360: Pay to Merkle Root (P2MR) (#1670)
Review comments and assistance by:
  Armin Sabouri <armins88@gmail.com>
  D++ <82842780+dplusplus1024@users.noreply.github.com>
  Jameson Lopp <jameson.lopp@gmail.com>
  jbride <jbride2001@yahoo.com>
  Joey Yandle <xoloki@gmail.com>
  Jon Atack <jon@atack.com>
  Jonas Nick <jonasd.nick@gmail.com>
  Kyle Crews <kylecrews@Kyles-Mac-Studio.local>
  Mark "Murch" Erhardt <murch@murch.one>
  notmike-5 <notmike-5@users.noreply.github.com>
  Vojtěch Strnad <43024885+vostrnad@users.noreply.github.com>

Co-authored-by: Ethan Heilman <ethan.r.heilman@gmail.com>
Co-authored-by: Isabel Foxen Duke <110147802+Isabelfoxenduke@users.noreply.github.com>
2026-02-11 13:01:47 -08:00

175 lines
5.1 KiB
Plaintext

== bitcoin core
=== Two Different Size Limits:
* *MAX_SCRIPT_ELEMENT_SIZE* (in interpreter.cpp line 1882) - This is a consensus rule that limits individual stack elements to 520 bytes. This is what's currently blocking your SLH-DSA signature.
* *MAX_STANDARD_P2MR_STACK_ITEM_SIZE* (in policy.h) - This is a policy rule that limits P2MR stack items to 80 bytes (or 8000 bytes with your change) for standardness.
== P2MR changes to rust-bitcoin
# 1. p2mr module
The p2mr branch of rust-bitcoin includes a new module: `p2mr`.
Source code for this new module can be found [here](https://github.com/jbride/rust-bitcoin/blob/p2mr/bitcoin/src/p2mr/mod.rs).
Highlights of this _p2mr_ module as follows:
## 1.1. p2mrBuilder
This is struct inherits from the rust-bitcoin _TaprootBuilder_.
It has an important modification in that it disables keypath spend.
Similar to its Taproot parent, p2mrBuilder provides functionality to add leaves to a TapTree.
One its TapTree has been fully populated with all leaves, an instance of _p2mrSpendInfo_ can be retrieved from p2mrBuilder.
```
pub struct p2mrBuilder {
inner: TaprootBuilder
}
impl p2mrBuilder {
/// Creates a new p2mr builder.
pub fn new() -> Self {
Self {
inner: TaprootBuilder::new()
}
}
/// Adds a leaf to the p2mr builder.
pub fn add_leaf_with_ver(
self,
depth: u8,
script: ScriptBuf,
leaf_version: LeafVersion,
) -> Result<Self, p2mrError> {
match self.inner.add_leaf_with_ver(depth, script, leaf_version) {
Ok(builder) => Ok(Self { inner: builder }),
Err(_) => Err(p2mrError::LeafAdditionError)
}
}
/// Finalizes the p2mr builder.
pub fn finalize(self) -> Result<p2mrSpendInfo, p2mrError> {
let node_info: NodeInfo = self.inner.try_into_node_info().unwrap();
Ok(p2mrSpendInfo {
merkle_root: Some(node_info.node_hash()),
//script_map: self.inner.script_map().clone(),
})
}
/// Converts the p2mr builder into a Taproot builder.
pub fn into_inner(self) -> TaprootBuilder {
self.inner
}
}
```
## 1.2. p2mrSpendInfo
Provides merkle_root of a completed p2mr TapTree
```
/// A struct for p2mr spend information.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct p2mrSpendInfo {
/// The merkle root of the script path.
pub merkle_root: Option<TapNodeHash>
}
```
## 1.3. p2mrScriptBuf
Allows for creation of a p2mr scriptPubKey UTXO using only the merkle root of a script tree only.
```
/// A wrapper around ScriptBuf for p2mr (Pay to Quantum Resistant Hash) scripts.
pub struct p2mrScriptBuf {
inner: ScriptBuf
}
impl p2mrScriptBuf {
/// Creates a new p2mr script from a ScriptBuf.
pub fn new(inner: ScriptBuf) -> Self {
Self { inner }
}
/// Generates p2mr scriptPubKey output
/// Only accepts the merkle_root (of type TapNodeHash)
/// since keypath spend is disabled in p2mr
pub fn new_p2mr(merkle_root: TapNodeHash) -> Self {
// https://github.com/cryptoquick/bips/blob/p2mr/bip-0360.mediawiki#scriptpubkey
let merkle_root_hash_bytes: [u8; 32] = merkle_root.to_byte_array();
let script = Builder::new()
.push_opcode(OP_PUSHNUM_3)
// automatically pre-fixes with OP_PUSHBYTES_32 (as per size of hash)
.push_slice(&merkle_root_hash_bytes)
.into_script();
p2mrScriptBuf::new(script)
}
/// Returns the script as a reference.
pub fn as_script(&self) -> &Script {
self.inner.as_script()
}
}
```
## 1.4. p2mr Control Block
Closely related to P2TR control block.
Difference being that _internal public key_ is not included.
```
/// A control block for p2mr (Pay to Quantum Resistant Hash) script path spending.
/// This is a simplified version of Taproot's control block that excludes key-related fields.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct p2mrControlBlock {
/// The version of the leaf.
pub leaf_version: LeafVersion,
/// The merkle branch of the leaf.
pub merkle_branch: TaprootMerkleBranch,
}
```
# 2. Witness Program
New p2mr related functions that allow for creation of a new V3 _witness program_ given a merkle_root only.
Found in bitcoin/src/blockdata/script/witness_program.rs
```
/// Creates a [`WitnessProgram`] from a 32 byte merkle root.
fn new_p2mr(program: [u8; 32]) -> Self {
WitnessProgram { version: WitnessVersion::V3, program: ArrayVec::from_slice(&program) }
}
/// Creates a pay to quantum resistant hash address from a merkle root.
pub fn p2mr(merkle_root: Option<TapNodeHash>) -> Self {
let merkle_root = merkle_root.unwrap();
WitnessProgram::new_p2mr(merkle_root.to_byte_array())
}
```
# 3. Address
New _p2mr_ function that allows for creation of a new _p2mr_ Address given a merkle_root only.
Found in bitcoin/src/address/mod.rs
```
/// Creates a pay to quantum resistant hash address from a merkle root.
pub fn p2mr(merkle_root: Option<TapNodeHash>, hrp: impl Into<KnownHrp>) -> Address {
let program = WitnessProgram::p2mr(merkle_root);
Address::from_witness_program(program, hrp)
}
```