Skip to main content

ab_merkle_tree/
mmr.rs

1use crate::hash_pair;
2use crate::unbalanced::UnbalancedMerkleTree;
3use ab_blake3::OUT_LEN;
4#[cfg(feature = "alloc")]
5use alloc::boxed::Box;
6#[cfg(feature = "alloc")]
7use alloc::vec::Vec;
8use core::mem;
9use core::mem::MaybeUninit;
10use core::ops::{Deref, DerefMut};
11
12/// Number of peaks in MMR with `MAX_N` leaves
13pub const NUM_PEAKS<const MAX_N: u64>: usize = MAX_N.next_power_of_two().ilog2() as usize;
14/// Max number of elements in a proof for MMR with `MAX_N` leaves
15pub const MAX_PROOF_ELEMENTS<const MAX_N: u64>: usize = MAX_N.next_power_of_two().ilog2() as usize;
16const STACK_SIZE<const MAX_N: u64>: usize = {
17    // This constraint is actually needed to prevent issues related to MMR peaks, but making it
18    // unrepresentable is better
19    assert!(
20        MAX_N > 1,
21        "This Merkle Mountain Range must have MAX_N > 1 leaves"
22    );
23
24    MAX_N.next_power_of_two().ilog2() as usize + 1
25};
26
27/// Size of [`MerkleMountainRange`]/[`MerkleMountainRangeBytes`] in bytes
28const MERKLE_MOUNTAIN_RANGE_BYTES_SIZE<const MAX_N: u64>: usize =
29    size_of::<u64>() + OUT_LEN * (MAX_N.next_power_of_two().ilog2() as usize + 1);
30
31const {
32    assert!(size_of::<MerkleMountainRangeBytes<2>>() == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<2>);
33    assert!(size_of::<MerkleMountainRange<2>>() == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<2>);
34    assert!(align_of::<MerkleMountainRangeBytes<2>>() == align_of::<MerkleMountainRange<2>>());
35
36    // `MAX_N` doesn't have to be a power of two, verify the layout formula for a few more shapes,
37    // including a large one, to guard against regressions in `MERKLE_MOUNTAIN_RANGE_BYTES_SIZE`
38    assert!(size_of::<MerkleMountainRangeBytes<100>>() == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<100>);
39    assert!(size_of::<MerkleMountainRange<100>>() == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<100>);
40    assert!(align_of::<MerkleMountainRangeBytes<100>>() == align_of::<MerkleMountainRange<100>>());
41
42    assert!(
43        size_of::<MerkleMountainRangeBytes<65536>>() == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<65536>
44    );
45    assert!(size_of::<MerkleMountainRange<65536>>() == MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<65536>);
46    assert!(
47        align_of::<MerkleMountainRangeBytes<65536>>() == align_of::<MerkleMountainRange<65536>>()
48    );
49}
50
51/// MMR peaks for [`MerkleMountainRange`].
52///
53/// Primarily intended to be used with [`MerkleMountainRange::from_peaks()`], can be sent over the
54/// network, etc.
55#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
56pub struct MmrPeaks<const MAX_N: u64> {
57    /// Number of leaves in MMR
58    pub num_leaves: u64,
59    /// MMR peaks, first [`Self::num_peaks()`] elements are occupied by values, the rest are
60    /// ignored and do not need to be retained.
61    pub peaks: [[u8; OUT_LEN]; NUM_PEAKS::<MAX_N>],
62}
63
64impl<const MAX_N: u64> MmrPeaks<MAX_N> {
65    /// Number of peaks stored in [`Self::peaks`] that are occupied by actual values
66    #[inline(always)]
67    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
68    pub fn num_peaks(&self) -> u8 {
69        self.num_leaves.count_ones() as u8
70    }
71}
72
73/// Byte representation of [`MerkleMountainRange`] with correct alignment.
74///
75/// Somewhat similar in function to [`MmrPeaks`], but for local use only.
76#[derive(Debug, Copy, Clone)]
77#[repr(C, align(8))]
78pub struct MerkleMountainRangeBytes<const MAX_N: u64>(
79    [u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N>],
80);
81
82impl<const MAX_N: u64> Default for MerkleMountainRangeBytes<MAX_N> {
83    #[inline(always)]
84    fn default() -> Self {
85        Self([0; _])
86    }
87}
88
89impl<const MAX_N: u64> From<[u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N>]>
90    for MerkleMountainRangeBytes<MAX_N>
91{
92    fn from(value: [u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N>]) -> Self {
93        Self(value)
94    }
95}
96
97impl<const MAX_N: u64> From<MerkleMountainRangeBytes<MAX_N>>
98    for [u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N>]
99{
100    fn from(value: MerkleMountainRangeBytes<MAX_N>) -> Self {
101        value.0
102    }
103}
104
105impl<const MAX_N: u64> Deref for MerkleMountainRangeBytes<MAX_N> {
106    type Target = [u8; MERKLE_MOUNTAIN_RANGE_BYTES_SIZE::<MAX_N>];
107
108    #[inline(always)]
109    fn deref(&self) -> &Self::Target {
110        &self.0
111    }
112}
113
114impl<const MAX_N: u64> DerefMut for MerkleMountainRangeBytes<MAX_N> {
115    #[inline(always)]
116    fn deref_mut(&mut self) -> &mut Self::Target {
117        &mut self.0
118    }
119}
120
121/// Merkle Mountain Range variant that has pre-hashed leaves with arbitrary number of elements.
122///
123/// This can be considered a general case of [`UnbalancedMerkleTree`]. The root and proofs are
124/// identical for both. [`UnbalancedMerkleTree`] is more efficient and should be preferred when
125/// possible, while this data structure is designed for aggregating data incrementally over long
126/// periods of time.
127///
128/// `MAX_N` generic constant defines the maximum number of elements supported and controls stack
129/// usage.
130#[derive(Debug, Copy, Clone)]
131#[repr(C)]
132pub struct MerkleMountainRange<const MAX_N: u64> {
133    num_leaves: u64,
134    // Stack of intermediate nodes per tree level
135    stack: [[u8; OUT_LEN]; STACK_SIZE::<MAX_N>],
136}
137
138impl<const MAX_N: u64> Default for MerkleMountainRange<MAX_N>
139where
140    [(); STACK_SIZE::<MAX_N>]:,
141{
142    #[inline(always)]
143    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
144    fn default() -> Self {
145        Self::new()
146    }
147}
148
149// TODO: Think harder about proof generation and verification API here
150impl<const MAX_N: u64> MerkleMountainRange<MAX_N>
151where
152    [(); STACK_SIZE::<MAX_N>]:,
153{
154    /// Create an empty instance
155    #[inline(always)]
156    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
157    pub fn new() -> Self {
158        // TODO: Technically redundant with the where-clause, which is not enforced in generic code
159        //  due to https://github.com/rust-lang/rust/issues/164019, remove once fixed
160        const { STACK_SIZE::<MAX_N> };
161
162        Self {
163            num_leaves: 0,
164            stack: [[0u8; OUT_LEN]; _],
165        }
166    }
167
168    /// Create a new instance from previously collected peaks.
169    ///
170    /// Returns `None` if input is invalid.
171    #[inline]
172    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
173    pub fn from_peaks(peaks: &MmrPeaks<MAX_N>) -> Option<Self> {
174        // TODO: Technically redundant with the where-clause, which is not enforced in generic code
175        //  due to https://github.com/rust-lang/rust/issues/164019, remove once fixed
176        const { STACK_SIZE::<MAX_N> };
177
178        // Stack and peaks may have space for more leaves than `MAX_N`
179        if peaks.num_leaves > MAX_N {
180            return None;
181        }
182
183        let mut result = Self {
184            num_leaves: peaks.num_leaves,
185            stack: [[0u8; OUT_LEN]; _],
186        };
187
188        // Convert peaks (where all occupied entries are all at the beginning of the list instead)
189        // to stack (where occupied entries are at corresponding offsets)
190        let mut stack_bits = peaks.num_leaves;
191        let mut peaks_offset = 0;
192
193        while stack_bits != 0 {
194            let stack_offset = stack_bits.trailing_zeros();
195
196            *result.stack.get_mut(stack_offset as usize)? = *peaks.peaks.get(peaks_offset)?;
197
198            peaks_offset += 1;
199            // Clear the lowest set bit
200            stack_bits &= !(1 << stack_offset);
201        }
202
203        Some(result)
204    }
205
206    /// Get byte representation of Merkle Mountain Range
207    #[inline(always)]
208    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
209    pub fn as_bytes(&self) -> &MerkleMountainRangeBytes<MAX_N> {
210        // SAFETY: Both are `#[repr(C)]`, the same size and alignment as `Self`, all bit patterns
211        // are valid
212        unsafe { mem::transmute(self) }
213    }
214
215    /// Create an instance from byte representation.
216    ///
217    /// # Safety
218    /// Bytes must be previously created by [`Self::as_bytes()`].
219    #[inline(always)]
220    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
221    pub unsafe fn from_bytes(bytes: &MerkleMountainRangeBytes<MAX_N>) -> &Self {
222        // SAFETY: Both are `#[repr(C)]`, the same size and alignment as `Self`, all bit patterns
223        // are valid. `::from_bytes()` is an `unsafe` function with correct invariant being a
224        // prerequisite of calling it.
225        unsafe { mem::transmute(bytes) }
226    }
227
228    /// Get number of leaves aggregated in Merkle Mountain Range so far
229    #[inline(always)]
230    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
231    pub fn num_leaves(&self) -> u64 {
232        self.num_leaves
233    }
234
235    /// Calculate the root of Merkle Mountain Range.
236    ///
237    /// In case MMR contains a single leaf hash, that leaf hash is returned, `None` is returned if
238    /// there were no leaves added yet.
239    #[inline]
240    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
241    pub fn root(&self) -> Option<[u8; OUT_LEN]> {
242        if self.num_leaves == 0 {
243            // If no leaves were provided
244            return None;
245        }
246
247        let mut root;
248        let mut stack_bits = self.num_leaves;
249        {
250            let lowest_active_level = stack_bits.trailing_zeros() as usize;
251            // SAFETY: Active level must have been set successfully before, hence it exists
252            root = *unsafe { self.stack.get_unchecked(lowest_active_level) };
253            // Clear lowest active level
254            stack_bits &= !(1 << lowest_active_level);
255        }
256
257        // Hash remaining peaks (if any) of the potentially unbalanced tree together
258        loop {
259            let lowest_active_level = stack_bits.trailing_zeros() as usize;
260
261            if lowest_active_level == u64::BITS as usize {
262                break;
263            }
264
265            // Clear lowest active level for next iteration
266            stack_bits &= !(1 << lowest_active_level);
267
268            // SAFETY: Active level must have been set successfully before, hence it exists
269            let lowest_active_level_item = unsafe { self.stack.get_unchecked(lowest_active_level) };
270
271            root = hash_pair(lowest_active_level_item, &root);
272        }
273
274        Some(root)
275    }
276
277    /// Get peaks of Merkle Mountain Range
278    #[inline]
279    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
280    pub fn peaks(&self) -> MmrPeaks<MAX_N> {
281        let mut result = MmrPeaks {
282            num_leaves: self.num_leaves,
283            peaks: [[0u8; OUT_LEN]; _],
284        };
285
286        // Convert stack (where occupied entries are at corresponding offsets) to peaks (where all
287        // occupied entries are all at the beginning of the list instead)
288        let mut stack_bits = self.num_leaves;
289        let mut peaks_offset = 0;
290        while stack_bits != 0 {
291            let stack_offset = stack_bits.trailing_zeros();
292
293            // SAFETY: Stack offset is always within the range of stack and peaks, this is
294            // guaranteed by internal invariants of the MMR
295            *unsafe { result.peaks.get_unchecked_mut(peaks_offset) } =
296                *unsafe { self.stack.get_unchecked(stack_offset as usize) };
297
298            peaks_offset += 1;
299            // Clear the lowest set bit
300            stack_bits &= !(1 << stack_offset);
301        }
302
303        result
304    }
305
306    /// Add leaf to Merkle Mountain Range.
307    ///
308    /// There is a more efficient version [`Self::add_leaves()`] in case multiple leaves are
309    /// available.
310    ///
311    /// Returns `true` on success, `false` if too many leaves were added.
312    #[inline]
313    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
314    pub fn add_leaf(&mut self, leaf: &[u8; OUT_LEN]) -> bool {
315        // How many leaves were processed so far. Should have been `num_leaves == MAX_N`, but `>=`
316        // helps compiler with panic safety checks.
317        if self.num_leaves >= MAX_N {
318            return false;
319        }
320
321        let mut current = *leaf;
322
323        // Every bit set to `1` corresponds to an active Merkle Tree level
324        let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
325        for item in self.stack.iter().take(lowest_active_levels) {
326            current = hash_pair(item, &current);
327        }
328
329        // Place the current hash at the first inactive level
330        *self
331            .stack
332            .get_mut(lowest_active_levels)
333            .expect("Stack has enough levels for `num_leaves < MAX_N`; qed") = current;
334        self.num_leaves += 1;
335
336        true
337    }
338
339    /// Add many leaves to Merkle Mountain Range.
340    ///
341    /// This is a more efficient version of [`Self::add_leaf()`] in case multiple leaves are
342    /// available.
343    ///
344    /// Returns `true` on success, `false` if too many leaves were added.
345    #[inline]
346    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
347    pub fn add_leaves<'a, Item, Iter>(&mut self, leaves: Iter) -> bool
348    where
349        Item: Into<[u8; OUT_LEN]>,
350        Iter: IntoIterator<Item = Item> + 'a,
351    {
352        // TODO: This can be optimized further
353        for leaf in leaves {
354            // How many leaves were processed so far. Should have been `num_leaves == MAX_N`, but
355            // `>=` helps compiler with panic safety checks.
356            if self.num_leaves >= MAX_N {
357                return false;
358            }
359
360            let mut current = leaf.into();
361
362            // Every bit set to `1` corresponds to an active Merkle Tree level
363            let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
364            for item in self.stack.iter().take(lowest_active_levels) {
365                current = hash_pair(item, &current);
366            }
367
368            // Place the current hash at the first inactive level
369            self.stack[lowest_active_levels] = current;
370            self.num_leaves += 1;
371        }
372
373        true
374    }
375
376    /// Add leaf to Merkle Mountain Range and generate inclusion proof.
377    ///
378    /// Returns `Some((root, proof))` on success, `None` if too many leaves were added.
379    #[inline]
380    #[cfg(feature = "alloc")]
381    pub fn add_leaf_and_compute_proof(
382        &mut self,
383        leaf: &[u8; OUT_LEN],
384    ) -> Option<([u8; OUT_LEN], Vec<[u8; OUT_LEN]>)> {
385        // SAFETY: Inner value is `MaybeUninit`
386        let mut proof =
387            unsafe { Box::<[MaybeUninit<[u8; OUT_LEN]>; _]>::new_uninit().assume_init() };
388
389        let (root, proof_length) = self.add_leaf_and_compute_proof_inner(leaf, &mut proof)?;
390
391        let proof_capacity = proof.len();
392        let proof = Box::into_raw(proof);
393        // SAFETY: Points to correctly allocated memory where `proof_length` elements were
394        // initialized
395        let proof = unsafe {
396            Vec::from_raw_parts(proof.cast::<[u8; OUT_LEN]>(), proof_length, proof_capacity)
397        };
398
399        Some((root, proof))
400    }
401
402    /// Add leaf to Merkle Mountain Range and generate inclusion proof.
403    ///
404    /// Returns `Some((root, proof))` on success, `None` if too many leaves were added.
405    #[inline]
406    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
407    pub fn add_leaf_and_compute_proof_in<'proof>(
408        &mut self,
409        leaf: &[u8; OUT_LEN],
410        proof: &'proof mut [MaybeUninit<[u8; OUT_LEN]>; MAX_PROOF_ELEMENTS::<MAX_N>],
411    ) -> Option<([u8; OUT_LEN], &'proof mut [[u8; OUT_LEN]])> {
412        let (root, proof_length) = self.add_leaf_and_compute_proof_inner(leaf, proof)?;
413
414        // SAFETY: Just correctly initialized `proof_length` elements
415        let proof = unsafe { proof.get_unchecked_mut(..proof_length).assume_init_mut() };
416
417        Some((root, proof))
418    }
419
420    #[inline]
421    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
422    fn add_leaf_and_compute_proof_inner(
423        &mut self,
424        leaf: &[u8; OUT_LEN],
425        proof: &mut [MaybeUninit<[u8; OUT_LEN]>; MAX_PROOF_ELEMENTS::<MAX_N>],
426    ) -> Option<([u8; OUT_LEN], usize)> {
427        let mut proof_length = 0;
428
429        let current_target_level;
430        let mut position = self.num_leaves;
431
432        {
433            // How many leaves were processed so far. Should have been `num_leaves == MAX_N`, but
434            // `>=` helps compiler with panic safety checks.
435            if self.num_leaves >= MAX_N {
436                return None;
437            }
438
439            let mut current = *leaf;
440
441            // Every bit set to `1` corresponds to an active Merkle Tree level
442            let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
443
444            for item in self.stack.iter().take(lowest_active_levels) {
445                // If at the target leaf index, need to collect the proof
446                proof
447                    .get_mut(proof_length)
448                    .expect("Proof has enough capacity for `num_leaves < MAX_N` checked above; qed")
449                    .write(*item);
450                proof_length += 1;
451
452                current = hash_pair(item, &current);
453
454                // Move up the tree
455                position /= 2;
456            }
457
458            current_target_level = lowest_active_levels;
459
460            // Place the current hash at the first inactive level
461            self.stack[lowest_active_levels] = current;
462            self.num_leaves += 1;
463        }
464
465        let mut root;
466        let mut stack_bits = self.num_leaves;
467
468        {
469            let lowest_active_level = stack_bits.trailing_zeros() as usize;
470            // SAFETY: Active level must have been set successfully before, hence it exists
471            root = *unsafe { self.stack.get_unchecked(lowest_active_level) };
472            // Clear lowest active level
473            stack_bits &= !(1 << lowest_active_level);
474        }
475
476        // Hash remaining peaks (if any) of the potentially unbalanced tree together and collect
477        // proof hashes
478        let mut merged_peaks = false;
479        loop {
480            let lowest_active_level = stack_bits.trailing_zeros() as usize;
481
482            if lowest_active_level == u64::BITS as usize {
483                break;
484            }
485
486            // Clear lowest active level for next iteration
487            stack_bits &= !(1 << lowest_active_level);
488
489            // SAFETY: Active level must have been set successfully before, hence it exists
490            let lowest_active_level_item = unsafe { self.stack.get_unchecked(lowest_active_level) };
491
492            if lowest_active_level > current_target_level
493                || (lowest_active_level == current_target_level
494                    && !position.is_multiple_of(2)
495                    && !merged_peaks)
496            {
497                // SAFETY: Method signature guarantees upper bound of the proof length
498                unsafe { proof.get_unchecked_mut(proof_length) }.write(*lowest_active_level_item);
499                proof_length += 1;
500                merged_peaks = false;
501            } else if lowest_active_level == current_target_level {
502                // SAFETY: Method signature guarantees upper bound of the proof length
503                unsafe { proof.get_unchecked_mut(proof_length) }.write(root);
504                proof_length += 1;
505                merged_peaks = false;
506            } else {
507                // Not collecting proof because of the need to merge peaks of an unbalanced tree
508                merged_peaks = true;
509            }
510
511            // Collect the lowest peak into the proof
512            root = hash_pair(lowest_active_level_item, &root);
513
514            position /= 2;
515        }
516
517        Some((root, proof_length))
518    }
519
520    /// Verify a Merkle proof for a leaf at the given index.
521    ///
522    /// NOTE: `MAX_N` constant doesn't matter here and can be anything that is `> 1`.
523    #[inline]
524    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
525    pub fn verify(
526        root: &[u8; OUT_LEN],
527        proof: &[[u8; OUT_LEN]],
528        leaf_index: u64,
529        leaf: [u8; OUT_LEN],
530        num_leaves: u64,
531    ) -> bool {
532        // TODO: Technically redundant with the where-clause, which is not enforced in generic code
533        //  due to https://github.com/rust-lang/rust/issues/164019, remove once fixed
534        const { STACK_SIZE::<MAX_N> };
535
536        UnbalancedMerkleTree::verify(root, proof, leaf_index, leaf, num_leaves)
537    }
538}