Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions bip-0360/ref-impl/common/tests/data/p2mr_construction.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@
"scriptPubKey": "522041646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b",
"bip350Address": "bc1zg9jxlrqlu25kmkkh74r3h387uldfs72wlrz95n60c6j4n4svna4s4lhfhe",
"scriptPathControlBlocks": [
"c1c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9",
"c1632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42"
"c1632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42",
"c1c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9"
]
}
},
Expand Down Expand Up @@ -205,8 +205,8 @@
"bip350Address": "bc1zej7kd3hhar76k3an5jr0t8fgyc47s4lnp4rh8uk4afrlwasuur3qzgewqq",
"scriptPathControlBlocks": [
"c1ffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
"c1ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
"c19e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
"c19e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
"c1ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
]
}
},
Expand Down Expand Up @@ -251,8 +251,8 @@
"bip350Address": "bc1z9a4jc5uhkmtgegvwpx3lq5tpv68layaf3pvz64wx7paatvejnhhsv52lcv",
"scriptPathControlBlocks": [
"c13cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
"c1737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
"c1d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
"c1d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
"c1737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
]
}
}
Expand Down
20 changes: 10 additions & 10 deletions bip-0360/ref-impl/common/tests/data/p2mr_pqc_construction.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@
"scriptPubKey": "52201619ce6d22a46dea045c4adf7f5f33d6810d00d0e9c8a4c7ba35db37b915c604",
"bip350Address": "bc1zzcvuumfz53k75pzuft0h7hen66qs6qxsa8y2f3a6xhdn0wg4cczq0h84sj",
"scriptPathControlBlocks": [
"c13bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc",
"c1f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
"c1f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
"c13bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc"
]
}
},
Expand Down Expand Up @@ -110,8 +110,8 @@
"scriptPubKey": "52202794771cd51f215ba3a19fbcdf08c771edb7de782a0c34457e0e9be5d0e4008f",
"bip350Address": "bc1zy728w8x4rus4hgapn77d7zx8w8km0hnc9gxrg3t7p6d7t58yqz8sg0nccq",
"scriptPathControlBlocks": [
"c1cfd5fc07ac39947cba799e14f933f20e7c233dea72dc2792f5547c58cdce743e",
"c1a9745ac96d4f3702b78751f1e08f3040fbe6347e7b4f520d22d3f907730cbb7e"
"c1a9745ac96d4f3702b78751f1e08f3040fbe6347e7b4f520d22d3f907730cbb7e",
"c1cfd5fc07ac39947cba799e14f933f20e7c233dea72dc2792f5547c58cdce743e"
]
}
},
Expand Down Expand Up @@ -147,8 +147,8 @@
"scriptPubKey": "52205112b3edfd2c0b717491e9d4888ed2d5dfeaa25115143540e0a08516b68c008c",
"bip350Address": "bc1z2yft8m0a9s9hzay3a82g3rkj6h074gj3z52r2s8q5zz3dd5vqzxqngpk2w",
"scriptPathControlBlocks": [
"c19de7eeded7832c28c6f80de76904dd79f98fd302747823b5bc5be440186b0c6d",
"c12cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb"
"c12cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
"c19de7eeded7832c28c6f80de76904dd79f98fd302747823b5bc5be440186b0c6d"
]
}
},
Expand Down Expand Up @@ -194,9 +194,9 @@
"scriptPubKey": "5220eaf8f557fdb9673de7bb9bad7e7452da9f44a3e65133fdadf2849c55cfb3cf5b",
"bip350Address": "bc1zatu024lah9nnmeamnwkhuazjm205fglx2yelmt0jsjw9tnaneadszq7wg7",
"scriptPathControlBlocks": [
"c1837ef6677aeb0df2b0de47f45024684cc6ca03bda10fa30bb5bc05a94beb8dd1b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a",
"c118781f42f664d67acaf0ce7c6826437e5440eb1789f232af05e9a09fdf547903",
"c10840c39e59eda6c9deee687a480cb169130c2f053ed2eb3134511ec1cfd8a2c7b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a",
"c118781f42f664d67acaf0ce7c6826437e5440eb1789f232af05e9a09fdf547903"
"c1837ef6677aeb0df2b0de47f45024684cc6ca03bda10fa30bb5bc05a94beb8dd1b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a"
]
}
},
Expand Down Expand Up @@ -242,9 +242,9 @@
"scriptPubKey": "522051e3c1151ba73d9efce801837773331bf9030977242f62dfeb6756795f482409",
"bip350Address": "bc1z283uz9gm5u7eal8gqxphwuenr0usxzthyshk9hltvat8jh6gysys28twnc",
"scriptPathControlBlocks": [
"c1dcef3ce86cc8cea78c9e00f3d9ef58360cb6ed3cb90ec62efe00b9703854ba5cddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361",
"c1b45680a7821e4b9450096ab38adbc3c99225af8f6c7ec121a0a5f1ae02893ba3",
"c152e9326c2bf04d926b7e9f6c7645dd853f3f007b870201de9b814952750c9310ddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361",
"c1b45680a7821e4b9450096ab38adbc3c99225af8f6c7ec121a0a5f1ae02893ba3"
"c1dcef3ce86cc8cea78c9e00f3d9ef58360cb6ed3cb90ec62efe00b9703854ba5cddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361"
]
}
}
Expand Down
52 changes: 17 additions & 35 deletions bip-0360/ref-impl/rust/tests/p2mr_construction.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashSet;
use std::collections::HashMap;
use bitcoin::{Network, ScriptBuf};
use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash};
use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo};
Expand Down Expand Up @@ -136,21 +136,20 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
// Use of TaprootBuilder avoids user error in constructing branches manually and ensures Merkle tree correctness and determinism
let mut p2mr_builder: P2mrBuilder = P2mrBuilder::new();

let mut control_block_data: Vec<(ScriptBuf, LeafVersion)> = Vec::new();
let mut script_to_id: HashMap<ScriptBuf, u8> = HashMap::new();

// 1) traverse test vector script tree and add leaves to P2MR builder
if let Some(script_tree) = tv_script_tree {

script_tree.traverse_with_right_subtree_first(0, Direction::Root,&mut |node, depth, direction| {

if let TVScriptTree::Leaf(tv_leaf) = node {

let tv_leaf_script_bytes = hex::decode(&tv_leaf.script).unwrap();

// NOTE: IOT to execute script_info.control_block(..), will add these to a vector

let tv_leaf_script_buf = ScriptBuf::from_bytes(tv_leaf_script_bytes.clone());
let tv_leaf_version = LeafVersion::from_consensus(tv_leaf.leaf_version).unwrap();
control_block_data.push((tv_leaf_script_buf.clone(), tv_leaf_version));
script_to_id.insert(tv_leaf_script_buf.clone(), tv_leaf.id);

let mut modified_depth = depth + 1;
if direction == Direction::Root {
Expand Down Expand Up @@ -194,14 +193,10 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
);
debug!("just passed merkle root validation: {}", test_vector_merkle_root);

let test_vector_leaf_hashes_vec: Vec<String> = test_vector.intermediary.leaf_hashes.clone();
let test_vector_leaf_hash_set: HashSet<String> = test_vector_leaf_hashes_vec.iter().cloned().collect();
let test_vector_control_blocks_vec = &test_vector.expected.script_path_control_blocks;
let test_vector_control_blocks_set: HashSet<String> = test_vector_control_blocks_vec.as_ref().unwrap().iter().cloned().collect();
let expected_control_blocks = test_vector.expected.script_path_control_blocks.as_ref().unwrap();
let tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap();
let script_leaves: ScriptLeaves = tap_tree.script_leaves();

// TO-DO: Investigate why the ordering of script leaves seems to be reverse of test vectors.
// 3) Iterate through leaves of derived script tree and verify both script leaf hashes and control blocks
for derived_leaf in script_leaves {

Expand All @@ -211,34 +206,21 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {

let derived_leaf_hash: TapLeafHash = TapLeafHash::from_script(script, version);
let leaf_hash = hex::encode(derived_leaf_hash.as_raw_hash().to_byte_array());
assert!(
test_vector_leaf_hash_set.contains(&leaf_hash),
"Leaf hash not found in expected set for {}", leaf_hash
);
debug!("just passed leaf_hash validation: {}", leaf_hash);

// Each leaf in the script tree has a corresponding control block.
// Specific to P2TR, the 3 sections of the control block (control byte, public key & merkle path) are highlighted here:
// https://learnmeabitcoin.com/technical/upgrades/taproot/#script-path-spend-control-block
// The control block, which includes the Merkle path, must be 33 + 32 * n bytes, where n is the number of Merkle path hashes (n ≥ 0).
// There is no consensus limit on n, but large Merkle trees increase the witness size, impacting block weight.
// NOTE: Control blocks could have also been obtained from spend_info.control_block(..) using the data in control_block_data
debug!("merkle_branch nodes: {:?}", merkle_branch);

let leaf_id = script_to_id.get(script)
.unwrap_or_else(|| panic!("leaf script not found in script_to_id map: {}", hex::encode(script.as_bytes())));

let derived_control_block: P2mrControlBlock = P2mrControlBlock{
merkle_branch: merkle_branch.clone(),
};
let serialized_control_block = derived_control_block.serialize();
debug!("derived_control_block: {:?}, merkle_branch size: {}, control_block size: {}, serialized size: {}",
derived_control_block,
merkle_branch.len(),
derived_control_block.size(),
serialized_control_block.len());
let derived_serialized_control_block = hex::encode(serialized_control_block);
assert!(
test_vector_control_blocks_set.contains(&derived_serialized_control_block),
"Control block mismatch: {}, expected: {:?}", derived_serialized_control_block, test_vector_control_blocks_set
let derived_serialized_control_block = hex::encode(derived_control_block.serialize());

let expected_cb = &expected_control_blocks[*leaf_id as usize];
assert_eq!(
derived_serialized_control_block, *expected_cb,
"Control block mismatch for leaf id {}: derived {}, expected {}", leaf_id, derived_serialized_control_block, expected_cb
);
debug!("leaf_hash: {}, derived_serialized_control_block: {}", leaf_hash, derived_serialized_control_block);
debug!("leaf_id: {}, leaf_hash: {}, derived_serialized_control_block: {}", leaf_id, leaf_hash, derived_serialized_control_block);

}

Expand Down
52 changes: 17 additions & 35 deletions bip-0360/ref-impl/rust/tests/p2mr_pqc_construction.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashSet;
use std::collections::HashMap;
use bitcoin::{Network, ScriptBuf};
use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash};
use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo};
Expand Down Expand Up @@ -114,21 +114,20 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
// Use of TaprootBuilder avoids user error in constructing branches manually and ensures Merkle tree correctness and determinism
let mut p2mr_builder: P2mrBuilder = P2mrBuilder::new();

let mut control_block_data: Vec<(ScriptBuf, LeafVersion)> = Vec::new();
let mut script_to_id: HashMap<ScriptBuf, u8> = HashMap::new();

// 1) traverse test vector script tree and add leaves to P2MR builder
if let Some(script_tree) = tv_script_tree {

script_tree.traverse_with_right_subtree_first(0, Direction::Root,&mut |node, depth, direction| {

if let TVScriptTree::Leaf(tv_leaf) = node {

let tv_leaf_script_bytes = hex::decode(&tv_leaf.script).unwrap();

// NOTE: IOT to execute script_info.control_block(..), will add these to a vector

let tv_leaf_script_buf = ScriptBuf::from_bytes(tv_leaf_script_bytes.clone());
let tv_leaf_version = LeafVersion::from_consensus(tv_leaf.leaf_version).unwrap();
control_block_data.push((tv_leaf_script_buf.clone(), tv_leaf_version));
script_to_id.insert(tv_leaf_script_buf.clone(), tv_leaf.id);

let mut modified_depth = depth + 1;
if direction == Direction::Root {
Expand Down Expand Up @@ -172,14 +171,10 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
);
debug!("just passed merkle root validation: {}", test_vector_merkle_root);

let test_vector_leaf_hashes_vec: Vec<String> = test_vector.intermediary.leaf_hashes.clone();
let test_vector_leaf_hash_set: HashSet<String> = test_vector_leaf_hashes_vec.iter().cloned().collect();
let test_vector_control_blocks_vec = &test_vector.expected.script_path_control_blocks;
let test_vector_control_blocks_set: HashSet<String> = test_vector_control_blocks_vec.as_ref().unwrap().iter().cloned().collect();
let expected_control_blocks = test_vector.expected.script_path_control_blocks.as_ref().unwrap();
let tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap();
let script_leaves: ScriptLeaves = tap_tree.script_leaves();

// TO-DO: Investigate why the ordering of script leaves seems to be reverse of test vectors.
// 3) Iterate through leaves of derived script tree and verify both script leaf hashes and control blocks
for derived_leaf in script_leaves {

Expand All @@ -189,34 +184,21 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {

let derived_leaf_hash: TapLeafHash = TapLeafHash::from_script(script, version);
let leaf_hash = hex::encode(derived_leaf_hash.as_raw_hash().to_byte_array());
assert!(
test_vector_leaf_hash_set.contains(&leaf_hash),
"Leaf hash not found in expected set for {}", leaf_hash
);
debug!("just passed leaf_hash validation: {}", leaf_hash);

// Each leaf in the script tree has a corresponding control block.
// Specific to P2TR, the 3 sections of the control block (control byte, public key & merkle path) are highlighted here:
// https://learnmeabitcoin.com/technical/upgrades/taproot/#script-path-spend-control-block
// The control block, which includes the Merkle path, must be 33 + 32 * n bytes, where n is the number of Merkle path hashes (n ≥ 0).
// There is no consensus limit on n, but large Merkle trees increase the witness size, impacting block weight.
// NOTE: Control blocks could have also been obtained from spend_info.control_block(..) using the data in control_block_data
debug!("merkle_branch nodes: {:?}", merkle_branch);

let leaf_id = script_to_id.get(script)
.unwrap_or_else(|| panic!("leaf script not found in script_to_id map: {}", hex::encode(script.as_bytes())));

let derived_control_block: P2mrControlBlock = P2mrControlBlock{
merkle_branch: merkle_branch.clone(),
};
let serialized_control_block = derived_control_block.serialize();
debug!("derived_control_block: {:?}, merkle_branch size: {}, control_block size: {}, serialized size: {}",
derived_control_block,
merkle_branch.len(),
derived_control_block.size(),
serialized_control_block.len());
let derived_serialized_control_block = hex::encode(serialized_control_block);
assert!(
test_vector_control_blocks_set.contains(&derived_serialized_control_block),
"Control block mismatch: {}, expected: {:?}", derived_serialized_control_block, test_vector_control_blocks_set
let derived_serialized_control_block = hex::encode(derived_control_block.serialize());

let expected_cb = &expected_control_blocks[*leaf_id as usize];
assert_eq!(
derived_serialized_control_block, *expected_cb,
"Control block mismatch for leaf id {}: derived {}, expected {}", leaf_id, derived_serialized_control_block, expected_cb
);
debug!("leaf_hash: {}, derived_serialized_control_block: {}", leaf_hash, derived_serialized_control_block);
debug!("leaf_id: {}, leaf_hash: {}, derived_serialized_control_block: {}", leaf_id, leaf_hash, derived_serialized_control_block);

}

Expand Down