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