Skip to content

Commit 6c68c16

Browse files
committed
bip360: throw error when leaf version is non-standard ( 192 / c0 )
1 parent 351ceef commit 6c68c16

4 files changed

Lines changed: 27 additions & 23 deletions

File tree

bip-0360/ref-impl/common/tests/data/p2mr_construction.json

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
},
5858
{
5959
"id": "p2mr_different_version_leaves",
60-
"objective": "Tests P2MR with two script leaves of different versions. TO-DO: currently ignores given leaf version and over-rides. Probably better to throw error",
60+
"objective": "Tests P2MR with two script leaves of different versions. BIP-360 requires all leaves to use leaf version 0xc0; a non-standard version must throw an error.",
6161
"given": {
6262
"scriptTree": [
6363
{
@@ -75,20 +75,8 @@
7575
}
7676
]
7777
},
78-
"intermediary": {
79-
"leafHashes": [
80-
"8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7",
81-
"f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
82-
],
83-
"merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef"
84-
},
8578
"expected": {
86-
"scriptPubKey": "52206c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
87-
"bip350Address": "bc1zdskuzp4ts94h87ws0c7drmev3sf9dagewj8qsylyahfyqhf800hsam4d6e",
88-
"scriptPathControlBlocks": [
89-
"c1f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
90-
"c18ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
91-
]
79+
"error": "BIP-360 requires leaf version 0xc0; leaf 1 has version 250"
9280
}
9381
},
9482
{

bip-0360/ref-impl/rust/src/data_structures.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub struct TestVector {
111111
pub id: String,
112112
pub objective: String,
113113
pub given: TestVectorGiven,
114+
#[serde(default)]
114115
pub intermediary: TestVectorIntermediary,
115116
pub expected: TestVectorExpected,
116117
}
@@ -132,7 +133,7 @@ pub struct TestVectorGiven {
132133
pub control_block: Option<String>,
133134
}
134135

135-
#[derive(Debug, Serialize, Deserialize, Clone)]
136+
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
136137
pub struct TestVectorIntermediary {
137138

138139
#[serde(default)]

bip-0360/ref-impl/rust/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@ pub enum P2MRError {
1313
// We can add more specific error variants here as needed
1414
#[error("Invalid script tree structure: {0}")]
1515
InvalidScriptTree(String),
16+
17+
#[error("BIP-360 requires leaf version 0xc0; leaf {0} has version {1}")]
18+
InvalidLeafVersion(u8, u8),
1619
}

bip-0360/ref-impl/rust/tests/p2mr_construction.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashSet;
22
use bitcoin::{Network, ScriptBuf};
33
use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash};
4-
use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo};
4+
use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo, P2MR_LEAF_VERSION};
55
use bitcoin::hashes::Hash;
66

77
use hex;
@@ -72,7 +72,9 @@ fn test_p2mr_different_version_leaves() {
7272

7373
let test_vectors = &*TEST_VECTORS;
7474
let test_vector = test_vectors.test_vector_map.get(P2MR_DIFFERENT_VERSION_LEAVES_TEST).unwrap();
75-
process_test_vector_p2mr(test_vector).unwrap();
75+
let test_result = process_test_vector_p2mr(test_vector);
76+
assert!(matches!(test_result.unwrap_err().downcast_ref::<P2MRError>(),
77+
Some(P2MRError::InvalidLeafVersion(_, _))));
7678
}
7779

7880
#[test]
@@ -137,29 +139,37 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
137139
let mut p2mr_builder: P2mrBuilder = P2mrBuilder::new();
138140

139141
let mut control_block_data: Vec<(ScriptBuf, LeafVersion)> = Vec::new();
142+
let mut traversal_result: anyhow::Result<()> = Ok(());
140143

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

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

149+
if traversal_result.is_err() { return; }
150+
146151
if let TVScriptTree::Leaf(tv_leaf) = node {
147-
152+
148153
let tv_leaf_script_bytes = hex::decode(&tv_leaf.script).unwrap();
149-
154+
150155
// NOTE: IOT to execute script_info.control_block(..), will add these to a vector
151156
let tv_leaf_script_buf = ScriptBuf::from_bytes(tv_leaf_script_bytes.clone());
152157
let tv_leaf_version = LeafVersion::from_consensus(tv_leaf.leaf_version).unwrap();
158+
159+
if tv_leaf.leaf_version != P2MR_LEAF_VERSION {
160+
traversal_result = Err(P2MRError::InvalidLeafVersion(tv_leaf.id, tv_leaf.leaf_version).into());
161+
return;
162+
}
163+
153164
control_block_data.push((tv_leaf_script_buf.clone(), tv_leaf_version));
154-
165+
155166
let mut modified_depth = depth + 1;
156167
if direction == Direction::Root {
157168
modified_depth = depth;
158169
}
159-
debug!("traverse_with_depth: leaf_count: {}, depth: {}, modified_depth: {}, direction: {}, tv_leaf_script: {}",
170+
debug!("traverse_with_depth: leaf_count: {}, depth: {}, modified_depth: {}, direction: {}, tv_leaf_script: {}",
160171
tv_leaf_count, depth, modified_depth, direction, tv_leaf.script);
161-
162-
// NOTE: Some of the the test vectors in this project specify leaves with non-standard versions (ie: 250 / 0xfa)
172+
163173
p2mr_builder = p2mr_builder.clone().add_leaf_with_ver(depth, tv_leaf_script_buf.clone(), tv_leaf_version)
164174
.unwrap_or_else(|e| {
165175
panic!("Failed to add leaf: {:?}", e);
@@ -177,6 +187,8 @@ fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
177187
return Err(P2MRError::MissingScriptTreeLeaf.into());
178188
}
179189

190+
traversal_result?;
191+
180192
let spend_info: P2mrSpendInfo = p2mr_builder.clone()
181193
.finalize()
182194
.unwrap_or_else(|e| {

0 commit comments

Comments
 (0)