Skip to main content

miden_crypto/merkle/mmr/
full.rs

1//! A fully materialized Merkle mountain range (MMR).
2//!
3//! A MMR is a forest structure, i.e. it is an ordered set of disjoint rooted trees. The trees are
4//! ordered by size, from the most to least number of leaves. Every tree is a perfect binary tree,
5//! meaning a tree has all its leaves at the same depth, and every inner node has a branch-factor
6//! of 2 with both children set.
7//!
8//! Additionally the structure only supports adding leaves to the right-most tree, the one with the
9//! least number of leaves. The structure preserves the invariant that each tree has different
10//! depths, i.e. as part of adding a new element to the forest the trees with same depth are
11//! merged, creating a new tree with depth d+1, this process is continued until the property is
12//! reestablished.
13use alloc::{
14    string::{String, ToString},
15    sync::Arc,
16    vec::Vec,
17};
18use core::{iter::FusedIterator, ops::Index, slice};
19
20use super::{
21    super::{InnerNodeInfo, MerklePath},
22    MmrDelta, MmrError, MmrPath, MmrPeaks, MmrProof,
23    forest::{Forest, TreeSizeIterator},
24    nodes_from_mask,
25};
26use crate::{
27    Word,
28    hash::poseidon2::Poseidon2,
29    utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
30};
31
32// NODE STORE
33// ===============================================================================================
34
35/// Number of nodes per chunk in [NodeStore]: 1024 nodes * 32 bytes = 32 KiB per chunk.
36const NODE_CHUNK_CAPACITY: usize = 1024;
37
38/// Append-only node storage backed by fixed-size chunks shared between clones via [Arc].
39///
40/// The MMR's postorder node buffer is strictly append-only, so a clone taken at any point is
41/// fully described by a frozen prefix of the buffer. Cloning a [NodeStore] copies only the spine
42/// of [Arc] pointers, sharing all chunk contents with the original. [NodeStore::push] copies the
43/// last chunk before appending if (and only if) it is shared with a clone, bounding the
44/// copy-on-write cost at one chunk regardless of how many nodes the store holds.
45///
46/// Invariant: every chunk except the last contains exactly [NODE_CHUNK_CAPACITY] nodes, and no
47/// chunk is empty.
48#[derive(Debug, Clone, Default, PartialEq, Eq)]
49pub(super) struct NodeStore {
50    chunks: Vec<Arc<Vec<Word>>>,
51}
52
53impl NodeStore {
54    /// Constructor for an empty [NodeStore].
55    pub fn new() -> Self {
56        Self { chunks: Vec::new() }
57    }
58
59    /// Returns the number of nodes in the store.
60    pub fn len(&self) -> usize {
61        match self.chunks.last() {
62            Some(last) => (self.chunks.len() - 1) * NODE_CHUNK_CAPACITY + last.len(),
63            None => 0,
64        }
65    }
66
67    /// Appends a node to the store.
68    pub fn push(&mut self, node: Word) {
69        match self.chunks.last_mut() {
70            Some(last) if last.len() < NODE_CHUNK_CAPACITY => {
71                if Arc::get_mut(last).is_none() {
72                    // The chunk is shared with a clone; copy it before appending. A plain
73                    // `Arc::make_mut` would clone with capacity == len, growing past
74                    // NODE_CHUNK_CAPACITY on later pushes, so copy with the full capacity instead.
75                    let mut copy = Vec::with_capacity(NODE_CHUNK_CAPACITY);
76                    copy.extend_from_slice(last);
77                    *last = Arc::new(copy);
78                }
79                Arc::get_mut(last).expect("chunk is unique").push(node);
80            },
81            _ => {
82                let mut chunk = Vec::with_capacity(NODE_CHUNK_CAPACITY);
83                chunk.push(node);
84                self.chunks.push(Arc::new(chunk));
85            },
86        }
87    }
88
89    /// Returns an iterator over all nodes in the store, in insertion (postorder) order.
90    pub fn iter(&self) -> MmrNodeIter<'_> {
91        self.iter_from(0)
92    }
93
94    /// Returns an iterator over the nodes at indices `start..`, in insertion (postorder) order.
95    ///
96    /// Skips directly to the chunk containing `start` instead of walking from the front. Returns
97    /// an empty iterator if `start >= self.len()`.
98    pub fn iter_from(&self, start: usize) -> MmrNodeIter<'_> {
99        let first_chunk = start / NODE_CHUNK_CAPACITY;
100        let offset = start % NODE_CHUNK_CAPACITY;
101        match self.chunks.get(first_chunk) {
102            Some(chunk) => MmrNodeIter {
103                current: chunk[offset.min(chunk.len())..].iter(),
104                chunks: &self.chunks[first_chunk + 1..],
105            },
106            None => MmrNodeIter { current: [].iter(), chunks: &[] },
107        }
108    }
109}
110
111impl Index<usize> for NodeStore {
112    type Output = Word;
113
114    fn index(&self, index: usize) -> &Word {
115        &self.chunks[index / NODE_CHUNK_CAPACITY][index % NODE_CHUNK_CAPACITY]
116    }
117}
118
119impl FromIterator<Word> for NodeStore {
120    fn from_iter<T: IntoIterator<Item = Word>>(iter: T) -> Self {
121        let mut store = Self::new();
122        for node in iter {
123            store.push(node);
124        }
125        store
126    }
127}
128
129impl PartialEq<&[Word]> for NodeStore {
130    fn eq(&self, other: &&[Word]) -> bool {
131        self.len() == other.len() && self.iter().eq(other.iter())
132    }
133}
134
135// MMR
136// ===============================================================================================
137
138/// A fully materialized Merkle Mountain Range, with every tree in the forest and all their
139/// elements.
140///
141/// Since this is a full representation of the MMR, elements are never removed and the MMR will
142/// grow roughly `O(2n)` in number of leaf elements.
143///
144/// Cloning is cheap: the nodes are stored in chunks shared between clones, so a clone copies
145/// `O(num_nodes / 1024)` pointers instead of the full node buffer, and appending to the original
146/// after a clone copies at most one chunk.
147#[derive(Debug, Clone)]
148pub struct Mmr {
149    /// Refer to the `forest` method documentation for details of the semantics of this value.
150    pub(super) forest: Forest,
151
152    /// Contains every element of the forest.
153    ///
154    /// The trees are in postorder sequential representation. This representation allows for all
155    /// the elements of every tree in the forest to be stored in the same sequential buffer. It
156    /// also means new elements can be added to the forest, and merging of trees is very cheap with
157    /// no need to copy elements.
158    pub(super) nodes: NodeStore,
159}
160
161impl Default for Mmr {
162    fn default() -> Self {
163        Self::new()
164    }
165}
166
167impl Mmr {
168    // CONSTRUCTORS
169    // ============================================================================================
170
171    /// Constructor for an empty `Mmr`.
172    pub fn new() -> Mmr {
173        Mmr {
174            forest: Forest::empty(),
175            nodes: NodeStore::new(),
176        }
177    }
178
179    /// Constructs an MMR from an iterator of leaves.
180    ///
181    /// # Errors
182    /// Returns an error if the maximum forest size is exceeded.
183    pub fn try_from_iter<T: IntoIterator<Item = Word>>(values: T) -> Result<Self, MmrError> {
184        Self::try_from_iter_with_limit(values, Forest::MAX_LEAVES)
185    }
186
187    /// Constructs an MMR from its forest and complete node array, in insertion (postorder) order,
188    /// e.g. as previously obtained from `mmr.nodes_from(0).copied()` (see [Mmr::nodes_from]).
189    ///
190    /// The only validation performed is structural: the node count must match `forest`. The
191    /// nodes are otherwise taken verbatim — no hashes are recomputed or verified.
192    /// Comparing the result's [Mmr::peaks] against a trusted commitment checks the accumulator
193    /// state, but because the peaks are read from the stored nodes rather than recomputed, it does
194    /// not validate any non-peak nodes. The nodes must therefore come from a trusted source, e.g.
195    /// the caller's own previously validated state.
196    ///
197    /// # Errors
198    ///
199    /// Returns an error if the number of nodes does not match the node count of `forest`.
200    pub fn from_nodes_unchecked(
201        forest: Forest,
202        nodes: impl IntoIterator<Item = Word>,
203    ) -> Result<Self, MmrError> {
204        Self::from_store(forest, nodes.into_iter().collect())
205    }
206
207    /// Constructs an MMR from its forest and node store, validating the node count.
208    fn from_store(forest: Forest, nodes: NodeStore) -> Result<Self, MmrError> {
209        if nodes.len() != forest.num_nodes() {
210            return Err(MmrError::InvalidNodeCount {
211                expected: forest.num_nodes(),
212                actual: nodes.len(),
213            });
214        }
215        Ok(Self { forest, nodes })
216    }
217
218    pub(crate) fn try_from_iter_with_limit<T: IntoIterator<Item = Word>>(
219        values: T,
220        max_leaves: usize,
221    ) -> Result<Self, MmrError> {
222        let mut mmr = Mmr::new();
223        let iter = values.into_iter();
224        let (lower, _) = iter.size_hint();
225        if lower > max_leaves {
226            return Err(MmrError::ForestSizeExceeded { requested: lower, max: max_leaves });
227        }
228        let mut count = 0usize;
229        for v in iter {
230            count += 1;
231            if count > max_leaves {
232                return Err(MmrError::ForestSizeExceeded { requested: count, max: max_leaves });
233            }
234            mmr.add(v)?;
235        }
236        Ok(mmr)
237    }
238
239    /// Reconstructs an MMR from serialized parts after validating its stored structure.
240    fn from_serialized_parts(forest: Forest, nodes: NodeStore) -> Result<Self, String> {
241        let mmr = Self::from_store(forest, nodes).map_err(|err| err.to_string())?;
242        if mmr
243            .inner_nodes()
244            .any(|node| node.value != Poseidon2::merge(&[node.left, node.right]))
245        {
246            return Err("Mmr contains a parent node inconsistent with its children".into());
247        }
248
249        Ok(mmr)
250    }
251
252    // ACCESSORS
253    // ============================================================================================
254
255    /// Returns the MMR forest representation. See [`Forest`].
256    pub const fn forest(&self) -> Forest {
257        self.forest
258    }
259
260    /// Returns an iterator over the MMR's nodes at indices `start..`, in insertion (postorder)
261    /// order. Returns an empty iterator if `start` is greater than or equal to the total node
262    /// count, which is given by `self.forest().num_nodes()`.
263    ///
264    /// The node buffer is strictly append-only, so a consumer that has persisted the first
265    /// `start` nodes can incrementally sync by appending only the nodes returned here.
266    ///
267    /// Positioning is cheap: the iterator starts directly at `start` without walking the
268    /// preceding nodes, and it knows its exact remaining length.
269    pub fn nodes_from(&self, start: usize) -> impl ExactSizeIterator<Item = &Word> + Clone {
270        self.nodes.iter_from(start)
271    }
272
273    // FUNCTIONALITY
274    // ============================================================================================
275
276    /// Returns an [MmrProof] for the leaf at the specified position.
277    ///
278    /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
279    /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
280    /// has position 0, the second position 1, and so on.
281    ///
282    /// # Errors
283    /// Returns an error if the specified leaf position is out of bounds for this MMR.
284    pub fn open(&self, pos: usize) -> Result<MmrProof, MmrError> {
285        self.open_at(pos, self.forest)
286    }
287
288    /// Returns an [MmrProof] for the leaf at the specified position using the state of the MMR
289    /// at the specified `forest`.
290    ///
291    /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
292    /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
293    /// has position 0, the second position 1, and so on.
294    ///
295    /// # Errors
296    /// Returns an error if:
297    /// - The specified leaf position is out of bounds for this MMR.
298    /// - The specified `forest` value is not valid for this MMR.
299    pub fn open_at(&self, pos: usize, forest: Forest) -> Result<MmrProof, MmrError> {
300        if forest > self.forest {
301            return Err(MmrError::ForestOutOfBounds(forest.num_leaves(), self.forest.num_leaves()));
302        }
303        let (leaf, path) = self.collect_merkle_path_and_value(pos, forest)?;
304
305        let path = MmrPath::new(forest, pos, MerklePath::new(path));
306
307        Ok(MmrProof::new(path, leaf))
308    }
309
310    /// Returns the leaf value at position `pos`.
311    ///
312    /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
313    /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
314    /// has position 0, the second position 1, and so on.
315    pub fn get(&self, pos: usize) -> Result<Word, MmrError> {
316        let (value, _) = self.collect_merkle_path_and_value(pos, self.forest)?;
317
318        Ok(value)
319    }
320
321    /// Adds a new element to the MMR.
322    ///
323    /// # Errors
324    /// Returns an error if the MMR exceeds the maximum supported forest size.
325    pub fn add(&mut self, el: Word) -> Result<(), MmrError> {
326        // Fail early before mutating nodes.
327        let old_forest = self.forest;
328        self.forest.append_leaf()?;
329        // Note: every node is also a tree of size 1, adding an element to the forest creates a new
330        // rooted-tree of size 1. This may temporarily break the invariant that every tree in the
331        // forest has different sizes, the loop below will eagerly merge trees of same size and
332        // restore the invariant.
333        self.nodes.push(el);
334
335        let mut left_offset = self.nodes.len().saturating_sub(2);
336        let mut right = el;
337        let mut left_tree = 1usize;
338        while (old_forest.num_leaves() & left_tree) != 0 {
339            right = Poseidon2::merge(&[self.nodes[left_offset], right]);
340            self.nodes.push(right);
341
342            debug_assert!(left_tree <= Forest::MAX_LEAVES);
343            let left_nodes = left_tree * 2 - 1;
344            left_offset = left_offset.saturating_sub(left_nodes);
345
346            match left_tree.checked_shl(1) {
347                Some(next) => left_tree = next,
348                None => break,
349            }
350        }
351
352        Ok(())
353    }
354
355    /// Returns the current peaks of the MMR.
356    pub fn peaks(&self) -> MmrPeaks {
357        self.peaks_at(self.forest).expect("failed to get peaks at current forest")
358    }
359
360    /// Returns the peaks of the MMR at the state specified by `forest`.
361    ///
362    /// # Errors
363    /// Returns an error if the specified `forest` value is not valid for this MMR.
364    pub fn peaks_at(&self, forest: Forest) -> Result<MmrPeaks, MmrError> {
365        if forest > self.forest {
366            return Err(MmrError::ForestOutOfBounds(forest.num_leaves(), self.forest.num_leaves()));
367        }
368
369        let peaks: Vec<Word> = TreeSizeIterator::new(forest)
370            .rev()
371            .map(Forest::num_nodes)
372            .scan(0, |offset, el| {
373                *offset += el;
374                Some(*offset)
375            })
376            .map(|offset| self.nodes[offset - 1])
377            .collect();
378
379        // Safety: the invariant is maintained by the [Mmr]
380        let peaks = MmrPeaks::new(forest, peaks)?;
381
382        Ok(peaks)
383    }
384
385    /// Compute the required update to `original_forest`.
386    ///
387    /// The result is a packed sequence of the authentication elements required to update the trees
388    /// that have been merged together, followed by the new peaks of the [Mmr].
389    pub fn get_delta(&self, from_forest: Forest, to_forest: Forest) -> Result<MmrDelta, MmrError> {
390        if to_forest > self.forest {
391            return Err(MmrError::ForestOutOfBounds(
392                to_forest.num_leaves(),
393                self.forest.num_leaves(),
394            ));
395        }
396        if from_forest > to_forest {
397            return Err(MmrError::ForestOutOfBounds(
398                from_forest.num_leaves(),
399                to_forest.num_leaves(),
400            ));
401        }
402
403        if from_forest == to_forest {
404            return Ok(MmrDelta { forest: to_forest, data: Vec::new() });
405        }
406
407        let mut result = Vec::new();
408
409        // Find the largest tree in this [Mmr] which is new to `from_forest`.
410        let candidate_mask = to_forest.num_leaves() ^ from_forest.num_leaves();
411        let mut new_high = super::forest::largest_tree_from_mask(candidate_mask);
412
413        // Collect authentication nodes used for tree merges
414        // ----------------------------------------------------------------------------------------
415
416        // Find the trees from `from_forest` that have been merged into `new_high`.
417        let mut merges = from_forest & new_high.all_smaller_trees_unchecked();
418
419        // Find the peaks that are common to `from_forest` and this [Mmr]
420        let common_trees = from_forest ^ merges;
421
422        if !merges.is_empty() {
423            // Skip the smallest trees unknown to `from_forest`.
424            let mut target = merges.smallest_tree_unchecked();
425
426            // Collect siblings required to computed the merged tree's peak
427            while target < new_high {
428                // Computes the offset to the smallest know peak
429                // - common_trees: peaks unchanged in the current update, target comes after these.
430                // - merges: peaks that have not been merged so far, target comes after these.
431                // - target: tree from which to load the sibling. On the first iteration this is a
432                //   value known by the partial mmr, on subsequent iterations this value is to be
433                //   computed from the known peaks and provided authentication nodes.
434                let known_mask =
435                    common_trees.num_leaves() | merges.num_leaves() | target.num_leaves();
436                let known = nodes_from_mask(known_mask);
437                let sibling = target.num_nodes();
438                result.push(self.nodes[known + sibling - 1]);
439
440                // Update the target and account for tree merges
441                target = target.next_larger_tree()?;
442                while !(merges & target).is_empty() {
443                    target = target.next_larger_tree()?;
444                }
445                // Remove the merges done so far
446                merges ^= merges & target.all_smaller_trees_unchecked();
447            }
448        } else {
449            // The new high tree may not be the result of any merges, if it is smaller than all the
450            // trees of `from_forest`.
451            new_high = Forest::empty();
452        }
453
454        // Collect the new [Mmr] peaks
455        // ----------------------------------------------------------------------------------------
456
457        let mut new_peaks = to_forest ^ common_trees ^ new_high;
458        let old_peaks = to_forest ^ new_peaks;
459        let mut offset = old_peaks.num_nodes();
460        while !new_peaks.is_empty() {
461            let target = new_peaks.largest_tree_unchecked();
462            offset += target.num_nodes();
463            result.push(self.nodes[offset - 1]);
464            new_peaks ^= target;
465        }
466
467        Ok(MmrDelta { forest: to_forest, data: result })
468    }
469
470    /// An iterator over inner nodes in the MMR. The order of iteration is unspecified.
471    pub fn inner_nodes(&self) -> MmrNodes<'_> {
472        MmrNodes {
473            mmr: self,
474            forest: 0,
475            last_right: 0,
476            index: 0,
477        }
478    }
479
480    // UTILITIES
481    // ============================================================================================
482
483    /// Internal function used to collect the leaf value and its Merkle path.
484    ///
485    /// The arguments are relative to the target tree. To compute the opening of the second leaf
486    /// for a tree with depth 2 in the forest `0b110`:
487    ///
488    /// - `leaf_idx`: Position corresponding to the order the leaves were added.
489    /// - `forest`: State of the MMR.
490    fn collect_merkle_path_and_value(
491        &self,
492        leaf_idx: usize,
493        forest: Forest,
494    ) -> Result<(Word, Vec<Word>), MmrError> {
495        // find the target tree responsible for the MMR position
496        let tree_bit = forest
497            .leaf_to_corresponding_tree(leaf_idx)
498            .ok_or(MmrError::PositionNotFound(leaf_idx))?;
499
500        // isolate the trees before the target
501        let forest_before = forest.trees_larger_than(tree_bit);
502        let index_offset = forest_before.num_nodes();
503
504        // update the value position from global to the target tree
505        let relative_pos = leaf_idx - forest_before.num_leaves();
506
507        // see documentation of `leaf_to_corresponding_tree` for details
508        let tree_depth = (tree_bit + 1) as usize;
509        let mut path = Vec::with_capacity(tree_depth);
510
511        // The tree walk below goes from the root to the leaf, compute the root index to start
512        let mut forest_target: usize = 1usize << tree_bit;
513        let mut index = nodes_from_mask(forest_target) - 1;
514
515        // Loop until the leaf is reached
516        while forest_target > 1 {
517            // Update the depth of the tree to correspond to a subtree
518            forest_target >>= 1;
519
520            // compute the indices of the right and left subtrees based on the post-order
521            let right_offset = index - 1;
522            let left_offset = right_offset - nodes_from_mask(forest_target);
523
524            let left_or_right = relative_pos & forest_target;
525            let sibling = if left_or_right != 0 {
526                // going down the right subtree, the right child becomes the new root
527                index = right_offset;
528                // and the left child is the authentication
529                self.nodes[index_offset + left_offset]
530            } else {
531                index = left_offset;
532                self.nodes[index_offset + right_offset]
533            };
534
535            path.push(sibling);
536        }
537
538        debug_assert!(path.len() == tree_depth - 1);
539
540        // the rest of the codebase has the elements going from leaf to root, adjust it here for
541        // easy of use/consistency sake
542        path.reverse();
543
544        let value = self.nodes[index_offset + index];
545        Ok((value, path))
546    }
547}
548
549// CONVERSIONS
550// ================================================================================================
551
552// No TryFrom<T> impl: it conflicts with core’s blanket TryFrom<U> where U: Into<T>.
553
554// SERIALIZATION
555// ================================================================================================
556
557impl Serializable for Mmr {
558    fn write_into<W: ByteWriter>(&self, target: &mut W) {
559        self.forest.write_into(target);
560        // Matches the wire format of `Vec<Word>`: a `write_usize` length prefix followed by the
561        // elements in postorder.
562        target.write_usize(self.nodes.len());
563        target.write_many(self.nodes.iter());
564    }
565}
566
567impl Deserializable for Mmr {
568    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
569        let forest = Forest::read_from(source)?;
570        let count = source.read_usize()?;
571        // Reject a forest/count mismatch before reading the nodes, so malformed input fails fast.
572        if count != forest.num_nodes() {
573            return Err(DeserializationError::InvalidValue(
574                MmrError::InvalidNodeCount {
575                    expected: forest.num_nodes(),
576                    actual: count,
577                }
578                .to_string(),
579            ));
580        }
581        let nodes = source.read_many_iter(count)?.collect::<Result<NodeStore, _>>()?;
582        Self::from_serialized_parts(forest, nodes).map_err(DeserializationError::InvalidValue)
583    }
584}
585
586// ITERATOR
587// ===============================================================================================
588
589/// Iterator over a suffix of the [Mmr]'s node buffer, in insertion (postorder) order.
590///
591/// Underlies [Mmr::nodes_from], which returns it opaquely. Positioning is cheap: [Iterator::nth]
592/// (and therefore [Iterator::skip]) jumps over whole chunks instead of advancing one node at a
593/// time, and the iterator knows its exact remaining length ([ExactSizeIterator]).
594#[derive(Clone, Debug)]
595pub(super) struct MmrNodeIter<'a> {
596    /// Remainder of the chunk currently being yielded.
597    current: slice::Iter<'a, Word>,
598    /// Chunks after the current one; every chunk except the last is full.
599    chunks: &'a [Arc<Vec<Word>>],
600}
601
602impl<'a> MmrNodeIter<'a> {
603    /// Advances `current` to the next chunk, or returns `None` if no chunks remain.
604    ///
605    /// On `None` the iterator is left exhausted even if `current` still held items, so a caller
606    /// skipping past the end (see [Iterator::nth]) doesn't leave the skipped items behind.
607    fn advance_chunk(&mut self) -> Option<()> {
608        match self.chunks.split_first() {
609            Some((chunk, rest)) => {
610                self.current = chunk.iter();
611                self.chunks = rest;
612                Some(())
613            },
614            None => {
615                self.current = [].iter();
616                None
617            },
618        }
619    }
620}
621
622impl<'a> Iterator for MmrNodeIter<'a> {
623    type Item = &'a Word;
624
625    fn next(&mut self) -> Option<&'a Word> {
626        loop {
627            if let Some(node) = self.current.next() {
628                return Some(node);
629            }
630            self.advance_chunk()?;
631        }
632    }
633
634    fn nth(&mut self, mut n: usize) -> Option<&'a Word> {
635        loop {
636            let len = self.current.len();
637            if n < len {
638                return self.current.nth(n);
639            }
640            n -= len;
641            self.advance_chunk()?;
642        }
643    }
644
645    fn size_hint(&self) -> (usize, Option<usize>) {
646        let len = self.len();
647        (len, Some(len))
648    }
649
650    fn count(self) -> usize {
651        self.len()
652    }
653}
654
655impl ExactSizeIterator for MmrNodeIter<'_> {
656    fn len(&self) -> usize {
657        self.current.len()
658            + match self.chunks.split_last() {
659                Some((last, full)) => full.len() * NODE_CHUNK_CAPACITY + last.len(),
660                None => 0,
661            }
662    }
663}
664
665impl FusedIterator for MmrNodeIter<'_> {}
666
667/// Yields inner nodes of the [Mmr].
668pub struct MmrNodes<'a> {
669    /// [Mmr] being yielded, when its `forest` value is matched, the iterations is finished.
670    mmr: &'a Mmr,
671    /// Keeps track of the left nodes yielded so far waiting for a right pair, this matches the
672    /// semantics of the [Mmr]'s forest attribute, since that too works as a buffer of left nodes
673    /// waiting for a pair to be hashed together.
674    forest: usize,
675    /// Keeps track of the last right node yielded, after this value is set, the next iteration
676    /// will be its parent with its corresponding left node that has been yield already.
677    last_right: usize,
678    /// The current index in the `nodes` vector.
679    index: usize,
680}
681
682impl Iterator for MmrNodes<'_> {
683    type Item = InnerNodeInfo;
684
685    fn next(&mut self) -> Option<Self::Item> {
686        debug_assert!(self.last_right.count_ones() <= 1, "last_right tracks zero or one element");
687
688        // only parent nodes are emitted, remove the single node tree from the forest
689        let target = self.mmr.forest.without_single_leaf().num_leaves();
690
691        if self.forest < target {
692            if self.last_right == 0 {
693                // yield the left leaf
694                debug_assert!(self.last_right == 0, "left must be before right");
695                self.forest |= 1;
696                self.index += 1;
697
698                // yield the right leaf
699                debug_assert!((self.forest & 1) == 1, "right must be after left");
700                self.last_right |= 1;
701                self.index += 1;
702            };
703
704            debug_assert!(
705                self.forest & self.last_right != 0,
706                "parent requires both a left and right",
707            );
708
709            // compute the number of nodes in the right tree, this is the offset to the
710            // previous left parent
711            let right_nodes = Forest::new(self.last_right).unwrap().num_nodes();
712            // the next parent position is one above the position of the pair
713            let parent = self.last_right << 1;
714
715            // the left node has been paired and the current parent yielded, removed it from the
716            // forest
717            self.forest ^= self.last_right;
718            if self.forest & parent == 0 {
719                // this iteration yielded the left parent node
720                debug_assert!(self.forest & 1 == 0, "next iteration yields a left leaf");
721                self.last_right = 0;
722                self.forest ^= parent;
723            } else {
724                // the left node of the parent level has been yielded already, this iteration
725                // was the right parent. Next iteration yields their parent.
726                self.last_right = parent;
727            }
728
729            // yields a parent
730            let value = self.mmr.nodes[self.index];
731            let right = self.mmr.nodes[self.index - 1];
732            let left = self.mmr.nodes[self.index - 1 - right_nodes];
733            self.index += 1;
734            let node = InnerNodeInfo { value, left, right };
735
736            Some(node)
737        } else {
738            None
739        }
740    }
741}
742
743// TESTS
744// ================================================================================================
745#[cfg(test)]
746mod tests {
747    use alloc::{sync::Arc, vec::Vec};
748
749    use super::{super::nodes_from_mask, NODE_CHUNK_CAPACITY};
750    use crate::{
751        Felt, Word, ZERO,
752        merkle::mmr::{Forest, Mmr, MmrError},
753        utils::{Deserializable, DeserializationError, Serializable},
754    };
755
756    fn leaves(count: u64) -> impl Iterator<Item = Word> {
757        (0..count).map(|value| Word::new([ZERO, ZERO, ZERO, Felt::new_unchecked(value)]))
758    }
759
760    #[test]
761    fn test_serialization() {
762        let nodes = (0u64..128u64)
763            .map(|value| Word::new([ZERO, ZERO, ZERO, Felt::new_unchecked(value)]))
764            .collect::<Vec<_>>();
765
766        let mmr = Mmr::try_from_iter(nodes).unwrap();
767        let serialized = mmr.to_bytes();
768        let deserialized = Mmr::read_from_bytes(&serialized).unwrap();
769        assert_eq!(mmr.forest, deserialized.forest);
770        assert_eq!(mmr.nodes, deserialized.nodes);
771    }
772
773    #[test]
774    fn test_deserialization_rejects_large_forest() {
775        let mut bytes = (Forest::MAX_LEAVES + 1).to_bytes();
776        bytes.extend_from_slice(&0usize.to_bytes()); // empty nodes vector
777
778        let result = Mmr::read_from_bytes(&bytes);
779        assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
780    }
781
782    #[test]
783    fn test_serialization_matches_vec_format() {
784        // Build an MMR spanning multiple chunks (> 2048 nodes) to cover chunk boundaries.
785        let num_leaves = NODE_CHUNK_CAPACITY as u64 + NODE_CHUNK_CAPACITY as u64 / 2;
786        let mmr = Mmr::try_from_iter(leaves(num_leaves)).unwrap();
787        assert!(mmr.nodes.len() > 2 * NODE_CHUNK_CAPACITY);
788
789        let mut expected = mmr.forest.to_bytes();
790        let nodes_vec: Vec<Word> = mmr.nodes.iter().copied().collect();
791        expected.extend_from_slice(&nodes_vec.to_bytes());
792
793        assert_eq!(mmr.to_bytes(), expected);
794        let deserialized = Mmr::read_from_bytes(&expected).unwrap();
795        assert_eq!(mmr.forest, deserialized.forest);
796        assert_eq!(mmr.nodes, deserialized.nodes);
797    }
798
799    #[test]
800    fn test_deserialization_rejects_node_count_mismatch() {
801        let mmr = Mmr::try_from_iter(leaves(8)).unwrap();
802        let mut bytes = mmr.forest.to_bytes();
803        let mut nodes_vec: Vec<Word> = mmr.nodes.iter().copied().collect();
804        nodes_vec.pop();
805        bytes.extend_from_slice(&nodes_vec.to_bytes());
806
807        let result = Mmr::read_from_bytes(&bytes);
808        assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
809    }
810
811    #[test]
812    fn test_clone_stays_frozen_after_push() {
813        let num_leaves = 2 * NODE_CHUNK_CAPACITY as u64;
814        let mut mmr = Mmr::try_from_iter(leaves(num_leaves)).unwrap();
815        let clone = mmr.clone();
816
817        for leaf in leaves(3 * NODE_CHUNK_CAPACITY as u64).skip(num_leaves as usize) {
818            mmr.add(leaf).unwrap();
819        }
820
821        // The clone is an unchanged snapshot of the original at the time of cloning.
822        let reference = Mmr::try_from_iter(leaves(num_leaves)).unwrap();
823        assert_eq!(clone.forest, reference.forest);
824        assert_eq!(clone.nodes, reference.nodes);
825        assert_eq!(clone.peaks(), reference.peaks());
826
827        // The original matches a freshly built MMR of the same size.
828        let reference = Mmr::try_from_iter(leaves(3 * NODE_CHUNK_CAPACITY as u64)).unwrap();
829        assert_eq!(mmr.forest, reference.forest);
830        assert_eq!(mmr.nodes, reference.nodes);
831        assert_eq!(mmr.peaks(), reference.peaks());
832    }
833
834    #[test]
835    fn test_clone_shares_full_chunks() {
836        let mut mmr = Mmr::try_from_iter(leaves(NODE_CHUNK_CAPACITY as u64)).unwrap();
837        let clone = mmr.clone();
838        mmr.add(Word::empty()).unwrap();
839
840        // Pushing into the original diverges only the last (shared) chunk.
841        let orig_chunks = &mmr.nodes.chunks;
842        let clone_chunks = &clone.nodes.chunks;
843        assert_eq!(orig_chunks.len(), clone_chunks.len());
844        for (orig, cloned) in orig_chunks.iter().zip(clone_chunks).take(orig_chunks.len() - 1) {
845            assert!(Arc::ptr_eq(orig, cloned));
846        }
847        assert!(!Arc::ptr_eq(orig_chunks.last().unwrap(), clone_chunks.last().unwrap()));
848    }
849
850    #[test]
851    fn test_nodes_from() {
852        // Span multiple chunks to cover chunk boundaries.
853        let mmr = Mmr::try_from_iter(leaves(2 * NODE_CHUNK_CAPACITY as u64)).unwrap();
854        let num_nodes = mmr.forest().num_nodes();
855        let all: Vec<Word> = mmr.nodes_from(0).copied().collect();
856        assert_eq!(all.len(), num_nodes);
857
858        // Starts at chunk boundaries, mid-chunk, and in the last (partial) chunk.
859        for start in [
860            0,
861            1,
862            NODE_CHUNK_CAPACITY - 1,
863            NODE_CHUNK_CAPACITY,
864            NODE_CHUNK_CAPACITY + 1,
865            num_nodes - 1,
866            num_nodes,
867            num_nodes + 1,
868        ] {
869            let suffix: Vec<Word> = mmr.nodes_from(start).copied().collect();
870            assert_eq!(suffix, all[start.min(num_nodes)..]);
871        }
872    }
873
874    #[test]
875    fn test_node_iter_skip_matches_nodes_from() {
876        // Span multiple chunks so skips cross chunk boundaries.
877        let mmr = Mmr::try_from_iter(leaves(2 * NODE_CHUNK_CAPACITY as u64)).unwrap();
878        let num_nodes = mmr.forest().num_nodes();
879        let all: Vec<Word> = mmr.nodes_from(0).copied().collect();
880
881        for start in [
882            0,
883            1,
884            NODE_CHUNK_CAPACITY - 1,
885            NODE_CHUNK_CAPACITY,
886            NODE_CHUNK_CAPACITY + 1,
887            num_nodes - 1,
888            num_nodes,
889            num_nodes + 1,
890        ] {
891            let skipped: Vec<Word> = mmr.nodes_from(0).skip(start).copied().collect();
892            assert_eq!(skipped, all[start.min(num_nodes)..]);
893        }
894
895        // `nth` positions across a chunk boundary and resumes in order.
896        let mut iter = mmr.nodes_from(0);
897        assert_eq!(iter.nth(NODE_CHUNK_CAPACITY + 1), Some(&all[NODE_CHUNK_CAPACITY + 1]));
898        assert_eq!(iter.next(), Some(&all[NODE_CHUNK_CAPACITY + 2]));
899
900        // `nth` past the end exhausts the iterator.
901        let mut iter = mmr.nodes_from(0);
902        assert_eq!(iter.nth(num_nodes), None);
903        assert_eq!(iter.next(), None);
904    }
905
906    #[test]
907    fn test_node_iter_len() {
908        let mmr = Mmr::try_from_iter(leaves(2 * NODE_CHUNK_CAPACITY as u64)).unwrap();
909        let num_nodes = mmr.forest().num_nodes();
910
911        for start in [0, 1, NODE_CHUNK_CAPACITY, num_nodes - 1, num_nodes, num_nodes + 1] {
912            let iter = mmr.nodes_from(start);
913            assert_eq!(iter.len(), num_nodes.saturating_sub(start));
914            assert_eq!(iter.size_hint(), (iter.len(), Some(iter.len())));
915        }
916
917        // The length stays exact as the iterator advances, including across chunks.
918        let mut iter = mmr.nodes_from(0);
919        iter.next();
920        assert_eq!(iter.len(), num_nodes - 1);
921        iter.nth(NODE_CHUNK_CAPACITY);
922        assert_eq!(iter.len(), num_nodes - NODE_CHUNK_CAPACITY - 2);
923        assert_eq!(iter.count(), num_nodes - NODE_CHUNK_CAPACITY - 2);
924    }
925
926    #[test]
927    fn test_nodes_from_incremental_persistence() {
928        // Simulate a flat-file consumer: persist all nodes, grow the MMR, append only the new
929        // nodes, and verify the result matches a full dump of the final state.
930        let initial_leaves = NODE_CHUNK_CAPACITY as u64 / 2;
931        let final_leaves = 2 * NODE_CHUNK_CAPACITY as u64;
932
933        let mut mmr = Mmr::try_from_iter(leaves(initial_leaves)).unwrap();
934        let mut persisted: Vec<Word> = mmr.nodes_from(0).copied().collect();
935
936        for leaf in leaves(final_leaves).skip(initial_leaves as usize) {
937            mmr.add(leaf).unwrap();
938        }
939        persisted.extend(mmr.nodes_from(persisted.len()).copied());
940
941        assert_eq!(persisted.len(), mmr.forest().num_nodes());
942        assert!(mmr.nodes == persisted.as_slice());
943    }
944
945    #[test]
946    fn test_from_nodes_unchecked_round_trip() {
947        // Sizes: empty forest, single-chunk, and multi-chunk with a partial last chunk.
948        let multi_chunk = NODE_CHUNK_CAPACITY as u64 + NODE_CHUNK_CAPACITY as u64 / 2;
949        for num_leaves in [0, 1, 8, multi_chunk] {
950            let mmr = Mmr::try_from_iter(leaves(num_leaves)).unwrap();
951            let rebuilt =
952                Mmr::from_nodes_unchecked(mmr.forest(), mmr.nodes_from(0).copied()).unwrap();
953            assert_eq!(mmr.forest, rebuilt.forest);
954            assert_eq!(mmr.nodes, rebuilt.nodes);
955            assert_eq!(mmr.peaks(), rebuilt.peaks());
956
957            // Openings from the rebuilt MMR still verify against its peaks.
958            let peaks = rebuilt.peaks();
959            for pos in [0, num_leaves.saturating_sub(1) as usize] {
960                if num_leaves > 0 {
961                    let proof = rebuilt.open(pos).unwrap();
962                    let leaf = rebuilt.get(pos).unwrap();
963                    peaks.verify(leaf, proof).unwrap();
964                }
965            }
966        }
967    }
968
969    #[test]
970    fn test_from_nodes_unchecked_rejects_count_mismatch() {
971        let mmr = Mmr::try_from_iter(leaves(8)).unwrap();
972        let nodes: Vec<Word> = mmr.nodes_from(0).copied().collect();
973
974        let too_few =
975            Mmr::from_nodes_unchecked(mmr.forest(), nodes.iter().copied().take(nodes.len() - 1));
976        assert!(matches!(
977            too_few,
978            Err(MmrError::InvalidNodeCount { expected, actual })
979                if expected == nodes.len() && actual == nodes.len() - 1
980        ));
981
982        let too_many =
983            Mmr::from_nodes_unchecked(mmr.forest(), nodes.iter().copied().chain([Word::empty()]));
984        assert!(matches!(
985            too_many,
986            Err(MmrError::InvalidNodeCount { expected, actual })
987                if expected == nodes.len() && actual == nodes.len() + 1
988        ));
989    }
990
991    #[test]
992    fn test_nodes_from_mask_at_max_leaves() {
993        let expected = (Forest::MAX_LEAVES as u128)
994            .saturating_mul(2)
995            .saturating_sub(Forest::MAX_LEAVES.count_ones() as u128);
996        assert!(expected <= usize::MAX as u128);
997        assert_eq!(nodes_from_mask(Forest::MAX_LEAVES), expected as usize);
998    }
999}