1use bitcoin_hashes::{sha256, Hash};
19
20pub struct Forest {
21 pub roots: Vec<[u8; 33]>, }
23
24pub struct Proof {
25 pub tree_index: usize,
26
27 pub merkle_path: Vec<[u8; 33]>,
30}
31
32impl Forest {
33 pub fn new() -> Self {
34 Forest { roots: Vec::new() }
35 }
36
37 pub fn add(&mut self, entry: &[u8]) -> ([u8; 32], Proof) {
38 let hash = sha256::Hash::hash(entry);
39 let proof = self.add_hash(hash.as_byte_array());
40 (*hash.as_byte_array(), proof)
41 }
42
43 pub fn add_hash(&mut self, hash: &[u8; 32]) -> Proof {
44 let mut new_merkle_root = vec![0u8; 33];
45 new_merkle_root[1..33].copy_from_slice(hash);
46
47 let mut proof = Proof {
48 tree_index: 0,
49 merkle_path: Vec::with_capacity(32),
50 };
51
52 let mut level = 0;
54 loop {
55 match self.roots.last() {
57 Some(prev_root) if prev_root[0] == level => {
58 let mut path_item = vec![0u8; 33];
59 path_item[1..33].copy_from_slice(&prev_root[1..33]);
60 proof.merkle_path.push(path_item.try_into().unwrap());
63
64 let mut combined_merkle = vec![0u8; 64];
66 combined_merkle[0..32].copy_from_slice(&prev_root[1..33]);
67 combined_merkle[32..64].copy_from_slice(&new_merkle_root[1..33]);
68
69 new_merkle_root[1..33]
70 .copy_from_slice(sha256::Hash::hash(&combined_merkle).as_byte_array());
71 new_merkle_root[0] = level + 1;
72
73 self.roots.remove(self.roots.len() - 1);
75
76 level += 1;
78
79 continue;
80 }
81 _ => {
82 proof.tree_index = self.roots.len();
83 self.roots.push(new_merkle_root.try_into().unwrap());
84 return proof;
85 }
86 }
87 }
88 }
89
90 pub fn check_presence(&self, entry: [u8; 32], proof: &Proof) -> bool {
91 self.roots.get(proof.tree_index).map_or(false, |root| {
92 let mut current_value = entry;
93 let mut combined_merkle = vec![0u8; 64];
94 for path_item in &proof.merkle_path {
95 if path_item[0] == 0 {
96 combined_merkle[0..32].copy_from_slice(&path_item[1..33]);
97 combined_merkle[32..64].copy_from_slice(¤t_value);
98 } else {
99 combined_merkle[0..32].copy_from_slice(¤t_value);
100 combined_merkle[32..64].copy_from_slice(&path_item[1..33]);
101 }
102
103 current_value = *sha256::Hash::hash(&combined_merkle).as_byte_array();
104 }
105
106 current_value == root[1..33]
107 })
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn tree_building_manual() {
117 let mut forest = Forest::new();
118 forest.add(&vec![1, 2, 3, 4, 5]);
119 assert_eq!(forest.roots.len(), 1, "length 1 at 1");
120 forest.add(&vec![1, 2, 3, 4, 5]);
121 forest.add(&vec![1, 2, 3, 4, 5]);
122 assert_eq!(forest.roots.len(), 2, "length 2 at 3");
123 forest.add(&vec![1, 2, 3, 4, 5]);
124 assert_eq!(forest.roots.len(), 1, "length 1 at 4");
125 assert_eq!(forest.roots[0][0], 2, "level 2 at 4");
126 forest.add(&vec![1, 2, 3, 4, 5]);
127 forest.add(&vec![1, 2, 3, 4, 5]);
128 forest.add(&vec![1, 2, 3, 4, 5]);
129 forest.add(&vec![1, 2, 3, 4, 5]);
130 forest.add(&vec![1, 2, 3, 4, 5]);
131 forest.add(&vec![1, 2, 3, 4, 5]);
132 forest.add(&vec![1, 2, 3, 4, 5]);
133 assert_eq!(forest.roots.len(), 3, "length 3 at 12");
134 assert_eq!(forest.roots[0][0], 3, "level 3 at 12");
135 }
136
137 #[test]
138 fn tree_building() {
139 let mut forest = Forest::new();
140 for i in 0..(u64::pow(2, 16) - 1) {
141 forest.add(format!("entry:{}", i).as_bytes());
142 }
143 assert_eq!(forest.roots.len(), 16, "16 trees right before level 16");
144 forest.add("last".as_bytes());
145 assert_eq!(forest.roots.len(), 1, "perfect single tree with 16 levels");
146 assert_eq!(forest.roots[0][0], 16, "level 16 after 2**16 entries");
147 }
148
149 #[test]
150 fn correct_hashing() {
151 let mut forest1 = Forest::new();
152 let h = sha256::Hash::hash(&vec![1, 2, 3, 4, 5]);
153 forest1.add_hash(h.as_byte_array());
154
155 assert_eq!(
156 forest1.roots[0],
157 [
158 0u8, 116u8, 248u8, 31u8, 225u8, 103u8, 217u8, 155u8, 76u8, 180u8, 29u8, 109u8,
159 12u8, 205u8, 168u8, 34u8, 120u8, 202u8, 238u8, 159u8, 62u8, 47u8, 37u8, 213u8,
160 229u8, 163u8, 147u8, 111u8, 243u8, 220u8, 236u8, 96u8, 208u8,
161 ]
162 );
163
164 forest1.add_hash(h.as_byte_array());
165 forest1.add_hash(h.as_byte_array());
166 forest1.add_hash(h.as_byte_array());
167 forest1.add_hash(h.as_byte_array());
168
169 let mut forest2 = Forest::new();
170 forest2.add(&vec![1, 2, 3, 4, 5]);
171 forest2.add(&vec![1, 2, 3, 4, 5]);
172 forest2.add(&vec![1, 2, 3, 4, 5]);
173 forest2.add(&vec![1, 2, 3, 4, 5]);
174 forest2.add(&vec![1, 2, 3, 4, 5]);
175
176 assert_eq!(forest1.roots, forest2.roots);
177 assert_eq!(
178 forest2.roots[0],
179 [
180 2u8, 217u8, 21u8, 129u8, 3u8, 237u8, 23u8, 184u8, 184u8, 149u8, 37u8, 236u8, 24u8,
181 71u8, 86u8, 103u8, 102u8, 187u8, 212u8, 251u8, 124u8, 220u8, 154u8, 90u8, 54u8,
182 144u8, 46u8, 225u8, 145u8, 124u8, 70u8, 214u8, 70u8,
183 ]
184 );
185 }
186
187 #[test]
188 fn proofs() {
189 let mut forest = Forest::new();
190 forest.add(&vec![1, 2, 3, 4, 5]);
191 let (hash, proof) = forest.add(&vec![0, 0, 0, 0, 0]);
192 assert_eq!(proof.tree_index, 0, "proof tree index");
193 assert_eq!(proof.merkle_path.len(), 1, "merkle path size");
194 assert_eq!(
195 forest.check_presence(hash, &proof),
196 true,
197 "presence should be confirmed"
198 );
199 forest.add(&vec![1, 2, 3, 4, 5]);
200 forest.add(&vec![1, 2, 3, 4, 5]);
201 forest.add(&vec![1, 2, 3, 4, 5]);
202 forest.add(&vec![1, 2, 3, 4, 5]);
203 forest.add(&vec![1, 2, 3, 4, 5]);
204 let (hash, proof) = forest.add(&vec![1, 2, 3, 4, 5]);
205 assert_eq!(proof.tree_index, 0, "proof tree index");
206 assert_eq!(proof.merkle_path.len(), 3, "merkle path size");
207 assert_eq!(
208 forest.check_presence(hash, &proof),
209 true,
210 "presence should be confirmed"
211 );
212
213 let (hash, _) = forest.add(&vec![0, 0, 0, 0, 0]);
214 assert_eq!(
215 forest.check_presence(hash, &proof),
216 false,
217 "proof for a different entry shouldn't work"
218 );
219 }
220}