1use crate::error::BitcoinError;
7use bitcoin::hashes::Hash;
8use bitcoin::{Script, TapLeafHash};
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct TapscriptLeaf {
15 pub script: Vec<u8>,
17 pub version: u8,
19 pub weight: u32,
21}
22
23impl TapscriptLeaf {
24 pub fn new(script: Vec<u8>, weight: u32) -> Self {
26 Self {
27 script,
28 version: 0xc0, weight,
30 }
31 }
32
33 pub fn leaf_hash(&self) -> Result<TapLeafHash, BitcoinError> {
35 use bitcoin::hashes::{HashEngine, sha256};
36 let script = Script::from_bytes(&self.script);
37
38 let mut engine = sha256::Hash::engine();
40 engine.input(&[self.version]);
41 engine.input(script.as_bytes());
42 let hash = sha256::Hash::from_engine(engine);
43
44 Ok(TapLeafHash::from_byte_array(hash.to_byte_array()))
45 }
46}
47
48#[derive(Debug, Clone)]
50pub enum TapscriptNode {
51 Leaf(TapscriptLeaf),
53 Branch {
55 left: Box<TapscriptNode>,
56 right: Box<TapscriptNode>,
57 },
58}
59
60impl TapscriptNode {
61 pub fn node_hash(&self) -> Result<[u8; 32], BitcoinError> {
63 match self {
64 TapscriptNode::Leaf(leaf) => {
65 let hash = leaf.leaf_hash()?;
66 Ok(*hash.as_byte_array())
67 }
68 TapscriptNode::Branch { left, right } => {
69 let left_hash = left.node_hash()?;
70 let right_hash = right.node_hash()?;
71
72 let (first, second) = if left_hash < right_hash {
74 (left_hash, right_hash)
75 } else {
76 (right_hash, left_hash)
77 };
78
79 use bitcoin::hashes::{Hash, HashEngine, sha256};
81 let mut engine = sha256::Hash::engine();
82 engine.input(&[0x01]); engine.input(&first);
84 engine.input(&second);
85 let hash = sha256::Hash::from_engine(engine);
86
87 Ok(hash.to_byte_array())
88 }
89 }
90 }
91
92 pub fn total_weight(&self) -> u32 {
94 match self {
95 TapscriptNode::Leaf(leaf) => leaf.weight,
96 TapscriptNode::Branch { left, right } => left.total_weight() + right.total_weight(),
97 }
98 }
99
100 pub fn depth(&self) -> usize {
102 match self {
103 TapscriptNode::Leaf(_) => 1,
104 TapscriptNode::Branch { left, right } => 1 + std::cmp::max(left.depth(), right.depth()),
105 }
106 }
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct MerkleProof {
112 pub script: Vec<u8>,
114 pub proof_hashes: Vec<[u8; 32]>,
116 pub leaf_version: u8,
118}
119
120impl MerkleProof {
121 pub fn new(script: Vec<u8>, proof_hashes: Vec<[u8; 32]>, leaf_version: u8) -> Self {
123 Self {
124 script,
125 proof_hashes,
126 leaf_version,
127 }
128 }
129
130 pub fn verify(&self, root_hash: &[u8; 32]) -> Result<bool, BitcoinError> {
132 let leaf = TapscriptLeaf {
133 script: self.script.clone(),
134 version: self.leaf_version,
135 weight: 1,
136 };
137
138 let mut current_hash = *leaf.leaf_hash()?.as_byte_array();
139
140 for proof_hash in &self.proof_hashes {
141 let (first, second) = if current_hash < *proof_hash {
142 (current_hash, *proof_hash)
143 } else {
144 (*proof_hash, current_hash)
145 };
146
147 use bitcoin::hashes::{Hash, HashEngine, sha256};
148 let mut engine = sha256::Hash::engine();
149 engine.input(&[0x01]);
150 engine.input(&first);
151 engine.input(&second);
152 current_hash = sha256::Hash::from_engine(engine).to_byte_array();
153 }
154
155 Ok(current_hash == *root_hash)
156 }
157}
158
159pub struct TapscriptTreeBuilder {
161 leaves: Vec<TapscriptLeaf>,
162}
163
164impl TapscriptTreeBuilder {
165 pub fn new() -> Self {
167 Self { leaves: Vec::new() }
168 }
169
170 pub fn add_leaf(&mut self, script: Vec<u8>, weight: u32) {
172 self.leaves.push(TapscriptLeaf::new(script, weight));
173 }
174
175 pub fn add_simple_leaf(&mut self, script: Vec<u8>) {
177 self.add_leaf(script, 1);
178 }
179
180 pub fn build_balanced(&self) -> Result<TapscriptNode, BitcoinError> {
182 if self.leaves.is_empty() {
183 return Err(BitcoinError::InvalidTransaction(
184 "No leaves to build tree".to_string(),
185 ));
186 }
187
188 let mut nodes: Vec<TapscriptNode> = self
189 .leaves
190 .iter()
191 .map(|leaf| TapscriptNode::Leaf(leaf.clone()))
192 .collect();
193
194 while nodes.len() > 1 {
195 let mut new_nodes = Vec::new();
196
197 for chunk in nodes.chunks(2) {
198 if chunk.len() == 2 {
199 new_nodes.push(TapscriptNode::Branch {
200 left: Box::new(chunk[0].clone()),
201 right: Box::new(chunk[1].clone()),
202 });
203 } else {
204 new_nodes.push(chunk[0].clone());
205 }
206 }
207
208 nodes = new_nodes;
209 }
210
211 Ok(nodes.into_iter().next().unwrap())
212 }
213
214 pub fn build_huffman(&self) -> Result<TapscriptNode, BitcoinError> {
219 if self.leaves.is_empty() {
220 return Err(BitcoinError::InvalidTransaction(
221 "No leaves to build tree".to_string(),
222 ));
223 }
224
225 if self.leaves.len() == 1 {
226 return Ok(TapscriptNode::Leaf(self.leaves[0].clone()));
227 }
228
229 let mut nodes: Vec<TapscriptNode> = self
231 .leaves
232 .iter()
233 .map(|leaf| TapscriptNode::Leaf(leaf.clone()))
234 .collect();
235
236 while nodes.len() > 1 {
238 nodes.sort_by_key(|n| n.total_weight());
240
241 let left = nodes.remove(0);
243 let right = nodes.remove(0);
244
245 let branch = TapscriptNode::Branch {
247 left: Box::new(left),
248 right: Box::new(right),
249 };
250
251 nodes.push(branch);
253 }
254
255 Ok(nodes.into_iter().next().unwrap())
256 }
257
258 pub fn generate_proof(
260 &self,
261 tree: &TapscriptNode,
262 target_script: &[u8],
263 ) -> Result<MerkleProof, BitcoinError> {
264 let mut proof_hashes = Vec::new();
265
266 if !self.find_proof(tree, target_script, &mut proof_hashes)? {
267 return Err(BitcoinError::InvalidTransaction(
268 "Script not found in tree".to_string(),
269 ));
270 }
271
272 Ok(MerkleProof::new(target_script.to_vec(), proof_hashes, 0xc0))
273 }
274
275 fn find_proof(
277 &self,
278 node: &TapscriptNode,
279 target: &[u8],
280 proof: &mut Vec<[u8; 32]>,
281 ) -> Result<bool, BitcoinError> {
282 match node {
283 TapscriptNode::Leaf(leaf) => Ok(leaf.script == target),
284 TapscriptNode::Branch { left, right } => {
285 if self.find_proof(left, target, proof)? {
286 proof.push(right.node_hash()?);
287 Ok(true)
288 } else if self.find_proof(right, target, proof)? {
289 proof.push(left.node_hash()?);
290 Ok(true)
291 } else {
292 Ok(false)
293 }
294 }
295 }
296 }
297}
298
299impl Default for TapscriptTreeBuilder {
300 fn default() -> Self {
301 Self::new()
302 }
303}
304
305pub struct ScriptPathOptimizer {
307 script_frequencies: HashMap<Vec<u8>, u32>,
309}
310
311impl ScriptPathOptimizer {
312 pub fn new() -> Self {
314 Self {
315 script_frequencies: HashMap::new(),
316 }
317 }
318
319 pub fn record_usage(&mut self, script: Vec<u8>) {
321 *self.script_frequencies.entry(script).or_insert(0) += 1;
322 }
323
324 pub fn build_optimized_tree(&self) -> Result<TapscriptNode, BitcoinError> {
326 let mut builder = TapscriptTreeBuilder::new();
327
328 for (script, frequency) in &self.script_frequencies {
329 builder.add_leaf(script.clone(), *frequency);
330 }
331
332 builder.build_huffman()
333 }
334
335 pub fn calculate_expected_witness_size(&self, tree: &TapscriptNode) -> f64 {
337 let total_frequency: u32 = self.script_frequencies.values().sum();
338 if total_frequency == 0 {
339 return 0.0;
340 }
341
342 let mut expected_size = 0.0;
343
344 for (script, frequency) in &self.script_frequencies {
345 let depth = self.get_script_depth(tree, script).unwrap_or(0);
346 let probability = *frequency as f64 / total_frequency as f64;
347 expected_size += probability * (script.len() + depth * 32) as f64;
348 }
349
350 expected_size
351 }
352
353 fn get_script_depth(&self, node: &TapscriptNode, target: &[u8]) -> Option<usize> {
355 match node {
356 TapscriptNode::Leaf(leaf) => {
357 if leaf.script == target {
358 Some(0)
359 } else {
360 None
361 }
362 }
363 TapscriptNode::Branch { left, right } => {
364 if let Some(depth) = self.get_script_depth(left, target) {
365 Some(depth + 1)
366 } else {
367 self.get_script_depth(right, target).map(|depth| depth + 1)
368 }
369 }
370 }
371 }
372}
373
374impl Default for ScriptPathOptimizer {
375 fn default() -> Self {
376 Self::new()
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383
384 #[test]
385 fn test_tapscript_leaf() {
386 let script = vec![0x51]; let leaf = TapscriptLeaf::new(script.clone(), 1);
388
389 assert_eq!(leaf.script, script);
390 assert_eq!(leaf.version, 0xc0);
391 assert_eq!(leaf.weight, 1);
392 }
393
394 #[test]
395 fn test_tree_builder_balanced() {
396 let mut builder = TapscriptTreeBuilder::new();
397 builder.add_simple_leaf(vec![0x51]); builder.add_simple_leaf(vec![0x52]); let tree = builder.build_balanced();
401 assert!(tree.is_ok());
402 }
403
404 #[test]
405 fn test_tree_builder_huffman() {
406 let mut builder = TapscriptTreeBuilder::new();
407 builder.add_leaf(vec![0x51], 10); builder.add_leaf(vec![0x52], 1); let tree = builder.build_huffman();
411 assert!(tree.is_ok());
412 }
413
414 #[test]
415 fn test_script_path_optimizer() {
416 let mut optimizer = ScriptPathOptimizer::new();
417 optimizer.record_usage(vec![0x51]);
418 optimizer.record_usage(vec![0x51]);
419 optimizer.record_usage(vec![0x52]);
420
421 let tree = optimizer.build_optimized_tree();
422 assert!(tree.is_ok());
423 }
424
425 #[test]
426 fn test_merkle_proof_creation() {
427 let mut builder = TapscriptTreeBuilder::new();
428 let script1 = vec![0x51];
429 let script2 = vec![0x52];
430
431 builder.add_simple_leaf(script1.clone());
432 builder.add_simple_leaf(script2.clone());
433
434 let tree = builder.build_balanced().unwrap();
435 let proof = builder.generate_proof(&tree, &script1);
436
437 assert!(proof.is_ok());
438 }
439
440 #[test]
441 fn test_node_depth() {
442 let leaf = TapscriptNode::Leaf(TapscriptLeaf::new(vec![0x51], 1));
443 assert_eq!(leaf.depth(), 1);
444
445 let branch = TapscriptNode::Branch {
446 left: Box::new(leaf.clone()),
447 right: Box::new(leaf),
448 };
449 assert_eq!(branch.depth(), 2);
450 }
451
452 #[test]
453 fn test_node_total_weight() {
454 let leaf1 = TapscriptNode::Leaf(TapscriptLeaf::new(vec![0x51], 5));
455 let leaf2 = TapscriptNode::Leaf(TapscriptLeaf::new(vec![0x52], 3));
456
457 let branch = TapscriptNode::Branch {
458 left: Box::new(leaf1),
459 right: Box::new(leaf2),
460 };
461
462 assert_eq!(branch.total_weight(), 8);
463 }
464}