1use crate::{MerkleHasher, NewMerkleHasherForTreeSize, hash_pairs};
2#[cfg(feature = "alloc")]
3use alloc::boxed::Box;
4use core::iter::TrustedLen;
5use core::mem::MaybeUninit;
6use core::num::NonZero;
7
8const BATCH_HASH_NUM_PAIRS: usize = 16;
11const BATCH_HASH_NUM_LEAVES: usize = BATCH_HASH_NUM_PAIRS * 2;
13
14const TREE_SIZE_WITHOUT_LEAVES<const N: usize>: usize = {
15 assert!(
17 N.is_power_of_two(),
18 "Balanced Merkle Tree must have a number of leaves that is a power of 2"
19 );
20
21 assert!(
22 N > 1,
23 "This Balanced Merkle Tree must have more than one leaf"
24 );
25
26 N - 1
27};
28pub const PROOF_ELEMENTS<const N: usize>: usize = N.ilog2() as usize;
30const ROOT_ONLY_LARGE_STACK_SIZE<const N: usize>: usize = {
31 if N < BATCH_HASH_NUM_LEAVES {
34 1
35 } else {
36 (N / BATCH_HASH_NUM_LEAVES).ilog2() as usize + 1
37 }
38};
39
40#[derive(Debug)]
60pub struct BalancedMerkleTree<'a, const N: usize, H>
61where
62 H: MerkleHasher,
63{
64 leaves: &'a [[u8; H::OUT_LEN]; N],
65 tree: [[u8; H::OUT_LEN]; TREE_SIZE_WITHOUT_LEAVES::<N>],
67}
68
69impl<'a, const N: usize, H> BalancedMerkleTree<'a, N, H>
70where
71 [(); TREE_SIZE_WITHOUT_LEAVES::<N>]:,
72 H: MerkleHasher + const NewMerkleHasherForTreeSize,
73{
74 #[cfg_attr(
81 all(feature = "no-panic", not(target_arch = "riscv64")),
82 no_panic::no_panic
83 )]
84 pub fn new(leaves: &'a [[u8; H::OUT_LEN]; N]) -> Self {
85 const { TREE_SIZE_WITHOUT_LEAVES::<N> };
88
89 let mut tree = [MaybeUninit::<[u8; H::OUT_LEN]>::uninit(); _];
90
91 Self::init_internal(leaves, &mut tree);
92
93 Self {
94 leaves,
95 tree: unsafe { tree.transpose().assume_init() },
97 }
98 }
99
100 #[cfg_attr(
104 all(feature = "no-panic", not(target_arch = "riscv64")),
105 no_panic::no_panic
106 )]
107 pub fn new_in<'b>(
108 instance: &'b mut MaybeUninit<Self>,
109 leaves: &'a [[u8; H::OUT_LEN]; N],
110 ) -> &'b mut Self {
111 const { TREE_SIZE_WITHOUT_LEAVES::<N> };
114
115 let instance_ptr = instance.as_mut_ptr();
116 unsafe {
118 (&raw mut (*instance_ptr).leaves).write(leaves);
119 }
120 let tree = {
121 let tree_ptr = unsafe { &raw mut (*instance_ptr).tree };
123 unsafe {
125 tree_ptr
126 .cast::<[MaybeUninit<[u8; H::OUT_LEN]>; TREE_SIZE_WITHOUT_LEAVES::<N>]>()
127 .as_mut_unchecked()
128 }
129 };
130
131 Self::init_internal(leaves, tree);
132
133 unsafe { instance.assume_init_mut() }
135 }
136
137 #[cfg(feature = "alloc")]
140 pub fn new_boxed(leaves: &'a [[u8; H::OUT_LEN]; N]) -> Box<Self> {
141 let mut instance = Box::<Self>::new_uninit();
142
143 Self::new_in(&mut instance, leaves);
144
145 unsafe { instance.assume_init() }
147 }
148
149 #[cfg_attr(
152 all(feature = "no-panic", not(target_arch = "riscv64")),
153 no_panic::no_panic
154 )]
155 fn init_internal(
156 leaves: &[[u8; H::OUT_LEN]; N],
157 tree: &mut [MaybeUninit<[u8; H::OUT_LEN]>; TREE_SIZE_WITHOUT_LEAVES::<N>],
158 ) {
159 let hasher = const { H::new_for_tree_size(N as u64) };
160 let mut tree_hashes = tree.as_mut_slice();
161 let mut level_hashes = leaves.as_slice();
162
163 while level_hashes.len() > 1 {
164 let num_pairs = level_hashes.len() / 2;
165 let parent_hashes;
166 (parent_hashes, tree_hashes) = unsafe { tree_hashes.split_at_mut_unchecked(num_pairs) };
169
170 let (parent_hashes_chunks, parent_hashes_remainder) =
171 parent_hashes.as_chunks_mut::<BATCH_HASH_NUM_PAIRS>();
172 if parent_hashes_remainder.is_empty() {
173 for (pairs, hashes) in level_hashes
174 .as_chunks::<BATCH_HASH_NUM_LEAVES>()
175 .0
176 .iter()
177 .zip(parent_hashes_chunks)
178 {
179 *hashes = MaybeUninit::new(hash_pairs(&hasher, pairs)).into();
182 }
183 } else {
184 for (pair, parent_hash) in level_hashes
185 .as_chunks::<2>()
186 .0
187 .iter()
188 .zip(parent_hashes.iter_mut())
189 {
190 parent_hash.write(hasher.hash_pair(pair));
191 }
192 }
193
194 level_hashes = unsafe { parent_hashes.assume_init_ref() };
196 }
197 }
198
199 #[inline]
205 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
206 pub fn compute_root_only(leaves: &[[u8; H::OUT_LEN]; N]) -> [u8; H::OUT_LEN] {
207 const { TREE_SIZE_WITHOUT_LEAVES::<N> };
210
211 let hasher = const { H::new_for_tree_size(N as u64) };
212
213 match N {
215 2 => {
216 let [root] = hash_pairs(&hasher, leaves);
217
218 return root;
219 }
220 4 => {
221 let hashes = hash_pairs::<2, _, _>(&hasher, leaves);
222 let [root] = hash_pairs(&hasher, &hashes);
223
224 return root;
225 }
226 8 => {
227 let hashes = hash_pairs::<4, _, _>(&hasher, leaves);
228 let hashes = hash_pairs::<2, _, _>(&hasher, &hashes);
229 let [root] = hash_pairs(&hasher, &hashes);
230
231 return root;
232 }
233 16 => {
234 let hashes = hash_pairs::<8, _, _>(&hasher, leaves);
235 let hashes = hash_pairs::<4, _, _>(&hasher, &hashes);
236 let hashes = hash_pairs::<2, _, _>(&hasher, &hashes);
237 let [root] = hash_pairs(&hasher, &hashes);
238
239 return root;
240 }
241 _ => {
242 assert!(N >= BATCH_HASH_NUM_LEAVES);
244 }
245 }
246
247 let mut stack =
251 [[[0u8; H::OUT_LEN]; BATCH_HASH_NUM_PAIRS]; ROOT_ONLY_LARGE_STACK_SIZE::<N>];
252
253 let mut parent_current = [[0u8; H::OUT_LEN]; BATCH_HASH_NUM_LEAVES];
256 for (num_chunks, chunk_leaves) in leaves
257 .as_chunks::<BATCH_HASH_NUM_LEAVES>()
258 .0
259 .iter()
260 .enumerate()
261 {
262 let current_half = &mut parent_current[BATCH_HASH_NUM_PAIRS..];
263
264 let current = hash_pairs::<BATCH_HASH_NUM_PAIRS, _, _>(&hasher, chunk_leaves);
265 current_half.copy_from_slice(¤t);
266
267 let lowest_active_levels = num_chunks.trailing_ones() as usize;
269 for parent in &mut stack[..lowest_active_levels] {
270 let parent_half = &mut parent_current[..BATCH_HASH_NUM_PAIRS];
271 parent_half.copy_from_slice(parent);
272
273 let current = hash_pairs::<BATCH_HASH_NUM_PAIRS, _, _>(&hasher, &parent_current);
274
275 let current_half = &mut parent_current[BATCH_HASH_NUM_PAIRS..];
276 current_half.copy_from_slice(¤t);
277 }
278
279 let current_half = &mut parent_current[BATCH_HASH_NUM_PAIRS..];
280
281 stack[lowest_active_levels].copy_from_slice(current_half);
283 }
284
285 let hashes = &stack[ROOT_ONLY_LARGE_STACK_SIZE::<N> - 1];
286 let hashes = hash_pairs::<{ BATCH_HASH_NUM_PAIRS / 2 }, _, _>(&hasher, hashes);
287 let hashes = hash_pairs::<{ BATCH_HASH_NUM_PAIRS / 4 }, _, _>(&hasher, &hashes);
288 let hashes = hash_pairs::<{ BATCH_HASH_NUM_PAIRS / 8 }, _, _>(&hasher, &hashes);
289 let [root] = hash_pairs::<{ BATCH_HASH_NUM_PAIRS / 16 }, _, _>(&hasher, &hashes);
290
291 root
292 }
293
294 #[inline]
296 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
297 pub fn root(&self) -> [u8; H::OUT_LEN] {
298 *self
299 .tree
300 .last()
301 .or(self.leaves.last())
302 .expect("There is always at least one leaf hash; qed")
303 }
304
305 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
307 pub fn all_proofs(&self) -> ProofsIterator<'_, N, H> {
308 ProofsIterator {
309 leaves: self.leaves,
310 tree: &self.tree,
311 leaf_index: 0,
312 }
313 }
314
315 #[inline]
317 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
318 pub fn verify(
319 root: &[u8; H::OUT_LEN],
320 proof: &[[u8; H::OUT_LEN]; PROOF_ELEMENTS::<N>],
321 leaf_index: usize,
322 leaf: [u8; H::OUT_LEN],
323 ) -> bool {
324 const { TREE_SIZE_WITHOUT_LEAVES::<N> };
327
328 if leaf_index >= N {
329 return false;
330 }
331
332 let hasher = const { H::new_for_tree_size(N as u64) };
333 let mut computed_root = leaf;
334
335 let mut position = leaf_index;
336 for hash in proof {
337 computed_root = if position.is_multiple_of(2) {
338 hasher.hash_pair(&[computed_root, *hash])
339 } else {
340 hasher.hash_pair(&[*hash, computed_root])
341 };
342
343 position /= 2;
344 }
345
346 root == &computed_root
347 }
348}
349
350#[derive(Debug)]
352pub struct ProofsIterator<'a, const N: usize, H>
353where
354 H: MerkleHasher,
355{
356 leaves: &'a [[u8; H::OUT_LEN]; N],
357 tree: &'a [[u8; H::OUT_LEN]; TREE_SIZE_WITHOUT_LEAVES::<N>],
358 leaf_index: usize,
360}
361
362impl<const N: usize, H> ProofsIterator<'_, N, H>
363where
364 H: MerkleHasher,
365{
366 #[inline(always)]
367 fn remaining(&self) -> usize {
368 N - self.leaf_index
369 }
370}
371
372impl<const N: usize, H> Iterator for ProofsIterator<'_, N, H>
373where
374 H: MerkleHasher,
375{
376 type Item = [[u8; H::OUT_LEN]; PROOF_ELEMENTS::<N>];
377
378 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
379 fn next(&mut self) -> Option<Self::Item> {
380 let index = self.leaf_index;
381
382 let sibling_index = index ^ 1;
389 let sibling_hash = *self.leaves.get(sibling_index)?;
392 self.leaf_index += 1;
393
394 let mut proof = [MaybeUninit::<[u8; H::OUT_LEN]>::uninit(); _];
395 proof[0].write(sibling_hash);
396
397 let shared_proof = &mut proof[1..];
399
400 let mut tree_hashes = self.tree.as_slice();
401 let mut parent_position = index / 2;
402 let mut parent_level_size = N / 2;
403
404 for hash in shared_proof {
405 let parent_other_position = parent_position ^ 1;
406
407 let other_hash = tree_hashes.get(parent_other_position).expect(
408 "`parent_position` is within the current level of the tree, whose size is an \
409 even number; qed",
410 );
411 hash.write(*other_hash);
412 tree_hashes = &tree_hashes[parent_level_size..];
413
414 parent_position /= 2;
415 parent_level_size /= 2;
416 }
417
418 Some(unsafe { proof.transpose().assume_init() })
420 }
421
422 #[inline(always)]
423 fn size_hint(&self) -> (usize, Option<usize>) {
424 let remaining = self.remaining();
425 (remaining, Some(remaining))
426 }
427
428 #[inline(always)]
429 fn count(self) -> usize {
430 self.remaining()
431 }
432
433 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
434 fn last(mut self) -> Option<Self::Item> {
435 if self.leaf_index >= N {
436 return None;
437 }
438 self.leaf_index = N - 1;
439 self.next()
440 }
441
442 #[inline(always)]
443 fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
444 let advance = n.min(self.remaining());
445 self.leaf_index += advance;
446 NonZero::new(n - advance).map_or(Ok(()), Err)
447 }
448
449 #[inline(always)]
450 fn nth(&mut self, n: usize) -> Option<Self::Item> {
451 match self.advance_by(n) {
452 Ok(()) => self.next(),
453 Err(_) => None,
454 }
455 }
456}
457
458impl<const N: usize, H> ExactSizeIterator for ProofsIterator<'_, N, H>
459where
460 H: MerkleHasher,
461{
462 #[inline(always)]
463 fn len(&self) -> usize {
464 self.remaining()
465 }
466}
467
468unsafe impl<const N: usize, H> TrustedLen for ProofsIterator<'_, N, H> where H: MerkleHasher {}