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