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> {
139    #[inline(always)]
140    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
141    fn default() -> Self {
142        Self::new()
143    }
144}
145
146// TODO: Think harder about proof generation and verification API here
147impl<const MAX_N: u64> MerkleMountainRange<MAX_N> {
148    /// Create an empty instance
149    #[inline(always)]
150    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
151    pub fn new() -> Self {
152        Self {
153            num_leaves: 0,
154            stack: [[0u8; OUT_LEN]; _],
155        }
156    }
157
158    /// Create a new instance from previously collected peaks.
159    ///
160    /// Returns `None` if input is invalid.
161    #[inline]
162    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
163    pub fn from_peaks(peaks: &MmrPeaks<MAX_N>) -> Option<Self> {
164        let mut result = Self {
165            num_leaves: peaks.num_leaves,
166            stack: [[0u8; OUT_LEN]; _],
167        };
168
169        // Convert peaks (where all occupied entries are all at the beginning of the list instead)
170        // to stack (where occupied entries are at corresponding offsets)
171        let mut stack_bits = peaks.num_leaves;
172        let mut peaks_offset = 0;
173
174        while stack_bits != 0 {
175            let stack_offset = stack_bits.trailing_zeros();
176
177            *result.stack.get_mut(stack_offset as usize)? = *peaks.peaks.get(peaks_offset)?;
178
179            peaks_offset += 1;
180            // Clear the lowest set bit
181            stack_bits &= !(1 << stack_offset);
182        }
183
184        Some(result)
185    }
186
187    /// Get byte representation of Merkle Mountain Range
188    #[inline(always)]
189    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
190    pub fn as_bytes(&self) -> &MerkleMountainRangeBytes<MAX_N> {
191        // SAFETY: Both are `#[repr(C)]`, the same size and alignment as `Self`, all bit patterns
192        // are valid
193        unsafe { mem::transmute(self) }
194    }
195
196    /// Create an instance from byte representation.
197    ///
198    /// # Safety
199    /// Bytes must be previously created by [`Self::as_bytes()`].
200    #[inline(always)]
201    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
202    pub unsafe fn from_bytes(bytes: &MerkleMountainRangeBytes<MAX_N>) -> &Self {
203        // SAFETY: Both are `#[repr(C)]`, the same size and alignment as `Self`, all bit patterns
204        // are valid. `::from_bytes()` is an `unsafe` function with correct invariant being a
205        // prerequisite of calling it.
206        unsafe { mem::transmute(bytes) }
207    }
208
209    /// Get number of leaves aggregated in Merkle Mountain Range so far
210    #[inline(always)]
211    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
212    pub fn num_leaves(&self) -> u64 {
213        self.num_leaves
214    }
215
216    /// Calculate the root of Merkle Mountain Range.
217    ///
218    /// In case MMR contains a single leaf hash, that leaf hash is returned, `None` is returned if
219    /// there were no leaves added yet.
220    #[inline]
221    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
222    pub fn root(&self) -> Option<[u8; OUT_LEN]> {
223        if self.num_leaves == 0 {
224            // If no leaves were provided
225            return None;
226        }
227
228        let mut root;
229        let mut stack_bits = self.num_leaves;
230        {
231            let lowest_active_level = stack_bits.trailing_zeros() as usize;
232            // SAFETY: Active level must have been set successfully before, hence it exists
233            root = *unsafe { self.stack.get_unchecked(lowest_active_level) };
234            // Clear lowest active level
235            stack_bits &= !(1 << lowest_active_level);
236        }
237
238        // Hash remaining peaks (if any) of the potentially unbalanced tree together
239        loop {
240            let lowest_active_level = stack_bits.trailing_zeros() as usize;
241
242            if lowest_active_level == u64::BITS as usize {
243                break;
244            }
245
246            // Clear lowest active level for next iteration
247            stack_bits &= !(1 << lowest_active_level);
248
249            // SAFETY: Active level must have been set successfully before, hence it exists
250            let lowest_active_level_item = unsafe { self.stack.get_unchecked(lowest_active_level) };
251
252            root = hash_pair(lowest_active_level_item, &root);
253        }
254
255        Some(root)
256    }
257
258    /// Get peaks of Merkle Mountain Range
259    #[inline]
260    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
261    pub fn peaks(&self) -> MmrPeaks<MAX_N> {
262        let mut result = MmrPeaks {
263            num_leaves: self.num_leaves,
264            peaks: [[0u8; OUT_LEN]; _],
265        };
266
267        // Convert stack (where occupied entries are at corresponding offsets) to peaks (where all
268        // occupied entries are all at the beginning of the list instead)
269        let mut stack_bits = self.num_leaves;
270        let mut peaks_offset = 0;
271        while stack_bits != 0 {
272            let stack_offset = stack_bits.trailing_zeros();
273
274            // SAFETY: Stack offset is always within the range of stack and peaks, this is
275            // guaranteed by internal invariants of the MMR
276            *unsafe { result.peaks.get_unchecked_mut(peaks_offset) } =
277                *unsafe { self.stack.get_unchecked(stack_offset as usize) };
278
279            peaks_offset += 1;
280            // Clear the lowest set bit
281            stack_bits &= !(1 << stack_offset);
282        }
283
284        result
285    }
286
287    /// Add leaf to Merkle Mountain Range.
288    ///
289    /// There is a more efficient version [`Self::add_leaves()`] in case multiple leaves are
290    /// available.
291    ///
292    /// Returns `true` on success, `false` if too many leaves were added.
293    #[inline]
294    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
295    pub fn add_leaf(&mut self, leaf: &[u8; OUT_LEN]) -> bool {
296        // How many leaves were processed so far. Should have been `num_leaves == MAX_N`, but `>=`
297        // helps compiler with panic safety checks.
298        if self.num_leaves >= MAX_N {
299            return false;
300        }
301
302        let mut current = *leaf;
303
304        // Every bit set to `1` corresponds to an active Merkle Tree level
305        let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
306        for item in self.stack.iter().take(lowest_active_levels) {
307            current = hash_pair(item, &current);
308        }
309
310        // Place the current hash at the first inactive level
311        // SAFETY: Stack is statically guaranteed to support all active levels with number of leaves
312        // checked at the beginning of the function.
313        // In fact the same exact code in `add_leaves()` doesn't require unchecked access, but here
314        // compiler is somehow unable to prove that panic can't happen otherwise.
315        *unsafe { self.stack.get_unchecked_mut(lowest_active_levels) } = current;
316        self.num_leaves += 1;
317
318        true
319    }
320
321    /// Add many leaves to Merkle Mountain Range.
322    ///
323    /// This is a more efficient version of [`Self::add_leaf()`] in case multiple leaves are
324    /// available.
325    ///
326    /// Returns `true` on success, `false` if too many leaves were added.
327    #[inline]
328    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
329    pub fn add_leaves<'a, Item, Iter>(&mut self, leaves: Iter) -> bool
330    where
331        Item: Into<[u8; OUT_LEN]>,
332        Iter: IntoIterator<Item = Item> + 'a,
333    {
334        // TODO: This can be optimized further
335        for leaf in leaves {
336            // How many leaves were processed so far. Should have been `num_leaves == MAX_N`, but
337            // `>=` helps compiler with panic safety checks.
338            if self.num_leaves >= MAX_N {
339                return false;
340            }
341
342            let mut current = leaf.into();
343
344            // Every bit set to `1` corresponds to an active Merkle Tree level
345            let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
346            for item in self.stack.iter().take(lowest_active_levels) {
347                current = hash_pair(item, &current);
348            }
349
350            // Place the current hash at the first inactive level
351            self.stack[lowest_active_levels] = current;
352            self.num_leaves += 1;
353        }
354
355        true
356    }
357
358    /// Add leaf to Merkle Mountain Range and generate inclusion proof.
359    ///
360    /// Returns `Some((root, proof))` on success, `None` if too many leaves were added.
361    #[inline]
362    #[cfg(feature = "alloc")]
363    pub fn add_leaf_and_compute_proof(
364        &mut self,
365        leaf: &[u8; OUT_LEN],
366    ) -> Option<([u8; OUT_LEN], Vec<[u8; OUT_LEN]>)> {
367        // SAFETY: Inner value is `MaybeUninit`
368        let mut proof =
369            unsafe { Box::<[MaybeUninit<[u8; OUT_LEN]>; _]>::new_uninit().assume_init() };
370
371        let (root, proof_length) = self.add_leaf_and_compute_proof_inner(leaf, &mut proof)?;
372
373        let proof_capacity = proof.len();
374        let proof = Box::into_raw(proof);
375        // SAFETY: Points to correctly allocated memory where `proof_length` elements were
376        // initialized
377        let proof = unsafe {
378            Vec::from_raw_parts(proof.cast::<[u8; OUT_LEN]>(), proof_length, proof_capacity)
379        };
380
381        Some((root, proof))
382    }
383
384    /// Add leaf to Merkle Mountain Range and generate inclusion proof.
385    ///
386    /// Returns `Some((root, proof))` on success, `None` if too many leaves were added.
387    #[inline]
388    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
389    pub fn add_leaf_and_compute_proof_in<'proof>(
390        &mut self,
391        leaf: &[u8; OUT_LEN],
392        proof: &'proof mut [MaybeUninit<[u8; OUT_LEN]>; MAX_PROOF_ELEMENTS::<MAX_N>],
393    ) -> Option<([u8; OUT_LEN], &'proof mut [[u8; OUT_LEN]])> {
394        let (root, proof_length) = self.add_leaf_and_compute_proof_inner(leaf, proof)?;
395
396        // SAFETY: Just correctly initialized `proof_length` elements
397        let proof = unsafe { proof.get_unchecked_mut(..proof_length).assume_init_mut() };
398
399        Some((root, proof))
400    }
401
402    #[inline]
403    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
404    pub fn add_leaf_and_compute_proof_inner(
405        &mut self,
406        leaf: &[u8; OUT_LEN],
407        proof: &mut [MaybeUninit<[u8; OUT_LEN]>; MAX_PROOF_ELEMENTS::<MAX_N>],
408    ) -> Option<([u8; OUT_LEN], usize)> {
409        let mut proof_length = 0;
410
411        let current_target_level;
412        let mut position = self.num_leaves;
413
414        {
415            // How many leaves were processed so far. Should have been `num_leaves == MAX_N`, but
416            // `>=` helps compiler with panic safety checks.
417            if self.num_leaves >= MAX_N {
418                return None;
419            }
420
421            let mut current = *leaf;
422
423            // Every bit set to `1` corresponds to an active Merkle Tree level
424            let lowest_active_levels = self.num_leaves.trailing_ones() as usize;
425
426            for item in self.stack.iter().take(lowest_active_levels) {
427                // If at the target leaf index, need to collect the proof
428                // SAFETY: Method signature guarantees upper bound of the proof length
429                unsafe { proof.get_unchecked_mut(proof_length) }.write(*item);
430                proof_length += 1;
431
432                current = hash_pair(item, &current);
433
434                // Move up the tree
435                position /= 2;
436            }
437
438            current_target_level = lowest_active_levels;
439
440            // Place the current hash at the first inactive level
441            self.stack[lowest_active_levels] = current;
442            self.num_leaves += 1;
443        }
444
445        let mut root;
446        let mut stack_bits = self.num_leaves;
447
448        {
449            let lowest_active_level = stack_bits.trailing_zeros() as usize;
450            // SAFETY: Active level must have been set successfully before, hence it exists
451            root = *unsafe { self.stack.get_unchecked(lowest_active_level) };
452            // Clear lowest active level
453            stack_bits &= !(1 << lowest_active_level);
454        }
455
456        // Hash remaining peaks (if any) of the potentially unbalanced tree together and collect
457        // proof hashes
458        let mut merged_peaks = false;
459        loop {
460            let lowest_active_level = stack_bits.trailing_zeros() as usize;
461
462            if lowest_active_level == u64::BITS as usize {
463                break;
464            }
465
466            // Clear lowest active level for next iteration
467            stack_bits &= !(1 << lowest_active_level);
468
469            // SAFETY: Active level must have been set successfully before, hence it exists
470            let lowest_active_level_item = unsafe { self.stack.get_unchecked(lowest_active_level) };
471
472            if lowest_active_level > current_target_level
473                || (lowest_active_level == current_target_level
474                    && !position.is_multiple_of(2)
475                    && !merged_peaks)
476            {
477                // SAFETY: Method signature guarantees upper bound of the proof length
478                unsafe { proof.get_unchecked_mut(proof_length) }.write(*lowest_active_level_item);
479                proof_length += 1;
480                merged_peaks = false;
481            } else if lowest_active_level == current_target_level {
482                // SAFETY: Method signature guarantees upper bound of the proof length
483                unsafe { proof.get_unchecked_mut(proof_length) }.write(root);
484                proof_length += 1;
485                merged_peaks = false;
486            } else {
487                // Not collecting proof because of the need to merge peaks of an unbalanced tree
488                merged_peaks = true;
489            }
490
491            // Collect the lowest peak into the proof
492            root = hash_pair(lowest_active_level_item, &root);
493
494            position /= 2;
495        }
496
497        Some((root, proof_length))
498    }
499
500    /// Verify a Merkle proof for a leaf at the given index.
501    ///
502    /// NOTE: `MAX_N` constant doesn't matter here and can be anything that is `>= 1`.
503    #[inline]
504    #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
505    pub fn verify(
506        root: &[u8; OUT_LEN],
507        proof: &[[u8; OUT_LEN]],
508        leaf_index: u64,
509        leaf: [u8; OUT_LEN],
510        num_leaves: u64,
511    ) -> bool {
512        UnbalancedMerkleTree::verify(root, proof, leaf_index, leaf, num_leaves)
513    }
514}