taproot_assets_types/
mssmt.rs1use crate::error::Error;
2use alloc::{string::ToString, vec::Vec};
3use bitcoin::hashes::{Hash, sha256::Hash as Sha256Hash};
4use bitcoin::io::Read;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub struct MssmtNode {
10 pub hash: Sha256Hash,
12 pub sum: u64,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
18pub struct MssmtProof {
19 pub nodes: Vec<MssmtNode>,
22}
23
24impl MssmtProof {
25 pub fn decode_tlv<R: Read>(mut r: R) -> Result<Self, Error> {
26 let mut num_nodes_bytes = [0u8; 2];
33 r.read_exact(&mut num_nodes_bytes).map_err(Error::Io)?;
34 let num_nodes = u16::from_be_bytes(num_nodes_bytes) as usize;
35
36 let mut explicit_nodes = Vec::with_capacity(num_nodes);
38 for _ in 0..num_nodes {
39 let mut hash_bytes = [0u8; 32];
41 r.read_exact(&mut hash_bytes).map_err(Error::Io)?;
42 let hash = Sha256Hash::from_byte_array(hash_bytes);
43
44 let mut sum_bytes = [0u8; 8];
46 r.read_exact(&mut sum_bytes).map_err(Error::Io)?;
47 let sum = u64::from_be_bytes(sum_bytes);
48
49 explicit_nodes.push(MssmtNode { hash, sum });
50 }
51
52 let mut packed_bits = [0u8; 32];
55 r.read_exact(&mut packed_bits).map_err(Error::Io)?;
56
57 let mut bits = Vec::with_capacity(256);
61 for i in 0..256 {
62 let byte_idx = i / 8;
63 let bit_idx = i % 8;
64 let byte_val = packed_bits[byte_idx];
65 let bit_set = (byte_val >> bit_idx) & 1 == 1;
66 bits.push(bit_set);
67 }
68
69 let mut nodes = Vec::new();
71 let mut explicit_node_idx = 0;
72
73 let false_bits = bits.iter().filter(|&&b| !b).count();
75
76 if false_bits != explicit_nodes.len() {
81 return Err(Error::InvalidTlvValue(
82 0,
83 "Bit/node count mismatch: false bits != explicit nodes".to_string(),
84 ));
85 }
86
87 for (_level, bit_set) in bits.iter().enumerate() {
88 if *bit_set {
89 nodes.push(MssmtNode {
91 hash: Sha256Hash::all_zeros(),
92 sum: 0,
93 });
94 } else {
95 if explicit_node_idx >= explicit_nodes.len() {
97 return Err(Error::InvalidTlvValue(
98 0,
99 "Insufficient explicit nodes for compressed proof".to_string(),
100 ));
101 }
102 nodes.push(explicit_nodes[explicit_node_idx].clone());
103 explicit_node_idx += 1;
104 }
105 }
106
107 if explicit_node_idx != explicit_nodes.len() {
109 return Err(Error::InvalidTlvValue(
110 0,
111 "Too many explicit nodes for compressed proof".to_string(),
112 ));
113 }
114
115 Ok(MssmtProof { nodes })
116 }
117}