1use crate::MerkleHasher;
2use crate::unbalanced::UnbalancedMerkleTree;
3#[cfg(feature = "alloc")]
4use alloc::boxed::Box;
5#[cfg(feature = "alloc")]
6use alloc::vec::Vec;
7use core::mem;
8use core::mem::MaybeUninit;
9use core::ops::{Deref, DerefMut};
10
11pub const NUM_PEAKS<const MAX_N: u64>: usize = MAX_N.next_power_of_two().ilog2() as usize;
13pub const MAX_PROOF_ELEMENTS<const MAX_N: u64>: usize = MAX_N.next_power_of_two().ilog2() as usize;
15const STACK_SIZE<const MAX_N: u64>: usize = {
16 assert!(
19 MAX_N > 1,
20 "This Merkle Mountain Range must have MAX_N > 1 leaves"
21 );
22
23 MAX_N.next_power_of_two().ilog2() as usize + 1
24};
25
26const MERKLE_MOUNTAIN_RANGE_BYTES_SIZE<const MAX_N: u64, H: MerkleHasher>: usize =
28 size_of::<u64>() + H::OUT_LEN * (MAX_N.next_power_of_two().ilog2() as usize + 1);
29
30#[derive(Debug)]
32struct LayoutHasher<const OUT_LEN: usize>;
33
34impl<const OUT_LEN: usize> MerkleHasher for LayoutHasher<OUT_LEN> {
35 const OUT_LEN: usize = OUT_LEN;
36
37 fn hash_pair(
38 &self,
39 pair: &[[u8; <Self as MerkleHasher>::OUT_LEN]; 2],
40 ) -> [u8; <Self as MerkleHasher>::OUT_LEN] {
41 let [left, _right] = pair;
42 *left
43 }
44}
45
46const {
47 assert!(
48 size_of::<MerkleMountainRangeBytes<2, LayoutHasher<32>>>()
49 == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<2, LayoutHasher<32>>
50 );
51 assert!(
52 size_of::<MerkleMountainRange<2, LayoutHasher<32>>>()
53 == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<2, LayoutHasher<32>>
54 );
55 assert!(
56 align_of::<MerkleMountainRangeBytes<2, LayoutHasher<32>>>()
57 == align_of::<MerkleMountainRange<2, LayoutHasher<32>>>()
58 );
59
60 assert!(
63 size_of::<MerkleMountainRangeBytes<100, LayoutHasher<32>>>()
64 == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<100, LayoutHasher<32>>
65 );
66 assert!(
67 size_of::<MerkleMountainRange<100, LayoutHasher<32>>>()
68 == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<100, LayoutHasher<32>>
69 );
70 assert!(
71 align_of::<MerkleMountainRangeBytes<100, LayoutHasher<32>>>()
72 == align_of::<MerkleMountainRange<100, LayoutHasher<32>>>()
73 );
74
75 assert!(
76 size_of::<MerkleMountainRangeBytes<65536, LayoutHasher<32>>>()
77 == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<65536, LayoutHasher<32>>
78 );
79 assert!(
80 size_of::<MerkleMountainRange<65536, LayoutHasher<32>>>()
81 == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<65536, LayoutHasher<32>>
82 );
83 assert!(
84 align_of::<MerkleMountainRangeBytes<65536, LayoutHasher<32>>>()
85 == align_of::<MerkleMountainRange<65536, LayoutHasher<32>>>()
86 );
87
88 assert!(
91 size_of::<MerkleMountainRangeBytes<4, LayoutHasher<20>>>()
92 == size_of::<MerkleMountainRange<4, LayoutHasher<20>>>()
93 );
94 assert!(
95 align_of::<MerkleMountainRangeBytes<4, LayoutHasher<20>>>()
96 == align_of::<MerkleMountainRange<4, LayoutHasher<20>>>()
97 );
98}
99
100#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
105pub struct MmrPeaks<const MAX_N: u64, H>
106where
107 H: MerkleHasher,
108{
109 pub num_leaves: u64,
111 pub peaks: [[u8; H::OUT_LEN]; NUM_PEAKS::<MAX_N>],
114}
115
116impl<const MAX_N: u64, H> MmrPeaks<MAX_N, H>
117where
118 H: MerkleHasher,
119{
120 #[inline(always)]
122 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
123 pub fn num_peaks(&self) -> u8 {
124 self.num_leaves.count_ones() as u8
125 }
126}
127
128#[derive(Debug, Copy, Clone)]
132#[repr(C, align(8))]
133pub struct MerkleMountainRangeBytes<const MAX_N: u64, H>(
134 [u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N, H>],
135)
136where
137 H: MerkleHasher;
138
139impl<const MAX_N: u64, H> Default for MerkleMountainRangeBytes<MAX_N, H>
140where
141 H: MerkleHasher,
142{
143 #[inline(always)]
144 fn default() -> Self {
145 Self([0; _])
146 }
147}
148
149impl<const MAX_N: u64, H> From<[u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N, H>]>
150 for MerkleMountainRangeBytes<MAX_N, H>
151where
152 H: MerkleHasher,
153{
154 fn from(value: [u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N, H>]) -> Self {
155 Self(value)
156 }
157}
158
159impl<const MAX_N: u64, H> From<MerkleMountainRangeBytes<MAX_N, H>>
160 for [u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N, H>]
161where
162 H: MerkleHasher,
163{
164 fn from(value: MerkleMountainRangeBytes<MAX_N, H>) -> Self {
165 value.0
166 }
167}
168
169impl<const MAX_N: u64, H> Deref for MerkleMountainRangeBytes<MAX_N, H>
170where
171 H: MerkleHasher,
172{
173 type Target = [u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N, H>];
174
175 #[inline(always)]
176 fn deref(&self) -> &Self::Target {
177 &self.0
178 }
179}
180
181impl<const MAX_N: u64, H> DerefMut for MerkleMountainRangeBytes<MAX_N, H>
182where
183 H: MerkleHasher,
184{
185 #[inline(always)]
186 fn deref_mut(&mut self) -> &mut Self::Target {
187 &mut self.0
188 }
189}
190
191#[derive(Debug, Copy, Clone)]
204#[repr(C)]
205pub struct MerkleMountainRange<const MAX_N: u64, H>
206where
207 H: MerkleHasher,
208{
209 num_leaves: u64,
210 stack: [[u8; H::OUT_LEN]; STACK_SIZE::<MAX_N>],
212}
213
214impl<const MAX_N: u64, H> Default for MerkleMountainRange<MAX_N, H>
215where
216 [(); STACK_SIZE::<MAX_N>]:,
217 H: MerkleHasher + Default,
218{
219 #[inline(always)]
220 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
221 fn default() -> Self {
222 Self::new()
223 }
224}
225
226impl<const MAX_N: u64, H> MerkleMountainRange<MAX_N, H>
228where
229 [(); STACK_SIZE::<MAX_N>]:,
230 H: MerkleHasher + Default,
231{
232 #[inline(always)]
234 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
235 pub fn new() -> Self {
236 const { STACK_SIZE::<MAX_N> };
239
240 Self {
241 num_leaves: 0,
242 stack: [[0u8; H::OUT_LEN]; _],
243 }
244 }
245
246 #[inline]
250 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
251 pub fn from_peaks(peaks: &MmrPeaks<MAX_N, H>) -> Option<Self> {
252 const { STACK_SIZE::<MAX_N> };
255
256 if peaks.num_leaves > MAX_N {
258 return None;
259 }
260
261 let mut result = Self {
262 num_leaves: peaks.num_leaves,
263 stack: [[0u8; H::OUT_LEN]; _],
264 };
265
266 let mut stack_bits = peaks.num_leaves;
269 let mut peaks_offset = 0;
270
271 while stack_bits != 0 {
272 let stack_offset = stack_bits.trailing_zeros();
273
274 *result.stack.get_mut(stack_offset as usize)? = *peaks.peaks.get(peaks_offset)?;
275
276 peaks_offset += 1;
277 stack_bits &= !(1 << stack_offset);
279 }
280
281 Some(result)
282 }
283
284 #[inline(always)]
286 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
287 pub fn as_bytes(&self) -> &MerkleMountainRangeBytes<MAX_N, H> {
288 unsafe { mem::transmute(self) }
291 }
292
293 #[inline(always)]
298 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
299 pub unsafe fn from_bytes(bytes: &MerkleMountainRangeBytes<MAX_N, H>) -> &Self {
300 unsafe { mem::transmute(bytes) }
304 }
305
306 #[inline(always)]
308 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
309 pub fn num_leaves(&self) -> u64 {
310 self.num_leaves
311 }
312
313 #[inline]
318 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
319 pub fn root(&self) -> Option<[u8; H::OUT_LEN]> {
320 if self.num_leaves == 0 {
321 return None;
323 }
324
325 let hasher = H::default();
326 let mut root;
327 let mut stack_bits = self.num_leaves;
328 {
329 let lowest_active_level = stack_bits.trailing_zeros() as usize;
330 root = *unsafe { self.stack.get_unchecked(lowest_active_level) };
332 stack_bits &= !(1 << lowest_active_level);
334 }
335
336 loop {
338 let lowest_active_level = stack_bits.trailing_zeros() as usize;
339
340 if lowest_active_level == u64::BITS as usize {
341 break;
342 }
343
344 stack_bits &= !(1 << lowest_active_level);
346
347 let lowest_active_level_item = unsafe { self.stack.get_unchecked(lowest_active_level) };
349
350 root = hasher.hash_pair(&[*lowest_active_level_item, root]);
351 }
352
353 if self.num_leaves == 1 {
354 root = hasher.hash_single_leaf(&root);
355 }
356
357 Some(root)
358 }
359
360 #[inline]
362 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
363 pub fn peaks(&self) -> MmrPeaks<MAX_N, H> {
364 let mut result = MmrPeaks {
365 num_leaves: self.num_leaves,
366 peaks: [[0u8; H::OUT_LEN]; _],
367 };
368
369 let mut stack_bits = self.num_leaves;
372 let mut peaks_offset = 0;
373 while stack_bits != 0 {
374 let stack_offset = stack_bits.trailing_zeros();
375
376 *unsafe { result.peaks.get_unchecked_mut(peaks_offset) } =
379 *unsafe { self.stack.get_unchecked(stack_offset as usize) };
380
381 peaks_offset += 1;
382 stack_bits &= !(1 << stack_offset);
384 }
385
386 result
387 }
388
389 #[inline]
396 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
397 pub fn add_leaf(&mut self, leaf: &[u8; H::OUT_LEN]) -> bool {
398 if self.num_leaves >= MAX_N {
401 return false;
402 }
403
404 let hasher = H::default();
405 let mut current = *leaf;
406
407 let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
409 for item in self.stack.iter().take(lowest_active_levels) {
410 current = hasher.hash_pair(&[*item, current]);
411 }
412
413 *self
415 .stack
416 .get_mut(lowest_active_levels)
417 .expect("Stack has enough levels for `num_leaves < MAX_N`; qed") = current;
418 self.num_leaves += 1;
419
420 true
421 }
422
423 #[inline]
430 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
431 pub fn add_leaves<'a, Item, Iter>(&mut self, leaves: Iter) -> bool
432 where
433 Item: Into<[u8; H::OUT_LEN]>,
434 Iter: IntoIterator<Item = Item> + 'a,
435 {
436 let hasher = H::default();
437
438 for leaf in leaves {
440 if self.num_leaves >= MAX_N {
443 return false;
444 }
445
446 let mut current = leaf.into();
447
448 let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
450 for item in self.stack.iter().take(lowest_active_levels) {
451 current = hasher.hash_pair(&[*item, current]);
452 }
453
454 self.stack[lowest_active_levels] = current;
456 self.num_leaves += 1;
457 }
458
459 true
460 }
461
462 #[expect(clippy::type_complexity, reason = "Return type")]
466 #[inline]
467 #[cfg(feature = "alloc")]
468 pub fn add_leaf_and_compute_proof(
469 &mut self,
470 leaf: &[u8; H::OUT_LEN],
471 ) -> Option<([u8; H::OUT_LEN], Vec<[u8; H::OUT_LEN]>)> {
472 let mut proof =
474 unsafe { Box::<[MaybeUninit<[u8; H::OUT_LEN]>; _]>::new_uninit().assume_init() };
475
476 let (root, proof_length) = self.add_leaf_and_compute_proof_inner(leaf, &mut proof)?;
477
478 let proof_capacity = proof.len();
479 let proof = Box::into_raw(proof);
480 let proof = unsafe {
483 Vec::from_raw_parts(
484 proof.cast::<[u8; H::OUT_LEN]>(),
485 proof_length,
486 proof_capacity,
487 )
488 };
489
490 Some((root, proof))
491 }
492
493 #[expect(clippy::type_complexity, reason = "Return type")]
497 #[inline]
498 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
499 pub fn add_leaf_and_compute_proof_in<'proof>(
500 &mut self,
501 leaf: &[u8; H::OUT_LEN],
502 proof: &'proof mut [MaybeUninit<[u8; H::OUT_LEN]>; MAX_PROOF_ELEMENTS::<MAX_N>],
503 ) -> Option<([u8; H::OUT_LEN], &'proof mut [[u8; H::OUT_LEN]])> {
504 let (root, proof_length) = self.add_leaf_and_compute_proof_inner(leaf, proof)?;
505
506 let proof = unsafe { proof.get_unchecked_mut(..proof_length).assume_init_mut() };
508
509 Some((root, proof))
510 }
511
512 #[inline]
513 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
514 fn add_leaf_and_compute_proof_inner(
515 &mut self,
516 leaf: &[u8; H::OUT_LEN],
517 proof: &mut [MaybeUninit<[u8; H::OUT_LEN]>; MAX_PROOF_ELEMENTS::<MAX_N>],
518 ) -> Option<([u8; H::OUT_LEN], usize)> {
519 let hasher = H::default();
520 let mut proof_length = 0;
521
522 let current_target_level;
523 let mut position = self.num_leaves;
524
525 {
526 if self.num_leaves >= MAX_N {
529 return None;
530 }
531
532 let mut current = *leaf;
533
534 let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
536
537 for item in self.stack.iter().take(lowest_active_levels) {
538 proof
540 .get_mut(proof_length)
541 .expect("Proof has enough capacity for `num_leaves < MAX_N` checked above; qed")
542 .write(*item);
543 proof_length += 1;
544
545 current = hasher.hash_pair(&[*item, current]);
546
547 position /= 2;
549 }
550
551 current_target_level = lowest_active_levels;
552
553 self.stack[lowest_active_levels] = current;
555 self.num_leaves += 1;
556 }
557
558 let mut root;
559 let mut stack_bits = self.num_leaves;
560
561 {
562 let lowest_active_level = stack_bits.trailing_zeros() as usize;
563 root = *unsafe { self.stack.get_unchecked(lowest_active_level) };
565 stack_bits &= !(1 << lowest_active_level);
567 }
568
569 let mut merged_peaks = false;
572 loop {
573 let lowest_active_level = stack_bits.trailing_zeros() as usize;
574
575 if lowest_active_level == u64::BITS as usize {
576 break;
577 }
578
579 stack_bits &= !(1 << lowest_active_level);
581
582 let lowest_active_level_item = unsafe { self.stack.get_unchecked(lowest_active_level) };
584
585 if lowest_active_level > current_target_level
586 || (lowest_active_level == current_target_level
587 && !position.is_multiple_of(2)
588 && !merged_peaks)
589 {
590 unsafe { proof.get_unchecked_mut(proof_length) }.write(*lowest_active_level_item);
592 proof_length += 1;
593 merged_peaks = false;
594 } else if lowest_active_level == current_target_level {
595 unsafe { proof.get_unchecked_mut(proof_length) }.write(root);
597 proof_length += 1;
598 merged_peaks = false;
599 } else {
600 merged_peaks = true;
602 }
603
604 root = hasher.hash_pair(&[*lowest_active_level_item, root]);
606
607 position /= 2;
608 }
609
610 if self.num_leaves == 1 {
611 root = hasher.hash_single_leaf(&root);
612 }
613
614 Some((root, proof_length))
615 }
616
617 #[inline]
621 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
622 pub fn verify(
623 root: &[u8; H::OUT_LEN],
624 proof: &[[u8; H::OUT_LEN]],
625 leaf_index: u64,
626 leaf: [u8; H::OUT_LEN],
627 num_leaves: u64,
628 ) -> bool {
629 const { STACK_SIZE::<MAX_N> };
632
633 UnbalancedMerkleTree::<H>::verify(root, proof, leaf_index, leaf, num_leaves)
634 }
635}