miden_crypto/merkle/mmr/forest.rs
1use core::{
2 fmt::{Binary, Display},
3 ops::{BitAnd, BitOr, BitXor, BitXorAssign},
4};
5
6use super::{InOrderIndex, MmrError};
7use crate::{
8 Felt,
9 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
10};
11
12/// A compact representation of trees in a forest. Used in the Merkle forest (MMR).
13///
14/// Each active bit of the stored number represents a disjoint tree with number of leaves
15/// equal to the bit position.
16///
17/// The forest value has the following interpretations:
18/// - its value is the number of leaves in the forest
19/// - the version number (MMR is append only so the number of leaves always increases)
20/// - bit count corresponds to the number of trees (trees) in the forest
21/// - each true bit position determines the depth of a tree in the forest
22///
23/// Examples:
24/// - `Forest(0)` is a forest with no trees.
25/// - `Forest(0b01)` is a forest with a single leaf/node (the smallest tree possible).
26/// - `Forest(0b10)` is a forest with a single binary tree with 2 leaves (3 nodes).
27/// - `Forest(0b11)` is a forest with two trees: one with 1 leaf (1 node), and one with 2 leaves (3
28/// nodes).
29/// - `Forest(0b1010)` is a forest with two trees: one with 8 leaves (15 nodes), one with 2 leaves
30/// (3 nodes).
31/// - `Forest(0b1000)` is a forest with one tree, which has 8 leaves (15 nodes).
32///
33/// Forest sizes are capped at [`Forest::MAX_LEAVES`]. Use [`Forest::new`] or
34/// [`Forest::append_leaf`] to enforce the limit.
35#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize))]
37pub struct Forest(usize);
38
39impl Forest {
40 /// Maximum number of leaves supported by the forest.
41 ///
42 /// Rationale:
43 /// - We require `MAX_LEAVES <= usize::MAX / 2 + 1` so `num_nodes()` stays indexable via
44 /// `usize`.
45 /// - We choose `usize::MAX / 2` (hard cutoff) rather than `usize::MAX / 2 + 1` so the cap is
46 /// always of the form `2^k - 1` on all targets.
47 /// - With that shape, bitwise OR/XOR of valid forest values remains within bounds, so OR/XOR
48 /// does not need additional overflow protection.
49 pub const MAX_LEAVES: usize = if (u32::MAX as usize) < (usize::MAX / 2) {
50 u32::MAX as usize
51 } else {
52 usize::MAX / 2
53 };
54
55 /// Creates an empty forest (no trees).
56 pub const fn empty() -> Self {
57 Self(0)
58 }
59
60 /// Creates a forest with `num_leaves` leaves, returning an error if the value is too large.
61 pub fn new(num_leaves: usize) -> Result<Self, DeserializationError> {
62 if !Self::is_valid_size(num_leaves) {
63 return Err(DeserializationError::InvalidValue(format!(
64 "forest size {} exceeds maximum {}",
65 num_leaves,
66 Self::MAX_LEAVES
67 )));
68 }
69 Ok(Self(num_leaves))
70 }
71
72 /// Creates a forest with a given height.
73 ///
74 /// This is equivalent to creating a forest with `1 << height` leaves.
75 ///
76 /// # Panics
77 ///
78 /// This will panic if `height` is greater than `usize::BITS - 1`.
79 pub fn with_height(height: usize) -> Self {
80 assert!(height < usize::BITS as usize);
81 Self::new(1 << height).expect("forest height exceeds maximum")
82 }
83
84 /// Returns true if `num_leaves` is within the supported bounds.
85 pub const fn is_valid_size(num_leaves: usize) -> bool {
86 num_leaves <= Self::MAX_LEAVES
87 }
88
89 /// Returns true if there are no trees in the forest.
90 pub fn is_empty(self) -> bool {
91 self.0 == 0
92 }
93
94 /// Adds exactly one more leaf to the capacity of this forest.
95 ///
96 /// Some smaller trees might be merged together.
97 pub fn append_leaf(&mut self) -> Result<(), MmrError> {
98 if self.0 >= Self::MAX_LEAVES {
99 return Err(MmrError::ForestSizeExceeded {
100 requested: self.0.saturating_add(1),
101 max: Self::MAX_LEAVES,
102 });
103 }
104 self.0 += 1;
105 Ok(())
106 }
107
108 /// Returns a count of leaves in the entire underlying forest (MMR).
109 pub fn num_leaves(self) -> usize {
110 self.0
111 }
112
113 /// Return the total number of nodes of a given forest.
114 ///
115 /// This relies on the `Forest` invariant that `num_leaves() <= Forest::MAX_LEAVES`.
116 /// The internal assertion is a defensive check and should be unreachable for values created
117 /// through validated constructors/deserializers.
118 pub const fn num_nodes(self) -> usize {
119 assert!(self.0 <= Self::MAX_LEAVES);
120 if self.0 <= usize::MAX / 2 {
121 self.0 * 2 - self.num_trees()
122 } else {
123 // If `self.0 > usize::MAX / 2` then we need 128-bit math to double it.
124 let (inner, num_trees) = (self.0 as u128, self.num_trees() as u128);
125 (inner * 2 - num_trees) as usize
126 }
127 }
128
129 /// Return the total number of trees of a given forest (the number of active bits).
130 pub const fn num_trees(self) -> usize {
131 self.0.count_ones() as usize
132 }
133
134 /// Returns the height (bit position) of the largest tree in the forest.
135 ///
136 /// # Panics
137 ///
138 /// This will panic if the forest is empty.
139 pub fn largest_tree_height_unchecked(self) -> usize {
140 // ilog2 is computed with leading zeros, which itself is computed with the intrinsic ctlz.
141 // [Rust 1.67.0] x86 uses the `bsr` instruction. AArch64 uses the `clz` instruction.
142 self.0.ilog2() as usize
143 }
144
145 /// Returns the height (bit position) of the largest tree in the forest.
146 ///
147 /// If the forest cannot be empty, use [`largest_tree_height_unchecked`] for performance.
148 ///
149 /// [`largest_tree_height_unchecked`]: Self::largest_tree_height_unchecked
150 pub fn largest_tree_height(self) -> Option<usize> {
151 if self.is_empty() {
152 return None;
153 }
154
155 Some(self.largest_tree_height_unchecked())
156 }
157
158 /// Returns a forest with only the largest tree present.
159 ///
160 /// # Panics
161 ///
162 /// This will panic if the forest is empty.
163 pub fn largest_tree_unchecked(self) -> Self {
164 Self::with_height(self.largest_tree_height_unchecked())
165 }
166
167 /// Returns a forest with only the largest tree present.
168 ///
169 /// If forest cannot be empty, use `largest_tree` for better performance.
170 pub fn largest_tree(self) -> Self {
171 if self.is_empty() {
172 return Self::empty();
173 }
174
175 self.largest_tree_unchecked()
176 }
177
178 /// Returns the height (bit position) of the smallest tree in the forest.
179 ///
180 /// # Panics
181 ///
182 /// This will panic if the forest is empty.
183 pub fn smallest_tree_height_unchecked(self) -> usize {
184 // Trailing_zeros is computed with the intrinsic cttz. [Rust 1.67.0] x86 uses the `bsf`
185 // instruction. AArch64 uses the `rbit clz` instructions.
186 self.0.trailing_zeros() as usize
187 }
188
189 /// Returns the height (bit position) of the smallest tree in the forest.
190 ///
191 /// If the forest cannot be empty, use [`smallest_tree_height_unchecked`] for better
192 /// performance.
193 ///
194 /// [`smallest_tree_height_unchecked`]: Self::smallest_tree_height_unchecked
195 pub fn smallest_tree_height(self) -> Option<usize> {
196 if self.is_empty() {
197 return None;
198 }
199
200 Some(self.smallest_tree_height_unchecked())
201 }
202
203 /// Returns a forest with only the smallest tree present.
204 ///
205 /// # Panics
206 ///
207 /// This will panic if the forest is empty.
208 pub fn smallest_tree_unchecked(self) -> Self {
209 Self::with_height(self.smallest_tree_height_unchecked())
210 }
211
212 /// Returns a forest with only the smallest tree present.
213 ///
214 /// If forest cannot be empty, use `smallest_tree` for performance.
215 pub fn smallest_tree(self) -> Self {
216 if self.is_empty() {
217 return Self::empty();
218 }
219 self.smallest_tree_unchecked()
220 }
221
222 /// Keeps only trees larger than the reference tree.
223 ///
224 /// For example, if we start with the bit pattern `0b0101_0110`, and keep only the trees larger
225 /// than tree index 1, that targets this bit:
226 /// ```text
227 /// Forest(0b0101_0110).trees_larger_than(1)
228 /// ^
229 /// Becomes: 0b0101_0100
230 /// ^
231 /// ```
232 /// And keeps only trees *after* that bit, meaning that the tree at `tree_idx` is also removed,
233 /// resulting in `0b0101_0100`.
234 ///
235 /// ```
236 /// # use miden_crypto::merkle::mmr::Forest;
237 /// let range = Forest::new(0b0101_0110).unwrap();
238 /// assert_eq!(range.trees_larger_than(1), Forest::new(0b0101_0100).unwrap());
239 /// ```
240 pub fn trees_larger_than(self, tree_idx: u32) -> Self {
241 let mask = high_bitmask(tree_idx + 1);
242 Self::new(self.0 & mask).expect("forest size exceeds maximum")
243 }
244
245 /// Creates a new forest with all possible trees smaller than the smallest tree in this
246 /// forest.
247 ///
248 /// This forest must have exactly one tree.
249 ///
250 /// # Panics
251 /// With debug assertions enabled, this function panics if this forest does not have
252 /// exactly one tree.
253 ///
254 /// For a non-panicking version of this function, see [`Forest::all_smaller_trees()`].
255 pub fn all_smaller_trees_unchecked(self) -> Self {
256 debug_assert_eq!(self.num_trees(), 1);
257 Self::new(self.0 - 1).expect("forest size exceeds maximum")
258 }
259
260 /// Creates a new forest with all possible trees smaller than the smallest tree in this
261 /// forest, or returns `None` if this forest has more or less than one tree.
262 ///
263 /// If the forest cannot have more or less than one tree, use
264 /// [`Forest::all_smaller_trees_unchecked()`] for performance.
265 pub fn all_smaller_trees(self) -> Option<Forest> {
266 if self.num_trees() != 1 {
267 return None;
268 }
269 Some(self.all_smaller_trees_unchecked())
270 }
271
272 /// Returns a forest with exactly one tree, one size (depth) larger than the current one.
273 ///
274 /// # Errors
275 /// Returns an error if the resulting forest would exceed [`Forest::MAX_LEAVES`].
276 pub(crate) fn next_larger_tree(self) -> Result<Self, MmrError> {
277 debug_assert_eq!(self.num_trees(), 1);
278 let value = self.0.saturating_mul(2);
279 if value > Self::MAX_LEAVES {
280 return Err(MmrError::ForestSizeExceeded { requested: value, max: Self::MAX_LEAVES });
281 }
282 Ok(Forest(value))
283 }
284
285 /// Returns true if the forest contains a single-node tree.
286 pub fn has_single_leaf_tree(self) -> bool {
287 self.0 & 1 != 0
288 }
289
290 /// Add a single-node tree if not already present in the forest.
291 pub fn with_single_leaf(self) -> Self {
292 // Setting the lowest bit cannot exceed MAX_LEAVES when MAX_LEAVES is 2^k - 1.
293 Self(self.0 | 1)
294 }
295
296 /// Remove the single-node tree if present in the forest.
297 pub fn without_single_leaf(self) -> Self {
298 // Clearing the lowest bit does not add leaves.
299 Self(self.0 & (usize::MAX - 1))
300 }
301
302 /// Returns a new forest that does not have the trees that `other` has.
303 pub fn without_trees(self, other: Forest) -> Self {
304 // Clearing bits does not add leaves.
305 Self(self.0 & !other.0)
306 }
307
308 /// Returns index of the forest tree for a specified leaf index.
309 pub fn tree_index(&self, leaf_idx: usize) -> usize {
310 let root = self
311 .leaf_to_corresponding_tree(leaf_idx)
312 .expect("position must be part of the forest");
313 let smaller_tree_mask =
314 Self::new(2_usize.pow(root) - 1).expect("forest size exceeds maximum");
315 let num_smaller_trees = (*self & smaller_tree_mask).num_trees();
316 self.num_trees() - num_smaller_trees - 1
317 }
318
319 /// Returns the smallest tree's root element as an [InOrderIndex].
320 ///
321 /// This function takes the smallest tree in this forest, "pretends" that it is a subtree of a
322 /// fully balanced binary tree, and returns the the in-order index of that balanced tree's root
323 /// node.
324 pub fn root_in_order_index(&self) -> InOrderIndex {
325 // Count total size of all trees in the forest.
326 let nodes = self.num_nodes();
327
328 // Add the count for the parent nodes that separate each tree. These are allocated but
329 // currently empty, and correspond to the nodes that will be used once the trees are merged.
330 let open_trees = self.num_trees() - 1;
331
332 // Remove the leaf-count of the rightmost subtree. The target tree root index comes before
333 // the subtree, for the in-order tree walk.
334 let right_subtree_count = self.smallest_tree_unchecked().num_leaves() - 1;
335
336 let idx = nodes + open_trees - right_subtree_count;
337
338 InOrderIndex::new(idx.try_into().unwrap())
339 }
340
341 /// Returns the in-order index of the rightmost element (the smallest tree).
342 pub fn rightmost_in_order_index(&self) -> InOrderIndex {
343 // Count total size of all trees in the forest.
344 let nodes = self.num_nodes();
345
346 // Add the count for the parent nodes that separate each tree. These are allocated but
347 // currently empty, and correspond to the nodes that will be used once the trees are merged.
348 let open_trees = self.num_trees() - 1;
349
350 let idx = nodes + open_trees;
351
352 InOrderIndex::new(idx.try_into().unwrap())
353 }
354
355 /// Checks if an in-order index corresponds to a valid node in the forest.
356 ///
357 /// Returns `true` if the index points to an actual node within one of the trees,
358 /// `false` if the index is:
359 /// - Zero (invalid, as `InOrderIndex` is 1-indexed)
360 /// - Beyond the forest bounds
361 /// - A separator position between trees (these positions are reserved for future parent nodes
362 /// when trees are merged, but don't correspond to actual nodes yet)
363 ///
364 /// # Example
365 /// For a forest with 7 leaves (0b111 = trees of 4, 2, and 1 leaves):
366 /// - Valid indices: 1-7 (first tree), 9-11 (second tree), 13 (third tree)
367 /// - Invalid separator indices: 8 (between first and second), 12 (between second and third)
368 pub fn is_valid_in_order_index(&self, idx: &InOrderIndex) -> bool {
369 // Index 0 is never valid (InOrderIndex is 1-indexed)
370 if idx.inner() == 0 {
371 return false;
372 }
373
374 // Empty forest has no valid indices
375 if self.is_empty() {
376 return false;
377 }
378
379 let idx_val = idx.inner();
380 let mut offset = 0usize;
381
382 // Iterate through trees from largest to smallest
383 for tree in TreeSizeIterator::new(*self).rev() {
384 let tree_nodes = tree.num_nodes();
385 let tree_start = offset + 1;
386 let tree_end = offset + tree_nodes;
387
388 if idx_val >= tree_start && idx_val <= tree_end {
389 return true;
390 }
391
392 // Move offset past this tree and the separator position
393 offset = tree_end + 1;
394 }
395
396 false
397 }
398
399 /// Given a leaf index in the current forest, return the tree number responsible for the
400 /// leaf.
401 ///
402 /// The result is a tree position `p`:
403 /// - `p+1` is the depth of the tree.
404 /// - Because the root element is not part of the proof, `p` is the length of the authentication
405 /// path.
406 /// - `2^p` is equal to the number of leaves in this particular tree.
407 /// - And `2^(p+1)-1` corresponds to the size of the tree.
408 ///
409 /// For example, given a forest with 6 leaves whose forest is `0b110`:
410 /// ```text
411 /// __ tree 2 __
412 /// / \
413 /// ____ ____ _ tree 1 _
414 /// / \ / \ / \
415 /// 0 1 2 3 4 5
416 /// ```
417 ///
418 /// Leaf indices `0..=3` are in the tree at index 2 and leaf indices `4..=5` are in the tree at
419 /// index 1.
420 pub fn leaf_to_corresponding_tree(self, leaf_idx: usize) -> Option<u32> {
421 let forest = self.0;
422
423 if leaf_idx >= forest {
424 None
425 } else {
426 // - each bit in the forest is a unique tree and the bit position is its power-of-two
427 // size
428 // - each tree is associated to a consecutive range of positions equal to its size from
429 // left-to-right
430 // - this means the first tree owns from `0` up to the `2^k_0` first positions, where
431 // `k_0` is the highest set bit position, the second tree from `2^k_0 + 1` up to
432 // `2^k_1` where `k_1` is the second highest bit, so on.
433 // - this means the highest bits work as a category marker, and the position is owned by
434 // the first tree which doesn't share a high bit with the position
435 let before = forest & leaf_idx;
436 let after = forest ^ before;
437 let tree_idx = after.ilog2();
438
439 Some(tree_idx)
440 }
441 }
442
443 /// Given a leaf index in the current forest, return the leaf index in the tree to which
444 /// the leaf belongs.
445 pub(super) fn leaf_relative_position(self, leaf_idx: usize) -> Option<usize> {
446 let tree_idx = self.leaf_to_corresponding_tree(leaf_idx)?;
447 let mask = high_bitmask(tree_idx + 1);
448 Some(leaf_idx - (self.0 & mask))
449 }
450}
451
452impl Display for Forest {
453 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
454 write!(f, "{}", self.0)
455 }
456}
457
458impl Binary for Forest {
459 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
460 write!(f, "{:b}", self.0)
461 }
462}
463
464impl BitAnd<Forest> for Forest {
465 type Output = Self;
466
467 fn bitand(self, rhs: Self) -> Self::Output {
468 Self::new(self.0 & rhs.0).expect("forest size exceeds maximum")
469 }
470}
471
472// Compile-time invariant: MAX_LEAVES must be exactly 2^k - 1.
473const _: () =
474 assert!(Forest::MAX_LEAVES != 0 && (Forest::MAX_LEAVES & (Forest::MAX_LEAVES + 1)) == 0);
475
476impl BitOr<Forest> for Forest {
477 type Output = Self;
478
479 fn bitor(self, rhs: Self) -> Self::Output {
480 Self(self.0 | rhs.0)
481 }
482}
483
484impl BitXor<Forest> for Forest {
485 type Output = Self;
486
487 fn bitxor(self, rhs: Self) -> Self::Output {
488 Self(self.0 ^ rhs.0)
489 }
490}
491
492impl BitXorAssign<Forest> for Forest {
493 fn bitxor_assign(&mut self, rhs: Self) {
494 self.0 ^= rhs.0;
495 }
496}
497
498impl TryFrom<Felt> for Forest {
499 type Error = MmrError;
500
501 fn try_from(value: Felt) -> Result<Self, Self::Error> {
502 let value = usize::try_from(value.as_canonical_u64()).map_err(|_| {
503 MmrError::ForestSizeExceeded {
504 requested: usize::MAX,
505 max: Self::MAX_LEAVES,
506 }
507 })?;
508 if value > Self::MAX_LEAVES {
509 return Err(MmrError::ForestSizeExceeded { requested: value, max: Self::MAX_LEAVES });
510 }
511 Ok(Self(value))
512 }
513}
514
515pub(crate) fn largest_tree_from_mask(mask: usize) -> Forest {
516 if mask == 0 {
517 Forest::empty()
518 } else {
519 let bit = mask.ilog2();
520 Forest::new(1usize << bit).expect("forest size exceeds maximum")
521 }
522}
523
524impl From<Forest> for Felt {
525 fn from(value: Forest) -> Self {
526 Felt::new_unchecked(value.0 as u64)
527 }
528}
529
530/// Return a bitmask for the bits including and above the given position.
531pub(crate) fn high_bitmask(bit: u32) -> usize {
532 if bit > usize::BITS - 1 { 0 } else { usize::MAX << bit }
533}
534
535// SERIALIZATION
536// ================================================================================================
537
538impl Serializable for Forest {
539 fn write_into<W: ByteWriter>(&self, target: &mut W) {
540 self.0.write_into(target);
541 }
542}
543
544impl Deserializable for Forest {
545 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
546 let value = source.read_usize()?;
547 Self::new(value)
548 }
549}
550
551#[cfg(feature = "serde")]
552impl<'de> serde::Deserialize<'de> for Forest {
553 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
554 where
555 D: serde::Deserializer<'de>,
556 {
557 let value = usize::deserialize(deserializer)?;
558 Self::new(value).map_err(serde::de::Error::custom)
559 }
560}
561
562// TREE SIZE ITERATOR
563// ================================================================================================
564
565/// Iterate over the trees within this `Forest`, from smallest to largest.
566///
567/// Each item is a "sub-forest", containing only one tree.
568pub struct TreeSizeIterator {
569 inner: Forest,
570}
571
572impl TreeSizeIterator {
573 pub fn new(value: Forest) -> TreeSizeIterator {
574 TreeSizeIterator { inner: value }
575 }
576}
577
578impl Iterator for TreeSizeIterator {
579 type Item = Forest;
580
581 fn next(&mut self) -> Option<<Self as Iterator>::Item> {
582 let tree = self.inner.smallest_tree();
583
584 if tree.is_empty() {
585 None
586 } else {
587 self.inner = self.inner.without_trees(tree);
588 Some(tree)
589 }
590 }
591}
592
593impl DoubleEndedIterator for TreeSizeIterator {
594 fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
595 let tree = self.inner.largest_tree();
596
597 if tree.is_empty() {
598 None
599 } else {
600 self.inner = self.inner.without_trees(tree);
601 Some(tree)
602 }
603 }
604}