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//! restabilished.
13use super::bit::TrueBitPositionIterator;
14use super::{
15 super::{InnerNodeInfo, MerklePath, Vec},
16 MmrPeaks, MmrProof, Rpo256, Word,
17};
18use core::fmt::{Display, Formatter};
19
20#[cfg(feature = "std")]
21use std::error::Error;
22
23// MMR
24// ===============================================================================================
25
26/// A fully materialized Merkle Mountain Range, with every tree in the forest and all their
27/// elements.
28///
29/// Since this is a full representation of the MMR, elements are never removed and the MMR will
30/// grow roughly `O(2n)` in number of leaf elements.
31pub struct Mmr {
32 /// Refer to the `forest` method documentation for details of the semantics of this value.
33 pub(super) forest: usize,
34
35 /// Contains every element of the forest.
36 ///
37 /// The trees are in postorder sequential representation. This representation allows for all
38 /// the elements of every tree in the forest to be stored in the same sequential buffer. It
39 /// also means new elements can be added to the forest, and merging of trees is very cheap with
40 /// no need to copy elements.
41 pub(super) nodes: Vec<Word>,
42}
43
44#[derive(Debug, PartialEq, Eq, Copy, Clone)]
45pub enum MmrError {
46 InvalidPosition(usize),
47}
48
49impl Display for MmrError {
50 fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
51 match self {
52 MmrError::InvalidPosition(pos) => write!(fmt, "Mmr does not contain position {pos}"),
53 }
54 }
55}
56
57#[cfg(feature = "std")]
58impl Error for MmrError {}
59
60impl Default for Mmr {
61 fn default() -> Self {
62 Self::new()
63 }
64}
65
66impl Mmr {
67 // CONSTRUCTORS
68 // ============================================================================================
69
70 /// Constructor for an empty `Mmr`.
71 pub fn new() -> Mmr {
72 Mmr {
73 forest: 0,
74 nodes: Vec::new(),
75 }
76 }
77
78 // ACCESSORS
79 // ============================================================================================
80
81 /// Returns the MMR forest representation.
82 ///
83 /// The forest value has the following interpretations:
84 /// - its value is the number of elements in the forest
85 /// - bit count corresponds to the number of trees in the forest
86 /// - each true bit position determines the depth of a tree in the forest
87 pub const fn forest(&self) -> usize {
88 self.forest
89 }
90
91 // FUNCTIONALITY
92 // ============================================================================================
93
94 /// Given a leaf position, returns the Merkle path to its corresponding peak. If the position
95 /// is greater-or-equal than the tree size an error is returned.
96 ///
97 /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
98 /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
99 /// has position 0, the second position 1, and so on.
100 pub fn open(&self, pos: usize) -> Result<MmrProof, MmrError> {
101 // find the target tree responsible for the MMR position
102 let tree_bit =
103 leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::InvalidPosition(pos))?;
104 let forest_target = 1usize << tree_bit;
105
106 // isolate the trees before the target
107 let forest_before = self.forest & high_bitmask(tree_bit + 1);
108 let index_offset = nodes_in_forest(forest_before);
109
110 // find the root
111 let index = nodes_in_forest(forest_target) - 1;
112
113 // update the value position from global to the target tree
114 let relative_pos = pos - forest_before;
115
116 // collect the path and the final index of the target value
117 let (_, path) =
118 self.collect_merkle_path_and_value(tree_bit, relative_pos, index_offset, index);
119
120 Ok(MmrProof {
121 forest: self.forest,
122 position: pos,
123 merkle_path: MerklePath::new(path),
124 })
125 }
126
127 /// Returns the leaf value at position `pos`.
128 ///
129 /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
130 /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
131 /// has position 0, the second position 1, and so on.
132 pub fn get(&self, pos: usize) -> Result<Word, MmrError> {
133 // find the target tree responsible for the MMR position
134 let tree_bit =
135 leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::InvalidPosition(pos))?;
136 let forest_target = 1usize << tree_bit;
137
138 // isolate the trees before the target
139 let forest_before = self.forest & high_bitmask(tree_bit + 1);
140 let index_offset = nodes_in_forest(forest_before);
141
142 // find the root
143 let index = nodes_in_forest(forest_target) - 1;
144
145 // update the value position from global to the target tree
146 let relative_pos = pos - forest_before;
147
148 // collect the path and the final index of the target value
149 let (value, _) =
150 self.collect_merkle_path_and_value(tree_bit, relative_pos, index_offset, index);
151
152 Ok(value)
153 }
154
155 /// Adds a new element to the MMR.
156 pub fn add(&mut self, el: Word) {
157 // Note: every node is also a tree of size 1, adding an element to the forest creates a new
158 // rooted-tree of size 1. This may temporarily break the invariant that every tree in the
159 // forest has different sizes, the loop below will eagerly merge trees of same size and
160 // restore the invariant.
161 self.nodes.push(el);
162
163 let mut left_offset = self.nodes.len().saturating_sub(2);
164 let mut right = el;
165 let mut left_tree = 1;
166 while self.forest & left_tree != 0 {
167 right = *Rpo256::merge(&[self.nodes[left_offset].into(), right.into()]);
168 self.nodes.push(right);
169
170 left_offset = left_offset.saturating_sub(nodes_in_forest(left_tree));
171 left_tree <<= 1;
172 }
173
174 self.forest += 1;
175 }
176
177 /// Returns an accumulator representing the current state of the MMMR.
178 pub fn accumulator(&self) -> MmrPeaks {
179 let peaks: Vec<Word> = TrueBitPositionIterator::new(self.forest)
180 .rev()
181 .map(|bit| nodes_in_forest(1 << bit))
182 .scan(0, |offset, el| {
183 *offset += el;
184 Some(*offset)
185 })
186 .map(|offset| self.nodes[offset - 1])
187 .collect();
188
189 MmrPeaks {
190 num_leaves: self.forest,
191 peaks,
192 }
193 }
194
195 /// An iterator over inner nodes in the [Mmm]. The order of iteration is unspecified.
196 pub fn inner_nodes(&self) -> MmrNodes {
197 MmrNodes {
198 mmr: self,
199 forest: 0,
200 last_right: 0,
201 index: 0,
202 }
203 }
204
205 // UTILITIES
206 // ============================================================================================
207
208 /// Internal function used to collect the Merkle path of a value.
209 fn collect_merkle_path_and_value(
210 &self,
211 tree_bit: u32,
212 relative_pos: usize,
213 index_offset: usize,
214 mut index: usize,
215 ) -> (Word, Vec<Word>) {
216 // collect the Merkle path
217 let mut tree_depth = tree_bit as usize;
218 let mut path = Vec::with_capacity(tree_depth + 1);
219 while tree_depth > 0 {
220 let bit = relative_pos & tree_depth;
221 let right_offset = index - 1;
222 let left_offset = right_offset - nodes_in_forest(tree_depth);
223
224 // Elements to the right have a higher position because they were
225 // added later. Therefore when the bit is true the node's path is
226 // to the right, and its sibling to the left.
227 let sibling = if bit != 0 {
228 index = right_offset;
229 self.nodes[index_offset + left_offset]
230 } else {
231 index = left_offset;
232 self.nodes[index_offset + right_offset]
233 };
234
235 tree_depth >>= 1;
236 path.push(sibling);
237 }
238
239 // the rest of the codebase has the elements going from leaf to root, adjust it here for
240 // easy of use/consistency sake
241 path.reverse();
242
243 let value = self.nodes[index_offset + index];
244 (value, path)
245 }
246}
247
248impl<T> From<T> for Mmr
249where
250 T: IntoIterator<Item = Word>,
251{
252 fn from(values: T) -> Self {
253 let mut mmr = Mmr::new();
254 for v in values {
255 mmr.add(v)
256 }
257 mmr
258 }
259}
260
261// ITERATOR
262// ===============================================================================================
263
264/// Yields inner nodes of the [Mmr].
265pub struct MmrNodes<'a> {
266 /// [Mmr] being yielded, when its `forest` value is matched, the iterations is finished.
267 mmr: &'a Mmr,
268 /// Keeps track of the left nodes yielded so far waiting for a right pair, this matches the
269 /// semantics of the [Mmr]'s forest attribute, since that too works as a buffer of left nodes
270 /// waiting for a pair to be hashed together.
271 forest: usize,
272 /// Keeps track of the last right node yielded, after this value is set, the next iteration
273 /// will be its parent with its corresponding left node that has been yield already.
274 last_right: usize,
275 /// The current index in the `nodes` vector.
276 index: usize,
277}
278
279impl<'a> Iterator for MmrNodes<'a> {
280 type Item = InnerNodeInfo;
281
282 fn next(&mut self) -> Option<Self::Item> {
283 debug_assert!(
284 self.last_right.count_ones() <= 1,
285 "last_right tracks zero or one element"
286 );
287
288 // only parent nodes are emitted, remove the single node tree from the forest
289 let target = self.mmr.forest & (usize::MAX << 1);
290
291 if self.forest < target {
292 if self.last_right == 0 {
293 // yield the left leaf
294 debug_assert!(self.last_right == 0, "left must be before right");
295 self.forest |= 1;
296 self.index += 1;
297
298 // yield the right leaf
299 debug_assert!((self.forest & 1) == 1, "right must be after left");
300 self.last_right |= 1;
301 self.index += 1;
302 };
303
304 debug_assert!(
305 self.forest & self.last_right != 0,
306 "parent requires both a left and right",
307 );
308
309 // compute the number of nodes in the right tree, this is the offset to the
310 // previous left parent
311 let right_nodes = nodes_in_forest(self.last_right);
312 // the next parent position is one above the position of the pair
313 let parent = self.last_right << 1;
314
315 // the left node has been paired and the current parent yielded, removed it from the forest
316 self.forest ^= self.last_right;
317 if self.forest & parent == 0 {
318 // this iteration yielded the left parent node
319 debug_assert!(self.forest & 1 == 0, "next iteration yields a left leaf");
320 self.last_right = 0;
321 self.forest ^= parent;
322 } else {
323 // the left node of the parent level has been yielded already, this iteration
324 // was the right parent. Next iteration yields their parent.
325 self.last_right = parent;
326 }
327
328 // yields a parent
329 let value = self.mmr.nodes[self.index];
330 let right = self.mmr.nodes[self.index - 1];
331 let left = self.mmr.nodes[self.index - 1 - right_nodes];
332 self.index += 1;
333 let node = InnerNodeInfo { value, left, right };
334
335 Some(node)
336 } else {
337 None
338 }
339 }
340}
341
342// UTILITIES
343// ===============================================================================================
344
345/// Given a 0-indexed leaf position and the current forest, return the tree number responsible for
346/// the position.
347///
348/// Note:
349/// The result is a tree position `p`, it has the following interpretations. $p+1$ is the depth of
350/// the tree, which corresponds to the size of a Merkle proof for that tree. $2^p$ is equal to the
351/// number of leaves in this particular tree. and $2^(p+1)-1$ corresponds to size of the tree.
352pub(crate) const fn leaf_to_corresponding_tree(pos: usize, forest: usize) -> Option<u32> {
353 if pos >= forest {
354 None
355 } else {
356 // - each bit in the forest is a unique tree and the bit position its power-of-two size
357 // - each tree owns a consecutive range of positions equal to its size from left-to-right
358 // - this means the first tree owns from `0` up to the `2^k_0` first positions, where `k_0`
359 // is the highest true bit position, the second tree from `2^k_0 + 1` up to `2^k_1` where
360 // `k_1` is the second higest bit, so on.
361 // - this means the highest bits work as a category marker, and the position is owned by
362 // the first tree which doesn't share a high bit with the position
363 let before = forest & pos;
364 let after = forest ^ before;
365 let tree = after.ilog2();
366
367 Some(tree)
368 }
369}
370
371/// Return a bitmask for the bits including and above the given position.
372pub(crate) const fn high_bitmask(bit: u32) -> usize {
373 if bit > usize::BITS - 1 {
374 0
375 } else {
376 usize::MAX << bit
377 }
378}
379
380/// Return the total number of nodes of a given forest
381///
382/// Panics:
383///
384/// This will panic if the forest has size greater than `usize::MAX / 2`
385pub(crate) const fn nodes_in_forest(forest: usize) -> usize {
386 // - the size of a perfect binary tree is $2^{k+1}-1$ or $2*2^k-1$
387 // - the forest represents the sum of $2^k$ so a single multiplication is necessary
388 // - the number of `-1` is the same as the number of trees, which is the same as the number
389 // bits set
390 let tree_count = forest.count_ones() as usize;
391 forest * 2 - tree_count
392}