miden_crypto/merkle/
sparse_path.rs

1use alloc::{borrow::Cow, vec::Vec};
2use core::{
3    iter::{self, FusedIterator},
4    num::NonZero,
5};
6
7use winter_utils::{Deserializable, DeserializationError, Serializable};
8
9use super::{
10    EmptySubtreeRoots, InnerNodeInfo, MerkleError, MerklePath, NodeIndex, Word, smt::SMT_MAX_DEPTH,
11};
12use crate::hash::rpo::Rpo256;
13
14/// A different representation of [`MerklePath`] designed for memory efficiency for Merkle paths
15/// with empty nodes.
16///
17/// Empty nodes in the path are stored only as their position, represented with a bitmask. A
18/// maximum of 64 nodes (`SMT_MAX_DEPTH`) can be stored (empty and non-empty). The more nodes in a
19/// path are empty, the less memory this struct will use. This type calculates empty nodes on-demand
20/// when iterated through, converted to a [MerklePath], or an empty node is retrieved with
21/// [`SparseMerklePath::at_depth()`], which will incur overhead.
22///
23/// NOTE: This type assumes that Merkle paths always span from the root of the tree to a leaf.
24/// Partial paths are not supported.
25#[derive(Clone, Debug, Default, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
27pub struct SparseMerklePath {
28    /// A bitmask representing empty nodes. The set bit corresponds to the depth of an empty node.
29    /// The least significant bit (bit 0) describes depth 1 node (root's children).
30    /// The `bit index + 1` is equal to node's depth.
31    empty_nodes_mask: u64,
32    /// The non-empty nodes, stored in depth-order, but not contiguous across depth.
33    nodes: Vec<Word>,
34}
35
36impl SparseMerklePath {
37    /// Constructs a new sparse Merkle path from a bitmask of empty nodes and a vector of non-empty
38    /// nodes.
39    ///
40    /// The `empty_nodes_mask` is a bitmask where each set bit indicates that the node at that
41    /// depth is empty. The least significant bit (bit 0) describes depth 1 node (root's children).
42    /// The `bit index + 1` is equal to node's depth.
43    /// The `nodes` vector must contain the non-empty nodes in depth order.
44    ///
45    /// # Errors
46    /// - [MerkleError::InvalidPathLength] if the provided `nodes` vector is shorter than the
47    ///   minimum length required by the `empty_nodes_mask`.
48    /// - [MerkleError::DepthTooBig] if the total depth of the path (calculated from the
49    ///   `empty_nodes_mask` and `nodes`) is greater than [SMT_MAX_DEPTH].
50    pub fn from_parts(empty_nodes_mask: u64, nodes: Vec<Word>) -> Result<Self, MerkleError> {
51        // The most significant set bit in the mask marks the minimum length of the path.
52        // For every zero bit before the first set bit, there must be a corresponding node in
53        // `nodes`.
54        // For example, if the mask is `0b1100`, this means that the first two nodes
55        // (depths 1 and 2) are non-empty, and the next two nodes (depths 3 and 4) are empty.
56        // The minimum length of the path is 4, and the `nodes` vector must contain at least 2
57        // nodes to account for the first two zeroes in the mask (depths 1 and 2).
58        let min_path_len = u64::BITS - empty_nodes_mask.leading_zeros();
59        let empty_nodes_count = empty_nodes_mask.count_ones();
60        let min_non_empty_nodes = (min_path_len - empty_nodes_count) as usize;
61
62        if nodes.len() < min_non_empty_nodes {
63            return Err(MerkleError::InvalidPathLength(min_non_empty_nodes));
64        }
65
66        let depth = Self::depth_from_parts(empty_nodes_mask, &nodes) as u8;
67        if depth > SMT_MAX_DEPTH {
68            return Err(MerkleError::DepthTooBig(depth as u64));
69        }
70
71        Ok(Self { empty_nodes_mask, nodes })
72    }
73
74    /// Constructs a sparse Merkle path from an iterator over Merkle nodes that also knows its
75    /// exact size (such as iterators created with [Vec::into_iter]). The iterator must be in order
76    /// of deepest to shallowest.
77    ///
78    /// Knowing the size is necessary to calculate the depth of the tree, which is needed to detect
79    /// which nodes are empty nodes.
80    ///
81    /// # Errors
82    /// Returns [MerkleError::DepthTooBig] if `tree_depth` is greater than [SMT_MAX_DEPTH].
83    pub fn from_sized_iter<I>(iterator: I) -> Result<Self, MerkleError>
84    where
85        I: IntoIterator<IntoIter: ExactSizeIterator, Item = Word>,
86    {
87        let iterator = iterator.into_iter();
88        let tree_depth = iterator.len() as u8;
89
90        if tree_depth > SMT_MAX_DEPTH {
91            return Err(MerkleError::DepthTooBig(tree_depth as u64));
92        }
93
94        let mut empty_nodes_mask: u64 = 0;
95        let mut nodes: Vec<Word> = Default::default();
96
97        for (depth, node) in iter::zip(path_depth_iter(tree_depth), iterator) {
98            let &equivalent_empty_node = EmptySubtreeRoots::entry(tree_depth, depth.get());
99            let is_empty = node == equivalent_empty_node;
100            let node = if is_empty { None } else { Some(node) };
101
102            match node {
103                Some(node) => nodes.push(node),
104                None => empty_nodes_mask |= Self::bitmask_for_depth(depth),
105            }
106        }
107
108        Ok(SparseMerklePath { nodes, empty_nodes_mask })
109    }
110
111    /// Returns the total depth of this path, i.e., the number of nodes this path represents.
112    pub fn depth(&self) -> u8 {
113        Self::depth_from_parts(self.empty_nodes_mask, &self.nodes) as u8
114    }
115
116    /// Get a specific node in this path at a given depth.
117    ///
118    /// The `depth` parameter is defined in terms of `self.depth()`. Merkle paths conventionally do
119    /// not include the root, so the shallowest depth is `1`, and the deepest depth is
120    /// `self.depth()`.
121    ///
122    /// # Errors
123    /// Returns [MerkleError::DepthTooBig] if `node_depth` is greater than the total depth of this
124    /// path.
125    pub fn at_depth(&self, node_depth: NonZero<u8>) -> Result<Word, MerkleError> {
126        if node_depth.get() > self.depth() {
127            return Err(MerkleError::DepthTooBig(node_depth.get().into()));
128        }
129
130        let node = if let Some(nonempty_index) = self.get_nonempty_index(node_depth) {
131            self.nodes[nonempty_index]
132        } else {
133            *EmptySubtreeRoots::entry(self.depth(), node_depth.get())
134        };
135
136        Ok(node)
137    }
138
139    /// Deconstructs this path into its component parts.
140    ///
141    /// Returns a tuple containing:
142    /// - a bitmask where each set bit indicates that the node at that depth is empty. The least
143    ///   significant bit (bit 0) describes depth 1 node (root's children).
144    /// - a vector of non-empty nodes in depth order.
145    pub fn into_parts(self) -> (u64, Vec<Word>) {
146        (self.empty_nodes_mask, self.nodes)
147    }
148
149    // PROVIDERS
150    // ============================================================================================
151
152    /// Constructs a borrowing iterator over the nodes in this path.
153    /// Starts from the leaf and iterates toward the root (excluding the root).
154    pub fn iter(&self) -> impl ExactSizeIterator<Item = Word> {
155        self.into_iter()
156    }
157
158    /// Computes the Merkle root for this opening.
159    pub fn compute_root(&self, index: u64, node_to_prove: Word) -> Result<Word, MerkleError> {
160        let mut index = NodeIndex::new(self.depth(), index)?;
161        let root = self.iter().fold(node_to_prove, |node, sibling| {
162            // Compute the node and move to the next iteration.
163            let children = index.build_node(node, sibling);
164            index.move_up();
165            Rpo256::merge(&children)
166        });
167
168        Ok(root)
169    }
170
171    /// Verifies the Merkle opening proof towards the provided root.
172    ///
173    /// # Errors
174    /// Returns an error if:
175    /// - provided node index is invalid.
176    /// - root calculated during the verification differs from the provided one.
177    pub fn verify(&self, index: u64, node: Word, &expected_root: &Word) -> Result<(), MerkleError> {
178        let computed_root = self.compute_root(index, node)?;
179        if computed_root != expected_root {
180            return Err(MerkleError::ConflictingRoots {
181                expected_root,
182                actual_root: computed_root,
183            });
184        }
185
186        Ok(())
187    }
188
189    /// Given the node this path opens to, return an iterator of all the nodes that are known via
190    /// this path.
191    ///
192    /// Each item in the iterator is an [InnerNodeInfo], containing the hash of a node as `.value`,
193    /// and its two children as `.left` and `.right`. The very first item in that iterator will be
194    /// the parent of `node_to_prove` as stored in this [SparseMerklePath].
195    ///
196    /// From there, the iterator will continue to yield every further parent and both of its
197    /// children, up to and including the root node.
198    ///
199    /// If `node_to_prove` is not the node this path is an opening to, or `index` is not the
200    /// correct index for that node, the returned nodes will be meaningless.
201    ///
202    /// # Errors
203    /// Returns an error if the specified index is not valid for this path.
204    pub fn authenticated_nodes(
205        &self,
206        index: u64,
207        node_to_prove: Word,
208    ) -> Result<InnerNodeIterator<'_>, MerkleError> {
209        let index = NodeIndex::new(self.depth(), index)?;
210        Ok(InnerNodeIterator { path: self, index, value: node_to_prove })
211    }
212
213    // PRIVATE HELPERS
214    // ============================================================================================
215
216    const fn bitmask_for_depth(node_depth: NonZero<u8>) -> u64 {
217        // - 1 because paths do not include the root.
218        1 << (node_depth.get() - 1)
219    }
220
221    const fn is_depth_empty(&self, node_depth: NonZero<u8>) -> bool {
222        (self.empty_nodes_mask & Self::bitmask_for_depth(node_depth)) != 0
223    }
224
225    /// Index of the non-empty node in the `self.nodes` vector. If the specified depth is
226    /// empty, None is returned.
227    fn get_nonempty_index(&self, node_depth: NonZero<u8>) -> Option<usize> {
228        if self.is_depth_empty(node_depth) {
229            return None;
230        }
231
232        let bit_index = node_depth.get() - 1;
233        let without_shallower = self.empty_nodes_mask >> bit_index;
234        let empty_deeper = without_shallower.count_ones() as usize;
235        // The vec index we would use if we didn't have any empty nodes to account for...
236        let normal_index = (self.depth() - node_depth.get()) as usize;
237        // subtracted by the number of empty nodes that are deeper than us.
238        Some(normal_index - empty_deeper)
239    }
240
241    /// Returns the total depth of this path from its parts.
242    fn depth_from_parts(empty_nodes_mask: u64, nodes: &[Word]) -> usize {
243        nodes.len() + empty_nodes_mask.count_ones() as usize
244    }
245}
246
247// SERIALIZATION
248// ================================================================================================
249
250impl Serializable for SparseMerklePath {
251    fn write_into<W: winter_utils::ByteWriter>(&self, target: &mut W) {
252        target.write_u8(self.depth());
253        target.write_u64(self.empty_nodes_mask);
254        target.write_many(&self.nodes);
255    }
256}
257
258impl Deserializable for SparseMerklePath {
259    fn read_from<R: winter_utils::ByteReader>(
260        source: &mut R,
261    ) -> Result<Self, DeserializationError> {
262        let depth = source.read_u8()?;
263        if depth > SMT_MAX_DEPTH {
264            return Err(DeserializationError::InvalidValue(format!(
265                "SparseMerklePath max depth exceeded ({depth} > {SMT_MAX_DEPTH})",
266            )));
267        }
268        let empty_nodes_mask = source.read_u64()?;
269        let empty_nodes_count = empty_nodes_mask.count_ones();
270        if empty_nodes_count > depth as u32 {
271            return Err(DeserializationError::InvalidValue(format!(
272                "SparseMerklePath has more empty nodes ({empty_nodes_count}) than its full length ({depth})",
273            )));
274        }
275        let count = depth as u32 - empty_nodes_count;
276        let nodes = source.read_many::<Word>(count as usize)?;
277        Ok(Self { empty_nodes_mask, nodes })
278    }
279}
280
281// CONVERSIONS
282// ================================================================================================
283
284impl From<SparseMerklePath> for MerklePath {
285    fn from(sparse_path: SparseMerklePath) -> Self {
286        MerklePath::from_iter(sparse_path)
287    }
288}
289
290impl TryFrom<MerklePath> for SparseMerklePath {
291    type Error = MerkleError;
292
293    /// # Errors
294    ///
295    /// This conversion returns [MerkleError::DepthTooBig] if the path length is greater than
296    /// [`SMT_MAX_DEPTH`].
297    fn try_from(path: MerklePath) -> Result<Self, MerkleError> {
298        SparseMerklePath::from_sized_iter(path)
299    }
300}
301
302impl From<SparseMerklePath> for Vec<Word> {
303    fn from(path: SparseMerklePath) -> Self {
304        Vec::from_iter(path)
305    }
306}
307
308// ITERATORS
309// ================================================================================================
310
311/// Iterator for [`SparseMerklePath`]. Starts from the leaf and iterates toward the root (excluding
312/// the root).
313pub struct SparseMerklePathIter<'p> {
314    /// The "inner" value we're iterating over.
315    path: Cow<'p, SparseMerklePath>,
316
317    /// The depth a `next()` call will get. `next_depth == 0` indicates that the iterator has been
318    /// exhausted.
319    next_depth: u8,
320}
321
322impl Iterator for SparseMerklePathIter<'_> {
323    type Item = Word;
324
325    fn next(&mut self) -> Option<Word> {
326        let this_depth = self.next_depth;
327        // Paths don't include the root, so if `this_depth` is 0 then we keep returning `None`.
328        let this_depth = NonZero::new(this_depth)?;
329        self.next_depth = this_depth.get() - 1;
330
331        // `this_depth` is only ever decreasing, so it can't ever exceed `self.path.depth()`.
332        let node = self
333            .path
334            .at_depth(this_depth)
335            .expect("current depth should never exceed the path depth");
336        Some(node)
337    }
338
339    // SparseMerkleIter always knows its exact size.
340    fn size_hint(&self) -> (usize, Option<usize>) {
341        let remaining = ExactSizeIterator::len(self);
342        (remaining, Some(remaining))
343    }
344}
345
346impl ExactSizeIterator for SparseMerklePathIter<'_> {
347    fn len(&self) -> usize {
348        self.next_depth as usize
349    }
350}
351
352impl FusedIterator for SparseMerklePathIter<'_> {}
353
354// TODO: impl DoubleEndedIterator.
355
356impl IntoIterator for SparseMerklePath {
357    type IntoIter = SparseMerklePathIter<'static>;
358    type Item = <Self::IntoIter as Iterator>::Item;
359
360    fn into_iter(self) -> SparseMerklePathIter<'static> {
361        let tree_depth = self.depth();
362        SparseMerklePathIter {
363            path: Cow::Owned(self),
364            next_depth: tree_depth,
365        }
366    }
367}
368
369impl<'p> IntoIterator for &'p SparseMerklePath {
370    type Item = <SparseMerklePathIter<'p> as Iterator>::Item;
371    type IntoIter = SparseMerklePathIter<'p>;
372
373    fn into_iter(self) -> SparseMerklePathIter<'p> {
374        let tree_depth = self.depth();
375        SparseMerklePathIter {
376            path: Cow::Borrowed(self),
377            next_depth: tree_depth,
378        }
379    }
380}
381
382/// An iterator over nodes known by a [SparseMerklePath]. See
383/// [`SparseMerklePath::authenticated_nodes()`].
384pub struct InnerNodeIterator<'p> {
385    path: &'p SparseMerklePath,
386    index: NodeIndex,
387    value: Word,
388}
389
390impl Iterator for InnerNodeIterator<'_> {
391    type Item = InnerNodeInfo;
392
393    fn next(&mut self) -> Option<Self::Item> {
394        if self.index.is_root() {
395            return None;
396        }
397
398        let index_depth = NonZero::new(self.index.depth()).expect("non-root depth cannot be 0");
399        let path_node = self.path.at_depth(index_depth).unwrap();
400
401        let children = self.index.build_node(self.value, path_node);
402        self.value = Rpo256::merge(&children);
403        self.index.move_up();
404
405        Some(InnerNodeInfo {
406            value: self.value,
407            left: children[0],
408            right: children[1],
409        })
410    }
411}
412
413// COMPARISONS
414// ================================================================================================
415impl PartialEq<MerklePath> for SparseMerklePath {
416    fn eq(&self, rhs: &MerklePath) -> bool {
417        if self.depth() != rhs.depth() {
418            return false;
419        }
420
421        for (node, &rhs_node) in iter::zip(self, rhs.iter()) {
422            if node != rhs_node {
423                return false;
424            }
425        }
426
427        true
428    }
429}
430
431impl PartialEq<SparseMerklePath> for MerklePath {
432    fn eq(&self, rhs: &SparseMerklePath) -> bool {
433        rhs == self
434    }
435}
436
437// HELPERS
438// ================================================================================================
439
440/// Iterator for path depths, which start at the deepest part of the tree and go the shallowest
441/// depth before the root (depth 1).
442fn path_depth_iter(tree_depth: u8) -> impl ExactSizeIterator<Item = NonZero<u8>> {
443    let top_down_iter = (1..=tree_depth).map(|depth| {
444        // SAFETY: `RangeInclusive<1, _>` cannot ever yield 0. Even if `tree_depth` is 0, then the
445        // range is `RangeInclusive<1, 0>` will simply not yield any values, and this block won't
446        // even be reached.
447        unsafe { NonZero::new_unchecked(depth) }
448    });
449
450    // Reverse the top-down iterator to get a bottom-up iterator.
451    top_down_iter.rev()
452}
453
454// TESTS
455// ================================================================================================
456#[cfg(test)]
457mod tests {
458    use alloc::vec::Vec;
459    use core::num::NonZero;
460
461    use assert_matches::assert_matches;
462    use winter_math::FieldElement;
463
464    use super::SparseMerklePath;
465    use crate::{
466        Felt, ONE, Word,
467        merkle::{
468            EmptySubtreeRoots, MerkleError, MerklePath, MerkleTree, NodeIndex,
469            smt::{LeafIndex, SMT_MAX_DEPTH, SimpleSmt, Smt, SparseMerkleTree},
470            sparse_path::path_depth_iter,
471        },
472    };
473
474    fn make_smt(pair_count: u64) -> Smt {
475        let entries: Vec<(Word, Word)> = (0..pair_count)
476            .map(|n| {
477                let leaf_index = ((n as f64 / pair_count as f64) * 255.0) as u64;
478                let key = Word::new([ONE, ONE, Felt::new(n), Felt::new(leaf_index)]);
479                let value = Word::new([ONE, ONE, ONE, ONE]);
480                (key, value)
481            })
482            .collect();
483
484        Smt::with_entries(entries).unwrap()
485    }
486
487    /// Manually test the exact bit patterns for a sample path of 8 nodes, including both empty and
488    /// non-empty nodes.
489    ///
490    /// This also offers an overview of what each part of the bit-math involved means and
491    /// represents.
492    #[test]
493    fn test_sparse_bits() {
494        const DEPTH: u8 = 8;
495        let raw_nodes: [Word; DEPTH as usize] = [
496            // Depth 8.
497            ([8u8, 8, 8, 8].into()),
498            // Depth 7.
499            *EmptySubtreeRoots::entry(DEPTH, 7),
500            // Depth 6.
501            *EmptySubtreeRoots::entry(DEPTH, 6),
502            // Depth 5.
503            [5u8, 5, 5, 5].into(),
504            // Depth 4.
505            [4u8, 4, 4, 4].into(),
506            // Depth 3.
507            *EmptySubtreeRoots::entry(DEPTH, 3),
508            // Depth 2.
509            *EmptySubtreeRoots::entry(DEPTH, 2),
510            // Depth 1.
511            *EmptySubtreeRoots::entry(DEPTH, 1),
512            // Root is not included.
513        ];
514
515        let sparse_nodes: [Option<Word>; DEPTH as usize] = [
516            // Depth 8.
517            Some([8u8, 8, 8, 8].into()),
518            // Depth 7.
519            None,
520            // Depth 6.
521            None,
522            // Depth 5.
523            Some([5u8, 5, 5, 5].into()),
524            // Depth 4.
525            Some([4u8, 4, 4, 4].into()),
526            // Depth 3.
527            None,
528            // Depth 2.
529            None,
530            // Depth 1.
531            None,
532            // Root is not included.
533        ];
534
535        const EMPTY_BITS: u64 = 0b0110_0111;
536
537        let sparse_path = SparseMerklePath::from_sized_iter(raw_nodes).unwrap();
538
539        assert_eq!(sparse_path.empty_nodes_mask, EMPTY_BITS);
540
541        // Keep track of how many non-empty nodes we have seen
542        let mut nonempty_idx = 0;
543
544        // Test starting from the deepest nodes (depth 8)
545        for depth in (1..=8).rev() {
546            let idx = (sparse_path.depth() - depth) as usize;
547            let bit = 1 << (depth - 1);
548
549            // Check that the depth bit is set correctly...
550            let is_set = (sparse_path.empty_nodes_mask & bit) != 0;
551            assert_eq!(is_set, sparse_nodes.get(idx).unwrap().is_none());
552
553            if is_set {
554                // Check that we don't return digests for empty nodes
555                let &test_node = sparse_nodes.get(idx).unwrap();
556                assert_eq!(test_node, None);
557            } else {
558                // Check that we can calculate non-empty indices correctly.
559                let control_node = raw_nodes.get(idx).unwrap();
560                assert_eq!(
561                    sparse_path.get_nonempty_index(NonZero::new(depth).unwrap()).unwrap(),
562                    nonempty_idx
563                );
564                let test_node = sparse_path.nodes.get(nonempty_idx).unwrap();
565                assert_eq!(test_node, control_node);
566
567                nonempty_idx += 1;
568            }
569        }
570    }
571
572    #[test]
573    fn from_parts() {
574        const DEPTH: u8 = 8;
575        let raw_nodes: [Word; DEPTH as usize] = [
576            // Depth 8.
577            ([8u8, 8, 8, 8].into()),
578            // Depth 7.
579            *EmptySubtreeRoots::entry(DEPTH, 7),
580            // Depth 6.
581            *EmptySubtreeRoots::entry(DEPTH, 6),
582            // Depth 5.
583            [5u8, 5, 5, 5].into(),
584            // Depth 4.
585            [4u8, 4, 4, 4].into(),
586            // Depth 3.
587            *EmptySubtreeRoots::entry(DEPTH, 3),
588            // Depth 2.
589            *EmptySubtreeRoots::entry(DEPTH, 2),
590            // Depth 1.
591            *EmptySubtreeRoots::entry(DEPTH, 1),
592            // Root is not included.
593        ];
594
595        let empty_nodes_mask = 0b0110_0111;
596        let nodes = vec![[8u8, 8, 8, 8].into(), [5u8, 5, 5, 5].into(), [4u8, 4, 4, 4].into()];
597        let insufficient_nodes = vec![[4u8, 4, 4, 4].into()];
598
599        let error = SparseMerklePath::from_parts(empty_nodes_mask, insufficient_nodes).unwrap_err();
600        assert_matches!(error, MerkleError::InvalidPathLength(2));
601
602        let iter_sparse_path = SparseMerklePath::from_sized_iter(raw_nodes).unwrap();
603        let sparse_path = SparseMerklePath::from_parts(empty_nodes_mask, nodes).unwrap();
604
605        assert_eq!(sparse_path, iter_sparse_path);
606    }
607
608    #[test]
609    fn from_sized_iter() {
610        let tree = make_smt(8192);
611
612        for (key, _value) in tree.entries() {
613            let index = NodeIndex::from(Smt::key_to_leaf_index(key));
614            let sparse_path = tree.get_path(key);
615            for (sparse_node, proof_idx) in
616                itertools::zip_eq(sparse_path.clone(), index.proof_indices())
617            {
618                let proof_node = tree.get_node_hash(proof_idx);
619                assert_eq!(sparse_node, proof_node);
620            }
621        }
622    }
623
624    #[test]
625    fn test_zero_sized() {
626        let nodes: Vec<Word> = Default::default();
627
628        // Sparse paths that don't actually contain any nodes should still be well behaved.
629        let sparse_path = SparseMerklePath::from_sized_iter(nodes).unwrap();
630        assert_eq!(sparse_path.depth(), 0);
631        assert_matches!(
632            sparse_path.at_depth(NonZero::new(1).unwrap()),
633            Err(MerkleError::DepthTooBig(1))
634        );
635        assert_eq!(sparse_path.iter().next(), None);
636        assert_eq!(sparse_path.into_iter().next(), None);
637    }
638
639    use proptest::prelude::*;
640
641    // Arbitrary instance for Word
642    impl Arbitrary for Word {
643        type Parameters = ();
644        type Strategy = BoxedStrategy<Self>;
645
646        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
647            prop::collection::vec(any::<u64>(), 4)
648                .prop_map(|vals| {
649                    Word::new([
650                        Felt::new(vals[0]),
651                        Felt::new(vals[1]),
652                        Felt::new(vals[2]),
653                        Felt::new(vals[3]),
654                    ])
655                })
656                .no_shrink()
657                .boxed()
658        }
659    }
660
661    // Arbitrary instance for MerklePath
662    impl Arbitrary for MerklePath {
663        type Parameters = ();
664        type Strategy = BoxedStrategy<Self>;
665
666        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
667            prop::collection::vec(any::<Word>(), 0..=SMT_MAX_DEPTH as usize)
668                .prop_map(MerklePath::new)
669                .boxed()
670        }
671    }
672
673    // Arbitrary instance for SparseMerklePath
674    impl Arbitrary for SparseMerklePath {
675        type Parameters = ();
676        type Strategy = BoxedStrategy<Self>;
677
678        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
679            (0..=SMT_MAX_DEPTH as usize)
680                .prop_flat_map(|depth| {
681                    // Generate a bitmask for empty nodes - avoid overflow
682                    let max_mask = if depth > 0 && depth < 64 {
683                        (1u64 << depth) - 1
684                    } else if depth == 64 {
685                        u64::MAX
686                    } else {
687                        0
688                    };
689                    let empty_nodes_mask =
690                        prop::num::u64::ANY.prop_map(move |mask| mask & max_mask);
691
692                    // Generate non-empty nodes based on the mask
693                    empty_nodes_mask.prop_flat_map(move |mask| {
694                        let empty_count = mask.count_ones() as usize;
695                        let non_empty_count = depth.saturating_sub(empty_count);
696
697                        prop::collection::vec(any::<Word>(), non_empty_count).prop_map(
698                            move |nodes| SparseMerklePath::from_parts(mask, nodes).unwrap(),
699                        )
700                    })
701                })
702                .boxed()
703        }
704    }
705
706    proptest! {
707        #[test]
708        fn sparse_merkle_path_roundtrip_equivalence(path in any::<MerklePath>()) {
709            // Convert MerklePath to SparseMerklePath and back
710            let sparse_result = SparseMerklePath::try_from(path.clone());
711            if path.depth() <= SMT_MAX_DEPTH {
712                let sparse = sparse_result.unwrap();
713                let reconstructed = MerklePath::from(sparse);
714                prop_assert_eq!(path, reconstructed);
715            } else {
716                prop_assert!(sparse_result.is_err());
717            }
718        }
719    }
720    proptest! {
721
722        #[test]
723        fn merkle_path_roundtrip_equivalence(sparse in any::<SparseMerklePath>()) {
724            // Convert SparseMerklePath to MerklePath and back
725            let merkle = MerklePath::from(sparse.clone());
726            let reconstructed = SparseMerklePath::try_from(merkle.clone()).unwrap();
727            prop_assert_eq!(sparse, reconstructed);
728        }
729    }
730    proptest! {
731
732        #[test]
733        fn path_equivalence_tests(path in any::<MerklePath>(), path2 in any::<MerklePath>()) {
734            if path.depth() > SMT_MAX_DEPTH {
735                return Ok(());
736            }
737
738            let sparse = SparseMerklePath::try_from(path.clone()).unwrap();
739
740            // Depth consistency
741            prop_assert_eq!(path.depth(), sparse.depth());
742
743            // Node access consistency including path_depth_iter
744            if path.depth() > 0 {
745                for depth in path_depth_iter(path.depth()) {
746                    let merkle_node = path.at_depth(depth);
747                    let sparse_node = sparse.at_depth(depth);
748
749                    match (merkle_node, sparse_node) {
750                        (Some(m), Ok(s)) => prop_assert_eq!(m, s),
751                        (None, Err(_)) => {},
752                        _ => prop_assert!(false, "Inconsistent node access at depth {}", depth.get()),
753                    }
754                }
755            }
756
757            // Iterator consistency
758            if path.depth() > 0 {
759                let merkle_nodes: Vec<_> = path.iter().collect();
760                let sparse_nodes: Vec<_> = sparse.iter().collect();
761
762                prop_assert_eq!(merkle_nodes.len(), sparse_nodes.len());
763                for (m, s) in merkle_nodes.iter().zip(sparse_nodes.iter()) {
764                    prop_assert_eq!(*m, s);
765                }
766            }
767
768            // Test equality between different representations
769            if path2.depth() <= SMT_MAX_DEPTH {
770                let sparse2 = SparseMerklePath::try_from(path2.clone()).unwrap();
771                prop_assert_eq!(path == path2, sparse == sparse2);
772                prop_assert_eq!(path == sparse2, sparse == path2);
773            }
774        }
775    }
776    // rather heavy tests
777    proptest! {
778        #![proptest_config(ProptestConfig::with_cases(100))]
779
780        #[test]
781        fn compute_root_consistency(
782            tree_data in any::<RandomMerkleTree>(),
783            node in any::<Word>()
784        ) {
785            let RandomMerkleTree { tree, leaves: _,  indices } = tree_data;
786
787            for &leaf_index in indices.iter() {
788                let path = tree.get_path(NodeIndex::new(tree.depth(), leaf_index).unwrap()).unwrap();
789                let sparse = SparseMerklePath::from_sized_iter(path.clone().into_iter()).unwrap();
790
791                let merkle_root = path.compute_root(leaf_index, node);
792                let sparse_root = sparse.compute_root(leaf_index, node);
793
794                match (merkle_root, sparse_root) {
795                    (Ok(m), Ok(s)) => prop_assert_eq!(m, s),
796                    (Err(e1), Err(e2)) => {
797                        // Both should have the same error type
798                        prop_assert_eq!(format!("{:?}", e1), format!("{:?}", e2));
799                    },
800                    _ => prop_assert!(false, "Inconsistent compute_root results"),
801                }
802            }
803        }
804
805        #[test]
806        fn verify_consistency(
807            tree_data in any::<RandomMerkleTree>(),
808            node in any::<Word>()
809        ) {
810            let RandomMerkleTree { tree, leaves, indices } = tree_data;
811
812            for (i, &leaf_index) in indices.iter().enumerate() {
813                let leaf = leaves[i];
814                let path = tree.get_path(NodeIndex::new(tree.depth(), leaf_index).unwrap()).unwrap();
815                let sparse = SparseMerklePath::from_sized_iter(path.clone().into_iter()).unwrap();
816
817                let root = tree.root();
818
819                let merkle_verify = path.verify(leaf_index, leaf, &root);
820                let sparse_verify = sparse.verify(leaf_index, leaf, &root);
821
822                match (merkle_verify, sparse_verify) {
823                    (Ok(()), Ok(())) => {},
824                    (Err(e1), Err(e2)) => {
825                        // Both should have the same error type
826                        prop_assert_eq!(format!("{:?}", e1), format!("{:?}", e2));
827                    },
828                    _ => prop_assert!(false, "Inconsistent verify results"),
829                }
830
831                // Test with wrong node - both should fail
832                let wrong_verify = path.verify(leaf_index, node, &root);
833                let wrong_sparse_verify = sparse.verify(leaf_index, node, &root);
834
835                match (wrong_verify, wrong_sparse_verify) {
836                    (Ok(()), Ok(())) => prop_assert!(false, "Verification should have failed with wrong node"),
837                    (Err(_), Err(_)) => {},
838                    _ => prop_assert!(false, "Inconsistent verification results with wrong node"),
839                }
840            }
841        }
842
843        #[test]
844        fn authenticated_nodes_consistency(
845            tree_data in any::<RandomMerkleTree>()
846        ) {
847            let RandomMerkleTree { tree, leaves, indices } = tree_data;
848
849            for (i, &leaf_index) in indices.iter().enumerate() {
850                let leaf = leaves[i];
851                let path = tree.get_path(NodeIndex::new(tree.depth(), leaf_index).unwrap()).unwrap();
852                let sparse = SparseMerklePath::from_sized_iter(path.clone().into_iter()).unwrap();
853
854                let merkle_result = path.authenticated_nodes(leaf_index, leaf);
855                let sparse_result = sparse.authenticated_nodes(leaf_index, leaf);
856
857                match (merkle_result, sparse_result) {
858                    (Ok(m_iter), Ok(s_iter)) => {
859                        let merkle_nodes: Vec<_> = m_iter.collect();
860                        let sparse_nodes: Vec<_> = s_iter.collect();
861                        prop_assert_eq!(merkle_nodes.len(), sparse_nodes.len());
862                        for (m, s) in merkle_nodes.iter().zip(sparse_nodes.iter()) {
863                            prop_assert_eq!(m, s);
864                        }
865                    },
866                    (Err(e1), Err(e2)) => {
867                        prop_assert_eq!(format!("{:?}", e1), format!("{:?}", e2));
868                    },
869                    _ => prop_assert!(false, "Inconsistent authenticated_nodes results"),
870                }
871            }
872        }
873    }
874
875    #[test]
876    fn test_api_differences() {
877        // This test documents API differences between MerklePath and SparseMerklePath
878
879        // 1. MerklePath has Deref/DerefMut to Vec<Word> - SparseMerklePath does not
880        let merkle = MerklePath::new(vec![Word::default(); 3]);
881        let _vec_ref: &Vec<Word> = &merkle; // This works due to Deref
882        let _vec_mut: &mut Vec<Word> = &mut merkle.clone(); // This works due to DerefMut
883
884        // 2. SparseMerklePath has from_parts() - MerklePath uses new() or from_iter()
885        let sparse = SparseMerklePath::from_parts(0b101, vec![Word::default(); 2]).unwrap();
886        assert_eq!(sparse.depth(), 4); // depth is 4 because mask has bits set up to depth 4
887
888        // 3. SparseMerklePath has from_sized_iter() - MerklePath uses from_iter()
889        let nodes = vec![Word::default(); 3];
890        let sparse_from_iter = SparseMerklePath::from_sized_iter(nodes.clone()).unwrap();
891        let merkle_from_iter = MerklePath::from_iter(nodes);
892        assert_eq!(sparse_from_iter.depth(), merkle_from_iter.depth());
893    }
894
895    // Arbitrary instance for MerkleTree with random leaves
896    #[derive(Debug, Clone)]
897    struct RandomMerkleTree {
898        tree: MerkleTree,
899        leaves: Vec<Word>,
900        indices: Vec<u64>,
901    }
902
903    impl Arbitrary for RandomMerkleTree {
904        type Parameters = ();
905        type Strategy = BoxedStrategy<Self>;
906
907        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
908            // Generate trees with power-of-2 leaves up to 1024 (2^10)
909            prop::sample::select(&[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024])
910                .prop_flat_map(|num_leaves| {
911                    prop::collection::vec(any::<Word>(), num_leaves).prop_map(|leaves| {
912                        let tree = MerkleTree::new(leaves.clone()).unwrap();
913                        let indices: Vec<u64> = (0..leaves.len() as u64).collect();
914                        RandomMerkleTree { tree, leaves, indices }
915                    })
916                })
917                .boxed()
918        }
919    }
920
921    // Arbitrary instance for SimpleSmt with random entries
922    #[derive(Debug, Clone)]
923    struct RandomSimpleSmt {
924        tree: SimpleSmt<10>, // Depth 10 = 1024 leaves
925        entries: Vec<(u64, Word)>,
926    }
927
928    impl Arbitrary for RandomSimpleSmt {
929        type Parameters = ();
930        type Strategy = BoxedStrategy<Self>;
931
932        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
933            (1..=100usize) // 1-100 entries in an 1024-leaf tree
934                .prop_flat_map(|num_entries| {
935                    prop::collection::vec(
936                        (
937                            0..1024u64, // Valid indices for 1024-leaf tree
938                            any::<Word>(),
939                        ),
940                        num_entries,
941                    )
942                    .prop_map(|mut entries| {
943                        // Ensure unique indices to avoid duplicates
944                        let mut seen = alloc::collections::BTreeSet::new();
945                        entries.retain(|(idx, _)| seen.insert(*idx));
946
947                        let mut tree = SimpleSmt::new().unwrap();
948                        for (idx, value) in &entries {
949                            let leaf_idx = LeafIndex::new(*idx).unwrap();
950                            tree.insert(leaf_idx, *value);
951                        }
952                        RandomSimpleSmt { tree, entries }
953                    })
954                })
955                .boxed()
956        }
957    }
958
959    // Arbitrary instance for Smt with random entries
960    #[derive(Debug, Clone)]
961    struct RandomSmt {
962        tree: Smt,
963        entries: Vec<(Word, Word)>,
964    }
965
966    impl Arbitrary for RandomSmt {
967        type Parameters = ();
968        type Strategy = BoxedStrategy<Self>;
969
970        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
971            (1..=100usize) // 1-100 entries in a sparse tree
972                .prop_flat_map(|num_entries| {
973                    prop::collection::vec((any::<u64>(), any::<Word>()), num_entries).prop_map(
974                        |indices_n_values| {
975                            let entries: Vec<(Word, Word)> = indices_n_values
976                                .into_iter()
977                                .enumerate()
978                                .map(|(n, (leaf_index, value))| {
979                                    // SMT uses the most significant element (index 3) as leaf index
980                                    // Ensure we use valid leaf indices for the SMT depth
981                                    let valid_leaf_index = leaf_index % (1u64 << 60); // Use large but valid range
982                                    let key = Word::new([
983                                        Felt::new(n as u64),         // element 0
984                                        Felt::new(n as u64 + 1),     // element 1
985                                        Felt::new(n as u64 + 2),     // element 2
986                                        Felt::new(valid_leaf_index), // element 3 (leaf index)
987                                    ]);
988                                    (key, value)
989                                })
990                                .collect();
991
992                            // Ensure unique keys to avoid duplicates
993                            let mut seen = alloc::collections::BTreeSet::new();
994                            let unique_entries: Vec<_> =
995                                entries.into_iter().filter(|(key, _)| seen.insert(*key)).collect();
996
997                            let tree = Smt::with_entries(unique_entries.clone()).unwrap();
998                            RandomSmt { tree, entries: unique_entries }
999                        },
1000                    )
1001                })
1002                .boxed()
1003        }
1004    }
1005
1006    proptest! {
1007        #![proptest_config(ProptestConfig::with_cases(20))]
1008
1009        #[test]
1010        fn simple_smt_path_consistency(tree_data in any::<RandomSimpleSmt>()) {
1011            let RandomSimpleSmt { tree, entries } = tree_data;
1012
1013            for (leaf_index, value) in &entries {
1014                let merkle_path = tree.get_path(&LeafIndex::new(*leaf_index).unwrap());
1015                let sparse_path = SparseMerklePath::from_sized_iter(merkle_path.clone().into_iter()).unwrap();
1016
1017                // Verify both paths have same depth
1018                prop_assert_eq!(merkle_path.depth(), sparse_path.depth());
1019
1020                // Verify both paths produce same root for the same value
1021                let merkle_root = merkle_path.compute_root(*leaf_index, *value).unwrap();
1022                let sparse_root = sparse_path.compute_root(*leaf_index, *value).unwrap();
1023                prop_assert_eq!(merkle_root, sparse_root);
1024
1025                // Verify both paths verify correctly
1026                let tree_root = tree.root();
1027                prop_assert!(merkle_path.verify(*leaf_index, *value, &tree_root).is_ok());
1028                prop_assert!(sparse_path.verify(*leaf_index, *value, &tree_root).is_ok());
1029
1030                // Test with random additional leaf
1031                let random_leaf = Word::new([Felt::ONE; 4]);
1032                let random_index = *leaf_index ^ 1; // Ensure it's a sibling
1033
1034                // Both should fail verification with wrong leaf
1035                let merkle_wrong = merkle_path.verify(random_index, random_leaf, &tree_root);
1036                let sparse_wrong = sparse_path.verify(random_index, random_leaf, &tree_root);
1037                prop_assert_eq!(merkle_wrong.is_err(), sparse_wrong.is_err());
1038            }
1039        }
1040
1041        #[test]
1042        fn smt_path_consistency(tree_data in any::<RandomSmt>()) {
1043            let RandomSmt { tree, entries } = tree_data;
1044
1045            for (key, _value) in &entries {
1046                let (merkle_path, leaf) = tree.open(key).into_parts();
1047                let sparse_path = SparseMerklePath::from_sized_iter(merkle_path.clone().into_iter()).unwrap();
1048
1049                let leaf_index = Smt::key_to_leaf_index(key).value();
1050                let actual_value = leaf.hash(); // Use the actual leaf hash
1051
1052                // Verify both paths have same depth
1053                prop_assert_eq!(merkle_path.depth(), sparse_path.depth());
1054
1055                // Verify both paths produce same root for the same value
1056                let merkle_root = merkle_path.compute_root(leaf_index, actual_value).unwrap();
1057                let sparse_root = sparse_path.compute_root(leaf_index, actual_value).unwrap();
1058                prop_assert_eq!(merkle_root, sparse_root);
1059
1060                // Verify both paths verify correctly
1061                let tree_root = tree.root();
1062                prop_assert!(merkle_path.verify(leaf_index, actual_value, &tree_root).is_ok());
1063                prop_assert!(sparse_path.verify(leaf_index, actual_value, &tree_root).is_ok());
1064
1065                // Test authenticated nodes consistency
1066                let merkle_auth = merkle_path.authenticated_nodes(leaf_index, actual_value).unwrap().collect::<Vec<_>>();
1067                let sparse_auth = sparse_path.authenticated_nodes(leaf_index, actual_value).unwrap().collect::<Vec<_>>();
1068                prop_assert_eq!(merkle_auth, sparse_auth);
1069            }
1070        }
1071
1072        #[test]
1073        fn reverse_conversion_from_sparse(tree_data in any::<RandomMerkleTree>()) {
1074            let RandomMerkleTree { tree, leaves, indices } = tree_data;
1075
1076            for (i, &leaf_index) in indices.iter().enumerate() {
1077                let leaf = leaves[i];
1078                let merkle_path = tree.get_path(NodeIndex::new(tree.depth(), leaf_index).unwrap()).unwrap();
1079
1080                // Create SparseMerklePath first, then convert to MerklePath
1081                let sparse_path = SparseMerklePath::from_sized_iter(merkle_path.clone().into_iter()).unwrap();
1082                let converted_merkle = MerklePath::from(sparse_path.clone());
1083
1084                // Verify conversion back and forth works
1085                let back_to_sparse = SparseMerklePath::try_from(converted_merkle.clone()).unwrap();
1086                prop_assert_eq!(sparse_path, back_to_sparse);
1087
1088                // Verify all APIs work identically
1089                prop_assert_eq!(merkle_path.depth(), converted_merkle.depth());
1090
1091                let merkle_root = merkle_path.compute_root(leaf_index, leaf).unwrap();
1092                let converted_root = converted_merkle.compute_root(leaf_index, leaf).unwrap();
1093                prop_assert_eq!(merkle_root, converted_root);
1094            }
1095        }
1096    }
1097}