1
0
mirror of https://github.com/bitcoin/bips.git synced 2026-07-27 18:13:38 +00:00

bip360 test vectors: elements in control block array should be ordered to match tree structure of test vectors (#45)

This commit is contained in:
jbride
2026-04-03 18:38:43 -06:00
committed by notmike
parent b9883fbb4b
commit 35b9ffe21b
4 changed files with 50 additions and 86 deletions

View File

@@ -123,8 +123,8 @@
"scriptPubKey": "522041646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b", "scriptPubKey": "522041646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b",
"bip350Address": "bc1zg9jxlrqlu25kmkkh74r3h387uldfs72wlrz95n60c6j4n4svna4s4lhfhe", "bip350Address": "bc1zg9jxlrqlu25kmkkh74r3h387uldfs72wlrz95n60c6j4n4svna4s4lhfhe",
"scriptPathControlBlocks": [ "scriptPathControlBlocks": [
"c1c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9", "c1632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42",
"c1632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42" "c1c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9"
] ]
} }
}, },
@@ -205,8 +205,8 @@
"bip350Address": "bc1zej7kd3hhar76k3an5jr0t8fgyc47s4lnp4rh8uk4afrlwasuur3qzgewqq", "bip350Address": "bc1zej7kd3hhar76k3an5jr0t8fgyc47s4lnp4rh8uk4afrlwasuur3qzgewqq",
"scriptPathControlBlocks": [ "scriptPathControlBlocks": [
"c1ffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553", "c1ffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
"c1ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817", "c19e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
"c19e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817" "c1ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
] ]
} }
}, },
@@ -251,8 +251,8 @@
"bip350Address": "bc1z9a4jc5uhkmtgegvwpx3lq5tpv68layaf3pvz64wx7paatvejnhhsv52lcv", "bip350Address": "bc1z9a4jc5uhkmtgegvwpx3lq5tpv68layaf3pvz64wx7paatvejnhhsv52lcv",
"scriptPathControlBlocks": [ "scriptPathControlBlocks": [
"c13cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91", "c13cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
"c1737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d", "c1d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
"c1d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d" "c1737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
] ]
} }
} }

View File

@@ -71,8 +71,8 @@
"scriptPubKey": "52201619ce6d22a46dea045c4adf7f5f33d6810d00d0e9c8a4c7ba35db37b915c604", "scriptPubKey": "52201619ce6d22a46dea045c4adf7f5f33d6810d00d0e9c8a4c7ba35db37b915c604",
"bip350Address": "bc1zzcvuumfz53k75pzuft0h7hen66qs6qxsa8y2f3a6xhdn0wg4cczq0h84sj", "bip350Address": "bc1zzcvuumfz53k75pzuft0h7hen66qs6qxsa8y2f3a6xhdn0wg4cczq0h84sj",
"scriptPathControlBlocks": [ "scriptPathControlBlocks": [
"c13bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc", "c1f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
"c1f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a" "c13bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc"
] ]
} }
}, },
@@ -110,8 +110,8 @@
"scriptPubKey": "52202794771cd51f215ba3a19fbcdf08c771edb7de782a0c34457e0e9be5d0e4008f", "scriptPubKey": "52202794771cd51f215ba3a19fbcdf08c771edb7de782a0c34457e0e9be5d0e4008f",
"bip350Address": "bc1zy728w8x4rus4hgapn77d7zx8w8km0hnc9gxrg3t7p6d7t58yqz8sg0nccq", "bip350Address": "bc1zy728w8x4rus4hgapn77d7zx8w8km0hnc9gxrg3t7p6d7t58yqz8sg0nccq",
"scriptPathControlBlocks": [ "scriptPathControlBlocks": [
"c1cfd5fc07ac39947cba799e14f933f20e7c233dea72dc2792f5547c58cdce743e", "c1a9745ac96d4f3702b78751f1e08f3040fbe6347e7b4f520d22d3f907730cbb7e",
"c1a9745ac96d4f3702b78751f1e08f3040fbe6347e7b4f520d22d3f907730cbb7e" "c1cfd5fc07ac39947cba799e14f933f20e7c233dea72dc2792f5547c58cdce743e"
] ]
} }
}, },
@@ -147,8 +147,8 @@
"scriptPubKey": "52205112b3edfd2c0b717491e9d4888ed2d5dfeaa25115143540e0a08516b68c008c", "scriptPubKey": "52205112b3edfd2c0b717491e9d4888ed2d5dfeaa25115143540e0a08516b68c008c",
"bip350Address": "bc1z2yft8m0a9s9hzay3a82g3rkj6h074gj3z52r2s8q5zz3dd5vqzxqngpk2w", "bip350Address": "bc1z2yft8m0a9s9hzay3a82g3rkj6h074gj3z52r2s8q5zz3dd5vqzxqngpk2w",
"scriptPathControlBlocks": [ "scriptPathControlBlocks": [
"c19de7eeded7832c28c6f80de76904dd79f98fd302747823b5bc5be440186b0c6d", "c12cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
"c12cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb" "c19de7eeded7832c28c6f80de76904dd79f98fd302747823b5bc5be440186b0c6d"
] ]
} }
}, },
@@ -194,9 +194,9 @@
"scriptPubKey": "5220eaf8f557fdb9673de7bb9bad7e7452da9f44a3e65133fdadf2849c55cfb3cf5b", "scriptPubKey": "5220eaf8f557fdb9673de7bb9bad7e7452da9f44a3e65133fdadf2849c55cfb3cf5b",
"bip350Address": "bc1zatu024lah9nnmeamnwkhuazjm205fglx2yelmt0jsjw9tnaneadszq7wg7", "bip350Address": "bc1zatu024lah9nnmeamnwkhuazjm205fglx2yelmt0jsjw9tnaneadszq7wg7",
"scriptPathControlBlocks": [ "scriptPathControlBlocks": [
"c1837ef6677aeb0df2b0de47f45024684cc6ca03bda10fa30bb5bc05a94beb8dd1b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a", "c118781f42f664d67acaf0ce7c6826437e5440eb1789f232af05e9a09fdf547903",
"c10840c39e59eda6c9deee687a480cb169130c2f053ed2eb3134511ec1cfd8a2c7b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a", "c10840c39e59eda6c9deee687a480cb169130c2f053ed2eb3134511ec1cfd8a2c7b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a",
"c118781f42f664d67acaf0ce7c6826437e5440eb1789f232af05e9a09fdf547903" "c1837ef6677aeb0df2b0de47f45024684cc6ca03bda10fa30bb5bc05a94beb8dd1b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a"
] ]
} }
}, },
@@ -242,9 +242,9 @@
"scriptPubKey": "522051e3c1151ba73d9efce801837773331bf9030977242f62dfeb6756795f482409", "scriptPubKey": "522051e3c1151ba73d9efce801837773331bf9030977242f62dfeb6756795f482409",
"bip350Address": "bc1z283uz9gm5u7eal8gqxphwuenr0usxzthyshk9hltvat8jh6gysys28twnc", "bip350Address": "bc1z283uz9gm5u7eal8gqxphwuenr0usxzthyshk9hltvat8jh6gysys28twnc",
"scriptPathControlBlocks": [ "scriptPathControlBlocks": [
"c1dcef3ce86cc8cea78c9e00f3d9ef58360cb6ed3cb90ec62efe00b9703854ba5cddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361", "c1b45680a7821e4b9450096ab38adbc3c99225af8f6c7ec121a0a5f1ae02893ba3",
"c152e9326c2bf04d926b7e9f6c7645dd853f3f007b870201de9b814952750c9310ddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361", "c152e9326c2bf04d926b7e9f6c7645dd853f3f007b870201de9b814952750c9310ddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361",
"c1b45680a7821e4b9450096ab38adbc3c99225af8f6c7ec121a0a5f1ae02893ba3" "c1dcef3ce86cc8cea78c9e00f3d9ef58360cb6ed3cb90ec62efe00b9703854ba5cddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361"
] ]
} }
} }

View File

@@ -1,4 +1,4 @@
use std::collections::HashSet; use std::collections::HashMap;
use bitcoin::{Network, ScriptBuf}; use bitcoin::{Network, ScriptBuf};
use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash}; use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash};
use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo}; use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo};
@@ -136,7 +136,7 @@ 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 // 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 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 // 1) traverse test vector script tree and add leaves to P2MR builder
if let Some(script_tree) = tv_script_tree { if let Some(script_tree) = tv_script_tree {
@@ -147,10 +147,9 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
let tv_leaf_script_bytes = hex::decode(&tv_leaf.script).unwrap(); 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_script_buf = ScriptBuf::from_bytes(tv_leaf_script_bytes.clone());
let tv_leaf_version = LeafVersion::from_consensus(tv_leaf.leaf_version).unwrap(); 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; let mut modified_depth = depth + 1;
if direction == Direction::Root { if direction == Direction::Root {
@@ -194,14 +193,10 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
); );
debug!("just passed merkle root validation: {}", test_vector_merkle_root); 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 expected_control_blocks = test_vector.expected.script_path_control_blocks.as_ref().unwrap();
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 tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap(); let tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap();
let script_leaves: ScriptLeaves = tap_tree.script_leaves(); 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 // 3) Iterate through leaves of derived script tree and verify both script leaf hashes and control blocks
for derived_leaf in script_leaves { for derived_leaf in script_leaves {
@@ -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 derived_leaf_hash: TapLeafHash = TapLeafHash::from_script(script, version);
let leaf_hash = hex::encode(derived_leaf_hash.as_raw_hash().to_byte_array()); 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. let leaf_id = script_to_id.get(script)
// Specific to P2TR, the 3 sections of the control block (control byte, public key & merkle path) are highlighted here: .unwrap_or_else(|| panic!("leaf script not found in script_to_id map: {}", hex::encode(script.as_bytes())));
// 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 derived_control_block: P2mrControlBlock = P2mrControlBlock{ let derived_control_block: P2mrControlBlock = P2mrControlBlock{
merkle_branch: merkle_branch.clone(), merkle_branch: merkle_branch.clone(),
}; };
let serialized_control_block = derived_control_block.serialize(); let derived_serialized_control_block = hex::encode(derived_control_block.serialize());
debug!("derived_control_block: {:?}, merkle_branch size: {}, control_block size: {}, serialized size: {}",
derived_control_block, let expected_cb = &expected_control_blocks[*leaf_id as usize];
merkle_branch.len(), assert_eq!(
derived_control_block.size(), derived_serialized_control_block, *expected_cb,
serialized_control_block.len()); "Control block mismatch for leaf id {}: derived {}, expected {}", leaf_id, derived_serialized_control_block, expected_cb
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
); );
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);
} }

View File

@@ -1,4 +1,4 @@
use std::collections::HashSet; use std::collections::HashMap;
use bitcoin::{Network, ScriptBuf}; use bitcoin::{Network, ScriptBuf};
use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash}; use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash};
use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo}; use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo};
@@ -114,7 +114,7 @@ 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 // 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 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 // 1) traverse test vector script tree and add leaves to P2MR builder
if let Some(script_tree) = tv_script_tree { if let Some(script_tree) = tv_script_tree {
@@ -125,10 +125,9 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
let tv_leaf_script_bytes = hex::decode(&tv_leaf.script).unwrap(); 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_script_buf = ScriptBuf::from_bytes(tv_leaf_script_bytes.clone());
let tv_leaf_version = LeafVersion::from_consensus(tv_leaf.leaf_version).unwrap(); 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; let mut modified_depth = depth + 1;
if direction == Direction::Root { if direction == Direction::Root {
@@ -172,14 +171,10 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
); );
debug!("just passed merkle root validation: {}", test_vector_merkle_root); 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 expected_control_blocks = test_vector.expected.script_path_control_blocks.as_ref().unwrap();
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 tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap(); let tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap();
let script_leaves: ScriptLeaves = tap_tree.script_leaves(); 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 // 3) Iterate through leaves of derived script tree and verify both script leaf hashes and control blocks
for derived_leaf in script_leaves { for derived_leaf in script_leaves {
@@ -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 derived_leaf_hash: TapLeafHash = TapLeafHash::from_script(script, version);
let leaf_hash = hex::encode(derived_leaf_hash.as_raw_hash().to_byte_array()); 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. let leaf_id = script_to_id.get(script)
// Specific to P2TR, the 3 sections of the control block (control byte, public key & merkle path) are highlighted here: .unwrap_or_else(|| panic!("leaf script not found in script_to_id map: {}", hex::encode(script.as_bytes())));
// 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 derived_control_block: P2mrControlBlock = P2mrControlBlock{ let derived_control_block: P2mrControlBlock = P2mrControlBlock{
merkle_branch: merkle_branch.clone(), merkle_branch: merkle_branch.clone(),
}; };
let serialized_control_block = derived_control_block.serialize(); let derived_serialized_control_block = hex::encode(derived_control_block.serialize());
debug!("derived_control_block: {:?}, merkle_branch size: {}, control_block size: {}, serialized size: {}",
derived_control_block, let expected_cb = &expected_control_blocks[*leaf_id as usize];
merkle_branch.len(), assert_eq!(
derived_control_block.size(), derived_serialized_control_block, *expected_cb,
serialized_control_block.len()); "Control block mismatch for leaf id {}: derived {}, expected {}", leaf_id, derived_serialized_control_block, expected_cb
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
); );
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);
} }