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