Skip to main content

miden_crypto/merkle/
sparse_path.rs

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