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