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::vec::Vec;
14
15use super::{
16    super::{InnerNodeInfo, MerklePath},
17    MmrDelta, MmrError, MmrPeaks, MmrProof, Rpo256, RpoDigest,
18    bit::TrueBitPositionIterator,
19    leaf_to_corresponding_tree, nodes_in_forest,
20};
21
22// MMR
23// ===============================================================================================
24
25/// A fully materialized Merkle Mountain Range, with every tree in the forest and all their
26/// elements.
27///
28/// Since this is a full representation of the MMR, elements are never removed and the MMR will
29/// grow roughly `O(2n)` in number of leaf elements.
30#[derive(Debug, Clone)]
31#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
32pub struct Mmr {
33    /// Refer to the `forest` method documentation for details of the semantics of this value.
34    pub(super) forest: usize,
35
36    /// Contains every element of the forest.
37    ///
38    /// The trees are in postorder sequential representation. This representation allows for all
39    /// the elements of every tree in the forest to be stored in the same sequential buffer. It
40    /// also means new elements can be added to the forest, and merging of trees is very cheap with
41    /// no need to copy elements.
42    pub(super) nodes: Vec<RpoDigest>,
43}
44
45impl Default for Mmr {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51impl Mmr {
52    // CONSTRUCTORS
53    // ============================================================================================
54
55    /// Constructor for an empty `Mmr`.
56    pub fn new() -> Mmr {
57        Mmr { forest: 0, nodes: Vec::new() }
58    }
59
60    // ACCESSORS
61    // ============================================================================================
62
63    /// Returns the MMR forest representation.
64    ///
65    /// The forest value has the following interpretations:
66    /// - its value is the number of elements in the forest
67    /// - bit count corresponds to the number of trees in the forest
68    /// - each true bit position determines the depth of a tree in the forest
69    pub const fn forest(&self) -> usize {
70        self.forest
71    }
72
73    // FUNCTIONALITY
74    // ============================================================================================
75
76    /// Returns an [MmrProof] for the leaf at the specified position.
77    ///
78    /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
79    /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
80    /// has position 0, the second position 1, and so on.
81    ///
82    /// # Errors
83    /// Returns an error if the specified leaf position is out of bounds for this MMR.
84    pub fn open(&self, pos: usize) -> Result<MmrProof, MmrError> {
85        self.open_at(pos, self.forest)
86    }
87
88    /// Returns an [MmrProof] for the leaf at the specified position using the state of the MMR
89    /// at the specified `forest`.
90    ///
91    /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
92    /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
93    /// has position 0, the second position 1, and so on.
94    ///
95    /// # Errors
96    /// Returns an error if:
97    /// - The specified leaf position is out of bounds for this MMR.
98    /// - The specified `forest` value is not valid for this MMR.
99    pub fn open_at(&self, pos: usize, forest: usize) -> Result<MmrProof, MmrError> {
100        // find the target tree responsible for the MMR position
101        let tree_bit =
102            leaf_to_corresponding_tree(pos, forest).ok_or(MmrError::PositionNotFound(pos))?;
103
104        // isolate the trees before the target
105        let forest_before = forest & high_bitmask(tree_bit + 1);
106        let index_offset = nodes_in_forest(forest_before);
107
108        // update the value position from global to the target tree
109        let relative_pos = pos - forest_before;
110
111        // collect the path and the final index of the target value
112        let (_, path) = self.collect_merkle_path_and_value(tree_bit, relative_pos, index_offset);
113
114        Ok(MmrProof {
115            forest,
116            position: pos,
117            merkle_path: MerklePath::new(path),
118        })
119    }
120
121    /// Returns the leaf value at position `pos`.
122    ///
123    /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
124    /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
125    /// has position 0, the second position 1, and so on.
126    pub fn get(&self, pos: usize) -> Result<RpoDigest, MmrError> {
127        // find the target tree responsible for the MMR position
128        let tree_bit =
129            leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::PositionNotFound(pos))?;
130
131        // isolate the trees before the target
132        let forest_before = self.forest & high_bitmask(tree_bit + 1);
133        let index_offset = nodes_in_forest(forest_before);
134
135        // update the value position from global to the target tree
136        let relative_pos = pos - forest_before;
137
138        // collect the path and the final index of the target value
139        let (value, _) = self.collect_merkle_path_and_value(tree_bit, relative_pos, index_offset);
140
141        Ok(value)
142    }
143
144    /// Adds a new element to the MMR.
145    pub fn add(&mut self, el: RpoDigest) {
146        // Note: every node is also a tree of size 1, adding an element to the forest creates a new
147        // rooted-tree of size 1. This may temporarily break the invariant that every tree in the
148        // forest has different sizes, the loop below will eagerly merge trees of same size and
149        // restore the invariant.
150        self.nodes.push(el);
151
152        let mut left_offset = self.nodes.len().saturating_sub(2);
153        let mut right = el;
154        let mut left_tree = 1;
155        while self.forest & left_tree != 0 {
156            right = Rpo256::merge(&[self.nodes[left_offset], right]);
157            self.nodes.push(right);
158
159            left_offset = left_offset.saturating_sub(nodes_in_forest(left_tree));
160            left_tree <<= 1;
161        }
162
163        self.forest += 1;
164    }
165
166    /// Returns the current peaks of the MMR.
167    pub fn peaks(&self) -> MmrPeaks {
168        self.peaks_at(self.forest).expect("failed to get peaks at current forest")
169    }
170
171    /// Returns the peaks of the MMR at the state specified by `forest`.
172    ///
173    /// # Errors
174    /// Returns an error if the specified `forest` value is not valid for this MMR.
175    pub fn peaks_at(&self, forest: usize) -> Result<MmrPeaks, MmrError> {
176        if forest > self.forest {
177            return Err(MmrError::InvalidPeaks(format!(
178                "requested forest {forest} exceeds current forest {}",
179                self.forest
180            )));
181        }
182
183        let peaks: Vec<RpoDigest> = TrueBitPositionIterator::new(forest)
184            .rev()
185            .map(|bit| nodes_in_forest(1 << bit))
186            .scan(0, |offset, el| {
187                *offset += el;
188                Some(*offset)
189            })
190            .map(|offset| self.nodes[offset - 1])
191            .collect();
192
193        // Safety: the invariant is maintained by the [Mmr]
194        let peaks = MmrPeaks::new(forest, peaks).unwrap();
195
196        Ok(peaks)
197    }
198
199    /// Compute the required update to `original_forest`.
200    ///
201    /// The result is a packed sequence of the authentication elements required to update the trees
202    /// that have been merged together, followed by the new peaks of the [Mmr].
203    pub fn get_delta(&self, from_forest: usize, to_forest: usize) -> Result<MmrDelta, MmrError> {
204        if to_forest > self.forest || from_forest > to_forest {
205            return Err(MmrError::InvalidPeaks(format!(
206                "to_forest {to_forest} exceeds the current forest {} or from_forest {from_forest} exceeds to_forest",
207                self.forest
208            )));
209        }
210
211        if from_forest == to_forest {
212            return Ok(MmrDelta { forest: to_forest, data: Vec::new() });
213        }
214
215        let mut result = Vec::new();
216
217        // Find the largest tree in this [Mmr] which is new to `from_forest`.
218        let candidate_trees = to_forest ^ from_forest;
219        let mut new_high = 1 << candidate_trees.ilog2();
220
221        // Collect authentication nodes used for tree merges
222        // ----------------------------------------------------------------------------------------
223
224        // Find the trees from `from_forest` that have been merged into `new_high`.
225        let mut merges = from_forest & (new_high - 1);
226
227        // Find the peaks that are common to `from_forest` and this [Mmr]
228        let common_trees = from_forest ^ merges;
229
230        if merges != 0 {
231            // Skip the smallest trees unknown to `from_forest`.
232            let mut target = 1 << merges.trailing_zeros();
233
234            // Collect siblings required to computed the merged tree's peak
235            while target < new_high {
236                // Computes the offset to the smallest know peak
237                // - common_trees: peaks unchanged in the current update, target comes after these.
238                // - merges: peaks that have not been merged so far, target comes after these.
239                // - target: tree from which to load the sibling. On the first iteration this is a
240                //   value known by the partial mmr, on subsequent iterations this value is to be
241                //   computed from the known peaks and provided authentication nodes.
242                let known = nodes_in_forest(common_trees | merges | target);
243                let sibling = nodes_in_forest(target);
244                result.push(self.nodes[known + sibling - 1]);
245
246                // Update the target and account for tree merges
247                target <<= 1;
248                while merges & target != 0 {
249                    target <<= 1;
250                }
251                // Remove the merges done so far
252                merges ^= merges & (target - 1);
253            }
254        } else {
255            // The new high tree may not be the result of any merges, if it is smaller than all the
256            // trees of `from_forest`.
257            new_high = 0;
258        }
259
260        // Collect the new [Mmr] peaks
261        // ----------------------------------------------------------------------------------------
262
263        let mut new_peaks = to_forest ^ common_trees ^ new_high;
264        let old_peaks = to_forest ^ new_peaks;
265        let mut offset = nodes_in_forest(old_peaks);
266        while new_peaks != 0 {
267            let target = 1 << new_peaks.ilog2();
268            offset += nodes_in_forest(target);
269            result.push(self.nodes[offset - 1]);
270            new_peaks ^= target;
271        }
272
273        Ok(MmrDelta { forest: to_forest, data: result })
274    }
275
276    /// An iterator over inner nodes in the MMR. The order of iteration is unspecified.
277    pub fn inner_nodes(&self) -> MmrNodes {
278        MmrNodes {
279            mmr: self,
280            forest: 0,
281            last_right: 0,
282            index: 0,
283        }
284    }
285
286    // UTILITIES
287    // ============================================================================================
288
289    /// Internal function used to collect the Merkle path of a value.
290    ///
291    /// The arguments are relative to the target tree. To compute the opening of the second leaf
292    /// for a tree with depth 2 in the forest `0b110`:
293    ///
294    /// - `tree_bit`: Depth of the target tree, e.g. 2 for the smallest tree.
295    /// - `relative_pos`: 0-indexed leaf position in the target tree, e.g. 1 for the second leaf.
296    /// - `index_offset`: Node count prior to the target tree, e.g. 7 for the tree of depth 3.
297    fn collect_merkle_path_and_value(
298        &self,
299        tree_bit: u32,
300        relative_pos: usize,
301        index_offset: usize,
302    ) -> (RpoDigest, Vec<RpoDigest>) {
303        // see documentation of `leaf_to_corresponding_tree` for details
304        let tree_depth = (tree_bit + 1) as usize;
305        let mut path = Vec::with_capacity(tree_depth);
306
307        // The tree walk below goes from the root to the leaf, compute the root index to start
308        let mut forest_target = 1usize << tree_bit;
309        let mut index = nodes_in_forest(forest_target) - 1;
310
311        // Loop until the leaf is reached
312        while forest_target > 1 {
313            // Update the depth of the tree to correspond to a subtree
314            forest_target >>= 1;
315
316            // compute the indices of the right and left subtrees based on the post-order
317            let right_offset = index - 1;
318            let left_offset = right_offset - nodes_in_forest(forest_target);
319
320            let left_or_right = relative_pos & forest_target;
321            let sibling = if left_or_right != 0 {
322                // going down the right subtree, the right child becomes the new root
323                index = right_offset;
324                // and the left child is the authentication
325                self.nodes[index_offset + left_offset]
326            } else {
327                index = left_offset;
328                self.nodes[index_offset + right_offset]
329            };
330
331            path.push(sibling);
332        }
333
334        debug_assert!(path.len() == tree_depth - 1);
335
336        // the rest of the codebase has the elements going from leaf to root, adjust it here for
337        // easy of use/consistency sake
338        path.reverse();
339
340        let value = self.nodes[index_offset + index];
341        (value, path)
342    }
343}
344
345// CONVERSIONS
346// ================================================================================================
347
348impl<T> From<T> for Mmr
349where
350    T: IntoIterator<Item = RpoDigest>,
351{
352    fn from(values: T) -> Self {
353        let mut mmr = Mmr::new();
354        for v in values {
355            mmr.add(v)
356        }
357        mmr
358    }
359}
360
361// ITERATOR
362// ===============================================================================================
363
364/// Yields inner nodes of the [Mmr].
365pub struct MmrNodes<'a> {
366    /// [Mmr] being yielded, when its `forest` value is matched, the iterations is finished.
367    mmr: &'a Mmr,
368    /// Keeps track of the left nodes yielded so far waiting for a right pair, this matches the
369    /// semantics of the [Mmr]'s forest attribute, since that too works as a buffer of left nodes
370    /// waiting for a pair to be hashed together.
371    forest: usize,
372    /// Keeps track of the last right node yielded, after this value is set, the next iteration
373    /// will be its parent with its corresponding left node that has been yield already.
374    last_right: usize,
375    /// The current index in the `nodes` vector.
376    index: usize,
377}
378
379impl Iterator for MmrNodes<'_> {
380    type Item = InnerNodeInfo;
381
382    fn next(&mut self) -> Option<Self::Item> {
383        debug_assert!(self.last_right.count_ones() <= 1, "last_right tracks zero or one element");
384
385        // only parent nodes are emitted, remove the single node tree from the forest
386        let target = self.mmr.forest & (usize::MAX << 1);
387
388        if self.forest < target {
389            if self.last_right == 0 {
390                // yield the left leaf
391                debug_assert!(self.last_right == 0, "left must be before right");
392                self.forest |= 1;
393                self.index += 1;
394
395                // yield the right leaf
396                debug_assert!((self.forest & 1) == 1, "right must be after left");
397                self.last_right |= 1;
398                self.index += 1;
399            };
400
401            debug_assert!(
402                self.forest & self.last_right != 0,
403                "parent requires both a left and right",
404            );
405
406            // compute the number of nodes in the right tree, this is the offset to the
407            // previous left parent
408            let right_nodes = nodes_in_forest(self.last_right);
409            // the next parent position is one above the position of the pair
410            let parent = self.last_right << 1;
411
412            // the left node has been paired and the current parent yielded, removed it from the
413            // forest
414            self.forest ^= self.last_right;
415            if self.forest & parent == 0 {
416                // this iteration yielded the left parent node
417                debug_assert!(self.forest & 1 == 0, "next iteration yields a left leaf");
418                self.last_right = 0;
419                self.forest ^= parent;
420            } else {
421                // the left node of the parent level has been yielded already, this iteration
422                // was the right parent. Next iteration yields their parent.
423                self.last_right = parent;
424            }
425
426            // yields a parent
427            let value = self.mmr.nodes[self.index];
428            let right = self.mmr.nodes[self.index - 1];
429            let left = self.mmr.nodes[self.index - 1 - right_nodes];
430            self.index += 1;
431            let node = InnerNodeInfo { value, left, right };
432
433            Some(node)
434        } else {
435            None
436        }
437    }
438}
439
440// UTILITIES
441// ===============================================================================================
442
443/// Return a bitmask for the bits including and above the given position.
444pub(crate) const fn high_bitmask(bit: u32) -> usize {
445    if bit > usize::BITS - 1 { 0 } else { usize::MAX << bit }
446}