cmtree/
lib.rs

1#![no_std]
2#![cfg_attr(not(test), deny(missing_docs))]
3
4//! Deterministic Cartesian Merkle Tree implementation.
5//!
6//! This crate provides a no-std friendly version of the Cartesian Merkle Tree described in
7//! <https://arxiv.org/pdf/2504.10944>. A Cartesian Merkle Tree combines binary-search-tree
8//! ordering, heap balancing, and Merkle hashing. For each key we derive a deterministic
9//! priority from its hash, producing a unique tree layout regardless of insertion order. Every
10//! node carries an aggregated Merkle hash, enabling succinct membership and non-membership
11//! proofs.
12//!
13//! # Complexity
14//!
15//! The structure behaves similarly to a treap whose priorities are derived from the key
16//! material. Assuming a strong digest and random-looking priorities, the tree remains balanced
17//! with high probability, yielding:
18//!
19//! * [`CMTree::insert`], [`CMTree::remove`], [`CMTree::contains`] – `O(log n)` expected time.
20//! * [`CMTree::generate_proof`] – `O(log n)` time and proof size.
21//! * [`CMTree::root_hash`] – `O(1)` time (hashes are cached on each node).
22//!
23//! Space consumption is `O(n)` for `n` stored keys, with a single node allocated per entry
24//! plus cached digests for child subtrees.
25
26extern crate alloc;
27
28use alloc::boxed::Box;
29use alloc::vec::Vec;
30use core::cmp::{Ordering, min};
31use core::hash::{Hash, Hasher};
32use sha2::digest::Output;
33use sha2::{Digest, Sha256};
34
35/// Digest output for the default [`Sha256`] hasher used by [`CMTree`].
36pub type Sha256Hash = Output<Sha256>;
37
38type HashOf<H> = Output<H>;
39
40type Link<T, H, P> = Option<Box<Node<T, H, P>>>;
41
42/// Trait describing a priority type derived from hashed key material.
43pub trait Priority: Copy + Ord + Default {
44    /// Constructs a priority value from the provided digest bytes (big-endian).
45    fn from_digest_bytes(bytes: &[u8]) -> Self;
46}
47
48macro_rules! impl_priority_from_bytes {
49    ($($ty:ty),+) => {
50        $(
51            impl Priority for $ty {
52                #[inline(always)]
53                fn from_digest_bytes(bytes: &[u8]) -> Self {
54                    let mut out = [0u8; core::mem::size_of::<$ty>()];
55                    let copy_len = bytes.len().min(out.len());
56                    out[..copy_len].copy_from_slice(&bytes[..copy_len]);
57                    <$ty>::from_be_bytes(out)
58                }
59            }
60        )+
61    };
62}
63
64impl_priority_from_bytes!(u16, u32, u64, u128);
65
66struct Node<T, H, P>
67where
68    T: Clone + Ord + Hash,
69    H: Digest + Clone,
70    P: Priority,
71{
72    key: T,
73    key_digest: HashOf<H>,
74    priority: P,
75    hash: HashOf<H>,
76    left: Link<T, H, P>,
77    right: Link<T, H, P>,
78}
79
80impl<T, H, P> Node<T, H, P>
81where
82    T: Clone + Ord + Hash,
83    H: Digest + Clone,
84    P: Priority,
85{
86    #[inline(always)]
87    fn new(key: T) -> Self {
88        let key_digest = hash_key::<T, H>(&key);
89        let priority = P::from_digest_bytes(key_digest.as_ref());
90        let zero = zero_hash::<H>();
91        let hash = calculate_node_hash::<H>(&key_digest, &zero, &zero);
92        Self {
93            key,
94            key_digest,
95            priority,
96            hash,
97            left: None,
98            right: None,
99        }
100    }
101
102    #[inline(always)]
103    fn left_hash(&self) -> HashOf<H> {
104        self.left
105            .as_ref()
106            .map(|child| child.hash.clone())
107            .unwrap_or_else(|| zero_hash::<H>())
108    }
109
110    #[inline(always)]
111    fn right_hash(&self) -> HashOf<H> {
112        self.right
113            .as_ref()
114            .map(|child| child.hash.clone())
115            .unwrap_or_else(|| zero_hash::<H>())
116    }
117
118    #[inline(always)]
119    fn left_priority(&self) -> P {
120        self.left
121            .as_ref()
122            .map(|child| child.priority)
123            .unwrap_or_default()
124    }
125
126    #[inline(always)]
127    fn right_priority(&self) -> P {
128        self.right
129            .as_ref()
130            .map(|child| child.priority)
131            .unwrap_or_default()
132    }
133
134    #[inline(always)]
135    fn key_digest(&self) -> &HashOf<H> {
136        &self.key_digest
137    }
138
139    #[inline(always)]
140    fn update_hash(&mut self) {
141        let left = self.left_hash();
142        let right = self.right_hash();
143        self.hash = calculate_node_hash::<H>(self.key_digest(), &left, &right);
144    }
145}
146
147/// Deterministic Cartesian Merkle Tree backed by a cryptographic digest.
148///
149/// The structure maintains ordering via the [`Ord`] implementation for the key type `T`,
150/// balances using heap rotations directed by deterministic priorities, and produces Merkle
151/// proofs based on the digest `H`. Priorities are represented by the `P` type parameter, which
152/// defaults to `u128` but may be lowered (for example, to `u64`) by providing a type that
153/// implements [`Priority`].
154///
155/// # Complexity
156///
157/// * [`CMTree::insert`], [`CMTree::remove`], and [`CMTree::contains`] run in expected `O(log
158///   n)` time, where `n` is the number of stored keys.
159/// * [`CMTree::generate_proof`] executes in `O(log n)` time and produces a proof with `O(log
160///   n)` elements.
161/// * [`CMTree::root_hash`] reads the cached Merkle hash in `O(1)` time.
162///
163/// Space usage is `O(n)` for `n` keys, accounting for one node per key and the cached digests
164/// for children.
165///
166/// # Examples
167///
168/// Basic insertion and membership proof verification:
169///
170/// ```
171/// use cmtree::CMTree;
172///
173/// let mut tree = CMTree::<Vec<u8>>::new();
174/// tree.insert(b"alice".to_vec());
175/// tree.insert(b"bob".to_vec());
176/// tree.insert(b"carol".to_vec());
177///
178/// let root = tree.root_hash();
179/// let proof = tree.generate_proof(&b"bob".to_vec()).unwrap();
180///
181/// assert!(proof.existence);
182/// assert!(proof.verify(&b"bob".to_vec(), &root));
183/// ```
184pub struct CMTree<T, H = Sha256, P = u128>
185where
186    T: Clone + Ord + Hash,
187    H: Digest + Clone,
188    P: Priority,
189{
190    root: Link<T, H, P>,
191    size: usize,
192}
193
194impl<T, H, P> CMTree<T, H, P>
195where
196    T: Clone + Ord + Hash,
197    H: Digest + Clone,
198    P: Priority,
199{
200    /// Creates an empty Cartesian Merkle Tree.
201    #[inline(always)]
202    pub const fn new() -> Self {
203        Self {
204            root: None,
205            size: 0,
206        }
207    }
208
209    /// Returns the number of keys stored in the tree.
210    #[inline(always)]
211    pub const fn len(&self) -> usize {
212        self.size
213    }
214
215    /// Returns whether the tree contains no elements.
216    #[inline(always)]
217    pub const fn is_empty(&self) -> bool {
218        self.size == 0
219    }
220
221    /// Returns the current Merkle root of the tree.
222    ///
223    /// When the tree is empty the zero hash of the digest is returned.
224    #[inline(always)]
225    pub fn root_hash(&self) -> HashOf<H> {
226        self.root
227            .as_ref()
228            .map(|node| node.hash.clone())
229            .unwrap_or_else(|| zero_hash::<H>())
230    }
231
232    /// Inserts a key into the tree.
233    ///
234    /// Returns `true` if the key did not previously exist.
235    #[inline]
236    pub fn insert(&mut self, key: T) -> bool {
237        let (new_root, inserted) = Self::insert_node(self.root.take(), key);
238        self.root = new_root;
239        if inserted {
240            self.size += 1;
241        }
242        inserted
243    }
244
245    /// Returns `true` if the provided key exists in the tree.
246    #[inline]
247    pub fn contains(&self, key: &T) -> bool {
248        let mut current = self.root.as_deref();
249        while let Some(node) = current {
250            match key.cmp(&node.key) {
251                Ordering::Less => current = node.left.as_deref(),
252                Ordering::Greater => current = node.right.as_deref(),
253                Ordering::Equal => return true,
254            }
255        }
256        false
257    }
258
259    /// Removes the provided key from the tree.
260    ///
261    /// Returns `true` if the key was present and removed.
262    #[inline]
263    pub fn remove(&mut self, key: &T) -> bool {
264        let (new_root, removed) = Self::remove_node(self.root.take(), key);
265        if removed {
266            self.size -= 1;
267        }
268        self.root = new_root;
269        removed
270    }
271
272    /// Generates a membership or non-membership proof for the provided key.
273    ///
274    /// Returns `None` when the tree is empty. For membership proofs [`Proof::existence`] is
275    /// `true`. For non-membership proofs the closest node encountered during the lookup is
276    /// supplied as evidence alongside the queried key's child hashes.
277    #[inline]
278    pub fn generate_proof(&self, key: &T) -> Option<Proof<H>> {
279        let mut current = self.root.as_deref()?;
280        let mut path: Vec<(&Node<T, H, P>, Direction)> = Vec::new();
281        let mut existence = false;
282        let mut non_existence_key_digest: Option<HashOf<H>> = None;
283
284        let suffix = loop {
285            match key.cmp(&current.key) {
286                Ordering::Less => {
287                    if let Some(left_child) = current.left.as_deref() {
288                        path.push((current, Direction::Left));
289                        current = left_child;
290                    } else {
291                        non_existence_key_digest = Some(current.key_digest().clone());
292                        break [current.left_hash(), current.right_hash()];
293                    }
294                }
295                Ordering::Greater => {
296                    if let Some(right_child) = current.right.as_deref() {
297                        path.push((current, Direction::Right));
298                        current = right_child;
299                    } else {
300                        non_existence_key_digest = Some(current.key_digest().clone());
301                        break [current.left_hash(), current.right_hash()];
302                    }
303                }
304                Ordering::Equal => {
305                    existence = true;
306                    break [current.left_hash(), current.right_hash()];
307                }
308            }
309        };
310
311        let mut prefix = Vec::with_capacity(path.len());
312        for (node, direction) in path.into_iter().rev() {
313            let sibling_hash = match direction {
314                Direction::Left => node.right_hash(),
315                Direction::Right => node.left_hash(),
316            };
317            prefix.push(ProofNode {
318                parent_key_digest: node.key_digest().clone(),
319                sibling_hash,
320            });
321        }
322
323        Some(Proof {
324            prefix,
325            suffix,
326            existence,
327            non_existence_key_digest,
328        })
329    }
330
331    #[inline]
332    fn insert_node(node: Link<T, H, P>, key: T) -> (Link<T, H, P>, bool) {
333        match node {
334            None => (Some(Box::new(Node::new(key))), true),
335            Some(mut boxed) => match key.cmp(&boxed.key) {
336                Ordering::Less => {
337                    let (new_left, inserted) = Self::insert_node(boxed.left.take(), key);
338                    boxed.left = new_left;
339                    if inserted
340                        && boxed
341                            .left
342                            .as_ref()
343                            .is_some_and(|left| left.priority > boxed.priority)
344                    {
345                        boxed = Self::rotate_right_owned(boxed);
346                        return (Some(boxed), true);
347                    }
348                    boxed.update_hash();
349                    (Some(boxed), inserted)
350                }
351                Ordering::Greater => {
352                    let (new_right, inserted) = Self::insert_node(boxed.right.take(), key);
353                    boxed.right = new_right;
354                    if inserted
355                        && boxed
356                            .right
357                            .as_ref()
358                            .is_some_and(|right| right.priority > boxed.priority)
359                    {
360                        boxed = Self::rotate_left_owned(boxed);
361                        return (Some(boxed), true);
362                    }
363                    boxed.update_hash();
364                    (Some(boxed), inserted)
365                }
366                Ordering::Equal => (Some(boxed), false),
367            },
368        }
369    }
370
371    #[inline]
372    fn remove_node(node: Link<T, H, P>, key: &T) -> (Link<T, H, P>, bool) {
373        let mut boxed = match node {
374            Some(node) => node,
375            None => return (None, false),
376        };
377
378        match key.cmp(&boxed.key) {
379            Ordering::Less => {
380                let (new_left, removed) = Self::remove_node(boxed.left.take(), key);
381                boxed.left = new_left;
382                if removed {
383                    boxed.update_hash();
384                }
385                (Some(boxed), removed)
386            }
387            Ordering::Greater => {
388                let (new_right, removed) = Self::remove_node(boxed.right.take(), key);
389                boxed.right = new_right;
390                if removed {
391                    boxed.update_hash();
392                }
393                (Some(boxed), removed)
394            }
395            Ordering::Equal => {
396                if boxed.left.is_none() {
397                    return (boxed.right.take(), true);
398                }
399                if boxed.right.is_none() {
400                    return (boxed.left.take(), true);
401                }
402                if boxed.left_priority() > boxed.right_priority() {
403                    boxed = Self::rotate_right_owned(boxed);
404                    let (new_right, removed) = Self::remove_node(boxed.right.take(), key);
405                    boxed.right = new_right;
406                    boxed.update_hash();
407                    (Some(boxed), removed)
408                } else {
409                    boxed = Self::rotate_left_owned(boxed);
410                    let (new_left, removed) = Self::remove_node(boxed.left.take(), key);
411                    boxed.left = new_left;
412                    boxed.update_hash();
413                    (Some(boxed), removed)
414                }
415            }
416        }
417    }
418
419    #[inline]
420    fn rotate_left_owned(mut node: Box<Node<T, H, P>>) -> Box<Node<T, H, P>> {
421        let mut right = node
422            .right
423            .take()
424            .expect("rotate_left_owned requires a right child");
425        node.right = right.left.take();
426        node.update_hash();
427        right.left = Some(node);
428        right.update_hash();
429        right
430    }
431
432    #[inline]
433    fn rotate_right_owned(mut node: Box<Node<T, H, P>>) -> Box<Node<T, H, P>> {
434        let mut left = node
435            .left
436            .take()
437            .expect("rotate_right_owned requires a left child");
438        node.left = left.right.take();
439        node.update_hash();
440        left.right = Some(node);
441        left.update_hash();
442        left
443    }
444}
445
446impl<T, H, P> Default for CMTree<T, H, P>
447where
448    T: Clone + Ord + Hash,
449    H: Digest + Clone,
450    P: Priority,
451{
452    #[inline]
453    fn default() -> Self {
454        Self::new()
455    }
456}
457
458/// Authentication data for a single step in a Merkle proof.
459#[derive(Clone, Debug, PartialEq, Eq)]
460pub struct ProofNode<H>
461where
462    H: Digest + Clone,
463{
464    /// Digest of the parent node's key.
465    pub parent_key_digest: HashOf<H>,
466    /// Sibling subtree hash encountered on the path to the root.
467    pub sibling_hash: HashOf<H>,
468}
469
470/// Membership or non-membership proof for a Cartesian Merkle Tree.
471#[derive(Clone, Debug, PartialEq, Eq)]
472pub struct Proof<H>
473where
474    H: Digest + Clone,
475{
476    /// Path of ancestor nodes from the queried entry up to (but not including) the root.
477    pub prefix: Vec<ProofNode<H>>,
478    /// Left and right child hashes for the queried entry.
479    pub suffix: [HashOf<H>; 2],
480    /// Indicates whether this proof represents membership (`true`) or non-membership
481    /// (`false`).
482    pub existence: bool,
483    /// Digest used to demonstrate non-membership when [`Proof::existence`] is `false`.
484    pub non_existence_key_digest: Option<HashOf<H>>,
485}
486
487impl<H> Proof<H>
488where
489    H: Digest + Clone,
490{
491    /// Verifies the proof against the provided key and root hash.
492    ///
493    /// Membership proofs succeed when the key is present; non-membership proofs succeed when
494    /// the key is absent yet the proof demonstrates the unique neighbouring node that prevents
495    /// its insertion.
496    ///
497    /// ```
498    /// use cmtree::CMTree;
499    ///
500    /// let mut tree = CMTree::<Vec<u8>>::new();
501    /// for key in [b"a".to_vec(), b"b".to_vec(), b"c".to_vec()] {
502    ///     tree.insert(key);
503    /// }
504    ///
505    /// let root = tree.root_hash();
506    /// let proof = tree.generate_proof(&b"a".to_vec()).unwrap();
507    ///
508    /// assert!(proof.existence);
509    /// assert!(proof.verify(&b"a".to_vec(), &root));
510    /// ```
511    #[inline(always)]
512    pub fn verify<K>(&self, key: &K, expected_root: &HashOf<H>) -> bool
513    where
514        K: Hash,
515    {
516        let key_digest = hash_key::<K, H>(key);
517        self.verify_digest(&key_digest, expected_root)
518    }
519
520    #[inline(always)]
521    fn verify_digest(&self, key_digest: &HashOf<H>, expected_root: &HashOf<H>) -> bool {
522        let base_key = if self.existence {
523            key_digest
524        } else {
525            match self.non_existence_key_digest.as_ref() {
526                Some(d) => d,
527                None => return false,
528            }
529        };
530
531        let mut acc = calculate_node_hash::<H>(base_key, &self.suffix[0], &self.suffix[1]);
532        for node in &self.prefix {
533            acc = calculate_node_hash::<H>(&node.parent_key_digest, &acc, &node.sibling_hash);
534        }
535
536        &acc == expected_root
537    }
538}
539
540enum Direction {
541    Left,
542    Right,
543}
544
545struct DigestHasher<H>
546where
547    H: Digest + Clone,
548{
549    digest: H,
550}
551
552impl<H> DigestHasher<H>
553where
554    H: Digest + Clone,
555{
556    #[inline(always)]
557    fn new() -> Self {
558        Self { digest: H::new() }
559    }
560
561    #[inline(always)]
562    fn finalize(self) -> HashOf<H> {
563        self.digest.finalize()
564    }
565}
566
567impl<H> Hasher for DigestHasher<H>
568where
569    H: Digest + Clone,
570{
571    #[inline(always)]
572    fn finish(&self) -> u64 {
573        let output = self.digest.clone().finalize();
574        let bytes = output.as_ref();
575        let mut buf = [0u8; 8];
576        let copy_len = min(buf.len(), bytes.len());
577        buf[..copy_len].copy_from_slice(&bytes[..copy_len]);
578        u64::from_be_bytes(buf)
579    }
580
581    #[inline(always)]
582    fn write(&mut self, bytes: &[u8]) {
583        self.digest.update(bytes);
584    }
585}
586
587#[inline(always)]
588fn hash_key<T, H>(key: &T) -> HashOf<H>
589where
590    T: Hash,
591    H: Digest + Clone,
592{
593    let mut hasher = DigestHasher::<H>::new();
594    key.hash(&mut hasher);
595    hasher.finalize()
596}
597
598#[inline(always)]
599fn zero_hash<H: Digest>() -> HashOf<H> {
600    Output::<H>::default()
601}
602
603#[inline(always)]
604fn calculate_node_hash<H: Digest>(
605    key_digest: &HashOf<H>,
606    left: &HashOf<H>,
607    right: &HashOf<H>,
608) -> HashOf<H> {
609    let (low, high) = if left.as_ref() <= right.as_ref() {
610        (left, right)
611    } else {
612        (right, left)
613    };
614
615    let mut hasher = H::new();
616    hasher.update(key_digest.as_ref());
617    hasher.update(low.as_ref());
618    hasher.update(high.as_ref());
619    hasher.finalize()
620}
621
622#[cfg(test)]
623mod tests {
624    use super::*;
625    extern crate std;
626
627    fn key(bytes: &[u8]) -> Vec<u8> {
628        bytes.to_vec()
629    }
630
631    #[test]
632    fn insert_and_contains() {
633        let mut tree = CMTree::<Vec<u8>>::new();
634        let k10 = key(b"10");
635        let k5 = key(b"5");
636        let k20 = key(b"20");
637
638        assert!(tree.insert(k10.clone()));
639        assert!(tree.insert(k5.clone()));
640        assert!(tree.insert(k20.clone()));
641        assert!(!tree.insert(k5.clone()));
642
643        assert!(tree.contains(&k10));
644        assert!(tree.contains(&k5));
645        assert!(tree.contains(&k20));
646        assert!(!tree.contains(&key(b"1")));
647    }
648
649    #[test]
650    fn remove_keys() {
651        let mut tree = CMTree::<Vec<u8>>::new();
652        let k10 = key(b"10");
653        let k5 = key(b"5");
654        let k20 = key(b"20");
655        let k18 = key(b"18");
656        let k25 = key(b"25");
657
658        for k in [&k10, &k5, &k20, &k18, &k25] {
659            assert!(tree.insert((*k).clone()));
660        }
661        assert_eq!(tree.len(), 5);
662        assert!(tree.remove(&k20));
663        assert_eq!(tree.len(), 4);
664        assert!(!tree.contains(&k20));
665        assert!(tree.remove(&k10));
666        assert_eq!(tree.len(), 3);
667    }
668
669    #[test]
670    fn membership_proof_verifies() {
671        let mut tree = CMTree::<Vec<u8>>::new();
672        let keys = ["10", "5", "20", "18", "25"];
673        for k in keys {
674            let key_vec = key(k.as_bytes());
675            tree.insert(key_vec.clone());
676        }
677        let root = tree.root_hash();
678        let target = key(b"18");
679        let proof = tree.generate_proof(&target).unwrap();
680        assert!(proof.existence);
681        assert!(proof.verify(&target, &root));
682    }
683
684    #[test]
685    fn non_membership_proof_verifies() {
686        let mut tree = CMTree::<Vec<u8>>::new();
687        let keys = ["10", "5", "20", "18", "25"];
688        for k in keys {
689            tree.insert(key(k.as_bytes()));
690        }
691        let root = tree.root_hash();
692        let missing = key(b"13");
693        let proof = tree.generate_proof(&missing).unwrap();
694        assert!(!proof.existence);
695        assert!(proof.verify(&missing, &root));
696    }
697
698    #[test]
699    fn empty_tree_has_zero_root_and_no_proof() {
700        let tree = CMTree::<Vec<u8>>::new();
701        assert_eq!(tree.root_hash(), zero_hash::<Sha256>());
702        assert!(tree.generate_proof(&key(b"nonexistent")).is_none());
703    }
704
705    #[test]
706    fn removing_missing_key_does_not_change_tree() {
707        let mut tree = CMTree::<Vec<u8>>::new();
708        for k in ["1", "2", "3", "4"] {
709            assert!(tree.insert(key(k.as_bytes())));
710        }
711        let len_before = tree.len();
712        assert!(!tree.remove(&key(b"999")));
713        assert_eq!(tree.len(), len_before);
714    }
715
716    #[test]
717    fn removing_root_keeps_structure_valid() {
718        let mut tree = CMTree::<Vec<u8>>::new();
719        let root_key = key(b"10");
720        let left_key = key(b"05");
721        let right_key = key(b"20");
722        for k in [&root_key, &left_key, &right_key] {
723            assert!(tree.insert((*k).clone()));
724        }
725        assert!(tree.remove(&root_key));
726        assert_eq!(tree.len(), 2);
727        assert!(!tree.contains(&root_key));
728        assert!(tree.contains(&left_key));
729        assert!(tree.contains(&right_key));
730    }
731
732    #[test]
733    fn duplicate_insertions_are_idempotent() {
734        let mut tree = CMTree::<Vec<u8>>::new();
735        let set = ["a", "b", "c", "d", "e"];
736        for k in set {
737            assert!(tree.insert(key(k.as_bytes())));
738        }
739        let root_after_first = tree.root_hash();
740        for k in set {
741            assert!(!tree.insert(key(k.as_bytes())));
742        }
743        assert_eq!(tree.len(), set.len());
744        assert_eq!(tree.root_hash(), root_after_first);
745    }
746
747    #[test]
748    fn deterministic_root_for_different_insertion_orders() {
749        let mut tree_a = CMTree::<Vec<u8>>::new();
750        let mut tree_b = CMTree::<Vec<u8>>::new();
751        let mut inputs: Vec<Vec<u8>> = ["alpha", "beta", "gamma", "delta", "epsilon"]
752            .iter()
753            .map(|s| key(s.as_bytes()))
754            .collect();
755        for k in &inputs {
756            tree_a.insert(k.clone());
757        }
758        inputs.reverse();
759        for k in &inputs {
760            tree_b.insert(k.clone());
761        }
762        assert_eq!(tree_a.len(), tree_b.len());
763        assert_eq!(tree_a.root_hash(), tree_b.root_hash());
764    }
765
766    #[test]
767    fn proofs_match_across_insertion_orders() {
768        let mut tree_a = CMTree::<Vec<u8>>::new();
769        let mut tree_b = CMTree::<Vec<u8>>::new();
770        let mut inputs: Vec<Vec<u8>> = ["alpha", "beta", "gamma", "delta", "epsilon"]
771            .iter()
772            .map(|s| key(s.as_bytes()))
773            .collect();
774        for k in &inputs {
775            tree_a.insert(k.clone());
776        }
777        inputs.reverse();
778        for k in &inputs {
779            tree_b.insert(k.clone());
780        }
781
782        let target = key(b"gamma");
783        let proof_a = tree_a.generate_proof(&target).expect("proof from order A");
784        let proof_b = tree_b.generate_proof(&target).expect("proof from order B");
785
786        let root = tree_a.root_hash();
787        assert!(proof_a.verify(&target, &root));
788        assert!(proof_b.verify(&target, &root));
789        assert_eq!(proof_a.prefix.len(), proof_b.prefix.len());
790        assert_eq!(proof_a.suffix, proof_b.suffix);
791        assert_eq!(proof_a.existence, proof_b.existence);
792    }
793
794    #[test]
795    fn membership_proof_rejects_when_flag_flipped() {
796        let mut tree = CMTree::<Vec<u8>>::new();
797        for k in ["left", "right", "root", "branch"] {
798            tree.insert(key(k.as_bytes()));
799        }
800        let root = tree.root_hash();
801        let target = key(b"branch");
802        let mut proof = tree.generate_proof(&target).unwrap();
803        proof.existence = false;
804        assert!(!proof.verify(&target, &root));
805    }
806
807    #[test]
808    fn membership_proof_rejects_with_wrong_root() {
809        let mut tree_a = CMTree::<Vec<u8>>::new();
810        let mut tree_b = CMTree::<Vec<u8>>::new();
811        for k in ["1", "2", "3", "4"] {
812            let vec_key = key(k.as_bytes());
813            tree_a.insert(vec_key.clone());
814            tree_b.insert(vec_key);
815        }
816        tree_b.insert(key(b"extra"));
817        let proof = tree_a.generate_proof(&key(b"3")).unwrap();
818        assert!(proof.verify(&key(b"3"), &tree_a.root_hash()));
819        assert!(!proof.verify(&key(b"3"), &tree_b.root_hash()));
820    }
821
822    #[test]
823    fn mutated_suffix_breaks_non_membership_proof() {
824        let mut tree = CMTree::<Vec<u8>>::new();
825        for k in ["10", "5", "20", "18", "25"] {
826            tree.insert(key(k.as_bytes()));
827        }
828        let root = tree.root_hash();
829        let mut proof = tree.generate_proof(&key(b"13")).unwrap();
830        assert!(!proof.existence);
831        proof.suffix[0] = zero_hash::<Sha256>();
832        proof.suffix[1] = zero_hash::<Sha256>();
833        // By also forcing existence to true we ensure mismatch of accumulator path.
834        proof.existence = true;
835        assert!(!proof.verify(&key(b"13"), &root));
836    }
837
838    #[test]
839    fn supports_integer_keys() {
840        let mut tree = CMTree::<u64>::new();
841        for k in [10, 5, 20, 18, 25] {
842            assert!(tree.insert(k));
843        }
844        assert!(tree.contains(&18u64));
845        assert!(!tree.contains(&13u64));
846        let root = tree.root_hash();
847        let proof = tree.generate_proof(&18u64).unwrap();
848        assert!(proof.existence);
849        assert!(proof.verify(&18u64, &root));
850    }
851
852    #[test]
853    fn large_tree_membership_and_non_membership_proofs() {
854        const COUNT: usize = 5_000;
855        let mut tree = CMTree::<u64>::new();
856        for value in 0u64..COUNT as u64 {
857            assert!(tree.insert(value));
858        }
859        assert_eq!(tree.len(), COUNT);
860
861        let target = 3_456u64;
862        let root = tree.root_hash();
863        let proof = tree.generate_proof(&target).expect("proof should exist");
864        assert!(proof.existence);
865        assert!(proof.verify(&target, &root));
866
867        let missing = COUNT as u64 + 1;
868        let root_again = tree.root_hash();
869        let non_membership = tree
870            .generate_proof(&missing)
871            .expect("proof should be generated");
872        assert!(!non_membership.existence);
873        assert!(non_membership.verify(&missing, &root_again));
874    }
875
876    #[test]
877    fn large_tree_sequential_removals() {
878        const COUNT: usize = 10_000;
879        let mut tree = CMTree::<u64>::new();
880        for value in 0u64..COUNT as u64 {
881            assert!(tree.insert(value));
882        }
883        for value in 0u64..COUNT as u64 {
884            assert!(tree.remove(&value));
885        }
886        assert!(tree.is_empty());
887        assert_eq!(tree.root_hash(), zero_hash::<Sha256>());
888    }
889
890    #[test]
891    fn supports_lower_priority_width() {
892        let mut tree = CMTree::<Vec<u8>, Sha256, u64>::new();
893        for key in ["10", "5", "20", "18", "25"] {
894            assert!(tree.insert(key.as_bytes().to_vec()));
895        }
896        let root = tree.root_hash();
897        let proof = tree.generate_proof(&b"18".to_vec()).unwrap();
898        assert!(proof.existence);
899        assert!(proof.verify(&b"18".to_vec(), &root));
900    }
901
902    #[test]
903    fn works_with_alternative_digest() {
904        use sha2::Sha512;
905
906        let mut tree = CMTree::<Vec<u8>, Sha512>::new();
907        for key in ["alpha", "beta", "gamma", "delta"] {
908            assert!(tree.insert(key.as_bytes().to_vec()));
909        }
910        assert!(tree.contains(&b"gamma".to_vec()));
911        let root = tree.root_hash();
912        let proof = tree.generate_proof(&b"beta".to_vec()).unwrap();
913        assert!(proof.existence);
914        assert!(proof.verify(&b"beta".to_vec(), &root));
915    }
916}