//! A fully materialized Merkle mountain range (MMR). //! //! A MMR is a forest structure, i.e. it is an ordered set of disjoint rooted trees. The trees are //! ordered by size, from the most to least number of leaves. Every tree is a perfect binary tree, //! meaning a tree has all its leaves at the same depth, and every inner node has a branch-factor //! of 2 with both children set. //! //! Additionally the structure only supports adding leaves to the right-most tree, the one with the //! least number of leaves. The structure preserves the invariant that each tree has different //! depths, i.e. as part of adding adding a new element to the forest the trees with same depth are //! merged, creating a new tree with depth d+1, this process is continued until the property is //! reestablished. use super::{ super::{InnerNodeInfo, MerklePath}, bit::TrueBitPositionIterator, leaf_to_corresponding_tree, nodes_in_forest, MmrDelta, MmrError, MmrPeaks, MmrProof, Rpo256, RpoDigest, }; use crate::utils::collections::*; // MMR // =============================================================================================== /// A fully materialized Merkle Mountain Range, with every tree in the forest and all their /// elements. /// /// Since this is a full representation of the MMR, elements are never removed and the MMR will /// grow roughly `O(2n)` in number of leaf elements. #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Mmr { /// Refer to the `forest` method documentation for details of the semantics of this value. pub(super) forest: usize, /// Contains every element of the forest. /// /// The trees are in postorder sequential representation. This representation allows for all /// the elements of every tree in the forest to be stored in the same sequential buffer. It /// also means new elements can be added to the forest, and merging of trees is very cheap with /// no need to copy elements. pub(super) nodes: Vec, } impl Default for Mmr { fn default() -> Self { Self::new() } } impl Mmr { // CONSTRUCTORS // ============================================================================================ /// Constructor for an empty `Mmr`. pub fn new() -> Mmr { Mmr { forest: 0, nodes: Vec::new() } } // ACCESSORS // ============================================================================================ /// Returns the MMR forest representation. /// /// The forest value has the following interpretations: /// - its value is the number of elements in the forest /// - bit count corresponds to the number of trees in the forest /// - each true bit position determines the depth of a tree in the forest pub const fn forest(&self) -> usize { self.forest } // FUNCTIONALITY // ============================================================================================ /// Given a leaf position, returns the Merkle path to its corresponding peak. If the position /// is greater-or-equal than the tree size an error is returned. /// /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element /// has position 0, the second position 1, and so on. pub fn open(&self, pos: usize, target_forest: usize) -> Result { // find the target tree responsible for the MMR position let tree_bit = leaf_to_corresponding_tree(pos, target_forest).ok_or(MmrError::InvalidPosition(pos))?; // isolate the trees before the target let forest_before = target_forest & high_bitmask(tree_bit + 1); let index_offset = nodes_in_forest(forest_before); // update the value position from global to the target tree let relative_pos = pos - forest_before; // collect the path and the final index of the target value let (_, path) = self.collect_merkle_path_and_value(tree_bit, relative_pos, index_offset); Ok(MmrProof { forest: target_forest, position: pos, merkle_path: MerklePath::new(path), }) } /// Returns the leaf value at position `pos`. /// /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element /// has position 0, the second position 1, and so on. pub fn get(&self, pos: usize) -> Result { // find the target tree responsible for the MMR position let tree_bit = leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::InvalidPosition(pos))?; // isolate the trees before the target let forest_before = self.forest & high_bitmask(tree_bit + 1); let index_offset = nodes_in_forest(forest_before); // update the value position from global to the target tree let relative_pos = pos - forest_before; // collect the path and the final index of the target value let (value, _) = self.collect_merkle_path_and_value(tree_bit, relative_pos, index_offset); Ok(value) } /// Adds a new element to the MMR. pub fn add(&mut self, el: RpoDigest) { // Note: every node is also a tree of size 1, adding an element to the forest creates a new // rooted-tree of size 1. This may temporarily break the invariant that every tree in the // forest has different sizes, the loop below will eagerly merge trees of same size and // restore the invariant. self.nodes.push(el); let mut left_offset = self.nodes.len().saturating_sub(2); let mut right = el; let mut left_tree = 1; while self.forest & left_tree != 0 { right = Rpo256::merge(&[self.nodes[left_offset], right]); self.nodes.push(right); left_offset = left_offset.saturating_sub(nodes_in_forest(left_tree)); left_tree <<= 1; } self.forest += 1; } /// Returns an peaks of the MMR for the version specified by `forest`. pub fn peaks(&self, forest: usize) -> Result { if forest > self.forest { return Err(MmrError::InvalidPeaks); } let peaks: Vec = TrueBitPositionIterator::new(forest) .rev() .map(|bit| nodes_in_forest(1 << bit)) .scan(0, |offset, el| { *offset += el; Some(*offset) }) .map(|offset| self.nodes[offset - 1]) .collect(); // Safety: the invariant is maintained by the [Mmr] let peaks = MmrPeaks::new(forest, peaks).unwrap(); Ok(peaks) } /// Compute the required update to `original_forest`. /// /// The result is a packed sequence of the authentication elements required to update the trees /// that have been merged together, followed by the new peaks of the [Mmr]. pub fn get_delta(&self, from_forest: usize, to_forest: usize) -> Result { if to_forest > self.forest || from_forest > to_forest { return Err(MmrError::InvalidPeaks); } if from_forest == to_forest { return Ok(MmrDelta { forest: to_forest, data: Vec::new() }); } let mut result = Vec::new(); // Find the largest tree in this [Mmr] which is new to `from_forest`. let candidate_trees = to_forest ^ from_forest; let mut new_high = 1 << candidate_trees.ilog2(); // Collect authentication nodes used for tree merges // ---------------------------------------------------------------------------------------- // Find the trees from `from_forest` that have been merged into `new_high`. let mut merges = from_forest & (new_high - 1); // Find the peaks that are common to `from_forest` and this [Mmr] let common_trees = from_forest ^ merges; if merges != 0 { // Skip the smallest trees unknown to `from_forest`. let mut target = 1 << merges.trailing_zeros(); // Collect siblings required to computed the merged tree's peak while target < new_high { // Computes the offset to the smallest know peak // - common_trees: peaks unchanged in the current update, target comes after these. // - merges: peaks that have not been merged so far, target comes after these. // - target: tree from which to load the sibling. On the first iteration this is a // value known by the partial mmr, on subsequent iterations this value is to be // computed from the known peaks and provided authentication nodes. let known = nodes_in_forest(common_trees | merges | target); let sibling = nodes_in_forest(target); result.push(self.nodes[known + sibling - 1]); // Update the target and account for tree merges target <<= 1; while merges & target != 0 { target <<= 1; } // Remove the merges done so far merges ^= merges & (target - 1); } } else { // The new high tree may not be the result of any merges, if it is smaller than all the // trees of `from_forest`. new_high = 0; } // Collect the new [Mmr] peaks // ---------------------------------------------------------------------------------------- let mut new_peaks = to_forest ^ common_trees ^ new_high; let old_peaks = to_forest ^ new_peaks; let mut offset = nodes_in_forest(old_peaks); while new_peaks != 0 { let target = 1 << new_peaks.ilog2(); offset += nodes_in_forest(target); result.push(self.nodes[offset - 1]); new_peaks ^= target; } Ok(MmrDelta { forest: to_forest, data: result }) } /// An iterator over inner nodes in the MMR. The order of iteration is unspecified. pub fn inner_nodes(&self) -> MmrNodes { MmrNodes { mmr: self, forest: 0, last_right: 0, index: 0, } } // UTILITIES // ============================================================================================ /// Internal function used to collect the Merkle path of a value. /// /// The arguments are relative to the target tree. To compute the opening of the second leaf /// for a tree with depth 2 in the forest `0b110`: /// /// - `tree_bit`: Depth of the target tree, e.g. 2 for the smallest tree. /// - `relative_pos`: 0-indexed leaf position in the target tree, e.g. 1 for the second leaf. /// - `index_offset`: Node count prior to the target tree, e.g. 7 for the tree of depth 3. fn collect_merkle_path_and_value( &self, tree_bit: u32, relative_pos: usize, index_offset: usize, ) -> (RpoDigest, Vec) { // see documentation of `leaf_to_corresponding_tree` for details let tree_depth = (tree_bit + 1) as usize; let mut path = Vec::with_capacity(tree_depth); // The tree walk below goes from the root to the leaf, compute the root index to start let mut forest_target = 1usize << tree_bit; let mut index = nodes_in_forest(forest_target) - 1; // Loop until the leaf is reached while forest_target > 1 { // Update the depth of the tree to correspond to a subtree forest_target >>= 1; // compute the indices of the right and left subtrees based on the post-order let right_offset = index - 1; let left_offset = right_offset - nodes_in_forest(forest_target); let left_or_right = relative_pos & forest_target; let sibling = if left_or_right != 0 { // going down the right subtree, the right child becomes the new root index = right_offset; // and the left child is the authentication self.nodes[index_offset + left_offset] } else { index = left_offset; self.nodes[index_offset + right_offset] }; path.push(sibling); } debug_assert!(path.len() == tree_depth - 1); // the rest of the codebase has the elements going from leaf to root, adjust it here for // easy of use/consistency sake path.reverse(); let value = self.nodes[index_offset + index]; (value, path) } } // CONVERSIONS // ================================================================================================ impl From for Mmr where T: IntoIterator, { fn from(values: T) -> Self { let mut mmr = Mmr::new(); for v in values { mmr.add(v) } mmr } } // ITERATOR // =============================================================================================== /// Yields inner nodes of the [Mmr]. pub struct MmrNodes<'a> { /// [Mmr] being yielded, when its `forest` value is matched, the iterations is finished. mmr: &'a Mmr, /// Keeps track of the left nodes yielded so far waiting for a right pair, this matches the /// semantics of the [Mmr]'s forest attribute, since that too works as a buffer of left nodes /// waiting for a pair to be hashed together. forest: usize, /// Keeps track of the last right node yielded, after this value is set, the next iteration /// will be its parent with its corresponding left node that has been yield already. last_right: usize, /// The current index in the `nodes` vector. index: usize, } impl<'a> Iterator for MmrNodes<'a> { type Item = InnerNodeInfo; fn next(&mut self) -> Option { debug_assert!(self.last_right.count_ones() <= 1, "last_right tracks zero or one element"); // only parent nodes are emitted, remove the single node tree from the forest let target = self.mmr.forest & (usize::MAX << 1); if self.forest < target { if self.last_right == 0 { // yield the left leaf debug_assert!(self.last_right == 0, "left must be before right"); self.forest |= 1; self.index += 1; // yield the right leaf debug_assert!((self.forest & 1) == 1, "right must be after left"); self.last_right |= 1; self.index += 1; }; debug_assert!( self.forest & self.last_right != 0, "parent requires both a left and right", ); // compute the number of nodes in the right tree, this is the offset to the // previous left parent let right_nodes = nodes_in_forest(self.last_right); // the next parent position is one above the position of the pair let parent = self.last_right << 1; // the left node has been paired and the current parent yielded, removed it from the forest self.forest ^= self.last_right; if self.forest & parent == 0 { // this iteration yielded the left parent node debug_assert!(self.forest & 1 == 0, "next iteration yields a left leaf"); self.last_right = 0; self.forest ^= parent; } else { // the left node of the parent level has been yielded already, this iteration // was the right parent. Next iteration yields their parent. self.last_right = parent; } // yields a parent let value = self.mmr.nodes[self.index]; let right = self.mmr.nodes[self.index - 1]; let left = self.mmr.nodes[self.index - 1 - right_nodes]; self.index += 1; let node = InnerNodeInfo { value, left, right }; Some(node) } else { None } } } // UTILITIES // =============================================================================================== /// Return a bitmask for the bits including and above the given position. pub(crate) const fn high_bitmask(bit: u32) -> usize { if bit > usize::BITS - 1 { 0 } else { usize::MAX << bit } }