1use alloc::{borrow::Cow, vec::Vec};
2use core::{
3 iter::{self, FusedIterator},
4 num::NonZero,
5};
6
7use super::{
8 EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex, Word, smt::SMT_MAX_DEPTH,
9};
10use crate::{
11 hash::eidos::Eidos,
12 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
13};
14
15#[derive(Clone, Debug, Default, PartialEq, Eq)]
27#[cfg_attr(
28 all(feature = "arbitrary", test),
29 miden_test_serialization_macros::serialization_test
30)]
31pub struct SparseMerklePath {
32 empty_nodes_mask: u64,
36 nodes: Vec<Word>,
38}
39
40impl SparseMerklePath {
41 pub fn from_parts(empty_nodes_mask: u64, nodes: Vec<Word>) -> Result<Self, MerkleError> {
55 let min_path_len = u64::BITS - empty_nodes_mask.leading_zeros();
63 let empty_nodes_count = empty_nodes_mask.count_ones();
64 let min_non_empty_nodes = (min_path_len - empty_nodes_count) as usize;
65
66 if nodes.len() < min_non_empty_nodes {
67 return Err(MerkleError::InvalidPathLength(min_non_empty_nodes));
68 }
69
70 let depth = Self::depth_from_parts(empty_nodes_mask, &nodes);
73 if depth > SMT_MAX_DEPTH as usize {
74 return Err(MerkleError::DepthTooBig(depth as u64));
75 }
76
77 Ok(Self { empty_nodes_mask, nodes })
78 }
79
80 pub fn from_sized_iter<I>(iterator: I) -> Result<Self, MerkleError>
90 where
91 I: IntoIterator<IntoIter: ExactSizeIterator, Item = Word>,
92 {
93 let iterator = iterator.into_iter();
94 let tree_depth = iterator.len();
97 if tree_depth > SMT_MAX_DEPTH as usize {
98 return Err(MerkleError::DepthTooBig(tree_depth as u64));
99 }
100 let tree_depth = tree_depth as u8;
101
102 let mut empty_nodes_mask: u64 = 0;
103 let mut nodes: Vec<Word> = Default::default();
104
105 for (depth, node) in iter::zip(path_depth_iter(tree_depth), iterator) {
106 let &equivalent_empty_node = EmptySubtreeRoots::entry(tree_depth, depth.get());
107 let is_empty = node == equivalent_empty_node;
108 let node = if is_empty { None } else { Some(node) };
109
110 match node {
111 Some(node) => nodes.push(node),
112 None => empty_nodes_mask |= Self::bitmask_for_depth(depth),
113 }
114 }
115
116 Ok(SparseMerklePath { nodes, empty_nodes_mask })
117 }
118
119 pub fn depth(&self) -> u8 {
121 Self::depth_from_parts(self.empty_nodes_mask, &self.nodes) as u8
122 }
123
124 pub fn at_depth(&self, node_depth: NonZero<u8>) -> Result<Word, MerkleError> {
134 if node_depth.get() > self.depth() {
135 return Err(MerkleError::DepthTooBig(node_depth.get().into()));
136 }
137
138 let node = if let Some(nonempty_index) = self.get_nonempty_index(node_depth) {
139 self.nodes[nonempty_index]
140 } else {
141 *EmptySubtreeRoots::entry(self.depth(), node_depth.get())
142 };
143
144 Ok(node)
145 }
146
147 pub fn into_parts(self) -> (u64, Vec<Word>) {
154 (self.empty_nodes_mask, self.nodes)
155 }
156
157 pub fn iter(&self) -> impl ExactSizeIterator<Item = Word> {
163 self.into_iter()
164 }
165
166 pub fn compute_root(&self, index: u64, node_to_prove: Word) -> Result<Word, MerkleError> {
168 let mut index = NodeIndex::new(self.depth(), index)?;
169 let root = self.iter().fold(node_to_prove, |node, sibling| {
170 let children = index.build_node(node, sibling);
172 index.move_up();
173 Eidos::merge(&children)
174 });
175
176 Ok(root)
177 }
178
179 pub fn verify(&self, index: u64, node: Word, &expected_root: &Word) -> Result<(), MerkleError> {
186 let computed_root = self.compute_root(index, node)?;
187 if computed_root != expected_root {
188 return Err(MerkleError::ConflictingRoots {
189 expected_root,
190 actual_root: computed_root,
191 });
192 }
193
194 Ok(())
195 }
196
197 pub fn authenticated_nodes(
213 &self,
214 index: u64,
215 node_to_prove: Word,
216 ) -> Result<InnerNodeIterator<'_>, MerkleError> {
217 let index = NodeIndex::new(self.depth(), index)?;
218 Ok(InnerNodeIterator { path: self, index, value: node_to_prove })
219 }
220
221 const fn bitmask_for_depth(node_depth: NonZero<u8>) -> u64 {
225 1 << (node_depth.get() - 1)
227 }
228
229 const fn is_depth_empty(&self, node_depth: NonZero<u8>) -> bool {
230 (self.empty_nodes_mask & Self::bitmask_for_depth(node_depth)) != 0
231 }
232
233 fn get_nonempty_index(&self, node_depth: NonZero<u8>) -> Option<usize> {
236 if self.is_depth_empty(node_depth) {
237 return None;
238 }
239
240 let bit_index = node_depth.get() - 1;
241 let without_shallower = self.empty_nodes_mask >> bit_index;
242 let empty_deeper = without_shallower.count_ones() as usize;
243 let normal_index = (self.depth() - node_depth.get()) as usize;
245 Some(normal_index - empty_deeper)
247 }
248
249 fn depth_from_parts(empty_nodes_mask: u64, nodes: &[Word]) -> usize {
251 nodes.len() + empty_nodes_mask.count_ones() as usize
252 }
253}
254
255impl Serializable for SparseMerklePath {
259 fn write_into<W: ByteWriter>(&self, target: &mut W) {
260 target.write_u8(self.depth());
261 target.write_u64(self.empty_nodes_mask);
262 target.write_many(&self.nodes);
263 }
264}
265
266impl Deserializable for SparseMerklePath {
267 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
268 let depth = source.read_u8()?;
269 if depth > SMT_MAX_DEPTH {
270 return Err(DeserializationError::InvalidValue(format!(
271 "SparseMerklePath max depth exceeded ({depth} > {SMT_MAX_DEPTH})",
272 )));
273 }
274 let empty_nodes_mask = source.read_u64()?;
275 let empty_nodes_count = empty_nodes_mask.count_ones();
276 if empty_nodes_count > depth as u32 {
277 return Err(DeserializationError::InvalidValue(format!(
278 "SparseMerklePath has more empty nodes ({empty_nodes_count}) than its full length ({depth})",
279 )));
280 }
281 let count = depth as u32 - empty_nodes_count;
282 let nodes: Vec<Word> = source.read_many_iter(count as usize)?.collect::<Result<_, _>>()?;
283 Self::from_parts(empty_nodes_mask, nodes).map_err(|err| {
288 DeserializationError::InvalidValue(format!("invalid SparseMerklePath: {err}"))
289 })
290 }
291
292 fn min_serialized_size() -> usize {
293 1 + 8 }
295}
296
297impl From<SparseMerklePath> for MerklePath {
301 fn from(sparse_path: SparseMerklePath) -> Self {
302 MerklePath::from_iter(sparse_path)
303 }
304}
305
306impl TryFrom<MerklePath> for SparseMerklePath {
307 type Error = MerkleError;
308
309 fn try_from(path: MerklePath) -> Result<Self, MerkleError> {
314 SparseMerklePath::from_sized_iter(path)
315 }
316}
317
318impl From<SparseMerklePath> for Vec<Word> {
319 fn from(path: SparseMerklePath) -> Self {
320 Vec::from_iter(path)
321 }
322}
323
324pub struct SparseMerklePathIter<'p> {
330 path: Cow<'p, SparseMerklePath>,
332
333 next_depth: u8,
336}
337
338impl Iterator for SparseMerklePathIter<'_> {
339 type Item = Word;
340
341 fn next(&mut self) -> Option<Word> {
342 let this_depth = self.next_depth;
343 let this_depth = NonZero::new(this_depth)?;
345 self.next_depth = this_depth.get() - 1;
346
347 let node = self
349 .path
350 .at_depth(this_depth)
351 .expect("current depth should never exceed the path depth");
352 Some(node)
353 }
354
355 fn size_hint(&self) -> (usize, Option<usize>) {
357 let remaining = ExactSizeIterator::len(self);
358 (remaining, Some(remaining))
359 }
360}
361
362impl ExactSizeIterator for SparseMerklePathIter<'_> {
363 fn len(&self) -> usize {
364 self.next_depth as usize
365 }
366}
367
368impl FusedIterator for SparseMerklePathIter<'_> {}
369
370impl IntoIterator for SparseMerklePath {
373 type IntoIter = SparseMerklePathIter<'static>;
374 type Item = <Self::IntoIter as Iterator>::Item;
375
376 fn into_iter(self) -> SparseMerklePathIter<'static> {
377 let tree_depth = self.depth();
378 SparseMerklePathIter {
379 path: Cow::Owned(self),
380 next_depth: tree_depth,
381 }
382 }
383}
384
385impl<'p> IntoIterator for &'p SparseMerklePath {
386 type Item = <SparseMerklePathIter<'p> as Iterator>::Item;
387 type IntoIter = SparseMerklePathIter<'p>;
388
389 fn into_iter(self) -> SparseMerklePathIter<'p> {
390 let tree_depth = self.depth();
391 SparseMerklePathIter {
392 path: Cow::Borrowed(self),
393 next_depth: tree_depth,
394 }
395 }
396}
397
398pub struct InnerNodeIterator<'p> {
401 path: &'p SparseMerklePath,
402 index: NodeIndex,
403 value: Word,
404}
405
406impl Iterator for InnerNodeIterator<'_> {
407 type Item = InnerNodeInfo;
408
409 fn next(&mut self) -> Option<Self::Item> {
410 if self.index.is_root() {
411 return None;
412 }
413
414 let index_depth = NonZero::new(self.index.depth()).expect("non-root depth cannot be 0");
415 let path_node = self.path.at_depth(index_depth).unwrap();
416
417 let children = self.index.build_node(self.value, path_node);
418 self.value = Eidos::merge(&children);
419 self.index.move_up();
420
421 Some(InnerNodeInfo {
422 value: self.value,
423 left: children[0],
424 right: children[1],
425 })
426 }
427}
428
429impl PartialEq<MerklePath> for SparseMerklePath {
432 fn eq(&self, rhs: &MerklePath) -> bool {
433 if self.depth() != rhs.depth() {
434 return false;
435 }
436
437 for (node, &rhs_node) in iter::zip(self, rhs.iter()) {
438 if node != rhs_node {
439 return false;
440 }
441 }
442
443 true
444 }
445}
446
447impl PartialEq<SparseMerklePath> for MerklePath {
448 fn eq(&self, rhs: &SparseMerklePath) -> bool {
449 rhs == self
450 }
451}
452
453fn path_depth_iter(tree_depth: u8) -> impl ExactSizeIterator<Item = NonZero<u8>> {
459 let top_down_iter = (1..=tree_depth).map(|depth| {
460 NonZero::new(depth).expect("range is bounded by 1")
462 });
463
464 top_down_iter.rev()
466}
467
468#[cfg(any(test, feature = "arbitrary"))]
472mod arbitrary {
473 use proptest::prelude::*;
474
475 use super::{MerklePath, SparseMerklePath};
476 use crate::{
477 Word,
478 merkle::{MerkleProof, RootPath, smt::SMT_MAX_DEPTH},
479 };
480
481 impl Arbitrary for MerkleProof {
482 type Parameters = ();
483 type Strategy = BoxedStrategy<Self>;
484
485 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
486 (any::<Word>(), any::<MerklePath>())
488 .prop_map(|(value, path)| MerkleProof::new(value, path))
489 .boxed()
490 }
491 }
492
493 impl Arbitrary for RootPath {
494 type Parameters = ();
495 type Strategy = BoxedStrategy<Self>;
496
497 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
498 (any::<Word>(), any::<MerklePath>())
501 .prop_map(|(root, path)| RootPath { root, path })
502 .boxed()
503 }
504 }
505
506 impl Arbitrary for MerklePath {
507 type Parameters = ();
508 type Strategy = BoxedStrategy<Self>;
509
510 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
511 prop::collection::vec(any::<Word>(), 0..=SMT_MAX_DEPTH as usize)
512 .prop_map(MerklePath::new)
513 .boxed()
514 }
515 }
516
517 impl Arbitrary for SparseMerklePath {
518 type Parameters = ();
519 type Strategy = BoxedStrategy<Self>;
520
521 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
522 (0..=SMT_MAX_DEPTH as usize)
523 .prop_flat_map(|depth| {
524 let max_mask = if depth > 0 && depth < 64 {
525 (1u64 << depth) - 1
526 } else if depth == 64 {
527 u64::MAX
528 } else {
529 0
530 };
531 let empty_nodes_mask =
532 prop::num::u64::ANY.prop_map(move |mask| mask & max_mask);
533
534 empty_nodes_mask.prop_flat_map(move |mask| {
535 let empty_count = mask.count_ones() as usize;
536 let non_empty_count = depth.saturating_sub(empty_count);
537
538 prop::collection::vec(any::<Word>(), non_empty_count).prop_map(
539 move |nodes| SparseMerklePath::from_parts(mask, nodes).unwrap(),
540 )
541 })
542 })
543 .boxed()
544 }
545 }
546}
547
548#[cfg(test)]
551mod tests {
552 use alloc::vec::Vec;
553 use core::{
554 num::NonZero,
555 ops::{Deref, DerefMut},
556 };
557
558 use assert_matches::assert_matches;
559
560 use super::SparseMerklePath;
561 use crate::{
562 Felt, ONE, Word,
563 merkle::{
564 EmptySubtreeRoots, MerkleError, MerklePath, MerkleTree, NodeIndex,
565 smt::{LeafIndex, SMT_MAX_DEPTH, SimpleSmt, Smt, SparseMerkleTreeReader},
566 sparse_path::path_depth_iter,
567 },
568 };
569
570 #[test]
573 fn from_parts_rejects_depths_beyond_max_including_wrapped_ones() {
574 let node = Word::from([ONE, ONE, ONE, ONE]);
575 for len in [65usize, 256, 300] {
576 let result = SparseMerklePath::from_parts(0, vec![node; len]);
577 assert_matches!(result, Err(MerkleError::DepthTooBig(depth)) if depth == len as u64);
578 }
579 }
580
581 #[test]
583 fn from_sized_iter_rejects_depths_beyond_max_including_wrapped_ones() {
584 let node = Word::from([ONE, ONE, ONE, ONE]);
585 for len in [65usize, 256] {
586 let result = SparseMerklePath::from_sized_iter(vec![node; len]);
587 assert_matches!(result, Err(MerkleError::DepthTooBig(depth)) if depth == len as u64);
588 }
589 }
590
591 #[test]
595 fn deserialization_rejects_mask_bits_beyond_the_declared_depth() {
596 use crate::utils::{ByteWriter, Deserializable, Serializable};
597
598 let mut bytes = Vec::new();
599 bytes.write_u8(2);
600 bytes.write_u64(1u64 << 63);
601 Word::from([ONE, ONE, ONE, ONE]).write_into(&mut bytes);
602 assert!(SparseMerklePath::read_from_bytes(&bytes).is_err());
603 }
604
605 #[test]
606 fn binary_serialization_roundtrips_valid_boundary_paths() {
607 use crate::utils::{Deserializable, Serializable};
608
609 let node = Word::from([ONE, ONE, ONE, ONE]);
610 for (depth, empty_nodes_mask) in [
611 (0u8, 0u64),
612 (1, 0),
613 (1, 1),
614 (64, 0),
615 (64, 1u64 << 63),
616 (64, 0xaaaa_aaaa_aaaa_aaaa),
617 (64, u64::MAX),
618 ] {
619 let node_count = depth as usize - empty_nodes_mask.count_ones() as usize;
620 let path =
621 SparseMerklePath::from_parts(empty_nodes_mask, vec![node; node_count]).unwrap();
622
623 let decoded = SparseMerklePath::read_from_bytes(&path.to_bytes()).unwrap();
624 assert_eq!(decoded, path);
625 assert_eq!(decoded.depth(), depth);
626 }
627 }
628
629 fn make_smt(pair_count: u64) -> Smt {
630 let entries: Vec<(Word, Word)> = (0..pair_count)
631 .map(|n| {
632 let leaf_index = ((n as f64 / pair_count as f64) * 255.0) as u64;
633 let key =
634 Word::new([ONE, ONE, Felt::new_unchecked(n), Felt::new_unchecked(leaf_index)]);
635 let value = Word::new([ONE, ONE, ONE, ONE]);
636 (key, value)
637 })
638 .collect();
639
640 Smt::with_entries(entries).unwrap()
641 }
642
643 #[test]
649 fn test_sparse_bits() {
650 const DEPTH: u8 = 8;
651 let raw_nodes: [Word; DEPTH as usize] = [
652 ([8u8, 8, 8, 8].into()),
654 *EmptySubtreeRoots::entry(DEPTH, 7),
656 *EmptySubtreeRoots::entry(DEPTH, 6),
658 [5u8, 5, 5, 5].into(),
660 [4u8, 4, 4, 4].into(),
662 *EmptySubtreeRoots::entry(DEPTH, 3),
664 *EmptySubtreeRoots::entry(DEPTH, 2),
666 *EmptySubtreeRoots::entry(DEPTH, 1),
668 ];
670
671 let sparse_nodes: [Option<Word>; DEPTH as usize] = [
672 Some([8u8, 8, 8, 8].into()),
674 None,
676 None,
678 Some([5u8, 5, 5, 5].into()),
680 Some([4u8, 4, 4, 4].into()),
682 None,
684 None,
686 None,
688 ];
690
691 const EMPTY_BITS: u64 = 0b0110_0111;
692
693 let sparse_path = SparseMerklePath::from_sized_iter(raw_nodes).unwrap();
694
695 assert_eq!(sparse_path.empty_nodes_mask, EMPTY_BITS);
696
697 let mut nonempty_idx = 0;
699
700 for depth in (1..=8).rev() {
702 let idx = (sparse_path.depth() - depth) as usize;
703 let bit = 1 << (depth - 1);
704
705 let is_set = (sparse_path.empty_nodes_mask & bit) != 0;
707 assert_eq!(is_set, sparse_nodes.get(idx).unwrap().is_none());
708
709 if is_set {
710 let &test_node = sparse_nodes.get(idx).unwrap();
712 assert_eq!(test_node, None);
713 } else {
714 let control_node = raw_nodes.get(idx).unwrap();
716 assert_eq!(
717 sparse_path.get_nonempty_index(NonZero::new(depth).unwrap()).unwrap(),
718 nonempty_idx
719 );
720 let test_node = sparse_path.nodes.get(nonempty_idx).unwrap();
721 assert_eq!(test_node, control_node);
722
723 nonempty_idx += 1;
724 }
725 }
726 }
727
728 #[test]
729 fn from_parts() {
730 const DEPTH: u8 = 8;
731 let raw_nodes: [Word; DEPTH as usize] = [
732 ([8u8, 8, 8, 8].into()),
734 *EmptySubtreeRoots::entry(DEPTH, 7),
736 *EmptySubtreeRoots::entry(DEPTH, 6),
738 [5u8, 5, 5, 5].into(),
740 [4u8, 4, 4, 4].into(),
742 *EmptySubtreeRoots::entry(DEPTH, 3),
744 *EmptySubtreeRoots::entry(DEPTH, 2),
746 *EmptySubtreeRoots::entry(DEPTH, 1),
748 ];
750
751 let empty_nodes_mask = 0b0110_0111;
752 let nodes = vec![[8u8, 8, 8, 8].into(), [5u8, 5, 5, 5].into(), [4u8, 4, 4, 4].into()];
753 let insufficient_nodes = vec![[4u8, 4, 4, 4].into()];
754
755 let error = SparseMerklePath::from_parts(empty_nodes_mask, insufficient_nodes).unwrap_err();
756 assert_matches!(error, MerkleError::InvalidPathLength(2));
757
758 let iter_sparse_path = SparseMerklePath::from_sized_iter(raw_nodes).unwrap();
759 let sparse_path = SparseMerklePath::from_parts(empty_nodes_mask, nodes).unwrap();
760
761 assert_eq!(sparse_path, iter_sparse_path);
762 }
763
764 #[test]
765 fn from_sized_iter() {
766 let tree = make_smt(8192);
767
768 for (key, _value) in tree.entries() {
769 let index = NodeIndex::from(Smt::key_to_leaf_index(key));
770 let sparse_path = tree.get_path(key);
771 for (sparse_node, proof_idx) in
772 itertools::zip_eq(sparse_path.clone(), index.proof_indices())
773 {
774 let proof_node = tree.get_node_hash(proof_idx);
775 assert_eq!(sparse_node, proof_node);
776 }
777 }
778 }
779
780 #[test]
781 fn test_zero_sized() {
782 let nodes: Vec<Word> = Default::default();
783
784 let sparse_path = SparseMerklePath::from_sized_iter(nodes).unwrap();
786 assert_eq!(sparse_path.depth(), 0);
787 assert_matches!(
788 sparse_path.at_depth(NonZero::new(1).unwrap()),
789 Err(MerkleError::DepthTooBig(1))
790 );
791 assert_eq!(sparse_path.iter().next(), None);
792 assert_eq!(sparse_path.into_iter().next(), None);
793 }
794
795 use proptest::prelude::*;
796
797 proptest! {
798 #[test]
799 fn sparse_merkle_path_roundtrip_equivalence(path in any::<MerklePath>()) {
800 let sparse_result = SparseMerklePath::try_from(path.clone());
802 if path.depth() <= SMT_MAX_DEPTH {
803 let sparse = sparse_result.unwrap();
804 let reconstructed = MerklePath::from(sparse);
805 prop_assert_eq!(path, reconstructed);
806 } else {
807 prop_assert!(sparse_result.is_err());
808 }
809 }
810 }
811 proptest! {
812
813 #[test]
814 fn merkle_path_roundtrip_equivalence(sparse in any::<SparseMerklePath>()) {
815 let merkle = MerklePath::from(sparse.clone());
817 let reconstructed = SparseMerklePath::try_from(merkle).unwrap();
818 prop_assert_eq!(sparse, reconstructed);
819 }
820 }
821 proptest! {
822
823 #[test]
824 fn path_equivalence_tests(path in any::<MerklePath>(), path2 in any::<MerklePath>()) {
825 if path.depth() > SMT_MAX_DEPTH {
826 return Ok(());
827 }
828
829 let sparse = SparseMerklePath::try_from(path.clone()).unwrap();
830
831 prop_assert_eq!(path.depth(), sparse.depth());
833
834 if path.depth() > 0 {
836 for depth in path_depth_iter(path.depth()) {
837 let merkle_node = path.at_depth(depth);
838 let sparse_node = sparse.at_depth(depth);
839
840 match (merkle_node, sparse_node) {
841 (Some(m), Ok(s)) => prop_assert_eq!(m, s),
842 (None, Err(_)) => {},
843 _ => prop_assert!(false, "Inconsistent node access at depth {}", depth.get()),
844 }
845 }
846 }
847
848 if path.depth() > 0 {
850 let merkle_nodes: Vec<_> = path.iter().collect();
851 let sparse_nodes: Vec<_> = sparse.iter().collect();
852
853 prop_assert_eq!(merkle_nodes.len(), sparse_nodes.len());
854 for (m, s) in merkle_nodes.iter().zip(sparse_nodes.iter()) {
855 prop_assert_eq!(*m, s);
856 }
857 }
858
859 if path2.depth() <= SMT_MAX_DEPTH {
861 let sparse2 = SparseMerklePath::try_from(path2.clone()).unwrap();
862 prop_assert_eq!(path == path2, sparse == sparse2);
863 prop_assert_eq!(path == sparse2, sparse == path2);
864 }
865 }
866 }
867 proptest! {
869 #![proptest_config(ProptestConfig::with_cases(100))]
870
871 #[test]
872 fn compute_root_consistency(
873 tree_data in any::<RandomMerkleTree>(),
874 node in any::<Word>()
875 ) {
876 let RandomMerkleTree { tree, leaves: _, indices } = tree_data;
877
878 for &leaf_index in indices.iter() {
879 let path = tree.get_path(NodeIndex::new(tree.depth(), leaf_index).unwrap()).unwrap();
880 let sparse = SparseMerklePath::from_sized_iter(path.clone().into_iter()).unwrap();
881
882 let merkle_root = path.compute_root(leaf_index, node);
883 let sparse_root = sparse.compute_root(leaf_index, node);
884
885 match (merkle_root, sparse_root) {
886 (Ok(m), Ok(s)) => prop_assert_eq!(m, s),
887 (Err(e1), Err(e2)) => {
888 prop_assert_eq!(format!("{:?}", e1), format!("{:?}", e2));
890 },
891 _ => prop_assert!(false, "Inconsistent compute_root results"),
892 }
893 }
894 }
895
896 #[test]
897 fn verify_consistency(
898 tree_data in any::<RandomMerkleTree>(),
899 node in any::<Word>()
900 ) {
901 let RandomMerkleTree { tree, leaves, indices } = tree_data;
902
903 for (i, &leaf_index) in indices.iter().enumerate() {
904 let leaf = leaves[i];
905 let path = tree.get_path(NodeIndex::new(tree.depth(), leaf_index).unwrap()).unwrap();
906 let sparse = SparseMerklePath::from_sized_iter(path.clone().into_iter()).unwrap();
907
908 let root = tree.root();
909
910 let merkle_verify = path.verify(leaf_index, leaf, &root);
911 let sparse_verify = sparse.verify(leaf_index, leaf, &root);
912
913 match (merkle_verify, sparse_verify) {
914 (Ok(()), Ok(())) => {},
915 (Err(e1), Err(e2)) => {
916 prop_assert_eq!(format!("{:?}", e1), format!("{:?}", e2));
918 },
919 _ => prop_assert!(false, "Inconsistent verify results"),
920 }
921
922 let wrong_verify = path.verify(leaf_index, node, &root);
924 let wrong_sparse_verify = sparse.verify(leaf_index, node, &root);
925
926 match (wrong_verify, wrong_sparse_verify) {
927 (Ok(()), Ok(())) => prop_assert!(false, "Verification should have failed with wrong node"),
928 (Err(_), Err(_)) => {},
929 _ => prop_assert!(false, "Inconsistent verification results with wrong node"),
930 }
931 }
932 }
933
934 #[test]
935 fn authenticated_nodes_consistency(
936 tree_data in any::<RandomMerkleTree>()
937 ) {
938 let RandomMerkleTree { tree, leaves, indices } = tree_data;
939
940 for (i, &leaf_index) in indices.iter().enumerate() {
941 let leaf = leaves[i];
942 let path = tree.get_path(NodeIndex::new(tree.depth(), leaf_index).unwrap()).unwrap();
943 let sparse = SparseMerklePath::from_sized_iter(path.clone().into_iter()).unwrap();
944
945 let merkle_result = path.authenticated_nodes(leaf_index, leaf);
946 let sparse_result = sparse.authenticated_nodes(leaf_index, leaf);
947
948 match (merkle_result, sparse_result) {
949 (Ok(m_iter), Ok(s_iter)) => {
950 let merkle_nodes: Vec<_> = m_iter.collect();
951 let sparse_nodes: Vec<_> = s_iter.collect();
952 prop_assert_eq!(merkle_nodes.len(), sparse_nodes.len());
953 for (m, s) in merkle_nodes.iter().zip(sparse_nodes.iter()) {
954 prop_assert_eq!(m, s);
955 }
956 },
957 (Err(e1), Err(e2)) => {
958 prop_assert_eq!(format!("{:?}", e1), format!("{:?}", e2));
959 },
960 _ => prop_assert!(false, "Inconsistent authenticated_nodes results"),
961 }
962 }
963 }
964 }
965
966 #[test]
967 fn test_api_differences() {
968 fn assert_slice_deref<T>()
973 where
974 T: Deref<Target = [Word]> + DerefMut<Target = [Word]>,
975 {
976 }
977
978 assert_slice_deref::<MerklePath>();
979 let mut merkle = MerklePath::new(vec![Word::default(); 3]);
980 let replacement = Word::from([ONE, ONE, ONE, ONE]);
981 let nodes: &mut [Word] = &mut merkle;
982 nodes[0] = replacement;
983 assert_eq!(merkle[0], replacement);
984 assert_eq!(merkle.depth(), 3);
985
986 let sparse = SparseMerklePath::from_parts(0b101, vec![Word::default(); 2]).unwrap();
988 assert_eq!(sparse.depth(), 4); let nodes = vec![Word::default(); 3];
992 let sparse_from_iter = SparseMerklePath::from_sized_iter(nodes.clone()).unwrap();
993 let merkle_from_iter = MerklePath::from_iter(nodes);
994 assert_eq!(sparse_from_iter.depth(), merkle_from_iter.depth());
995 }
996
997 #[derive(Debug, Clone)]
999 struct RandomMerkleTree {
1000 tree: MerkleTree,
1001 leaves: Vec<Word>,
1002 indices: Vec<u64>,
1003 }
1004
1005 impl Arbitrary for RandomMerkleTree {
1006 type Parameters = ();
1007 type Strategy = BoxedStrategy<Self>;
1008
1009 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
1010 prop::sample::select(&[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024])
1012 .prop_flat_map(|num_leaves| {
1013 prop::collection::vec(any::<Word>(), num_leaves).prop_map(|leaves| {
1014 let tree = MerkleTree::new(leaves.clone()).unwrap();
1015 let indices: Vec<u64> = (0..leaves.len() as u64).collect();
1016 RandomMerkleTree { tree, leaves, indices }
1017 })
1018 })
1019 .boxed()
1020 }
1021 }
1022
1023 #[derive(Debug, Clone)]
1025 struct RandomSimpleSmt {
1026 tree: SimpleSmt<10>, entries: Vec<(u64, Word)>,
1028 }
1029
1030 impl Arbitrary for RandomSimpleSmt {
1031 type Parameters = ();
1032 type Strategy = BoxedStrategy<Self>;
1033
1034 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
1035 (1..=100usize) .prop_flat_map(|num_entries| {
1037 prop::collection::vec(
1038 (
1039 0..1024u64, any::<Word>(),
1041 ),
1042 num_entries,
1043 )
1044 .prop_map(|mut entries| {
1045 let mut seen = alloc::collections::BTreeSet::new();
1047 entries.retain(|(idx, _)| seen.insert(*idx));
1048
1049 let mut tree = SimpleSmt::new().unwrap();
1050 for (idx, value) in &entries {
1051 let leaf_idx = LeafIndex::new(*idx).unwrap();
1052 tree.insert(leaf_idx, *value);
1053 }
1054 RandomSimpleSmt { tree, entries }
1055 })
1056 })
1057 .boxed()
1058 }
1059 }
1060
1061 #[derive(Debug, Clone)]
1063 struct RandomSmt {
1064 tree: Smt,
1065 entries: Vec<(Word, Word)>,
1066 }
1067
1068 impl Arbitrary for RandomSmt {
1069 type Parameters = ();
1070 type Strategy = BoxedStrategy<Self>;
1071
1072 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
1073 (1..=100usize) .prop_flat_map(|num_entries| {
1075 prop::collection::vec((any::<u64>(), any::<Word>()), num_entries).prop_map(
1076 |indices_n_values| {
1077 let mut seen = alloc::collections::BTreeSet::new();
1079 let unique_entries: Vec<(Word, Word)> = indices_n_values
1080 .into_iter()
1081 .enumerate()
1082 .map(|(n, (leaf_index, value))| {
1083 let valid_leaf_index = leaf_index % (1u64 << 60); let key = Word::new([
1087 Felt::new_unchecked(n as u64), Felt::new_unchecked(n as u64 + 1), Felt::new_unchecked(n as u64 + 2), Felt::new_unchecked(valid_leaf_index), ]);
1092 (key, value)
1093 })
1094 .filter(|(key, _)| seen.insert(*key))
1095 .collect();
1096
1097 let tree = Smt::with_entries(unique_entries.clone()).unwrap();
1098 RandomSmt { tree, entries: unique_entries }
1099 },
1100 )
1101 })
1102 .boxed()
1103 }
1104 }
1105
1106 proptest! {
1107 #![proptest_config(ProptestConfig::with_cases(20))]
1108
1109 #[test]
1110 fn simple_smt_path_consistency(tree_data in any::<RandomSimpleSmt>()) {
1111 let RandomSimpleSmt { tree, entries } = tree_data;
1112
1113 for (leaf_index, value) in &entries {
1114 let merkle_path = tree.get_path(&LeafIndex::new(*leaf_index).unwrap());
1115 let sparse_path = SparseMerklePath::from_sized_iter(merkle_path.clone().into_iter()).unwrap();
1116
1117 prop_assert_eq!(merkle_path.depth(), sparse_path.depth());
1119
1120 let merkle_root = merkle_path.compute_root(*leaf_index, *value).unwrap();
1122 let sparse_root = sparse_path.compute_root(*leaf_index, *value).unwrap();
1123 prop_assert_eq!(merkle_root, sparse_root);
1124
1125 let tree_root = tree.root();
1127 prop_assert!(merkle_path.verify(*leaf_index, *value, &tree_root).is_ok());
1128 prop_assert!(sparse_path.verify(*leaf_index, *value, &tree_root).is_ok());
1129
1130 let random_leaf = Word::new([Felt::ONE; 4]);
1132 let random_index = *leaf_index ^ 1; let merkle_wrong = merkle_path.verify(random_index, random_leaf, &tree_root);
1136 let sparse_wrong = sparse_path.verify(random_index, random_leaf, &tree_root);
1137 prop_assert_eq!(merkle_wrong.is_err(), sparse_wrong.is_err());
1138 }
1139 }
1140
1141 #[test]
1142 fn smt_path_consistency(tree_data in any::<RandomSmt>()) {
1143 let RandomSmt { tree, entries } = tree_data;
1144
1145 for (key, _value) in &entries {
1146 let (merkle_path, leaf) = tree.open(key).into_parts();
1147 let sparse_path = SparseMerklePath::from_sized_iter(merkle_path.clone().into_iter()).unwrap();
1148
1149 let leaf_index = Smt::key_to_leaf_index(key).position();
1150 let actual_value = leaf.hash(); prop_assert_eq!(merkle_path.depth(), sparse_path.depth());
1154
1155 let merkle_root = merkle_path.compute_root(leaf_index, actual_value).unwrap();
1157 let sparse_root = sparse_path.compute_root(leaf_index, actual_value).unwrap();
1158 prop_assert_eq!(merkle_root, sparse_root);
1159
1160 let tree_root = tree.root();
1162 prop_assert!(merkle_path.verify(leaf_index, actual_value, &tree_root).is_ok());
1163 prop_assert!(sparse_path.verify(leaf_index, actual_value, &tree_root).is_ok());
1164
1165 let merkle_auth = merkle_path.authenticated_nodes(leaf_index, actual_value).unwrap().collect::<Vec<_>>();
1167 let sparse_auth = sparse_path.authenticated_nodes(leaf_index, actual_value).unwrap().collect::<Vec<_>>();
1168 prop_assert_eq!(merkle_auth, sparse_auth);
1169 }
1170 }
1171
1172 #[test]
1173 fn reverse_conversion_from_sparse(tree_data in any::<RandomMerkleTree>()) {
1174 let RandomMerkleTree { tree, leaves, indices } = tree_data;
1175
1176 for (i, &leaf_index) in indices.iter().enumerate() {
1177 let leaf = leaves[i];
1178 let merkle_path = tree.get_path(NodeIndex::new(tree.depth(), leaf_index).unwrap()).unwrap();
1179
1180 let sparse_path = SparseMerklePath::from_sized_iter(merkle_path.clone().into_iter()).unwrap();
1182 let converted_merkle = MerklePath::from(sparse_path.clone());
1183
1184 let back_to_sparse = SparseMerklePath::try_from(converted_merkle.clone()).unwrap();
1186 prop_assert_eq!(sparse_path, back_to_sparse);
1187
1188 prop_assert_eq!(merkle_path.depth(), converted_merkle.depth());
1190
1191 let merkle_root = merkle_path.compute_root(leaf_index, leaf).unwrap();
1192 let converted_root = converted_merkle.compute_root(leaf_index, leaf).unwrap();
1193 prop_assert_eq!(merkle_root, converted_root);
1194 }
1195 }
1196 }
1197}