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}