miden_crypto/merkle/mmr/
partial.rs

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