miden-crypto/src/merkle/mmr/partial.rs
src/merkle/mmr/partial.rsRaw
1use super::{MmrDelta, MmrProof, Rpo256, RpoDigest};
2use crate::{
3 merkle::{
4 mmr::{leaf_to_corresponding_tree, nodes_in_forest},
5 InOrderIndex, InnerNodeInfo, MerklePath, MmrError, MmrPeaks,
6 },
7 utils::{collections::*, vec},
8};
9
10// TYPE ALIASES
11// ================================================================================================
12
13type NodeMap = BTreeMap<InOrderIndex, RpoDigest>;
14
15// PARTIAL MERKLE MOUNTAIN RANGE
16// ================================================================================================
17/// Partially materialized Merkle Mountain Range (MMR), used to efficiently store and update the
18/// authentication paths for a subset of the elements in a full MMR.
19///
20/// This structure store only the authentication path for a value, the value itself is stored
21/// separately.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct PartialMmr {
24 /// The version of the MMR.
25 ///
26 /// This value serves the following purposes:
27 ///
28 /// - The forest is a counter for the total number of elements in the MMR.
29 /// - Since the MMR is an append-only structure, every change to it causes a change to the
30 /// `forest`, so this value has a dual purpose as a version tag.
31 /// - The bits in the forest also corresponds to the count and size of every perfect binary
32 /// tree that composes the MMR structure, which server to compute indexes and perform
33 /// validation.
34 pub(crate) forest: usize,
35
36 /// The MMR peaks.
37 ///
38 /// The peaks are used for two reasons:
39 ///
40 /// 1. It authenticates the addition of an element to the [PartialMmr], ensuring only valid
41 /// elements are tracked.
42 /// 2. During a MMR update peaks can be merged by hashing the left and right hand sides. The
43 /// peaks are used as the left hand.
44 ///
45 /// All the peaks of every tree in the MMR forest. The peaks are always ordered by number of
46 /// leaves, starting from the peak with most children, to the one with least.
47 pub(crate) peaks: Vec<RpoDigest>,
48
49 /// Authentication nodes used to construct merkle paths for a subset of the MMR's leaves.
50 ///
51 /// This does not include the MMR's peaks nor the tracked nodes, only the elements required to
52 /// construct their authentication paths. This property is used to detect when elements can be
53 /// safely removed, because they are no longer required to authenticate any element in the
54 /// [PartialMmr].
55 ///
56 /// The elements in the MMR are referenced using a in-order tree index. This indexing scheme
57 /// permits for easy computation of the relative nodes (left/right children, sibling, parent),
58 /// which is useful for traversal. The indexing is also stable, meaning that merges to the
59 /// trees in the MMR can be represented without rewrites of the indexes.
60 pub(crate) nodes: NodeMap,
61
62 /// Flag indicating if the odd element should be tracked.
63 ///
64 /// This flag is necessary because the sibling of the odd doesn't exist yet, so it can not be
65 /// added into `nodes` to signal the value is being tracked.
66 pub(crate) track_latest: bool,
67}
68
69impl PartialMmr {
70 // CONSTRUCTORS
71 // --------------------------------------------------------------------------------------------
72
73 /// Returns a new [PartialMmr] instantiated from the specified peaks.
74 pub fn from_peaks(peaks: MmrPeaks) -> Self {
75 let forest = peaks.num_leaves();
76 let peaks = peaks.into();
77 let nodes = BTreeMap::new();
78 let track_latest = false;
79
80 Self { forest, peaks, nodes, track_latest }
81 }
82
83 /// Returns a new [PartialMmr] instantiated from the specified components.
84 ///
85 /// This constructor does not check the consistency between peaks and nodes. If the specified
86 /// peaks are nodes are inconsistent, the returned partial MMR may exhibit undefined behavior.
87 pub fn from_parts(peaks: MmrPeaks, nodes: NodeMap, track_latest: bool) -> Self {
88 let forest = peaks.num_leaves();
89 let peaks = peaks.into();
90
91 Self { forest, peaks, nodes, track_latest }
92 }
93
94 // PUBLIC ACCESSORS
95 // --------------------------------------------------------------------------------------------
96
97 /// Returns the current `forest` of this [PartialMmr].
98 ///
99 /// This value corresponds to the version of the [PartialMmr] and the number of leaves in the
100 /// underlying MMR.
101 pub fn forest(&self) -> usize {
102 self.forest
103 }
104
105 /// Returns the number of leaves in the underlying MMR for this [PartialMmr].
106 pub fn num_leaves(&self) -> usize {
107 self.forest
108 }
109
110 /// Returns the peaks of the MMR for this [PartialMmr].
111 pub fn peaks(&self) -> MmrPeaks {
112 // expect() is OK here because the constructor ensures that MMR peaks can be constructed
113 // correctly
114 MmrPeaks::new(self.forest, self.peaks.clone()).expect("invalid MMR peaks")
115 }
116
117 /// Returns true if this partial MMR tracks an authentication path for the leaf at the
118 /// specified position.
119 pub fn is_tracked(&self, pos: usize) -> bool {
120 if pos >= self.forest {
121 return false;
122 } else if pos == self.forest - 1 && self.forest & 1 != 0 {
123 // if the number of leaves in the MMR is odd and the position is for the last leaf
124 // whether the leaf is tracked is defined by the `track_latest` flag
125 return self.track_latest;
126 }
127
128 let leaf_index = InOrderIndex::from_leaf_pos(pos);
129 self.is_tracked_node(&leaf_index)
130 }
131
132 /// Given a leaf position, returns the Merkle path to its corresponding peak, or None if this
133 /// partial MMR does not track an authentication paths for the specified leaf.
134 ///
135 /// Note: The leaf position is the 0-indexed number corresponding to the order the leaves were
136 /// added, this corresponds to the MMR size _prior_ to adding the element. So the 1st element
137 /// has position 0, the second position 1, and so on.
138 ///
139 /// # Errors
140 /// Returns an error if the specified position is greater-or-equal than the number of leaves
141 /// in the underlying MMR.
142 pub fn open(&self, pos: usize) -> Result<Option<MmrProof>, MmrError> {
143 let tree_bit =
144 leaf_to_corresponding_tree(pos, self.forest).ok_or(MmrError::InvalidPosition(pos))?;
145 let depth = tree_bit as usize;
146
147 let mut nodes = Vec::with_capacity(depth);
148 let mut idx = InOrderIndex::from_leaf_pos(pos);
149
150 while let Some(node) = self.nodes.get(&idx.sibling()) {
151 nodes.push(*node);
152 idx = idx.parent();
153 }
154
155 // If there are nodes then the path must be complete, otherwise it is a bug
156 debug_assert!(nodes.is_empty() || nodes.len() == depth);
157
158 if nodes.len() != depth {
159 // The requested `pos` is not being tracked.
160 Ok(None)
161 } else {
162 Ok(Some(MmrProof {
163 forest: self.forest,
164 position: pos,
165 merkle_path: MerklePath::new(nodes),
166 }))
167 }
168 }
169
170 // ITERATORS
171 // --------------------------------------------------------------------------------------------
172
173 /// Returns an iterator nodes of all authentication paths of this [PartialMmr].
174 pub fn nodes(&self) -> impl Iterator<Item = (&InOrderIndex, &RpoDigest)> {
175 self.nodes.iter()
176 }
177
178 /// Returns an iterator over inner nodes of this [PartialMmr] for the specified leaves.
179 ///
180 /// The order of iteration is not defined. If a leaf is not presented in this partial MMR it
181 /// is silently ignored.
182 pub fn inner_nodes<'a, I: Iterator<Item = (usize, RpoDigest)> + 'a>(
183 &'a self,
184 mut leaves: I,
185 ) -> impl Iterator<Item = InnerNodeInfo> + '_ {
186 let stack = if let Some((pos, leaf)) = leaves.next() {
187 let idx = InOrderIndex::from_leaf_pos(pos);
188 vec![(idx, leaf)]
189 } else {
190 Vec::new()
191 };
192
193 InnerNodeIterator {
194 nodes: &self.nodes,
195 leaves,
196 stack,
197 seen_nodes: BTreeSet::new(),
198 }
199 }
200
201 // STATE MUTATORS
202 // --------------------------------------------------------------------------------------------
203
204 /// Adds a new peak and optionally track it. Returns a vector of the authentication nodes
205 /// inserted into this [PartialMmr] as a result of this operation.
206 ///
207 /// When `track` is `true` the new leaf is tracked.
208 pub fn add(&mut self, leaf: RpoDigest, track: bool) -> Vec<(InOrderIndex, RpoDigest)> {
209 self.forest += 1;
210 let merges = self.forest.trailing_zeros() as usize;
211 let mut new_nodes = Vec::with_capacity(merges);
212
213 let peak = if merges == 0 {
214 self.track_latest = track;
215 leaf
216 } else {
217 let mut track_right = track;
218 let mut track_left = self.track_latest;
219
220 let mut right = leaf;
221 let mut right_idx = forest_to_rightmost_index(self.forest);
222
223 for _ in 0..merges {
224 let left = self.peaks.pop().expect("Missing peak");
225 let left_idx = right_idx.sibling();
226
227 if track_right {
228 let old = self.nodes.insert(left_idx, left);
229 new_nodes.push((left_idx, left));
230
231 debug_assert!(
232 old.is_none(),
233 "Idx {:?} already contained an element {:?}",
234 left_idx,
235 old
236 );
237 };
238 if track_left {
239 let old = self.nodes.insert(right_idx, right);
240 new_nodes.push((right_idx, right));
241
242 debug_assert!(
243 old.is_none(),
244 "Idx {:?} already contained an element {:?}",
245 right_idx,
246 old
247 );
248 };
249
250 // Update state for the next iteration.
251 // --------------------------------------------------------------------------------
252
253 // This layer is merged, go up one layer.
254 right_idx = right_idx.parent();
255
256 // Merge the current layer. The result is either the right element of the next
257 // merge, or a new peak.
258 right = Rpo256::merge(&[left, right]);
259
260 // This iteration merged the left and right nodes, the new value is always used as
261 // the next iteration's right node. Therefore the tracking flags of this iteration
262 // have to be merged into the right side only.
263 track_right = track_right || track_left;
264
265 // On the next iteration, a peak will be merged. If any of its children are tracked,
266 // then we have to track the left side
267 track_left = self.is_tracked_node(&right_idx.sibling());
268 }
269 right
270 };
271
272 self.peaks.push(peak);
273
274 new_nodes
275 }
276
277 /// Adds the authentication path represented by [MerklePath] if it is valid.
278 ///
279 /// The `leaf_pos` refers to the global position of the leaf in the MMR, these are 0-indexed
280 /// values assigned in a strictly monotonic fashion as elements are inserted into the MMR,
281 /// this value corresponds to the values used in the MMR structure.
282 ///
283 /// The `leaf` corresponds to the value at `leaf_pos`, and `path` is the authentication path for
284 /// that element up to its corresponding Mmr peak. The `leaf` is only used to compute the root
285 /// from the authentication path to valid the data, only the authentication data is saved in
286 /// the structure. If the value is required it should be stored out-of-band.
287 pub fn track(
288 &mut self,
289 leaf_pos: usize,
290 leaf: RpoDigest,
291 path: &MerklePath,
292 ) -> Result<(), MmrError> {
293 // Checks there is a tree with same depth as the authentication path, if not the path is
294 // invalid.
295 let tree = 1 << path.depth();
296 if tree & self.forest == 0 {
297 return Err(MmrError::UnknownPeak);
298 };
299
300 if leaf_pos + 1 == self.forest
301 && path.depth() == 0
302 && self.peaks.last().map_or(false, |v| *v == leaf)
303 {
304 self.track_latest = true;
305 return Ok(());
306 }
307
308 // ignore the trees smaller than the target (these elements are position after the current
309 // target and don't affect the target leaf_pos)
310 let target_forest = self.forest ^ (self.forest & (tree - 1));
311 let peak_pos = (target_forest.count_ones() - 1) as usize;
312
313 // translate from mmr leaf_pos to merkle path
314 let path_idx = leaf_pos - (target_forest ^ tree);
315
316 // Compute the root of the authentication path, and check it matches the current version of
317 // the PartialMmr.
318 let computed = path.compute_root(path_idx as u64, leaf).map_err(MmrError::MerkleError)?;
319 if self.peaks[peak_pos] != computed {
320 return Err(MmrError::InvalidPeak);
321 }
322
323 let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
324 for leaf in path.nodes() {
325 self.nodes.insert(idx.sibling(), *leaf);
326 idx = idx.parent();
327 }
328
329 Ok(())
330 }
331
332 /// Removes a leaf of the [PartialMmr] and the unused nodes from the authentication path.
333 ///
334 /// Note: `leaf_pos` corresponds to the position in the MMR and not on an individual tree.
335 pub fn untrack(&mut self, leaf_pos: usize) {
336 let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
337
338 self.nodes.remove(&idx.sibling());
339
340 // `idx` represent the element that can be computed by the authentication path, because
341 // these elements can be computed they are not saved for the authentication of the current
342 // target. In other words, if the idx is present it was added for the authentication of
343 // another element, and no more elements should be removed otherwise it would remove that
344 // element's authentication data.
345 while !self.nodes.contains_key(&idx) {
346 idx = idx.parent();
347 self.nodes.remove(&idx.sibling());
348 }
349 }
350
351 /// Applies updates to this [PartialMmr] and returns a vector of new authentication nodes
352 /// inserted into the partial MMR.
353 pub fn apply(&mut self, delta: MmrDelta) -> Result<Vec<(InOrderIndex, RpoDigest)>, MmrError> {
354 if delta.forest < self.forest {
355 return Err(MmrError::InvalidPeaks);
356 }
357
358 let mut inserted_nodes = Vec::new();
359
360 if delta.forest == self.forest {
361 if !delta.data.is_empty() {
362 return Err(MmrError::InvalidUpdate);
363 }
364
365 return Ok(inserted_nodes);
366 }
367
368 // find the tree merges
369 let changes = self.forest ^ delta.forest;
370 let largest = 1 << changes.ilog2();
371 let merges = self.forest & (largest - 1);
372
373 debug_assert!(
374 !self.track_latest || (merges & 1) == 1,
375 "if there is an odd element, a merge is required"
376 );
377
378 // count the number elements needed to produce largest from the current state
379 let (merge_count, new_peaks) = if merges != 0 {
380 let depth = largest.trailing_zeros();
381 let skipped = merges.trailing_zeros();
382 let computed = merges.count_ones() - 1;
383 let merge_count = depth - skipped - computed;
384
385 let new_peaks = delta.forest & (largest - 1);
386
387 (merge_count, new_peaks)
388 } else {
389 (0, changes)
390 };
391
392 // verify the delta size
393 if (delta.data.len() as u32) != merge_count + new_peaks.count_ones() {
394 return Err(MmrError::InvalidUpdate);
395 }
396
397 // keeps track of how many data elements from the update have been consumed
398 let mut update_count = 0;
399
400 if merges != 0 {
401 // starts at the smallest peak and follows the merged peaks
402 let mut peak_idx = forest_to_root_index(self.forest);
403
404 // match order of the update data while applying it
405 self.peaks.reverse();
406
407 // set to true when the data is needed for authentication paths updates
408 let mut track = self.track_latest;
409 self.track_latest = false;
410
411 let mut peak_count = 0;
412 let mut target = 1 << merges.trailing_zeros();
413 let mut new = delta.data[0];
414 update_count += 1;
415
416 while target < largest {
417 // check if either the left or right subtrees have saved for authentication paths.
418 // If so, turn tracking on to update those paths.
419 if target != 1 && !track {
420 track = self.is_tracked_node(&peak_idx);
421 }
422
423 // update data only contains the nodes from the right subtrees, left nodes are
424 // either previously known peaks or computed values
425 let (left, right) = if target & merges != 0 {
426 let peak = self.peaks[peak_count];
427 let sibling_idx = peak_idx.sibling();
428
429 // if the sibling peak is tracked, add this peaks to the set of
430 // authentication nodes
431 if self.is_tracked_node(&sibling_idx) {
432 self.nodes.insert(peak_idx, new);
433 inserted_nodes.push((peak_idx, new));
434 }
435 peak_count += 1;
436 (peak, new)
437 } else {
438 let update = delta.data[update_count];
439 update_count += 1;
440 (new, update)
441 };
442
443 if track {
444 let sibling_idx = peak_idx.sibling();
445 if peak_idx.is_left_child() {
446 self.nodes.insert(sibling_idx, right);
447 inserted_nodes.push((sibling_idx, right));
448 } else {
449 self.nodes.insert(sibling_idx, left);
450 inserted_nodes.push((sibling_idx, left));
451 }
452 }
453
454 peak_idx = peak_idx.parent();
455 new = Rpo256::merge(&[left, right]);
456 target <<= 1;
457 }
458
459 debug_assert!(peak_count == (merges.count_ones() as usize));
460
461 // restore the peaks order
462 self.peaks.reverse();
463 // remove the merged peaks
464 self.peaks.truncate(self.peaks.len() - peak_count);
465 // add the newly computed peak, the result of the merges
466 self.peaks.push(new);
467 }
468
469 // The rest of the update data is composed of peaks. None of these elements can contain
470 // tracked elements because the peaks were unknown, and it is not possible to add elements
471 // for tacking without authenticating it to a peak.
472 self.peaks.extend_from_slice(&delta.data[update_count..]);
473 self.forest = delta.forest;
474
475 debug_assert!(self.peaks.len() == (self.forest.count_ones() as usize));
476
477 Ok(inserted_nodes)
478 }
479
480 // HELPER METHODS
481 // --------------------------------------------------------------------------------------------
482
483 /// Returns true if this [PartialMmr] tracks authentication path for the node at the specified
484 /// index.
485 fn is_tracked_node(&self, node_index: &InOrderIndex) -> bool {
486 if node_index.is_leaf() {
487 self.nodes.contains_key(&node_index.sibling())
488 } else {
489 let left_child = node_index.left_child();
490 let right_child = node_index.right_child();
491 self.nodes.contains_key(&left_child) | self.nodes.contains_key(&right_child)
492 }
493 }
494}
495
496// CONVERSIONS
497// ================================================================================================
498
499impl From<MmrPeaks> for PartialMmr {
500 fn from(peaks: MmrPeaks) -> Self {
501 Self::from_peaks(peaks)
502 }
503}
504
505impl From<PartialMmr> for MmrPeaks {
506 fn from(partial_mmr: PartialMmr) -> Self {
507 // Safety: the [PartialMmr] maintains the constraints the number of true bits in the forest
508 // matches the number of peaks, as required by the [MmrPeaks]
509 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks).unwrap()
510 }
511}
512
513impl From<&MmrPeaks> for PartialMmr {
514 fn from(peaks: &MmrPeaks) -> Self {
515 Self::from_peaks(peaks.clone())
516 }
517}
518
519impl From<&PartialMmr> for MmrPeaks {
520 fn from(partial_mmr: &PartialMmr) -> Self {
521 // Safety: the [PartialMmr] maintains the constraints the number of true bits in the forest
522 // matches the number of peaks, as required by the [MmrPeaks]
523 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks.clone()).unwrap()
524 }
525}
526
527// ITERATORS
528// ================================================================================================
529
530/// An iterator over every inner node of the [PartialMmr].
531pub struct InnerNodeIterator<'a, I: Iterator<Item = (usize, RpoDigest)>> {
532 nodes: &'a NodeMap,
533 leaves: I,
534 stack: Vec<(InOrderIndex, RpoDigest)>,
535 seen_nodes: BTreeSet<InOrderIndex>,
536}
537
538impl<'a, I: Iterator<Item = (usize, RpoDigest)>> Iterator for InnerNodeIterator<'a, I> {
539 type Item = InnerNodeInfo;
540
541 fn next(&mut self) -> Option<Self::Item> {
542 while let Some((idx, node)) = self.stack.pop() {
543 let parent_idx = idx.parent();
544 let new_node = self.seen_nodes.insert(parent_idx);
545
546 // if we haven't seen this node's parent before, and the node has a sibling, return
547 // the inner node defined by the parent of this node, and move up the branch
548 if new_node {
549 if let Some(sibling) = self.nodes.get(&idx.sibling()) {
550 let (left, right) = if parent_idx.left_child() == idx {
551 (node, *sibling)
552 } else {
553 (*sibling, node)
554 };
555 let parent = Rpo256::merge(&[left, right]);
556 let inner_node = InnerNodeInfo { value: parent, left, right };
557
558 self.stack.push((parent_idx, parent));
559 return Some(inner_node);
560 }
561 }
562
563 // the previous leaf has been processed, try to process the next leaf
564 if let Some((pos, leaf)) = self.leaves.next() {
565 let idx = InOrderIndex::from_leaf_pos(pos);
566 self.stack.push((idx, leaf));
567 }
568 }
569
570 None
571 }
572}
573
574// UTILS
575// ================================================================================================
576
577/// Given the description of a `forest`, returns the index of the root element of the smallest tree
578/// in it.
579fn forest_to_root_index(forest: usize) -> InOrderIndex {
580 // Count total size of all trees in the forest.
581 let nodes = nodes_in_forest(forest);
582
583 // Add the count for the parent nodes that separate each tree. These are allocated but
584 // currently empty, and correspond to the nodes that will be used once the trees are merged.
585 let open_trees = (forest.count_ones() - 1) as usize;
586
587 // Remove the count of the right subtree of the target tree, target tree root index comes
588 // before the subtree for the in-order tree walk.
589 let right_subtree_count = ((1u32 << forest.trailing_zeros()) - 1) as usize;
590
591 let idx = nodes + open_trees - right_subtree_count;
592
593 InOrderIndex::new(idx.try_into().unwrap())
594}
595
596/// Given the description of a `forest`, returns the index of the right most element.
597fn forest_to_rightmost_index(forest: usize) -> InOrderIndex {
598 // Count total size of all trees in the forest.
599 let nodes = nodes_in_forest(forest);
600
601 // Add the count for the parent nodes that separate each tree. These are allocated but
602 // currently empty, and correspond to the nodes that will be used once the trees are merged.
603 let open_trees = (forest.count_ones() - 1) as usize;
604
605 let idx = nodes + open_trees;
606
607 InOrderIndex::new(idx.try_into().unwrap())
608}
609
610// TESTS
611// ================================================================================================
612
613#[cfg(test)]
614mod tests {
615 use super::{
616 forest_to_rightmost_index, forest_to_root_index, InOrderIndex, MmrPeaks, PartialMmr,
617 RpoDigest,
618 };
619 use crate::{
620 merkle::{int_to_node, MerkleStore, Mmr, NodeIndex},
621 utils::collections::*,
622 };
623
624 const LEAVES: [RpoDigest; 7] = [
625 int_to_node(0),
626 int_to_node(1),
627 int_to_node(2),
628 int_to_node(3),
629 int_to_node(4),
630 int_to_node(5),
631 int_to_node(6),
632 ];
633
634 #[test]
635 fn test_forest_to_root_index() {
636 fn idx(pos: usize) -> InOrderIndex {
637 InOrderIndex::new(pos.try_into().unwrap())
638 }
639
640 // When there is a single tree in the forest, the index is equivalent to the number of
641 // leaves in that tree, which is `2^n`.
642 assert_eq!(forest_to_root_index(0b0001), idx(1));
643 assert_eq!(forest_to_root_index(0b0010), idx(2));
644 assert_eq!(forest_to_root_index(0b0100), idx(4));
645 assert_eq!(forest_to_root_index(0b1000), idx(8));
646
647 assert_eq!(forest_to_root_index(0b0011), idx(5));
648 assert_eq!(forest_to_root_index(0b0101), idx(9));
649 assert_eq!(forest_to_root_index(0b1001), idx(17));
650 assert_eq!(forest_to_root_index(0b0111), idx(13));
651 assert_eq!(forest_to_root_index(0b1011), idx(21));
652 assert_eq!(forest_to_root_index(0b1111), idx(29));
653
654 assert_eq!(forest_to_root_index(0b0110), idx(10));
655 assert_eq!(forest_to_root_index(0b1010), idx(18));
656 assert_eq!(forest_to_root_index(0b1100), idx(20));
657 assert_eq!(forest_to_root_index(0b1110), idx(26));
658 }
659
660 #[test]
661 fn test_forest_to_rightmost_index() {
662 fn idx(pos: usize) -> InOrderIndex {
663 InOrderIndex::new(pos.try_into().unwrap())
664 }
665
666 for forest in 1..256 {
667 assert!(forest_to_rightmost_index(forest).inner() % 2 == 1, "Leaves are always odd");
668 }
669
670 assert_eq!(forest_to_rightmost_index(0b0001), idx(1));
671 assert_eq!(forest_to_rightmost_index(0b0010), idx(3));
672 assert_eq!(forest_to_rightmost_index(0b0011), idx(5));
673 assert_eq!(forest_to_rightmost_index(0b0100), idx(7));
674 assert_eq!(forest_to_rightmost_index(0b0101), idx(9));
675 assert_eq!(forest_to_rightmost_index(0b0110), idx(11));
676 assert_eq!(forest_to_rightmost_index(0b0111), idx(13));
677 assert_eq!(forest_to_rightmost_index(0b1000), idx(15));
678 assert_eq!(forest_to_rightmost_index(0b1001), idx(17));
679 assert_eq!(forest_to_rightmost_index(0b1010), idx(19));
680 assert_eq!(forest_to_rightmost_index(0b1011), idx(21));
681 assert_eq!(forest_to_rightmost_index(0b1100), idx(23));
682 assert_eq!(forest_to_rightmost_index(0b1101), idx(25));
683 assert_eq!(forest_to_rightmost_index(0b1110), idx(27));
684 assert_eq!(forest_to_rightmost_index(0b1111), idx(29));
685 }
686
687 #[test]
688 fn test_partial_mmr_apply_delta() {
689 // build an MMR with 10 nodes (2 peaks) and a partial MMR based on it
690 let mut mmr = Mmr::default();
691 (0..10).for_each(|i| mmr.add(int_to_node(i)));
692 let mut partial_mmr: PartialMmr = mmr.peaks(mmr.forest()).unwrap().into();
693
694 // add authentication path for position 1 and 8
695 {
696 let node = mmr.get(1).unwrap();
697 let proof = mmr.open(1, mmr.forest()).unwrap();
698 partial_mmr.track(1, node, &proof.merkle_path).unwrap();
699 }
700
701 {
702 let node = mmr.get(8).unwrap();
703 let proof = mmr.open(8, mmr.forest()).unwrap();
704 partial_mmr.track(8, node, &proof.merkle_path).unwrap();
705 }
706
707 // add 2 more nodes into the MMR and validate apply_delta()
708 (10..12).for_each(|i| mmr.add(int_to_node(i)));
709 validate_apply_delta(&mmr, &mut partial_mmr);
710
711 // add 1 more node to the MMR, validate apply_delta() and start tracking the node
712 mmr.add(int_to_node(12));
713 validate_apply_delta(&mmr, &mut partial_mmr);
714 {
715 let node = mmr.get(12).unwrap();
716 let proof = mmr.open(12, mmr.forest()).unwrap();
717 partial_mmr.track(12, node, &proof.merkle_path).unwrap();
718 assert!(partial_mmr.track_latest);
719 }
720
721 // by this point we are tracking authentication paths for positions: 1, 8, and 12
722
723 // add 3 more nodes to the MMR (collapses to 1 peak) and validate apply_delta()
724 (13..16).for_each(|i| mmr.add(int_to_node(i)));
725 validate_apply_delta(&mmr, &mut partial_mmr);
726 }
727
728 fn validate_apply_delta(mmr: &Mmr, partial: &mut PartialMmr) {
729 let tracked_leaves = partial
730 .nodes
731 .iter()
732 .filter_map(|(index, _)| if index.is_leaf() { Some(index.sibling()) } else { None })
733 .collect::<Vec<_>>();
734 let nodes_before = partial.nodes.clone();
735
736 // compute and apply delta
737 let delta = mmr.get_delta(partial.forest(), mmr.forest()).unwrap();
738 let nodes_delta = partial.apply(delta).unwrap();
739
740 // new peaks were computed correctly
741 assert_eq!(mmr.peaks(mmr.forest()).unwrap(), partial.peaks());
742
743 let mut expected_nodes = nodes_before;
744 for (key, value) in nodes_delta {
745 // nodes should not be duplicated
746 assert!(expected_nodes.insert(key, value).is_none());
747 }
748
749 // new nodes should be a combination of original nodes and delta
750 assert_eq!(expected_nodes, partial.nodes);
751
752 // make sure tracked leaves open to the same proofs as in the underlying MMR
753 for index in tracked_leaves {
754 let index_value: u64 = index.into();
755 let pos = index_value / 2;
756 let proof1 = partial.open(pos as usize).unwrap().unwrap();
757 let proof2 = mmr.open(pos as usize, mmr.forest()).unwrap();
758 assert_eq!(proof1, proof2);
759 }
760 }
761
762 #[test]
763 fn test_partial_mmr_inner_nodes_iterator() {
764 // build the MMR
765 let mmr: Mmr = LEAVES.into();
766 let first_peak = mmr.peaks(mmr.forest).unwrap().peaks()[0];
767
768 // -- test single tree ----------------------------
769
770 // get path and node for position 1
771 let node1 = mmr.get(1).unwrap();
772 let proof1 = mmr.open(1, mmr.forest()).unwrap();
773
774 // create partial MMR and add authentication path to node at position 1
775 let mut partial_mmr: PartialMmr = mmr.peaks(mmr.forest()).unwrap().into();
776 partial_mmr.track(1, node1, &proof1.merkle_path).unwrap();
777
778 // empty iterator should have no nodes
779 assert_eq!(partial_mmr.inner_nodes([].iter().cloned()).next(), None);
780
781 // build Merkle store from authentication paths in partial MMR
782 let mut store: MerkleStore = MerkleStore::new();
783 store.extend(partial_mmr.inner_nodes([(1, node1)].iter().cloned()));
784
785 let index1 = NodeIndex::new(2, 1).unwrap();
786 let path1 = store.get_path(first_peak, index1).unwrap().path;
787
788 assert_eq!(path1, proof1.merkle_path);
789
790 // -- test no duplicates --------------------------
791
792 // build the partial MMR
793 let mut partial_mmr: PartialMmr = mmr.peaks(mmr.forest()).unwrap().into();
794
795 let node0 = mmr.get(0).unwrap();
796 let proof0 = mmr.open(0, mmr.forest()).unwrap();
797
798 let node2 = mmr.get(2).unwrap();
799 let proof2 = mmr.open(2, mmr.forest()).unwrap();
800
801 partial_mmr.track(0, node0, &proof0.merkle_path).unwrap();
802 partial_mmr.track(1, node1, &proof1.merkle_path).unwrap();
803 partial_mmr.track(2, node2, &proof2.merkle_path).unwrap();
804
805 // make sure there are no duplicates
806 let leaves = [(0, node0), (1, node1), (2, node2)];
807 let mut nodes = BTreeSet::new();
808 for node in partial_mmr.inner_nodes(leaves.iter().cloned()) {
809 assert!(nodes.insert(node.value));
810 }
811
812 // and also that the store is still be built correctly
813 store.extend(partial_mmr.inner_nodes(leaves.iter().cloned()));
814
815 let index0 = NodeIndex::new(2, 0).unwrap();
816 let index1 = NodeIndex::new(2, 1).unwrap();
817 let index2 = NodeIndex::new(2, 2).unwrap();
818
819 let path0 = store.get_path(first_peak, index0).unwrap().path;
820 let path1 = store.get_path(first_peak, index1).unwrap().path;
821 let path2 = store.get_path(first_peak, index2).unwrap().path;
822
823 assert_eq!(path0, proof0.merkle_path);
824 assert_eq!(path1, proof1.merkle_path);
825 assert_eq!(path2, proof2.merkle_path);
826
827 // -- test multiple trees -------------------------
828
829 // build the partial MMR
830 let mut partial_mmr: PartialMmr = mmr.peaks(mmr.forest()).unwrap().into();
831
832 let node5 = mmr.get(5).unwrap();
833 let proof5 = mmr.open(5, mmr.forest()).unwrap();
834
835 partial_mmr.track(1, node1, &proof1.merkle_path).unwrap();
836 partial_mmr.track(5, node5, &proof5.merkle_path).unwrap();
837
838 // build Merkle store from authentication paths in partial MMR
839 let mut store: MerkleStore = MerkleStore::new();
840 store.extend(partial_mmr.inner_nodes([(1, node1), (5, node5)].iter().cloned()));
841
842 let index1 = NodeIndex::new(2, 1).unwrap();
843 let index5 = NodeIndex::new(1, 1).unwrap();
844
845 let second_peak = mmr.peaks(mmr.forest).unwrap().peaks()[1];
846
847 let path1 = store.get_path(first_peak, index1).unwrap().path;
848 let path5 = store.get_path(second_peak, index5).unwrap().path;
849
850 assert_eq!(path1, proof1.merkle_path);
851 assert_eq!(path5, proof5.merkle_path);
852 }
853
854 #[test]
855 fn test_partial_mmr_add_without_track() {
856 let mut mmr = Mmr::default();
857 let empty_peaks = MmrPeaks::new(0, vec![]).unwrap();
858 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
859
860 for el in (0..256).map(int_to_node) {
861 mmr.add(el);
862 partial_mmr.add(el, false);
863
864 let mmr_peaks = mmr.peaks(mmr.forest()).unwrap();
865 assert_eq!(mmr_peaks, partial_mmr.peaks());
866 assert_eq!(mmr.forest(), partial_mmr.forest());
867 }
868 }
869
870 #[test]
871 fn test_partial_mmr_add_with_track() {
872 let mut mmr = Mmr::default();
873 let empty_peaks = MmrPeaks::new(0, vec![]).unwrap();
874 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
875
876 for i in 0..256 {
877 let el = int_to_node(i);
878 mmr.add(el);
879 partial_mmr.add(el, true);
880
881 let mmr_peaks = mmr.peaks(mmr.forest()).unwrap();
882 assert_eq!(mmr_peaks, partial_mmr.peaks());
883 assert_eq!(mmr.forest(), partial_mmr.forest());
884
885 for pos in 0..i {
886 let mmr_proof = mmr.open(pos as usize, mmr.forest()).unwrap();
887 let partialmmr_proof = partial_mmr.open(pos as usize).unwrap().unwrap();
888 assert_eq!(mmr_proof, partialmmr_proof);
889 }
890 }
891 }
892
893 #[test]
894 fn test_partial_mmr_add_existing_track() {
895 let mut mmr = Mmr::from((0..7).map(int_to_node));
896
897 // derive a partial Mmr from it which tracks authentication path to leaf 5
898 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks(mmr.forest()).unwrap());
899 let path_to_5 = mmr.open(5, mmr.forest()).unwrap().merkle_path;
900 let leaf_at_5 = mmr.get(5).unwrap();
901 partial_mmr.track(5, leaf_at_5, &path_to_5).unwrap();
902
903 // add a new leaf to both Mmr and partial Mmr
904 let leaf_at_7 = int_to_node(7);
905 mmr.add(leaf_at_7);
906 partial_mmr.add(leaf_at_7, false);
907
908 // the openings should be the same
909 assert_eq!(mmr.open(5, mmr.forest()).unwrap(), partial_mmr.open(5).unwrap().unwrap());
910 }
911}