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