commonware_storage/bmt/
mod.rs

1//! Stateless Binary Merkle Tree (BMT).
2//!
3//! The Binary Merkle Tree is constructed level-by-level. The first level consists of position-hashed leaf digests.
4//! On each additional level, pairs of nodes are hashed from the previous level (if a level contains an odd
5//! number of nodes, the last node is duplicated). The root of the tree is the digest of the node in the top level.
6//!
7//! For example, given three leaves A, B, and C, the tree is constructed as follows:
8//!
9//! ```text
10//!     Level 2 (root):       [hash(hash(hash(0,A),hash(1,B)),hash(hash(2,C),hash(2,C)))]
11//!     Level 1:              [hash(hash(0,A),hash(1,B)),hash(hash(2,C),hash(2,C))]
12//!     Level 0 (leaves):     [hash(0,A),hash(1,B),hash(2,C)]
13//! ```
14//!
15//! A proof for one or more leaves is generated by collecting the siblings needed to reconstruct the root.
16//! An external process can then use this proof (with some trusted root) to verify that the leaves
17//! are part of the tree.
18//!
19//! # Example
20//!
21//! ```rust
22//! use commonware_storage::bmt::{Builder, Tree};
23//! use commonware_cryptography::{Sha256, sha256::Digest, Hasher as _};
24//!
25//! // Create transactions and compute their digests
26//! let txs = [b"tx1", b"tx2", b"tx3", b"tx4"];
27//! let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
28//!
29//! // Build a Merkle Tree from the digests
30//! let mut builder = Builder::<Sha256>::new(digests.len());
31//! for digest in &digests {
32//!    builder.add(digest);
33//! }
34//! let tree = builder.build();
35//! let root = tree.root();
36//!
37//! // Generate a proof for leaf at index 1
38//! let mut hasher = Sha256::default();
39//! let proof = tree.proof(1).unwrap();
40//! assert!(proof.verify_element_inclusion(&mut hasher, &digests[1], 1, &root).is_ok());
41//! ```
42
43use alloc::collections::btree_set::BTreeSet;
44use bytes::{Buf, BufMut};
45use commonware_codec::{EncodeSize, Read, ReadExt, ReadRangeExt, Write};
46use commonware_cryptography::{Digest, Hasher};
47use commonware_utils::{non_empty_vec, vec::NonEmptyVec};
48use thiserror::Error;
49
50/// There should never be more than 255 levels in a proof (would mean the Binary Merkle Tree
51/// has more than 2^255 leaves).
52pub const MAX_LEVELS: usize = u8::MAX as usize;
53
54/// Errors that can occur when working with a Binary Merkle Tree (BMT).
55#[derive(Error, Debug)]
56pub enum Error {
57    #[error("invalid position: {0}")]
58    InvalidPosition(u32),
59    #[error("invalid proof: {0} != {1}")]
60    InvalidProof(String, String),
61    #[error("no leaves")]
62    NoLeaves,
63    #[error("unaligned proof")]
64    UnalignedProof,
65    #[error("duplicate position: {0}")]
66    DuplicatePosition(u32),
67}
68
69/// Constructor for a Binary Merkle Tree (BMT).
70pub struct Builder<H: Hasher> {
71    hasher: H,
72    leaves: Vec<H::Digest>,
73}
74
75impl<H: Hasher> Builder<H> {
76    /// Creates a new Binary Merkle Tree builder.
77    pub fn new(leaves: usize) -> Self {
78        Self {
79            hasher: H::new(),
80            leaves: Vec::with_capacity(leaves),
81        }
82    }
83
84    /// Adds a leaf to the Binary Merkle Tree.
85    ///
86    /// When added, the leaf is hashed with its position.
87    pub fn add(&mut self, leaf: &H::Digest) -> u32 {
88        let position: u32 = self.leaves.len().try_into().expect("too many leaves");
89        self.hasher.update(&position.to_be_bytes());
90        self.hasher.update(leaf);
91        self.leaves.push(self.hasher.finalize());
92        position
93    }
94
95    /// Builds the Binary Merkle Tree.
96    ///
97    /// It is valid to build a tree with no leaves, in which case
98    /// just an "empty" node is included (no leaves will be provable).
99    pub fn build(self) -> Tree<H> {
100        Tree::new(self.hasher, self.leaves)
101    }
102}
103
104/// Constructed Binary Merkle Tree (BMT).
105#[derive(Clone, Debug)]
106pub struct Tree<H: Hasher> {
107    /// Records whether the tree is empty.
108    empty: bool,
109
110    /// The digests at each level of the tree (from leaves to root).
111    levels: NonEmptyVec<NonEmptyVec<H::Digest>>,
112}
113
114impl<H: Hasher> Tree<H> {
115    /// Builds a Merkle Tree from a slice of position-hashed leaf digests.
116    fn new(mut hasher: H, mut leaves: Vec<H::Digest>) -> Self {
117        // If no leaves, add an empty node.
118        //
119        // Because this node only includes a position, there is no way a valid proof
120        // can be generated that references it.
121        let mut empty = false;
122        if leaves.is_empty() {
123            leaves.push(hasher.finalize());
124            empty = true;
125        }
126
127        // Create the first level
128        let mut levels = non_empty_vec![non_empty_vec![@leaves]];
129
130        // Construct the tree level-by-level
131        let mut current_level = levels.last();
132        while !current_level.is_singleton() {
133            let mut next_level = Vec::with_capacity(current_level.len().get().div_ceil(2));
134            for chunk in current_level.chunks(2) {
135                // Hash the left child
136                hasher.update(&chunk[0]);
137
138                // Hash the right child
139                if chunk.len() == 2 {
140                    hasher.update(&chunk[1]);
141                } else {
142                    // If no right child exists, duplicate left child.
143                    hasher.update(&chunk[0]);
144                };
145
146                // Compute the parent digest
147                next_level.push(hasher.finalize());
148            }
149
150            // Add the computed level to the tree
151            levels.push(non_empty_vec![@next_level]);
152            current_level = levels.last();
153        }
154        Self { empty, levels }
155    }
156
157    /// Returns the root of the tree.
158    pub fn root(&self) -> H::Digest {
159        *self.levels.last().first()
160    }
161
162    /// Generates a Merkle proof for the leaf at `position`.
163    ///
164    /// This is a single-element multi-proof, which includes the minimal siblings
165    /// needed to reconstruct the root.
166    pub fn proof(&self, position: u32) -> Result<Proof<H::Digest>, Error> {
167        self.multi_proof(&[position])
168    }
169
170    /// Generates a Merkle range proof for a contiguous set of leaves from `start`
171    /// to `end` (inclusive).
172    ///
173    /// The proof contains the minimal set of sibling digests needed to reconstruct
174    /// the root for all elements in the range. This is more efficient than individual
175    /// proofs when proving multiple consecutive elements.
176    pub fn range_proof(&self, start: u32, end: u32) -> Result<RangeProof<H::Digest>, Error> {
177        // For empty trees, return an empty proof
178        if self.empty && start == 0 && end == 0 {
179            return Ok(RangeProof::default());
180        }
181
182        // Ensure the range is within bounds
183        if start > end {
184            return Err(Error::InvalidPosition(start));
185        }
186        let leaf_count = self.levels.first().len().get() as u32;
187        if start >= leaf_count {
188            return Err(Error::InvalidPosition(start));
189        }
190        if end >= leaf_count {
191            return Err(Error::InvalidPosition(end));
192        }
193
194        // For each level (except the root level) collect the necessary siblings
195        let mut siblings = Vec::new();
196        for (level_idx, level) in self.levels.iter().enumerate() {
197            // If the level has only one node, we're done
198            if level.is_singleton() {
199                break;
200            }
201
202            // Calculate the range of indices at this level
203            let level_start = (start as usize) >> level_idx;
204            let level_end = (end as usize) >> level_idx;
205
206            // Check if we need a left sibling
207            let mut left = None;
208            if level_start % 2 == 1 {
209                // Our range starts at an odd index, so we need the even sibling to the left
210                left = Some(level[level_start - 1]);
211            }
212
213            // Check if we need a right sibling
214            let mut right = None;
215            if level_end.is_multiple_of(2) {
216                if level_end + 1 < level.len().get() {
217                    // Our range ends at an even index, so we need the odd sibling to the right
218                    right = Some(level[level_end + 1]);
219                } else {
220                    // If no right child exists, use a duplicate of the current node.
221                    //
222                    // This doesn't affect the robustness of the proof (allow a non-existent position
223                    // to be proven or enable multiple proofs to be generated from a single leaf).
224                    right = Some(level[level_end]);
225                }
226            }
227
228            siblings.push(Bounds { left, right });
229        }
230
231        Ok(RangeProof { siblings })
232    }
233
234    /// Generates a Merkle proof for multiple non-contiguous leaves at the given `positions`.
235    ///
236    /// The proof contains the minimal set of sibling digests needed to reconstruct
237    /// the root for all elements at the specified positions. This is more efficient
238    /// than individual proofs when proving multiple elements because shared siblings
239    /// are deduplicated.
240    ///
241    /// Positions are sorted internally; duplicate positions will return an error.
242    pub fn multi_proof(&self, positions: &[u32]) -> Result<Proof<H::Digest>, Error> {
243        // Handle empty positions first - can't prove zero elements
244        if positions.is_empty() {
245            return Err(Error::NoLeaves);
246        }
247
248        // Handle empty tree case
249        if self.empty {
250            return Err(Error::InvalidPosition(positions[0]));
251        }
252
253        let leaf_count = self.levels.first().len().get() as u32;
254
255        // Get required sibling positions (this validates positions and checks for duplicates)
256        let sibling_positions =
257            siblings_required_for_multi_proof(leaf_count, positions.iter().copied())?;
258
259        // Collect sibling digests in order
260        let siblings: Vec<H::Digest> = sibling_positions
261            .iter()
262            .map(|&(level, index)| self.levels[level][index])
263            .collect();
264
265        Ok(Proof {
266            leaf_count,
267            siblings,
268        })
269    }
270}
271
272/// A pair of sibling digests, one on the left boundary and one on the right boundary.
273#[derive(Clone, Debug, Eq)]
274pub struct Bounds<D: Digest> {
275    /// The left sibling digest.
276    pub left: Option<D>,
277
278    /// The right sibling digest.
279    pub right: Option<D>,
280}
281
282impl<D: Digest> PartialEq for Bounds<D> {
283    fn eq(&self, other: &Self) -> bool {
284        self.left == other.left && self.right == other.right
285    }
286}
287
288impl<D: Digest> Write for Bounds<D> {
289    fn write(&self, writer: &mut impl BufMut) {
290        self.left.write(writer);
291        self.right.write(writer);
292    }
293}
294
295impl<D: Digest> Read for Bounds<D> {
296    type Cfg = ();
297
298    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, commonware_codec::Error> {
299        Ok(Self {
300            left: Option::<D>::read(reader)?,
301            right: Option::<D>::read(reader)?,
302        })
303    }
304}
305
306impl<D: Digest> EncodeSize for Bounds<D> {
307    fn encode_size(&self) -> usize {
308        self.left.encode_size() + self.right.encode_size()
309    }
310}
311
312#[cfg(feature = "arbitrary")]
313impl<D: Digest> arbitrary::Arbitrary<'_> for Bounds<D>
314where
315    D: for<'a> arbitrary::Arbitrary<'a>,
316{
317    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
318        Ok(Self {
319            left: u.arbitrary()?,
320            right: u.arbitrary()?,
321        })
322    }
323}
324
325/// A Merkle range proof for a contiguous set of leaves in a Binary Merkle Tree.
326#[derive(Clone, Debug, Eq, PartialEq)]
327pub struct RangeProof<D: Digest> {
328    /// The sibling digests needed to prove all elements in the range.
329    ///
330    /// Organized by level, from leaves to root. Each level can have at most
331    /// 2 siblings (one on the left boundary and one on the right boundary).
332    pub siblings: Vec<Bounds<D>>,
333}
334
335impl<D: Digest> Default for RangeProof<D> {
336    fn default() -> Self {
337        Self { siblings: vec![] }
338    }
339}
340
341#[cfg(feature = "arbitrary")]
342impl<D: Digest> arbitrary::Arbitrary<'_> for RangeProof<D>
343where
344    D: for<'a> arbitrary::Arbitrary<'a>,
345{
346    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
347        Ok(Self {
348            siblings: u.arbitrary()?,
349        })
350    }
351}
352
353/// A node tracked during range proof verification.
354struct Node<D: Digest> {
355    position: usize,
356    digest: D,
357}
358
359impl<D: Digest> RangeProof<D> {
360    /// Verifies that a given range of `leaves` starting at `position` are included
361    /// in a Binary Merkle Tree with `root` using the provided `hasher`.
362    ///
363    /// The proof contains the set of sibling digests needed to reconstruct
364    /// the root for all elements in the range.
365    pub fn verify<H: Hasher<Digest = D>>(
366        &self,
367        hasher: &mut H,
368        position: u32,
369        leaves: &[D],
370        root: &D,
371    ) -> Result<(), Error> {
372        // Handle empty tree case
373        if position == 0 && leaves.is_empty() && self.siblings.is_empty() {
374            let empty_root = hasher.finalize();
375            if empty_root == *root {
376                return Ok(());
377            } else {
378                return Err(Error::InvalidProof(
379                    empty_root.to_string(),
380                    root.to_string(),
381                ));
382            }
383        }
384
385        // Check that we have leaves and the position is valid
386        if leaves.is_empty() {
387            return Err(Error::NoLeaves);
388        }
389        if position.checked_add(leaves.len() as u32).is_none() {
390            return Err(Error::InvalidPosition(position));
391        }
392
393        // Compute position-hashed leaves
394        let mut nodes: Vec<Node<D>> = Vec::new();
395        for (i, leaf) in leaves.iter().enumerate() {
396            let leaf_position = position + i as u32;
397            hasher.update(&leaf_position.to_be_bytes());
398            hasher.update(leaf);
399            nodes.push(Node {
400                position: leaf_position as usize,
401                digest: hasher.finalize(),
402            });
403        }
404
405        // Process each level
406        for bounds in self.siblings.iter() {
407            // Check if we should have a left sibling
408            let first_pos = nodes[0].position;
409            let last_pos = nodes[nodes.len() - 1].position;
410            let needs_left = !first_pos.is_multiple_of(2);
411            let needs_right = last_pos.is_multiple_of(2);
412            if needs_left != bounds.left.is_some() {
413                return Err(Error::UnalignedProof);
414            }
415            if needs_right != bounds.right.is_some() {
416                return Err(Error::UnalignedProof);
417            }
418
419            // If we have a left sibling, we need to include it
420            let mut i = 0;
421            let mut next_nodes = Vec::new();
422            if let Some(left) = &bounds.left {
423                // The first node in our range needs its left sibling
424                let node = &nodes[0];
425                hasher.update(left);
426                hasher.update(&node.digest);
427                next_nodes.push(Node {
428                    position: node.position / 2,
429                    digest: hasher.finalize(),
430                });
431                i = 1;
432            }
433
434            // Process pairs of nodes in our range
435            while i < nodes.len() {
436                // Compute the parent position
437                let node = &nodes[i];
438                let parent_pos = node.position / 2;
439
440                // Check if we have a pair within our range
441                if i + 1 < nodes.len() && nodes[i + 1].position == node.position + 1 {
442                    // We have both children in our range
443                    hasher.update(&node.digest);
444                    hasher.update(&nodes[i + 1].digest);
445                    next_nodes.push(Node {
446                        position: parent_pos,
447                        digest: hasher.finalize(),
448                    });
449                    i += 2;
450                } else if i == nodes.len() - 1 {
451                    // This is the last node and it should have a right sibling
452                    let right = bounds.right.as_ref().ok_or(Error::UnalignedProof)?;
453                    hasher.update(&node.digest);
454                    hasher.update(right);
455                    next_nodes.push(Node {
456                        position: parent_pos,
457                        digest: hasher.finalize(),
458                    });
459                    i += 1;
460                } else {
461                    // Single node in the middle (shouldn't happen for contiguous range)
462                    return Err(Error::UnalignedProof);
463                }
464            }
465
466            nodes = next_nodes;
467        }
468
469        // Verify we ended up with the expected root
470        if nodes.len() != 1 {
471            return Err(Error::UnalignedProof);
472        }
473        let computed = nodes[0].digest;
474        if computed == *root {
475            Ok(())
476        } else {
477            Err(Error::InvalidProof(computed.to_string(), root.to_string()))
478        }
479    }
480}
481
482impl<D: Digest> Write for RangeProof<D> {
483    fn write(&self, writer: &mut impl BufMut) {
484        self.siblings.write(writer);
485    }
486}
487
488impl<D: Digest> Read for RangeProof<D> {
489    type Cfg = ();
490
491    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, commonware_codec::Error> {
492        let siblings = Vec::<Bounds<D>>::read_range(reader, ..=MAX_LEVELS)?;
493        Ok(Self { siblings })
494    }
495}
496
497impl<D: Digest> EncodeSize for RangeProof<D> {
498    fn encode_size(&self) -> usize {
499        self.siblings.encode_size()
500    }
501}
502
503/// A Merkle proof for multiple non-contiguous leaves in a Binary Merkle Tree.
504///
505/// This proof type is more space-efficient than generating individual proofs
506/// for each leaf because sibling nodes that are shared between multiple paths
507/// are deduplicated.
508#[derive(Clone, Debug, Eq, PartialEq)]
509pub struct Proof<D: Digest> {
510    /// The total number of leaves in the tree.
511    pub leaf_count: u32,
512    /// The deduplicated sibling digests required to verify all elements,
513    /// ordered by their position in the tree (level-major, then index within level).
514    pub siblings: Vec<D>,
515}
516
517impl<D: Digest> Default for Proof<D> {
518    fn default() -> Self {
519        Self {
520            leaf_count: 0,
521            siblings: vec![],
522        }
523    }
524}
525
526impl<D: Digest> Write for Proof<D> {
527    fn write(&self, writer: &mut impl BufMut) {
528        self.leaf_count.write(writer);
529        self.siblings.write(writer);
530    }
531}
532
533impl<D: Digest> Read for Proof<D> {
534    /// The maximum number of items being proven.
535    ///
536    /// The upper bound on sibling hashes is derived as `max_items * MAX_LEVELS`.
537    type Cfg = usize;
538
539    fn read_cfg(
540        reader: &mut impl Buf,
541        max_items: &Self::Cfg,
542    ) -> Result<Self, commonware_codec::Error> {
543        let leaf_count = u32::read(reader)?;
544        let max_siblings = max_items.saturating_mul(MAX_LEVELS);
545        let siblings = Vec::<D>::read_range(reader, ..=max_siblings)?;
546        Ok(Self {
547            leaf_count,
548            siblings,
549        })
550    }
551}
552
553impl<D: Digest> EncodeSize for Proof<D> {
554    fn encode_size(&self) -> usize {
555        self.leaf_count.encode_size() + self.siblings.encode_size()
556    }
557}
558
559#[cfg(feature = "arbitrary")]
560impl<D: Digest> arbitrary::Arbitrary<'_> for Proof<D>
561where
562    D: for<'a> arbitrary::Arbitrary<'a>,
563{
564    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
565        Ok(Self {
566            leaf_count: u.arbitrary()?,
567            siblings: u.arbitrary()?,
568        })
569    }
570}
571
572/// Returns the number of levels in a tree with `leaf_count` leaves.
573/// A tree with 1 leaf has 1 level, a tree with 2 leaves has 2 levels, etc.
574const fn levels_in_tree(leaf_count: u32) -> usize {
575    (u32::BITS - (leaf_count.saturating_sub(1)).leading_zeros() + 1) as usize
576}
577
578/// Returns the sorted, deduplicated positions of siblings required to prove
579/// inclusion of leaves at the given positions.
580///
581/// Each position in the result is encoded as `(level, index)` where level 0 is the leaf level.
582fn siblings_required_for_multi_proof(
583    leaf_count: u32,
584    positions: impl IntoIterator<Item = u32>,
585) -> Result<BTreeSet<(usize, usize)>, Error> {
586    // Validate positions and check for duplicates.
587    let mut current = BTreeSet::new();
588    for pos in positions {
589        if pos >= leaf_count {
590            return Err(Error::InvalidPosition(pos));
591        }
592        if !current.insert(pos as usize) {
593            return Err(Error::DuplicatePosition(pos));
594        }
595    }
596
597    if current.is_empty() {
598        return Err(Error::NoLeaves);
599    }
600
601    // Track positions we can compute at each level and record missing siblings.
602    // This keeps the work proportional to the number of positions, not the tree size.
603    let mut sibling_positions = BTreeSet::new();
604    let levels_count = levels_in_tree(leaf_count);
605    let mut level_size = leaf_count as usize;
606    for level in 0..levels_count - 1 {
607        for &index in &current {
608            let sibling_index = if index.is_multiple_of(2) {
609                if index + 1 < level_size {
610                    index + 1
611                } else {
612                    index
613                }
614            } else {
615                index - 1
616            };
617
618            if sibling_index != index && !current.contains(&sibling_index) {
619                sibling_positions.insert((level, sibling_index));
620            }
621        }
622
623        current = current.iter().map(|idx| idx / 2).collect();
624        level_size = level_size.div_ceil(2);
625    }
626
627    Ok(sibling_positions)
628}
629
630impl<D: Digest> Proof<D> {
631    /// Verifies that a given `leaf` at `position` is included in a Binary Merkle Tree
632    /// with `root` using the provided `hasher`.
633    ///
634    /// The proof consists of sibling hashes stored from the leaf up to the root. At each
635    /// level, if the current node is a left child (even index), the sibling is combined
636    /// to the right; if it is a right child (odd index), the sibling is combined to the
637    /// left.
638    pub fn verify_element_inclusion<H: Hasher<Digest = D>>(
639        &self,
640        hasher: &mut H,
641        leaf: &D,
642        mut position: u32,
643        root: &D,
644    ) -> Result<(), Error> {
645        // Validate position
646        if position >= self.leaf_count {
647            return Err(Error::InvalidPosition(position));
648        }
649
650        // Compute the position-hashed leaf
651        hasher.update(&position.to_be_bytes());
652        hasher.update(leaf);
653        let mut computed = hasher.finalize();
654
655        // Track level size to handle odd-sized levels
656        let mut level_size = self.leaf_count as usize;
657        let mut sibling_iter = self.siblings.iter();
658
659        // Traverse from leaf to root
660        while level_size > 1 {
661            // Check if this is the last node at an odd-sized level (no real sibling)
662            let is_last_odd = position.is_multiple_of(2) && position as usize + 1 >= level_size;
663
664            let (left_node, right_node) = if is_last_odd {
665                // Node is duplicated - no sibling consumed from proof
666                (&computed, &computed)
667            } else if position.is_multiple_of(2) {
668                // Even position: sibling is to the right
669                let sibling = sibling_iter.next().ok_or(Error::UnalignedProof)?;
670                (&computed, sibling)
671            } else {
672                // Odd position: sibling is to the left
673                let sibling = sibling_iter.next().ok_or(Error::UnalignedProof)?;
674                (sibling, &computed)
675            };
676
677            // Compute the parent digest
678            hasher.update(left_node);
679            hasher.update(right_node);
680            computed = hasher.finalize();
681
682            // Move up the tree
683            position /= 2;
684            level_size = level_size.div_ceil(2);
685        }
686
687        // Ensure all siblings were consumed
688        if sibling_iter.next().is_some() {
689            return Err(Error::UnalignedProof);
690        }
691
692        if computed == *root {
693            Ok(())
694        } else {
695            Err(Error::InvalidProof(computed.to_string(), root.to_string()))
696        }
697    }
698
699    /// Verifies that the given `elements` at their respective positions are included
700    /// in a Binary Merkle Tree with `root`.
701    ///
702    /// Elements can be provided in any order; positions are sorted internally.
703    /// Duplicate positions will cause verification to fail.
704    pub fn verify_multi_inclusion<H: Hasher<Digest = D>>(
705        &self,
706        hasher: &mut H,
707        elements: &[(D, u32)],
708        root: &D,
709    ) -> Result<(), Error> {
710        // Handle empty case
711        if elements.is_empty() {
712            if self.leaf_count == 0 && self.siblings.is_empty() {
713                let empty_root = hasher.finalize();
714                if empty_root == *root {
715                    return Ok(());
716                } else {
717                    return Err(Error::InvalidProof(
718                        empty_root.to_string(),
719                        root.to_string(),
720                    ));
721                }
722            }
723            return Err(Error::NoLeaves);
724        }
725
726        // 1. Sort elements by position and check for duplicates/bounds
727        let mut sorted: Vec<(u32, D)> = Vec::with_capacity(elements.len());
728        for (leaf, position) in elements {
729            if *position >= self.leaf_count {
730                return Err(Error::InvalidPosition(*position));
731            }
732            hasher.update(&position.to_be_bytes());
733            hasher.update(leaf);
734            sorted.push((*position, hasher.finalize()));
735        }
736        sorted.sort_unstable_by_key(|(pos, _)| *pos);
737
738        // Check for duplicates (adjacent elements with same position after sorting)
739        for i in 1..sorted.len() {
740            if sorted[i - 1].0 == sorted[i].0 {
741                return Err(Error::DuplicatePosition(sorted[i].0));
742            }
743        }
744
745        // 2. Iterate up the tree
746        // Since we process left-to-right and parent_pos = pos/2, next_level stays sorted.
747        let levels = levels_in_tree(self.leaf_count);
748        let mut level_size = self.leaf_count;
749        let mut sibling_iter = self.siblings.iter();
750        let mut current = sorted;
751        let mut next_level: Vec<(u32, D)> = Vec::with_capacity(current.len());
752
753        for _ in 0..levels - 1 {
754            let mut idx = 0;
755            while idx < current.len() {
756                let (pos, digest) = current[idx];
757                let parent_pos = pos / 2;
758
759                // Determine if we have the left or right child
760                let (left, right) = if pos % 2 == 0 {
761                    // We are the LEFT child
762                    let left = digest;
763
764                    // Check if we have the right child in our current set
765                    let right = if idx + 1 < current.len() && current[idx + 1].0 == pos + 1 {
766                        idx += 1;
767                        current[idx].1
768                    } else if pos + 1 >= level_size {
769                        // If no right child exists in tree, duplicate left
770                        left
771                    } else {
772                        // Otherwise, must consume a sibling
773                        *sibling_iter.next().ok_or(Error::UnalignedProof)?
774                    };
775                    (left, right)
776                } else {
777                    // We are the RIGHT child
778                    // This implies the LEFT child was missing from 'current', so it must be a sibling.
779                    let right = digest;
780                    let left = *sibling_iter.next().ok_or(Error::UnalignedProof)?;
781                    (left, right)
782                };
783
784                // Hash parent
785                hasher.update(&left);
786                hasher.update(&right);
787                next_level.push((parent_pos, hasher.finalize()));
788
789                idx += 1;
790            }
791
792            // Prepare for next level
793            core::mem::swap(&mut current, &mut next_level);
794            next_level.clear();
795            level_size = level_size.div_ceil(2);
796        }
797
798        // 3. Verify root
799        if sibling_iter.next().is_some() {
800            return Err(Error::UnalignedProof);
801        }
802
803        if current.len() != 1 {
804            return Err(Error::UnalignedProof);
805        }
806
807        let computed = current[0].1;
808        if computed == *root {
809            Ok(())
810        } else {
811            Err(Error::InvalidProof(computed.to_string(), root.to_string()))
812        }
813    }
814}
815
816#[cfg(test)]
817mod tests {
818    use super::*;
819    use commonware_codec::{Decode, DecodeExt, Encode};
820    use commonware_cryptography::sha256::{Digest, Sha256};
821    use commonware_utils::hex;
822    use rstest::rstest;
823
824    fn test_merkle_tree(n: usize) -> Digest {
825        // Build tree
826        let mut digests = Vec::with_capacity(n);
827        let mut builder = Builder::<Sha256>::new(n);
828        for i in 0..n {
829            let digest = Sha256::hash(&i.to_be_bytes());
830            builder.add(&digest);
831            digests.push(digest);
832        }
833        let tree = builder.build();
834        let root = tree.root();
835
836        // For each leaf, generate and verify its proof
837        let mut hasher = Sha256::default();
838        for (i, leaf) in digests.iter().enumerate() {
839            // Generate proof
840            let proof = tree.proof(i as u32).unwrap();
841            assert!(
842                proof
843                    .verify_element_inclusion(&mut hasher, leaf, i as u32, &root)
844                    .is_ok(),
845                "correct fail for size={n} leaf={i}"
846            );
847
848            // Serialize and deserialize the proof
849            let serialized = proof.encode();
850            let deserialized = Proof::<Digest>::decode_cfg(serialized, &1).unwrap();
851            assert!(
852                deserialized
853                    .verify_element_inclusion(&mut hasher, leaf, i as u32, &root)
854                    .is_ok(),
855                "deserialize fail for size={n} leaf={i}"
856            );
857
858            // Modify a sibling hash and ensure the proof fails
859            if !proof.siblings.is_empty() {
860                let mut update_tamper = proof.clone();
861                update_tamper.siblings[0] = Sha256::hash(b"tampered");
862                assert!(
863                    update_tamper
864                        .verify_element_inclusion(&mut hasher, leaf, i as u32, &root)
865                        .is_err(),
866                    "modify fail for size={n} leaf={i}"
867                );
868            }
869
870            // Add a sibling hash and ensure the proof fails
871            let mut add_tamper = proof.clone();
872            add_tamper.siblings.push(Sha256::hash(b"tampered"));
873            assert!(
874                add_tamper
875                    .verify_element_inclusion(&mut hasher, leaf, i as u32, &root)
876                    .is_err(),
877                "add fail for size={n} leaf={i}"
878            );
879
880            // Remove a sibling hash and ensure the proof fails
881            if !proof.siblings.is_empty() {
882                let mut remove_tamper = proof.clone();
883                remove_tamper.siblings.pop();
884                assert!(
885                    remove_tamper
886                        .verify_element_inclusion(&mut hasher, leaf, i as u32, &root)
887                        .is_err(),
888                    "remove fail for size={n} leaf={i}"
889                );
890            }
891        }
892
893        // Test proof for larger than size
894        assert!(tree.proof(n as u32).is_err());
895
896        // Return the root so we can ensure we don't silently change.
897        root
898    }
899
900    /// Roots for all trees with 1..201 leaves.
901    ///
902    /// We use these pre-generated roots to ensure that we don't silently change
903    /// the tree hashing algorithm.
904    const ROOTS: [&str; 200] = [
905        "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
906        "50ae5b142a0f31db537ba060ba07e46fafe1ec960ebec7b6f08f03dafe774f52",
907        "fce6b9d873d5a92d828695fbddb93d0cecc76747e311035cf7b2a80532f65ea2",
908        "33635879d11892586d0735076c9d1b9d661344861d46aa96c36450b71a32300c",
909        "e5e67dc697801aea53044bc042a0e8724abf1f96512c0b4a4dd9027697fbb160",
910        "4fe4f8ada41e7d98d2344a7faec0360cf4c718318c6cce2bbfdad544288ab746",
911        "1a80d0ad0413511f1a56490d9527a5dd2f4686884c4fdc4e912221b7a67462c3",
912        "924aeecd88420edaf033e055f276823ffea95eb965f8a24bedd3b71ff7a4e00e",
913        "48b65ee4de800d7ab900781dc0257bf22675e5d921395e4392e1f1ca81095d06",
914        "846ab5f09531e4176aa66a6bd03d83f7503c16dfc494aa7cf600825bb11df9c3",
915        "bd491c9ca0678c29f61ad2affcfb313edbbd5f59c58a7c0d5ce1f0dbb7baf282",
916        "422aab7074448c8d5563ba5636f18fb46ccab9de0a12c997d82d12f0273a9477",
917        "4ee0c261ba4eb3902ac003b6789675f7a2ccb09ffd23249fdc457f436e675b18",
918        "e303776cd1f6f708659765f938dcb79ffe7878f03b67d97947ee8320c2377480",
919        "787847b8cfd106d7264ed6280c72d4e5e62294c8c4f786f486b16217b993fcbb",
920        "2d7cb674b223d2b3bf82a3d76d53b58eb542b5f9cec672f075c2cd3056a869f8",
921        "9888bb342b33693d7885e1a84fa9cd803bdbb3fdb5593f6cabdd68511fc34e3a",
922        "d491440069227e34868e75ea9c4c0946bc3084651798946916100de64b1ee2c7",
923        "b3f496525d3b4b9db0d409a954a0f29078b1c9f7b4fbc5d32e4615bfbf657ab3",
924        "3ad08b0ce43aea793560e5b093398abfdfb37310e86c8bf0cfa91e7573f80100",
925        "86229048316a1c894883a9e3a8d3c3d3e95f0b843d1f648f9e58462aff9f3148",
926        "143f71172df1ea73e59c795d0b3a7ccaff6cb9d934200ddb7fe485a02bbcb25d",
927        "688a6084995fb4d5b65592f8fac5b5347d46252ff08059d825884ed7b46a92a9",
928        "1152caa5f17fd92aa0f86b4ec07a442b176b62961e525bfe84d5b82913ab5269",
929        "71e367ea9deacf960f80370f169accf59345b77e02e780bf916e9daab0be060b",
930        "05bcda0901af59dd91b74c3f34edc6f7ba9e4b6e61b77888053a02c65f7b75a3",
931        "6c8e49673a96942fa83ff46c4f82511806d7185e7025d8b39df159b98b1394fa",
932        "a38f666a29ea9c6d084eebce18a31422234db99be0e947205e5b6fb05dc344a4",
933        "b9325d2e47b15e451928b96feadaf29ae57107e15f28f04a59f54e44b3e152a0",
934        "5e35af451db9a82e17a904e477aa48ebf678abd3527c5a7a6c1e0d0cae033196",
935        "eb1e3e7c34f35cee920cae35d779675f8f0e4a226d513ff72e67a61f1cb07bed",
936        "dfffa428315478482fb39b6cabd19b82c4abe0fdfe28a2d8b637b00934694d26",
937        "e8af2e8391e3fcec5a1a4acd0df713dd56abea1949234aeec4f999c57adc6886",
938        "9ffeaf6d1802438062656b7a8ac052287b349172abb1cd0c6102de8d782c773b",
939        "637127e22c8c5505c95637436a8c7872523bb1e05000ce3b026b2c60335a9ec6",
940        "3a5ae08c9837b67941f2096b4e806b8bf54e1d11836e3b54c2d1ddd8be81d339",
941        "b9e868d4441e850c8989ab140cb7e7107fa916a7cc9f10532460669b5d185fb9",
942        "ca4e9513943517c7756ecb1fdfcf941f8b296eb59ca344960ddf447fc811b3fe",
943        "e889aa56a848a2b283fd3fd6e134fc83450c0d6c1d01f576c2bb5eb72a87f409",
944        "7f37830b35e2eaf1c22658508a2cf8cf2c4ad138ee96bbb4dca6d466699ab09d",
945        "5f30c90f31b8a32a117579c89ef258d3621e3c4ffd0051b50fe7032e7d16024c",
946        "022e9efb9c643379420118e4553d2355eec5e3bcb3502778bc4b2e85d57b4795",
947        "daa5d97c2202a64210ec877a9075dd17fb9f6178ad6b0905809a4d79df13e3c8",
948        "5d2873958ea245ac1e8ece124ae9fe1b5cecb36034a0fa644f447026728bcabd",
949        "7744dc3b7505d01edc098edb6873e8e923d371ec777b0abe2d7fc0f5e5abfcff",
950        "52fe4af553d4bb631cc42ceabb7395fd2a234ee1431b8720571d2878e4676e4b",
951        "c46c4647b7464f67c19ec8a66815b87487070fd0aad02dd51c537af08e7036b2",
952        "004828da3fd62ee55449394a54882573d2ce5f323e45cf021e99ca0c3f4b12fd",
953        "aea7466b24c3537178dfb0e2b23254162230c36613664f546923edda8f4a9cb9",
954        "12b52d15244e3e4f01f2b69dff8b18e4d30cda39e3d87b09875fba0918c0f3c4",
955        "cb774e0aba6a497ebeefdac5237ea4b91cf02d8df761e4d5931bca06f92ba7e7",
956        "730fd826be4ae1482b88affb6e74ff3461409903a499f86170168f4634a3e36b",
957        "12ac285defa63afcc7a47541993837d2da3f81def14004a058d0b82c340f3f28",
958        "e661d6c753cf32fa26eefa5d2c1e4602386df79e96b1e0bd3a54454de6fadc1c",
959        "608587b5ae578e310be49be55fee4d950bf85cda31af2ecd0306bfc34fab61d1",
960        "a41205347e79e7b2a688422cb620caef3862c06be97c3cceb0cc6cef39fbafe8",
961        "d332d4863654ba825c0e1ddb63b9a0c1bf35aea89a28f0c7234ec104e4e9e8e8",
962        "d21f7cbce3ba334611617b73f5abf283d17ca7a7a0e460f4e4c559bb6175cadb",
963        "ec13e53573f637e38ce6f45b55e8a9967f3121ee30b52fd2b8b680512b175ee0",
964        "b137cc53ae95e87de14667d94bfc77015d29ae978c09ada78ce00061b03f7d56",
965        "f41819163d7e13359c09c50776f0da810dc39d6e15ea67f2b047dbd2a609933f",
966        "f128a3ee5cb5b6d687aaf6908445256de0099d976346ef6e5496bd51a2b7400c",
967        "94141d70b9b61b86ec050753f11a9f2d275f3d28a07d044c7f0d8736128252a9",
968        "80acd071567fcca9e8740fe47d29c1197b2df093e22197c53e6176d9b1565045",
969        "55871c3b57591746d7febac3e386dd838cf13276572daf484332811f1a62e8f4",
970        "7674ec07655fb1f00bc1c46f9f7b3847674815b4c8a05327ac6a40ac031c7616",
971        "253794e58aab5d5ad517c2e1d007566e25c8be42033c1255f4139dc014914c2f",
972        "ad0ad5f5c95c2e5ad0f78354bafb7563f0c6573a74253145373ffc24eb13debb",
973        "c322c8902b4a4c10879856222f820d8f92ffd15d25d5d461a1ac126954580626",
974        "1e1be47b4c0b321f3ac638039ff9e47ca6ebadf15a6230699c6405a3ed7044dc",
975        "225a9d06465ac4b1cf65528c799966c5a8344e484d31289c8cfd9d29202bd02f",
976        "17382a91ee6946f78cb712e53a9e58d6c0e07a26be2b47463ecbfcada335dd6e",
977        "4635742a72a250016f3c92d510d3aa64b2f7f2d8f739cace99b49ae20bfda981",
978        "0b49ac169f476f95c84e376ca86c7ac66a82df44bd6783edf238be23bffaad5e",
979        "f18d45122b929ae17a7233f60414b5626577eb00b00e106a1eb852a6c4cf7f57",
980        "3ab2fb11c3d06ca1d8228402b7f6f3ebebc2072305e015fd142c51675cfddbec",
981        "c9dcb27313895d2f7c67af4d6ae6734a22aecc49cec0b9f3cdb27eed7e4d8f03",
982        "ed4397b2d47b98848253e66d79aba7bfa2beb2a44ffc3aa6d9b4056fcfd099cb",
983        "b35074c978d512800e700adfddf0a73fbf4de49215cfdb69430aa51525ce507e",
984        "58093e52dc8e10fed83fd8f60a6ebd5980cde59667044d3eaf6dd942c3dc110a",
985        "b23225934ef6cfbfc2fd95da072a030d8a4815502bf15d14f90a64b6b6bd1a83",
986        "e66ec3aff80f8224a1012ef0fd137e685ab294c4a3d47b976553d13afcc130cf",
987        "b06ec0ecaa3d9fba83a25bb25b44ef88ba66748c7dd6ca4692fa6c3efccfb44e",
988        "0a9e7cbb5b1697e45245329a5a4bff4b2ca1a93a7f1ed1cf8a552ac6493131ce",
989        "f9f3a65472790ca66b908e0e8bddd2040aa0db36557f453df8a8d6b4604a12c5",
990        "0650349d871b9efc044110657c49eaa2dcbb27257a320d6e59a18178c237ec38",
991        "49c04edb1576b51db9fe0bd990dbf16b90418837be51c7983b32d76bbf2f9f30",
992        "1b2ece1a345f9e762235b01c8f644277408281545f063732183386bab2a09dce",
993        "182b36c2af475f3ca465b409f8a110ec6a23e0e5388730ed7920628bbe15268e",
994        "a8aecf727c29a84d4e15be02399f78b4fd0f1b45a48d30062a8c871de684b612",
995        "9e0bc42a02db1b41d4ed9a7c6fcab527085c469b37471bc20f89fbeedd5e03ce",
996        "3b89297f5235f95c35dabe6235dd89958af0b15b1868e5151cde112fa3039773",
997        "15e7c5ef9b6c731b075322897799f54ec8622a00ca90cceac3411f83b49ea237",
998        "79e2533ad3eebb44325eb5a5b93e7cbb67278b564eeeff4a029c802935527a01",
999        "3a691d7163b2ff4bf566c0bee7ccef767a5303d3a9319729d799ae12e19f4c1a",
1000        "5799066961c8ca5c5b3d62e90e407fa51429488fd14c80ba8ba28529a2071c84",
1001        "ae530275bf76e94083b2c8de75ad44fe7ab4d45c46fd461ca796a7a2803e7608",
1002        "3f8eec5de2cc57152c9d58caa5fd4d2a3ddf22d666eae9a6ae0aee433127f9f6",
1003        "00f16a9bde34a6d3c1b0c21486165cc32dfa840e3a07da864625d7a2b1d493bf",
1004        "e57b868d21768ac786eca4889030c7517af93102198b0cdf15879bb12e434985",
1005        "48a705b3265d0696a69c7870d05052ed0d24c9c094727408be4429f6b236db62",
1006        "14e0743518594de85852563962db3b63688dda7034f86f86b903c9bec21860f2",
1007        "9d1b3b67045dc6b85b3a2c5cd4c2ed14c6ad2d1f17740a6fe29387865e433c71",
1008        "ca5afe197a9aeb4020a6110ac693e84b174800e4de4bd92d9a15cacf7d77f598",
1009        "7f833e5072a4c8c3802613626b5afa42a69790614f4fd84ee269ce2cc8de08fb",
1010        "d4f5f4d6b6c185e1d68dcac5d4e7d55828cd94c1eb6170e75d0ca474e21a14d8",
1011        "eaf15269b6f147771746cf2cd7f8b6f2eab92287a8468f03127eab68b78fcfa1",
1012        "f84c317503d500c03b32e2d14360a6d1877e791f5cccaccc9c0e15c71ed85705",
1013        "e0e6d90287b23f7065a13537ed8353d43bcc14b80e6902938db6cf5ac43e79fb",
1014        "2e244362779d657581f0a9879daba8acbe1c7234a2e27eef91c8a0a1be6c6efb",
1015        "7086f9c9e40a5f576235d41dac2187001ff1c315cc94dd3a0feaf3e905be7f7a",
1016        "4b9e14b2834ab37608e3ec4b85db30a4b45d0caf78dd6363e02d8802a2d51a41",
1017        "e3e44f53cf473636859fc6d6eb05dc505e5a56c612216636a44c8eac8efad382",
1018        "99d4638fb24b7aca63e936a60abb74abb70d7797643879be80735605a7e2a2ed",
1019        "1e8401b6c65c67dc544e9a1ce21c6ce9903702ac30c93d0caa0df64b6c0e1e36",
1020        "1bf14f3f0372956833770f87e9145cfc0a5b0dc985b1b694353e705961e94738",
1021        "ed9b69ad2d779f82b2d1a97a5bd1e2f941b2edfdfd82db99f121561964345128",
1022        "035c58d5ac8a38fc0e6dec6472f3459f47c17f76bb04eef929064482f5bfb2a9",
1023        "706ff9580c8869ab68edb9e801b5c631377a10ac07617fb34d9250616231ad52",
1024        "f9b815729a5cdfe9f1ebcaaca36a658464a5d49c2dad1dcae7aed2688c2209a7",
1025        "8c1e7468650b0f8309c23b7fb453ce59ab989fcaa80fa32bd82d02c25fc19b68",
1026        "557a00a4e6d55c60a033b23ca20975f5c774ed0fef3bc316f68fb4a6df66137e",
1027        "06516e2e9e5fa3583c643209666758483e38c642757e7a452ed29d716229370b",
1028        "f708b4d19acfadd56e1e4275ed1191d285c656ee045efd2b7049539a39caf5a2",
1029        "00a126e14b8ec6f7e7e31d0d4b551a24fcbcad62045490feb532b0b78d15a411",
1030        "c47d49034a6a7ce59fae50d10153fdd619783c39265789a7858b420cbc32b56e",
1031        "c7d67122fc2b83e565ee0108e16753936f2bb62128d38237454053e60ac918a8",
1032        "18db7a4c3694b83c2258a4bafdd062cf20d80d356d9d899bc429be9d732dac0e",
1033        "e3e55212157e06d8745eb23eb4a391611abf0d9e98efe19b482d0d0fdd66a053",
1034        "70d1830363a58704b037f018a417b7e8682f7a2bad6ed5eaefacf335b9f2de13",
1035        "559e34d21bf90025d69c0401e3bfb70abfd470fcd4a64f739728f41c0fed4075",
1036        "73828339c42835cd9f48291c11322d905a35e4d0cccca4095a93a1e4bb778664",
1037        "7f4cba2e2e584eae771dc328099a098819a6625ea5b2c9382120a1504964841b",
1038        "a1f44690445ccd1b9930f615e416aeda750601a49631b4eb536f6fd709293f0e",
1039        "5de9674bc7412231cdb526dc17bfd2e0ed0635be4224d9f72c16378bba7ad8dd",
1040        "7b217e77ea4175029928ba4839f6d350df9e41b67cff183b1a43ab52925193ca",
1041        "53bea1bad7659ccd0feb50136fc5093878888fe0cb16dee5ed7503b01d96e4ba",
1042        "084e489bf686d41db4e8f0ff1bce15a40ac24b948ddcc377a8095d99751673ea",
1043        "bf67b177d3000a2ac7df34d422486cec6606c6ee82ee50aa91dd98b567957f6d",
1044        "2f5777d29dcb3c78730c52fedff7d57270125f9a8a570c9d30cf0ad141803118",
1045        "3c06f61c8b538beb4a557bbdde61a379a631972b3d0698fbb98c68c874744698",
1046        "12d7d4f4c868b645681dc988d3a170b2f6e425c067ef89ee7a7f07c801ba226e",
1047        "6f0a289c5c41336a1b5d32aecaec5aa57d1352e319820b80e84d38979ce1ea2c",
1048        "a8e2f08c46aeadcf56bb10d427418174269e679af7a53c7a1fe92c3fe13f133b",
1049        "e7e04233a526c7b513eb02d65b8c81b48edf95782d0fbacd0ece7d391f3a7598",
1050        "d0c677a7b01abb943f00ab1dfa2d4097c4b2309566d6a9ada3cd0f0d1041b449",
1051        "2cc6597dfd2903bb9e8549f2d1f6842f0e136b0aab9872bbf4b86f49b59c3678",
1052        "0f230a73d7922eae8290b989014806fb9e6e3c042fa87a8adc742b31e99c4dcc",
1053        "ec0ab16c9228a1671d6501189cc53dedaafe17cb3aea8119f77fd78d035ec740",
1054        "f80b66f4f25c4995b19cb973dfd5be34cda67e47e359e944d7fb6ee63e4a64b4",
1055        "791066ca90c59ab7729bc242be45e26f8f1343656ed63e7c597eb3618ac34036",
1056        "5efea2b25d7407a8c14a9d0f232e7280a9b13b14e48635925be0703547060f3c",
1057        "5bb18cd0630e2cefec9817220b3561157f893570cf8f7374eb5d4d374be7d3fc",
1058        "97d1a186229ef63fd0616c3dc36777065ad201b11109b8a8b43a7326c868cd72",
1059        "d715dfb79b1bca2e5464e3c2c1f7b9cd3b3962fb7a9b42ddc629efd76a5b9b0d",
1060        "bb9960745bfd91f49aedda17a5151d3f2105523d637e8df3c4a19e201688e3ab",
1061        "4d694f1b092b6c514f50b832d483d14cbf2d22435c1d64b0a0143b1b91a7db0e",
1062        "f4aec328caed1748906126cd72f9dc032dc529e3cabc9a55f96ff7f08e136630",
1063        "65d7ca2883222a70edb0acadb0d969fb3824224e3de365ca98b8d41124955640",
1064        "5a7c37a041319dbc68a2aebb98d18dcf971bdd26f7679fb4c8d71023dd62e763",
1065        "45c7c8a9c1a6d073df038a63c8fb3585750f2186020fc42e67388ed90d687334",
1066        "76ceb2ed736c577275c47a270f13fc3f829db8f677fe52117a7916913f8e9f07",
1067        "83616f52af18dfb6bca88c39905c24d1d7443b8fafcb408ba92e3357bf64826d",
1068        "6184a19e674eb02c014ffd52ccfae8451d78bdd371d7f3c5d9c0b034ea75f34b",
1069        "73cbf19495785c2a8822229e71ae5246cb0572f5bfc31ab0c95a6f9bdbe42880",
1070        "ad417fcc01c49775fedc526cac80ed9751799f50db513d7107da4b5539e25025",
1071        "fcf56dcdb68b31aa8c71404585a886cfcc978e08be8f64c6c3ce8438044013ca",
1072        "f4c9a1a92630aa75afd8b8dbcaafdc212ffb2f34b69a7bdb2f40609aa332236d",
1073        "b932d9bc11b9f21ab792e3b5dff181a56cc9eeab2f3ee7afe4d3c82317fe3b9e",
1074        "f78f6c3055d0c1c49fe4303a4e97de9e85107d084a542e15d3a1f59d068d48cf",
1075        "aed078316e0c3c4624d12b253adc31114011bdc8550b3cf9aa7a3ae3528478ae",
1076        "67879ad6b94d3e536c41abcd2719df496d990e360e3cd1bf6168ad34681c9b7e",
1077        "3d9c7c5590c129b3ac13384367c823d2bf4fe8b681d617b3b5d627494897753a",
1078        "c5b437bb860c077c0a42eaf4574418da19681dcd8bae66f39d64c28488d73715",
1079        "c3a56646dde6bef7edbd352447a84d11887f90e6c701ba3f416657c2266e7dc0",
1080        "8d2540362789502dfb5a288bc65ac890265a214a0cda02f5ceaccb469b0cc137",
1081        "2e45352b458f89889bada37cf933852d182a7824113b025b88b6a85cb269c6aa",
1082        "6fc01506749124063a43a2120245bf3b1c5aea36f3d59bc39dc51e057e75f71f",
1083        "588efc61ec42e19f898bd5d958a7365c4c3baf8038a64a1460806f3cdc21948f",
1084        "808d865fc016720e9bf61a0d5eaa015f6f187d41d7633845c92c6cacdfe613c9",
1085        "e6a1d190049b0c050e189d26c00f96e2235eb8bcb196aca24fdc62fd0ecb9eae",
1086        "1a306d0a919c071c844e7bba1c052090637ede6b61cc4683f0f4b2c461eecdb8",
1087        "4e45867c281c31ee45c7fca4a8360deba83194d8e564ee67f3bf93ed3957bec7",
1088        "bf6327fddf29b861a04f968dc5774cfef7b3e10eb1f245e5efa8fd83fafa2bf1",
1089        "3e45cc36fbaf609569d86d61b35149cdb76ad98f89ece8346f3a37a3c1719cf4",
1090        "880158cad3643cf9a0edb91393c32054ddbc1f246e033ce487c8eb4d107c1194",
1091        "bb0df4b7018c0263acab38f3b17f39b275825c0f68d4433309723398933b8da7",
1092        "d7e391633d0961dd8a570346483012a0b6f63e00d246111fa34f2ccc47fb8703",
1093        "8200353a6675b2cf6f8d582522f4b5a3631c7d63e1c2241f11663349e76462f3",
1094        "fac2e4190f279be818ea9aa3480dc4a1e3cbcf7f0882f8e31c2157ef0508e90f",
1095        "17749a05e9cae5177d8e0faba46da779823d3e8d86ef5ed79b54d78135bb7223",
1096        "87028314fdab0aa49907b7ce8b8f3908907295d7e0c0b6bae2fe9b5ba5c0ceb4",
1097        "167183adfd0b5e5969f45cfc8ff6540e15ead0fdcd6c9dfc298d630759d189be",
1098        "537a57b808d97bd0bd43c44ed409c104453422052e55d6b5ff6c2f0e094e8be7",
1099        "91f9ca4ece65c41449b62d0bfc3b3394bd748bb084b8821e4c022a7eece1c612",
1100        "bbe7726fdfcf0ff06ec19af865ca1f63aa04c17ed76b61048d146a35790ad9bf",
1101        "e80cd26d4b358842e76d45a4e5560ec8998fcff4675a526d940739338bf427a7",
1102        "165b46546b409202ee4b213ee9cc36b4e401d90a726a9976c45b9c448df4b8ea",
1103        "fdd9b0055a0d85ae21f227a875ac22cef20592fba24cebc306cf401ab8d61fab",
1104        "a7df94accafd8e8cfc78996cb98b25dc2cf28b3eb4983106b50e359b81040eb5",
1105    ];
1106
1107    #[test]
1108    fn test_merkle_trees() {
1109        for (n, previous) in ROOTS.into_iter().enumerate() {
1110            let root = test_merkle_tree(n);
1111            assert_eq!(hex(&root), previous);
1112        }
1113    }
1114
1115    #[test]
1116    fn test_tampered_proof_no_siblings() {
1117        // Create transactions and digests
1118        let txs = [b"tx1", b"tx2", b"tx3", b"tx4"];
1119        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1120        let element = &digests[0];
1121
1122        // Build tree
1123        let mut builder = Builder::<Sha256>::new(txs.len());
1124        for digest in &digests {
1125            builder.add(digest);
1126        }
1127        let tree = builder.build();
1128        let root = tree.root();
1129
1130        // Build proof
1131        let mut proof = tree.proof(0).unwrap();
1132
1133        // Tamper with proof
1134        proof.siblings = Vec::new();
1135
1136        // Fail verification with an empty proof.
1137        let mut hasher = Sha256::default();
1138        assert!(proof
1139            .verify_element_inclusion(&mut hasher, element, 0, &root)
1140            .is_err());
1141    }
1142
1143    #[test]
1144    fn test_tampered_proof_extra_sibling() {
1145        // Create transactions and digests
1146        let txs = [b"tx1", b"tx2", b"tx3", b"tx4"];
1147        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1148        let element = &digests[0];
1149
1150        // Build tree
1151        let mut builder = Builder::<Sha256>::new(txs.len());
1152        for digest in &digests {
1153            builder.add(digest);
1154        }
1155        let tree = builder.build();
1156        let root = tree.root();
1157
1158        // Build proof
1159        let mut proof = tree.proof(0).unwrap();
1160
1161        // Tamper with proof
1162        proof.siblings.push(*element);
1163
1164        // Fail verification with extra sibling
1165        let mut hasher = Sha256::default();
1166        assert!(proof
1167            .verify_element_inclusion(&mut hasher, element, 0, &root)
1168            .is_err());
1169    }
1170
1171    #[test]
1172    fn test_invalid_proof_wrong_element() {
1173        // Create transactions and digests
1174        let txs = [b"tx1", b"tx2", b"tx3", b"tx4"];
1175        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1176
1177        // Build tree
1178        let mut builder = Builder::<Sha256>::new(txs.len());
1179        for digest in &digests {
1180            builder.add(digest);
1181        }
1182        let tree = builder.build();
1183        let root = tree.root();
1184
1185        // Generate a valid proof for leaf at index 2.
1186        let proof = tree.proof(2).unwrap();
1187
1188        // Use a wrong element (e.g. hash of a different transaction).
1189        let mut hasher = Sha256::default();
1190        let wrong_leaf = Sha256::hash(b"wrong_tx");
1191        assert!(proof
1192            .verify_element_inclusion(&mut hasher, &wrong_leaf, 2, &root)
1193            .is_err());
1194    }
1195
1196    #[test]
1197    fn test_invalid_proof_wrong_index() {
1198        // Create transactions and digests
1199        let txs = [b"tx1", b"tx2", b"tx3", b"tx4"];
1200        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1201
1202        // Build tree
1203        let mut builder = Builder::<Sha256>::new(txs.len());
1204        for digest in &digests {
1205            builder.add(digest);
1206        }
1207        let tree = builder.build();
1208        let root = tree.root();
1209
1210        // Generate a valid proof for leaf at index 1.
1211        let proof = tree.proof(1).unwrap();
1212
1213        // Use an incorrect index (e.g. 2 instead of 1).
1214        let mut hasher = Sha256::default();
1215        assert!(proof
1216            .verify_element_inclusion(&mut hasher, &digests[1], 2, &root)
1217            .is_err());
1218    }
1219
1220    #[test]
1221    fn test_invalid_proof_wrong_root() {
1222        // Create transactions and digests
1223        let txs = [b"tx1", b"tx2", b"tx3", b"tx4"];
1224        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1225
1226        // Build tree
1227        let mut builder = Builder::<Sha256>::new(txs.len());
1228        for digest in &digests {
1229            builder.add(digest);
1230        }
1231        let tree = builder.build();
1232
1233        // Generate a valid proof for leaf at index 0.
1234        let proof = tree.proof(0).unwrap();
1235
1236        // Use a wrong root (hash of a different input).
1237        let mut hasher = Sha256::default();
1238        let wrong_root = Sha256::hash(b"wrong_root");
1239        assert!(proof
1240            .verify_element_inclusion(&mut hasher, &digests[0], 0, &wrong_root)
1241            .is_err());
1242    }
1243
1244    #[test]
1245    fn test_invalid_proof_serialization_truncated() {
1246        // Create transactions and digests
1247        let txs = [b"tx1", b"tx2", b"tx3"];
1248        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1249
1250        // Build tree
1251        let mut builder = Builder::<Sha256>::new(txs.len());
1252        for digest in &digests {
1253            builder.add(digest);
1254        }
1255        let tree = builder.build();
1256
1257        // Generate a valid proof for leaf at index 1.
1258        let proof = tree.proof(1).unwrap();
1259        let mut serialized = proof.encode();
1260
1261        // Truncate one byte.
1262        serialized.truncate(serialized.len() - 1);
1263        assert!(Proof::<Digest>::decode_cfg(&mut serialized, &1).is_err());
1264    }
1265
1266    #[test]
1267    fn test_invalid_proof_serialization_extra() {
1268        // Create transactions and digests
1269        let txs = [b"tx1", b"tx2", b"tx3"];
1270        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1271
1272        // Build tree
1273        let mut builder = Builder::<Sha256>::new(txs.len());
1274        for digest in &digests {
1275            builder.add(digest);
1276        }
1277        let tree = builder.build();
1278
1279        // Generate a valid proof for leaf at index 1.
1280        let proof = tree.proof(1).unwrap();
1281        let mut serialized = proof.encode_mut();
1282
1283        // Append an extra byte.
1284        serialized.extend_from_slice(&[0u8]);
1285        assert!(Proof::<Digest>::decode_cfg(&mut serialized, &1).is_err());
1286    }
1287
1288    #[test]
1289    fn test_invalid_proof_modified_hash() {
1290        // Create transactions and digests
1291        let txs = [b"tx1", b"tx2", b"tx3", b"tx4"];
1292        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1293
1294        // Build tree
1295        let mut builder = Builder::<Sha256>::new(txs.len());
1296        for digest in &digests {
1297            builder.add(digest);
1298        }
1299        let tree = builder.build();
1300        let root = tree.root();
1301
1302        // Generate a valid proof for leaf at index 2.
1303        let mut proof = tree.proof(2).unwrap();
1304
1305        // Modify the first hash in the proof.
1306        let mut hasher = Sha256::default();
1307        proof.siblings[0] = Sha256::hash(b"modified");
1308        assert!(proof
1309            .verify_element_inclusion(&mut hasher, &digests[2], 2, &root)
1310            .is_err());
1311    }
1312
1313    #[test]
1314    fn test_odd_tree_duplicate_index_proof() {
1315        // Create transactions and digests
1316        let txs = [b"tx1", b"tx2", b"tx3"];
1317        let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1318
1319        // Build tree
1320        let mut builder = Builder::<Sha256>::new(txs.len());
1321        for digest in &digests {
1322            builder.add(digest);
1323        }
1324        let tree = builder.build();
1325        let root = tree.root();
1326
1327        // The tree was built with 3 leaves; index 2 is the last valid index.
1328        let proof = tree.proof(2).unwrap();
1329
1330        // Verification should succeed for the proper index 2.
1331        let mut hasher = Sha256::default();
1332        assert!(proof
1333            .verify_element_inclusion(&mut hasher, &digests[2], 2, &root)
1334            .is_ok());
1335
1336        // Should not be able to generate a proof for an out-of-range index (e.g. 3).
1337        assert!(tree.proof(3).is_err());
1338
1339        // Attempting to verify using an out-of-range index (e.g. 3, which would correspond
1340        // to a duplicate leaf that doesn't actually exist) should fail.
1341        assert!(proof
1342            .verify_element_inclusion(&mut hasher, &digests[2], 3, &root)
1343            .is_err());
1344    }
1345
1346    #[test]
1347    fn test_range_proof_basic() {
1348        // Create test data
1349        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1350
1351        // Build tree
1352        let mut builder = Builder::<Sha256>::new(digests.len());
1353        for digest in &digests {
1354            builder.add(digest);
1355        }
1356        let tree = builder.build();
1357        let root = tree.root();
1358
1359        // Test range proof for elements 2-5
1360        let range_proof = tree.range_proof(2, 5).unwrap();
1361        let mut hasher = Sha256::default();
1362        let range_leaves = &digests[2..6];
1363
1364        assert!(range_proof
1365            .verify(&mut hasher, 2, range_leaves, &root)
1366            .is_ok());
1367
1368        // Serialize and deserialize
1369        let mut serialized = range_proof.encode();
1370        let deserialized = RangeProof::<Digest>::decode(&mut serialized).unwrap();
1371        assert!(deserialized
1372            .verify(&mut hasher, 2, range_leaves, &root)
1373            .is_ok());
1374    }
1375
1376    #[test]
1377    fn test_range_proof_single_element() {
1378        // Create test data
1379        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1380
1381        // Build tree
1382        let mut builder = Builder::<Sha256>::new(digests.len());
1383        for digest in &digests {
1384            builder.add(digest);
1385        }
1386        let tree = builder.build();
1387        let root = tree.root();
1388
1389        // Test single element range proof
1390        for (i, digest) in digests.iter().enumerate() {
1391            let range_proof = tree.range_proof(i as u32, i as u32).unwrap();
1392            let mut hasher = Sha256::default();
1393
1394            let result = range_proof.verify(&mut hasher, i as u32, &[*digest], &root);
1395            assert!(result.is_ok());
1396        }
1397    }
1398
1399    #[test]
1400    fn test_range_proof_full_tree() {
1401        // Create test data
1402        let digests: Vec<Digest> = (0..7u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1403
1404        // Build tree
1405        let mut builder = Builder::<Sha256>::new(digests.len());
1406        for digest in &digests {
1407            builder.add(digest);
1408        }
1409        let tree = builder.build();
1410        let root = tree.root();
1411
1412        // Test full tree range proof
1413        let range_proof = tree.range_proof(0, (digests.len() - 1) as u32).unwrap();
1414        let mut hasher = Sha256::default();
1415        assert!(range_proof.verify(&mut hasher, 0, &digests, &root).is_ok());
1416    }
1417
1418    #[test]
1419    fn test_range_proof_edge_cases() {
1420        // Create test data
1421        let digests: Vec<Digest> = (0..15u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1422
1423        // Build tree
1424        let mut builder = Builder::<Sha256>::new(digests.len());
1425        for digest in &digests {
1426            builder.add(digest);
1427        }
1428        let tree = builder.build();
1429        let root = tree.root();
1430        let mut hasher = Sha256::default();
1431
1432        // Test first half
1433        let range_proof = tree.range_proof(0, 7).unwrap();
1434        assert!(range_proof
1435            .verify(&mut hasher, 0, &digests[0..8], &root)
1436            .is_ok());
1437
1438        // Test second half
1439        let range_proof = tree.range_proof(8, 14).unwrap();
1440        assert!(range_proof
1441            .verify(&mut hasher, 8, &digests[8..15], &root)
1442            .is_ok());
1443
1444        // Test last elements
1445        let range_proof = tree.range_proof(13, 14).unwrap();
1446        assert!(range_proof
1447            .verify(&mut hasher, 13, &digests[13..15], &root)
1448            .is_ok());
1449    }
1450
1451    #[test]
1452    fn test_range_proof_invalid_range() {
1453        // Create test data
1454        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1455
1456        // Build tree
1457        let mut builder = Builder::<Sha256>::new(digests.len());
1458        for digest in &digests {
1459            builder.add(digest);
1460        }
1461        let tree = builder.build();
1462
1463        // Test invalid ranges
1464        assert!(tree.range_proof(8, 8).is_err()); // Start out of bounds
1465        assert!(tree.range_proof(0, 8).is_err()); // End out of bounds
1466        assert!(tree.range_proof(5, 8).is_err()); // End out of bounds
1467        assert!(tree.range_proof(2, 1).is_err()); // Start > end
1468    }
1469
1470    #[test]
1471    fn test_range_proof_tampering() {
1472        // Create test data
1473        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1474
1475        // Build tree
1476        let mut builder = Builder::<Sha256>::new(digests.len());
1477        for digest in &digests {
1478            builder.add(digest);
1479        }
1480        let tree = builder.build();
1481        let root = tree.root();
1482
1483        // Get valid range proof
1484        let range_proof = tree.range_proof(2, 4).unwrap();
1485        let mut hasher = Sha256::default();
1486        let range_leaves = &digests[2..5];
1487
1488        // Test with wrong leaves
1489        let wrong_leaves = vec![
1490            Sha256::hash(b"wrong1"),
1491            Sha256::hash(b"wrong2"),
1492            Sha256::hash(b"wrong3"),
1493        ];
1494        assert!(range_proof
1495            .verify(&mut hasher, 2, &wrong_leaves, &root)
1496            .is_err());
1497
1498        // Test with wrong number of leaves
1499        assert!(range_proof
1500            .verify(&mut hasher, 2, &digests[2..4], &root)
1501            .is_err());
1502
1503        // Test with tampered proof
1504        let mut tampered_proof = range_proof.clone();
1505        assert!(!tampered_proof.siblings.is_empty());
1506        // Tamper with the first level's left sibling if it exists
1507        if let Some(ref mut left) = tampered_proof.siblings[0].left {
1508            *left = Sha256::hash(b"tampered");
1509        } else if let Some(ref mut right) = tampered_proof.siblings[0].right {
1510            *right = Sha256::hash(b"tampered");
1511        }
1512        assert!(tampered_proof
1513            .verify(&mut hasher, 2, range_leaves, &root)
1514            .is_err());
1515
1516        // Test with wrong root
1517        let wrong_root = Sha256::hash(b"wrong_root");
1518        assert!(range_proof
1519            .verify(&mut hasher, 2, range_leaves, &wrong_root)
1520            .is_err());
1521    }
1522
1523    #[test]
1524    fn test_range_proof_various_sizes() {
1525        // Test range proofs for trees of various sizes
1526        for tree_size in [1, 2, 3, 4, 5, 7, 8, 15, 16, 31, 32, 63, 64] {
1527            let digests: Vec<Digest> = (0..tree_size as u32)
1528                .map(|i| Sha256::hash(&i.to_be_bytes()))
1529                .collect();
1530
1531            // Build tree
1532            let mut builder = Builder::<Sha256>::new(digests.len());
1533            for digest in &digests {
1534                builder.add(digest);
1535            }
1536            let tree = builder.build();
1537            let root = tree.root();
1538            let mut hasher = Sha256::default();
1539
1540            // Test various range sizes
1541            for range_size in 1..=tree_size.min(8) {
1542                for start in 0..=(tree_size - range_size) {
1543                    let range_proof = tree
1544                        .range_proof(start as u32, (start + range_size - 1) as u32)
1545                        .unwrap();
1546                    let end = start + range_size;
1547                    assert!(
1548                        range_proof
1549                            .verify(&mut hasher, start as u32, &digests[start..end], &root)
1550                            .is_ok(),
1551                        "Failed for tree_size={tree_size}, start={start}, range_size={range_size}"
1552                    );
1553                }
1554            }
1555        }
1556    }
1557
1558    #[test]
1559    fn test_range_proof_malicious_wrong_position() {
1560        // Create test data
1561        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1562
1563        // Build tree
1564        let mut builder = Builder::<Sha256>::new(digests.len());
1565        for digest in &digests {
1566            builder.add(digest);
1567        }
1568        let tree = builder.build();
1569        let root = tree.root();
1570
1571        // Get valid range proof for position 2 to 4
1572        let range_proof = tree.range_proof(2, 4).unwrap();
1573        let mut hasher = Sha256::default();
1574        let range_leaves = &digests[2..5];
1575
1576        // Try to verify with wrong position
1577        assert!(range_proof
1578            .verify(&mut hasher, 3, range_leaves, &root)
1579            .is_err());
1580        assert!(range_proof
1581            .verify(&mut hasher, 1, range_leaves, &root)
1582            .is_err());
1583    }
1584
1585    #[test]
1586    fn test_range_proof_malicious_reordered_leaves() {
1587        // Create test data
1588        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1589
1590        // Build tree
1591        let mut builder = Builder::<Sha256>::new(digests.len());
1592        for digest in &digests {
1593            builder.add(digest);
1594        }
1595        let tree = builder.build();
1596        let root = tree.root();
1597
1598        // Get valid range proof for position 2 to 4
1599        let range_proof = tree.range_proof(2, 4).unwrap();
1600        let mut hasher = Sha256::default();
1601
1602        // Try to verify with reordered leaves
1603        let reordered_leaves = vec![digests[3], digests[2], digests[4]];
1604        assert!(range_proof
1605            .verify(&mut hasher, 2, &reordered_leaves, &root)
1606            .is_err());
1607    }
1608
1609    #[test]
1610    fn test_range_proof_malicious_extra_siblings() {
1611        // Create test data
1612        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1613
1614        // Build tree
1615        let mut builder = Builder::<Sha256>::new(digests.len());
1616        for digest in &digests {
1617            builder.add(digest);
1618        }
1619        let tree = builder.build();
1620        let root = tree.root();
1621
1622        // Get valid range proof
1623        let mut range_proof = tree.range_proof(2, 3).unwrap();
1624        let mut hasher = Sha256::default();
1625        let range_leaves = &digests[2..4];
1626
1627        // Tamper by setting both siblings when there should only be one or two
1628        assert!(!range_proof.siblings.is_empty());
1629        // Force an invalid state by modifying the siblings
1630        if range_proof.siblings[0].left.is_none() {
1631            range_proof.siblings[0].left = Some(Sha256::hash(b"extra"));
1632        } else if range_proof.siblings[0].right.is_none() {
1633            range_proof.siblings[0].right = Some(Sha256::hash(b"extra"));
1634        }
1635        assert!(range_proof
1636            .verify(&mut hasher, 2, range_leaves, &root)
1637            .is_err());
1638    }
1639
1640    #[test]
1641    fn test_range_proof_malicious_missing_siblings() {
1642        // Create test data
1643        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1644
1645        // Build tree
1646        let mut builder = Builder::<Sha256>::new(digests.len());
1647        for digest in &digests {
1648            builder.add(digest);
1649        }
1650        let tree = builder.build();
1651        let root = tree.root();
1652
1653        // Get valid range proof for a single element (which needs siblings)
1654        let mut range_proof = tree.range_proof(2, 2).unwrap();
1655        let mut hasher = Sha256::default();
1656        let range_leaves = &digests[2..3];
1657
1658        // The proof should have siblings at the first level
1659        assert!(!range_proof.siblings.is_empty());
1660        assert!(range_proof.siblings[0].left.is_some() || range_proof.siblings[0].right.is_some());
1661
1662        // Remove a sibling from a level
1663        range_proof.siblings[0].left = None;
1664        range_proof.siblings[0].right = None;
1665        assert!(range_proof
1666            .verify(&mut hasher, 2, range_leaves, &root)
1667            .is_err());
1668    }
1669
1670    #[test]
1671    fn test_range_proof_integer_overflow_protection() {
1672        // Create test data
1673        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1674
1675        // Build tree
1676        let mut builder = Builder::<Sha256>::new(digests.len());
1677        for digest in &digests {
1678            builder.add(digest);
1679        }
1680        let tree = builder.build();
1681
1682        // Test overflow in range_proof generation
1683        assert!(tree.range_proof(u32::MAX, u32::MAX).is_err());
1684        assert!(tree.range_proof(u32::MAX - 1, u32::MAX).is_err());
1685        assert!(tree.range_proof(7, u32::MAX).is_err());
1686    }
1687
1688    #[test]
1689    fn test_range_proof_malicious_wrong_tree_structure() {
1690        // Create test data
1691        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1692
1693        // Build tree
1694        let mut builder = Builder::<Sha256>::new(digests.len());
1695        for digest in &digests {
1696            builder.add(digest);
1697        }
1698        let tree = builder.build();
1699        let root = tree.root();
1700
1701        // Get valid range proof
1702        let mut range_proof = tree.range_proof(2, 3).unwrap();
1703        let mut hasher = Sha256::default();
1704        let range_leaves = &digests[2..4];
1705
1706        // Add extra level (simulating proof from different tree structure)
1707        range_proof.siblings.push(Bounds {
1708            left: Some(Sha256::hash(b"fake_level")),
1709            right: None,
1710        });
1711        assert!(range_proof
1712            .verify(&mut hasher, 2, range_leaves, &root)
1713            .is_err());
1714
1715        // Remove a level
1716        let mut range_proof = tree.range_proof(2, 2).unwrap();
1717        assert!(!range_proof.siblings.is_empty());
1718        range_proof.siblings.pop();
1719        assert!(range_proof
1720            .verify(&mut hasher, 2, range_leaves, &root)
1721            .is_err());
1722    }
1723
1724    #[test]
1725    fn test_range_proof_boundary_conditions() {
1726        // Test various power-of-2 boundary conditions
1727        for tree_size in [1, 2, 4, 8, 16, 32] {
1728            let digests: Vec<Digest> = (0..tree_size as u32)
1729                .map(|i| Sha256::hash(&i.to_be_bytes()))
1730                .collect();
1731
1732            // Build tree
1733            let mut builder = Builder::<Sha256>::new(digests.len());
1734            for digest in &digests {
1735                builder.add(digest);
1736            }
1737            let tree = builder.build();
1738            let root = tree.root();
1739            let mut hasher = Sha256::default();
1740
1741            // Test edge cases
1742            // First element only
1743            let proof = tree.range_proof(0, 0).unwrap();
1744            assert!(proof.verify(&mut hasher, 0, &digests[0..1], &root).is_ok());
1745
1746            // Last element only
1747            let last_idx = tree_size - 1;
1748            let proof = tree.range_proof(last_idx as u32, last_idx as u32).unwrap();
1749            assert!(proof
1750                .verify(
1751                    &mut hasher,
1752                    last_idx as u32,
1753                    &digests[last_idx..tree_size],
1754                    &root
1755                )
1756                .is_ok());
1757
1758            // Full tree
1759            let proof = tree.range_proof(0, (tree_size - 1) as u32).unwrap();
1760            assert!(proof.verify(&mut hasher, 0, &digests, &root).is_ok());
1761        }
1762    }
1763
1764    #[test]
1765    fn test_empty_tree_proof() {
1766        // Build an empty tree
1767        let builder = Builder::<Sha256>::new(0);
1768        let tree = builder.build();
1769
1770        // Empty tree should fail for any position since there are no elements
1771        assert!(tree.proof(0).is_err());
1772        assert!(tree.proof(1).is_err());
1773        assert!(tree.proof(100).is_err());
1774    }
1775
1776    #[test]
1777    fn test_empty_tree_range_proof() {
1778        // Build an empty tree
1779        let builder = Builder::<Sha256>::new(0);
1780        let tree = builder.build();
1781        let root = tree.root();
1782
1783        // Empty tree should return default range proof only for (0, 0)
1784        let range_proof = tree.range_proof(0, 0).unwrap();
1785        assert!(range_proof.siblings.is_empty());
1786        assert_eq!(range_proof, RangeProof::default());
1787
1788        // All other combinations should fail
1789        let invalid_ranges = vec![
1790            (0, 1),
1791            (0, 10),
1792            (1, 1),
1793            (1, 2),
1794            (5, 5),
1795            (10, 10),
1796            (0, u32::MAX),
1797            (u32::MAX, u32::MAX),
1798        ];
1799        for (start, end) in invalid_ranges {
1800            assert!(tree.range_proof(start, end).is_err());
1801        }
1802
1803        // Verify empty range proof against empty tree root
1804        let mut hasher = Sha256::default();
1805        let empty_leaves: &[Digest] = &[];
1806        assert!(range_proof
1807            .verify(&mut hasher, 0, empty_leaves, &root)
1808            .is_ok());
1809
1810        // Should fail with non-empty leaves
1811        let non_empty_leaves = vec![Sha256::hash(b"leaf")];
1812        assert!(range_proof
1813            .verify(&mut hasher, 0, &non_empty_leaves, &root)
1814            .is_err());
1815
1816        // Should fail with wrong root
1817        let wrong_root = Sha256::hash(b"wrong");
1818        assert!(range_proof
1819            .verify(&mut hasher, 0, empty_leaves, &wrong_root)
1820            .is_err());
1821
1822        // Should fail with wrong position
1823        assert!(range_proof
1824            .verify(&mut hasher, 1, empty_leaves, &root)
1825            .is_err());
1826    }
1827
1828    #[test]
1829    fn test_empty_range_proof_serialization() {
1830        let range_proof = RangeProof::<Digest>::default();
1831        let mut serialized = range_proof.encode();
1832        let deserialized = RangeProof::<Digest>::decode(&mut serialized).unwrap();
1833        assert_eq!(range_proof, deserialized);
1834    }
1835
1836    #[test]
1837    fn test_empty_tree_root_consistency() {
1838        // Create multiple empty trees and verify they have the same root
1839        let mut roots = Vec::new();
1840        for _ in 0..5 {
1841            let builder = Builder::<Sha256>::new(0);
1842            let tree = builder.build();
1843            roots.push(tree.root());
1844        }
1845
1846        // All empty trees should have the same root
1847        for i in 1..roots.len() {
1848            assert_eq!(roots[0], roots[i]);
1849        }
1850
1851        // The root should be the hash of empty data
1852        let mut hasher = Sha256::default();
1853        let expected_root = hasher.finalize();
1854        assert_eq!(roots[0], expected_root);
1855    }
1856
1857    #[rstest]
1858    #[case::need_left_sibling(1, 2)] // Range starting at odd index (needs left sibling)
1859    #[case::need_right_sibling(4, 4)] // Range starting at even index ending at odd (needs right sibling)
1860    #[case::boundaries_both_single_children(4, 4)] // Range with both boundaries needing siblings
1861    #[case::full_tree(0, 16)] // Full tree (no siblings needed at leaf level)
1862    fn test_range_proof_bounds_usage(#[case] start: u32, #[case] count: u32) {
1863        // This test ensures that all bounds in a range proof are actually used during verification
1864        // and that we don't have unnecessary siblings
1865        let digests: Vec<Digest> = (0..16u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1866
1867        // Build tree
1868        let mut builder = Builder::<Sha256>::new(digests.len());
1869        for digest in &digests {
1870            builder.add(digest);
1871        }
1872        let tree = builder.build();
1873        let root = tree.root();
1874        let mut hasher = Sha256::default();
1875
1876        let range_proof = tree.range_proof(start, start + count - 1).unwrap();
1877        let end = start as usize + count as usize;
1878
1879        // Verify the proof works
1880        assert!(range_proof
1881            .verify(&mut hasher, start, &digests[start as usize..end], &root)
1882            .is_ok());
1883
1884        // For each level with siblings, try removing them and verify the proof fails
1885        for level_idx in 0..range_proof.siblings.len() {
1886            let bounds = &range_proof.siblings[level_idx];
1887
1888            // If there's a left sibling, removing it should make the proof fail
1889            if bounds.left.is_some() {
1890                let mut tampered_proof = range_proof.clone();
1891                tampered_proof.siblings[level_idx].left = None;
1892                assert!(tampered_proof
1893                    .verify(&mut hasher, start, &digests[start as usize..end], &root)
1894                    .is_err());
1895            }
1896
1897            // If there's a right sibling, removing it should make the proof fail
1898            if bounds.right.is_some() {
1899                let mut tampered_proof = range_proof.clone();
1900                tampered_proof.siblings[level_idx].right = None;
1901                assert!(tampered_proof
1902                    .verify(&mut hasher, start, &digests[start as usize..end], &root)
1903                    .is_err());
1904            }
1905
1906            // If there's no left sibling, adding one should make the proof fail
1907            if bounds.left.is_none() {
1908                let mut tampered_proof = range_proof.clone();
1909                tampered_proof.siblings[level_idx].left = Some(Sha256::hash(b"fake_left"));
1910                assert!(tampered_proof
1911                    .verify(&mut hasher, start, &digests[start as usize..end], &root)
1912                    .is_err());
1913            }
1914
1915            // If there's no right sibling, adding one should make the proof fail
1916            if bounds.right.is_none() {
1917                let mut tampered_proof = range_proof.clone();
1918                tampered_proof.siblings[level_idx].right = Some(Sha256::hash(b"fake_right"));
1919                assert!(tampered_proof
1920                    .verify(&mut hasher, start, &digests[start as usize..end], &root)
1921                    .is_err());
1922            }
1923        }
1924    }
1925
1926    // Test trees with odd sizes that require duplicate nodes
1927    #[rstest]
1928    fn test_range_proof_duplicate_node_edge_cases(
1929        #[values(3, 5, 7, 9, 11, 13, 15)] tree_size: usize,
1930    ) {
1931        let digests: Vec<Digest> = (0..tree_size as u32)
1932            .map(|i| Sha256::hash(&i.to_be_bytes()))
1933            .collect();
1934
1935        // Build tree
1936        let mut builder = Builder::<Sha256>::new(digests.len());
1937        for digest in &digests {
1938            builder.add(digest);
1939        }
1940        let tree = builder.build();
1941        let root = tree.root();
1942        let mut hasher = Sha256::default();
1943
1944        // Test range including the last element (which may require duplicate handling)
1945        let start = tree_size - 2;
1946        let proof = tree
1947            .range_proof(start as u32, (tree_size - 1) as u32)
1948            .unwrap();
1949        assert!(proof
1950            .verify(&mut hasher, start as u32, &digests[start..tree_size], &root)
1951            .is_ok());
1952    }
1953
1954    #[test]
1955    fn test_multi_proof_basic() {
1956        // Create test data
1957        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1958
1959        // Build tree
1960        let mut builder = Builder::<Sha256>::new(digests.len());
1961        for digest in &digests {
1962            builder.add(digest);
1963        }
1964        let tree = builder.build();
1965        let root = tree.root();
1966
1967        // Test multi-proof for non-contiguous positions [0, 3, 5]
1968        let positions = [0, 3, 5];
1969        let multi_proof = tree.multi_proof(&positions).unwrap();
1970        let mut hasher = Sha256::default();
1971
1972        let elements: Vec<(Digest, u32)> = positions
1973            .iter()
1974            .map(|&p| (digests[p as usize], p))
1975            .collect();
1976        assert!(multi_proof
1977            .verify_multi_inclusion(&mut hasher, &elements, &root)
1978            .is_ok());
1979    }
1980
1981    #[test]
1982    fn test_multi_proof_single_element() {
1983        // Create test data
1984        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1985
1986        // Build tree
1987        let mut builder = Builder::<Sha256>::new(digests.len());
1988        for digest in &digests {
1989            builder.add(digest);
1990        }
1991        let tree = builder.build();
1992        let root = tree.root();
1993        let mut hasher = Sha256::default();
1994
1995        // Test single element multi-proof for each position
1996        for (i, digest) in digests.iter().enumerate() {
1997            let multi_proof = tree.multi_proof(&[i as u32]).unwrap();
1998            let elements = [(*digest, i as u32)];
1999            assert!(
2000                multi_proof
2001                    .verify_multi_inclusion(&mut hasher, &elements, &root)
2002                    .is_ok(),
2003                "Failed for position {i}"
2004            );
2005        }
2006    }
2007
2008    #[test]
2009    fn test_multi_proof_all_elements() {
2010        // Create test data
2011        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2012
2013        // Build tree
2014        let mut builder = Builder::<Sha256>::new(digests.len());
2015        for digest in &digests {
2016            builder.add(digest);
2017        }
2018        let tree = builder.build();
2019        let root = tree.root();
2020        let mut hasher = Sha256::default();
2021
2022        // Test multi-proof for all elements
2023        let positions: Vec<u32> = (0..digests.len() as u32).collect();
2024        let multi_proof = tree.multi_proof(&positions).unwrap();
2025
2026        let elements: Vec<(Digest, u32)> = positions
2027            .iter()
2028            .map(|&p| (digests[p as usize], p))
2029            .collect();
2030        assert!(multi_proof
2031            .verify_multi_inclusion(&mut hasher, &elements, &root)
2032            .is_ok());
2033
2034        // When proving all elements, we shouldn't need any siblings (all can be computed)
2035        assert!(multi_proof.siblings.is_empty());
2036    }
2037
2038    #[test]
2039    fn test_multi_proof_adjacent_elements() {
2040        // Create test data
2041        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2042
2043        // Build tree
2044        let mut builder = Builder::<Sha256>::new(digests.len());
2045        for digest in &digests {
2046            builder.add(digest);
2047        }
2048        let tree = builder.build();
2049        let root = tree.root();
2050        let mut hasher = Sha256::default();
2051
2052        // Test adjacent positions (should deduplicate shared siblings)
2053        let positions = [2, 3];
2054        let multi_proof = tree.multi_proof(&positions).unwrap();
2055
2056        let elements: Vec<(Digest, u32)> = positions
2057            .iter()
2058            .map(|&p| (digests[p as usize], p))
2059            .collect();
2060        assert!(multi_proof
2061            .verify_multi_inclusion(&mut hasher, &elements, &root)
2062            .is_ok());
2063    }
2064
2065    #[test]
2066    fn test_multi_proof_sparse_positions() {
2067        // Create test data
2068        let digests: Vec<Digest> = (0..16u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2069
2070        // Build tree
2071        let mut builder = Builder::<Sha256>::new(digests.len());
2072        for digest in &digests {
2073            builder.add(digest);
2074        }
2075        let tree = builder.build();
2076        let root = tree.root();
2077        let mut hasher = Sha256::default();
2078
2079        // Test widely separated positions
2080        let positions = [0, 7, 8, 15];
2081        let multi_proof = tree.multi_proof(&positions).unwrap();
2082
2083        let elements: Vec<(Digest, u32)> = positions
2084            .iter()
2085            .map(|&p| (digests[p as usize], p))
2086            .collect();
2087        assert!(multi_proof
2088            .verify_multi_inclusion(&mut hasher, &elements, &root)
2089            .is_ok());
2090    }
2091
2092    #[test]
2093    fn test_multi_proof_empty_tree() {
2094        // Build empty tree
2095        let builder = Builder::<Sha256>::new(0);
2096        let tree = builder.build();
2097
2098        // Empty tree with empty positions should return NoLeaves error
2099        // (we can't prove zero elements)
2100        assert!(matches!(tree.multi_proof(&[]), Err(Error::NoLeaves)));
2101
2102        // Empty tree with any position should fail with InvalidPosition
2103        assert!(matches!(
2104            tree.multi_proof(&[0]),
2105            Err(Error::InvalidPosition(0))
2106        ));
2107    }
2108
2109    #[test]
2110    fn test_multi_proof_empty_positions() {
2111        // Create test data
2112        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2113
2114        // Build tree
2115        let mut builder = Builder::<Sha256>::new(digests.len());
2116        for digest in &digests {
2117            builder.add(digest);
2118        }
2119        let tree = builder.build();
2120
2121        // Empty positions should return error
2122        assert!(matches!(tree.multi_proof(&[]), Err(Error::NoLeaves)));
2123    }
2124
2125    #[test]
2126    fn test_multi_proof_duplicate_positions_error() {
2127        // Create test data
2128        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2129
2130        // Build tree
2131        let mut builder = Builder::<Sha256>::new(digests.len());
2132        for digest in &digests {
2133            builder.add(digest);
2134        }
2135        let tree = builder.build();
2136
2137        // Duplicate positions should return error
2138        assert!(matches!(
2139            tree.multi_proof(&[1, 1]),
2140            Err(Error::DuplicatePosition(1))
2141        ));
2142        assert!(matches!(
2143            tree.multi_proof(&[0, 2, 2, 5]),
2144            Err(Error::DuplicatePosition(2))
2145        ));
2146    }
2147
2148    #[test]
2149    fn test_multi_proof_unsorted_input() {
2150        // Create test data
2151        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2152
2153        // Build tree
2154        let mut builder = Builder::<Sha256>::new(digests.len());
2155        for digest in &digests {
2156            builder.add(digest);
2157        }
2158        let tree = builder.build();
2159        let root = tree.root();
2160        let mut hasher = Sha256::default();
2161
2162        // Test with unsorted positions (should work - internal sorting)
2163        let positions = [5, 0, 3];
2164        let multi_proof = tree.multi_proof(&positions).unwrap();
2165
2166        // Verify with unsorted elements (should work - internal sorting)
2167        let unsorted_elements = [(digests[5], 5), (digests[0], 0), (digests[3], 3)];
2168        assert!(multi_proof
2169            .verify_multi_inclusion(&mut hasher, &unsorted_elements, &root)
2170            .is_ok());
2171    }
2172
2173    #[test]
2174    fn test_multi_proof_various_sizes() {
2175        // Test multi-proofs for trees of various sizes
2176        for tree_size in [1, 2, 3, 4, 5, 7, 8, 15, 16, 31, 32] {
2177            let digests: Vec<Digest> = (0..tree_size as u32)
2178                .map(|i| Sha256::hash(&i.to_be_bytes()))
2179                .collect();
2180
2181            // Build tree
2182            let mut builder = Builder::<Sha256>::new(digests.len());
2183            for digest in &digests {
2184                builder.add(digest);
2185            }
2186            let tree = builder.build();
2187            let root = tree.root();
2188            let mut hasher = Sha256::default();
2189
2190            // Test various position combinations
2191            // First and last
2192            if tree_size >= 2 {
2193                let positions = [0, (tree_size - 1) as u32];
2194                let multi_proof = tree.multi_proof(&positions).unwrap();
2195                let elements: Vec<(Digest, u32)> = positions
2196                    .iter()
2197                    .map(|&p| (digests[p as usize], p))
2198                    .collect();
2199                assert!(
2200                    multi_proof
2201                        .verify_multi_inclusion(&mut hasher, &elements, &root)
2202                        .is_ok(),
2203                    "Failed for tree_size={tree_size}, positions=[0, {}]",
2204                    tree_size - 1
2205                );
2206            }
2207
2208            // Every other element
2209            if tree_size >= 4 {
2210                let positions: Vec<u32> = (0..tree_size as u32).step_by(2).collect();
2211                let multi_proof = tree.multi_proof(&positions).unwrap();
2212                let elements: Vec<(Digest, u32)> = positions
2213                    .iter()
2214                    .map(|&p| (digests[p as usize], p))
2215                    .collect();
2216                assert!(
2217                    multi_proof
2218                        .verify_multi_inclusion(&mut hasher, &elements, &root)
2219                        .is_ok(),
2220                    "Failed for tree_size={tree_size}, every other element"
2221                );
2222            }
2223        }
2224    }
2225
2226    #[test]
2227    fn test_multi_proof_wrong_elements() {
2228        // Create test data
2229        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2230
2231        // Build tree
2232        let mut builder = Builder::<Sha256>::new(digests.len());
2233        for digest in &digests {
2234            builder.add(digest);
2235        }
2236        let tree = builder.build();
2237        let root = tree.root();
2238        let mut hasher = Sha256::default();
2239
2240        // Generate valid proof
2241        let positions = [0, 3, 5];
2242        let multi_proof = tree.multi_proof(&positions).unwrap();
2243
2244        // Verify with wrong elements
2245        let wrong_elements = [
2246            (Sha256::hash(b"wrong1"), 0),
2247            (digests[3], 3),
2248            (digests[5], 5),
2249        ];
2250        assert!(multi_proof
2251            .verify_multi_inclusion(&mut hasher, &wrong_elements, &root)
2252            .is_err());
2253    }
2254
2255    #[test]
2256    fn test_multi_proof_wrong_positions() {
2257        // Create test data
2258        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2259
2260        // Build tree
2261        let mut builder = Builder::<Sha256>::new(digests.len());
2262        for digest in &digests {
2263            builder.add(digest);
2264        }
2265        let tree = builder.build();
2266        let root = tree.root();
2267        let mut hasher = Sha256::default();
2268
2269        // Generate valid proof
2270        let positions = [0, 3, 5];
2271        let multi_proof = tree.multi_proof(&positions).unwrap();
2272
2273        // Verify with wrong positions (same elements, different positions)
2274        let wrong_positions = [
2275            (digests[0], 1), // wrong position
2276            (digests[3], 3),
2277            (digests[5], 5),
2278        ];
2279        assert!(multi_proof
2280            .verify_multi_inclusion(&mut hasher, &wrong_positions, &root)
2281            .is_err());
2282    }
2283
2284    #[test]
2285    fn test_multi_proof_wrong_root() {
2286        // Create test data
2287        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2288
2289        // Build tree
2290        let mut builder = Builder::<Sha256>::new(digests.len());
2291        for digest in &digests {
2292            builder.add(digest);
2293        }
2294        let tree = builder.build();
2295        let mut hasher = Sha256::default();
2296
2297        // Generate valid proof
2298        let positions = [0, 3, 5];
2299        let multi_proof = tree.multi_proof(&positions).unwrap();
2300
2301        let elements: Vec<(Digest, u32)> = positions
2302            .iter()
2303            .map(|&p| (digests[p as usize], p))
2304            .collect();
2305
2306        // Verify with wrong root
2307        let wrong_root = Sha256::hash(b"wrong_root");
2308        assert!(multi_proof
2309            .verify_multi_inclusion(&mut hasher, &elements, &wrong_root)
2310            .is_err());
2311    }
2312
2313    #[test]
2314    fn test_multi_proof_tampering() {
2315        // Create test data
2316        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2317
2318        // Build tree
2319        let mut builder = Builder::<Sha256>::new(digests.len());
2320        for digest in &digests {
2321            builder.add(digest);
2322        }
2323        let tree = builder.build();
2324        let root = tree.root();
2325        let mut hasher = Sha256::default();
2326
2327        // Generate valid proof
2328        let positions = [0, 5];
2329        let multi_proof = tree.multi_proof(&positions).unwrap();
2330
2331        let elements: Vec<(Digest, u32)> = positions
2332            .iter()
2333            .map(|&p| (digests[p as usize], p))
2334            .collect();
2335
2336        // Tamper with sibling
2337        assert!(!multi_proof.siblings.is_empty());
2338        let mut modified = multi_proof.clone();
2339        modified.siblings[0] = Sha256::hash(b"tampered");
2340        assert!(modified
2341            .verify_multi_inclusion(&mut hasher, &elements, &root)
2342            .is_err());
2343
2344        // Add extra sibling
2345        let mut extra = multi_proof.clone();
2346        extra.siblings.push(Sha256::hash(b"extra"));
2347        assert!(extra
2348            .verify_multi_inclusion(&mut hasher, &elements, &root)
2349            .is_err());
2350
2351        // Remove a sibling
2352        let mut missing = multi_proof;
2353        missing.siblings.pop();
2354        assert!(missing
2355            .verify_multi_inclusion(&mut hasher, &elements, &root)
2356            .is_err());
2357    }
2358
2359    #[test]
2360    fn test_multi_proof_deduplication() {
2361        // Create test data
2362        let digests: Vec<Digest> = (0..16u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2363
2364        // Build tree
2365        let mut builder = Builder::<Sha256>::new(digests.len());
2366        for digest in &digests {
2367            builder.add(digest);
2368        }
2369        let tree = builder.build();
2370
2371        // Get individual proofs
2372        let individual_siblings: usize = [0u32, 1, 8, 9]
2373            .iter()
2374            .map(|&p| tree.proof(p).unwrap().siblings.len())
2375            .sum();
2376
2377        // Get multi-proof for same positions
2378        let multi_proof = tree.multi_proof(&[0, 1, 8, 9]).unwrap();
2379
2380        // Multi-proof should have fewer siblings due to deduplication
2381        assert!(
2382            multi_proof.siblings.len() < individual_siblings,
2383            "Multi-proof ({}) should have fewer siblings than sum of individual proofs ({})",
2384            multi_proof.siblings.len(),
2385            individual_siblings
2386        );
2387    }
2388
2389    #[test]
2390    fn test_multi_proof_serialization() {
2391        // Create test data
2392        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2393
2394        // Build tree
2395        let mut builder = Builder::<Sha256>::new(digests.len());
2396        for digest in &digests {
2397            builder.add(digest);
2398        }
2399        let tree = builder.build();
2400        let root = tree.root();
2401        let mut hasher = Sha256::default();
2402
2403        // Generate proof
2404        let positions = [0, 3, 5];
2405        let multi_proof = tree.multi_proof(&positions).unwrap();
2406
2407        // Serialize and deserialize
2408        let serialized = multi_proof.encode();
2409        let deserialized = Proof::<Digest>::decode_cfg(serialized, &positions.len()).unwrap();
2410
2411        assert_eq!(multi_proof, deserialized);
2412
2413        // Verify deserialized proof works
2414        let elements: Vec<(Digest, u32)> = positions
2415            .iter()
2416            .map(|&p| (digests[p as usize], p))
2417            .collect();
2418        assert!(deserialized
2419            .verify_multi_inclusion(&mut hasher, &elements, &root)
2420            .is_ok());
2421    }
2422
2423    #[test]
2424    fn test_multi_proof_serialization_truncated() {
2425        // Create test data
2426        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2427
2428        // Build tree
2429        let mut builder = Builder::<Sha256>::new(digests.len());
2430        for digest in &digests {
2431            builder.add(digest);
2432        }
2433        let tree = builder.build();
2434
2435        // Generate proof
2436        let positions = [0, 3, 5];
2437        let multi_proof = tree.multi_proof(&positions).unwrap();
2438
2439        // Serialize and truncate
2440        let mut serialized = multi_proof.encode();
2441        serialized.truncate(serialized.len() - 1);
2442
2443        // Should fail to deserialize
2444        assert!(Proof::<Digest>::decode_cfg(&mut serialized, &positions.len()).is_err());
2445    }
2446
2447    #[test]
2448    fn test_multi_proof_serialization_extra() {
2449        // Create test data
2450        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2451
2452        // Build tree
2453        let mut builder = Builder::<Sha256>::new(digests.len());
2454        for digest in &digests {
2455            builder.add(digest);
2456        }
2457        let tree = builder.build();
2458
2459        // Generate proof
2460        let positions = [0, 3, 5];
2461        let multi_proof = tree.multi_proof(&positions).unwrap();
2462
2463        // Serialize and add extra byte
2464        let mut serialized = multi_proof.encode_mut();
2465        serialized.extend_from_slice(&[0u8]);
2466
2467        // Should fail to deserialize
2468        assert!(Proof::<Digest>::decode_cfg(&mut serialized, &positions.len()).is_err());
2469    }
2470
2471    #[test]
2472    fn test_multi_proof_decode_insufficient_data() {
2473        let mut serialized = Vec::new();
2474        serialized.extend_from_slice(&8u32.encode()); // leaf_count
2475        serialized.extend_from_slice(&1usize.encode()); // claims 1 sibling but no data follows
2476
2477        // Should fail because the buffer claims 1 sibling but doesn't have the data
2478        let err = Proof::<Digest>::decode_cfg(serialized.as_slice(), &1).unwrap_err();
2479        assert!(matches!(err, commonware_codec::Error::EndOfBuffer));
2480    }
2481
2482    #[test]
2483    fn test_multi_proof_invalid_position() {
2484        // Create test data
2485        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2486
2487        // Build tree
2488        let mut builder = Builder::<Sha256>::new(digests.len());
2489        for digest in &digests {
2490            builder.add(digest);
2491        }
2492        let tree = builder.build();
2493
2494        // Test out of bounds position
2495        assert!(matches!(
2496            tree.multi_proof(&[0, 8]),
2497            Err(Error::InvalidPosition(8))
2498        ));
2499        assert!(matches!(
2500            tree.multi_proof(&[100]),
2501            Err(Error::InvalidPosition(100))
2502        ));
2503    }
2504
2505    #[test]
2506    fn test_multi_proof_verify_invalid_position() {
2507        // Create test data
2508        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2509
2510        // Build tree
2511        let mut builder = Builder::<Sha256>::new(digests.len());
2512        for digest in &digests {
2513            builder.add(digest);
2514        }
2515        let tree = builder.build();
2516        let root = tree.root();
2517        let mut hasher = Sha256::default();
2518
2519        // Generate valid proof
2520        let positions = [0, 3];
2521        let multi_proof = tree.multi_proof(&positions).unwrap();
2522
2523        // Try to verify with out of bounds position
2524        let invalid_elements = [(digests[0], 0), (digests[3], 100)];
2525        assert!(multi_proof
2526            .verify_multi_inclusion(&mut hasher, &invalid_elements, &root)
2527            .is_err());
2528    }
2529
2530    #[test]
2531    fn test_multi_proof_odd_tree_sizes() {
2532        // Test odd-sized trees that require node duplication
2533        for tree_size in [3, 5, 7, 9, 11, 13, 15] {
2534            let digests: Vec<Digest> = (0..tree_size as u32)
2535                .map(|i| Sha256::hash(&i.to_be_bytes()))
2536                .collect();
2537
2538            // Build tree
2539            let mut builder = Builder::<Sha256>::new(digests.len());
2540            for digest in &digests {
2541                builder.add(digest);
2542            }
2543            let tree = builder.build();
2544            let root = tree.root();
2545            let mut hasher = Sha256::default();
2546
2547            // Test with positions including the last element
2548            let positions = [0, (tree_size - 1) as u32];
2549            let multi_proof = tree.multi_proof(&positions).unwrap();
2550
2551            let elements: Vec<(Digest, u32)> = positions
2552                .iter()
2553                .map(|&p| (digests[p as usize], p))
2554                .collect();
2555            assert!(
2556                multi_proof
2557                    .verify_multi_inclusion(&mut hasher, &elements, &root)
2558                    .is_ok(),
2559                "Failed for tree_size={tree_size}"
2560            );
2561        }
2562    }
2563
2564    #[test]
2565    fn test_multi_proof_verify_empty_elements() {
2566        // Create a valid proof and try to verify with empty elements
2567        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2568
2569        let mut builder = Builder::<Sha256>::new(digests.len());
2570        for digest in &digests {
2571            builder.add(digest);
2572        }
2573        let tree = builder.build();
2574        let root = tree.root();
2575        let mut hasher = Sha256::default();
2576
2577        // Generate valid proof
2578        let positions = [0, 3];
2579        let multi_proof = tree.multi_proof(&positions).unwrap();
2580
2581        // Try to verify with empty elements
2582        let empty_elements: &[(Digest, u32)] = &[];
2583        assert!(multi_proof
2584            .verify_multi_inclusion(&mut hasher, empty_elements, &root)
2585            .is_err());
2586    }
2587
2588    #[test]
2589    fn test_multi_proof_default_verify() {
2590        // Default (empty) proof should only verify against empty tree
2591        let mut hasher = Sha256::default();
2592        let default_proof = Proof::<Digest>::default();
2593
2594        // Empty elements against default proof
2595        let empty_elements: &[(Digest, u32)] = &[];
2596
2597        // Build empty tree to get the empty root
2598        let builder = Builder::<Sha256>::new(0);
2599        let empty_tree = builder.build();
2600        let empty_root = empty_tree.root();
2601
2602        assert!(default_proof
2603            .verify_multi_inclusion(&mut hasher, empty_elements, &empty_root)
2604            .is_ok());
2605
2606        // Should fail with wrong root
2607        let wrong_root = Sha256::hash(b"not_empty");
2608        assert!(default_proof
2609            .verify_multi_inclusion(&mut hasher, empty_elements, &wrong_root)
2610            .is_err());
2611    }
2612
2613    #[test]
2614    fn test_multi_proof_single_leaf_tree() {
2615        // Edge case: tree with exactly one leaf
2616        let digest = Sha256::hash(b"only_leaf");
2617
2618        // Build single-leaf tree
2619        let mut builder = Builder::<Sha256>::new(1);
2620        builder.add(&digest);
2621        let tree = builder.build();
2622        let root = tree.root();
2623        let mut hasher = Sha256::default();
2624
2625        // Generate multi-proof for the only leaf
2626        let multi_proof = tree.multi_proof(&[0]).unwrap();
2627
2628        // Single leaf tree: leaf_count should be 1
2629        assert_eq!(multi_proof.leaf_count, 1);
2630
2631        // Single leaf tree: no siblings needed (leaf is the root after position hashing)
2632        assert!(
2633            multi_proof.siblings.is_empty(),
2634            "Single leaf tree should have no siblings"
2635        );
2636
2637        // Verify the proof
2638        let elements = [(digest, 0u32)];
2639        assert!(
2640            multi_proof
2641                .verify_multi_inclusion(&mut hasher, &elements, &root)
2642                .is_ok(),
2643            "Single leaf multi-proof verification failed"
2644        );
2645
2646        // Verify with wrong digest fails
2647        let wrong_digest = Sha256::hash(b"wrong");
2648        let wrong_elements = [(wrong_digest, 0u32)];
2649        assert!(
2650            multi_proof
2651                .verify_multi_inclusion(&mut hasher, &wrong_elements, &root)
2652                .is_err(),
2653            "Should fail with wrong digest"
2654        );
2655
2656        // Verify with wrong position fails
2657        let wrong_position_elements = [(digest, 1u32)];
2658        assert!(
2659            multi_proof
2660                .verify_multi_inclusion(&mut hasher, &wrong_position_elements, &root)
2661                .is_err(),
2662            "Should fail with invalid position"
2663        );
2664    }
2665
2666    #[test]
2667    fn test_multi_proof_malicious_leaf_count_zero() {
2668        // Attacker sets leaf_count = 0 but provides siblings
2669        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2670
2671        let mut builder = Builder::<Sha256>::new(digests.len());
2672        for digest in &digests {
2673            builder.add(digest);
2674        }
2675        let tree = builder.build();
2676        let root = tree.root();
2677        let mut hasher = Sha256::default();
2678
2679        // Generate valid proof and tamper with leaf_count
2680        let positions = [0, 3];
2681        let mut multi_proof = tree.multi_proof(&positions).unwrap();
2682        multi_proof.leaf_count = 0;
2683
2684        let elements: Vec<(Digest, u32)> = positions
2685            .iter()
2686            .map(|&p| (digests[p as usize], p))
2687            .collect();
2688
2689        // Should fail - leaf_count=0 but we have elements
2690        assert!(multi_proof
2691            .verify_multi_inclusion(&mut hasher, &elements, &root)
2692            .is_err());
2693    }
2694
2695    #[test]
2696    fn test_multi_proof_malicious_leaf_count_larger() {
2697        // Attacker inflates leaf_count to claim proof is for larger tree
2698        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2699
2700        let mut builder = Builder::<Sha256>::new(digests.len());
2701        for digest in &digests {
2702            builder.add(digest);
2703        }
2704        let tree = builder.build();
2705        let root = tree.root();
2706        let mut hasher = Sha256::default();
2707
2708        // Generate valid proof and inflate leaf_count
2709        let positions = [0, 3];
2710        let mut multi_proof = tree.multi_proof(&positions).unwrap();
2711        let original_leaf_count = multi_proof.leaf_count;
2712        multi_proof.leaf_count = 1000;
2713
2714        let elements: Vec<(Digest, u32)> = positions
2715            .iter()
2716            .map(|&p| (digests[p as usize], p))
2717            .collect();
2718
2719        // Should fail - inflated leaf_count changes required siblings
2720        assert!(
2721            multi_proof
2722                .verify_multi_inclusion(&mut hasher, &elements, &root)
2723                .is_err(),
2724            "Should reject proof with inflated leaf_count ({} -> {})",
2725            original_leaf_count,
2726            multi_proof.leaf_count
2727        );
2728    }
2729
2730    #[test]
2731    fn test_multi_proof_malicious_leaf_count_smaller() {
2732        // Attacker deflates leaf_count to claim proof is for smaller tree
2733        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2734
2735        let mut builder = Builder::<Sha256>::new(digests.len());
2736        for digest in &digests {
2737            builder.add(digest);
2738        }
2739        let tree = builder.build();
2740        let root = tree.root();
2741        let mut hasher = Sha256::default();
2742
2743        // Generate valid proof and deflate leaf_count
2744        let positions = [0, 3];
2745        let mut multi_proof = tree.multi_proof(&positions).unwrap();
2746        multi_proof.leaf_count = 4; // Smaller than actual tree
2747
2748        let elements: Vec<(Digest, u32)> = positions
2749            .iter()
2750            .map(|&p| (digests[p as usize], p))
2751            .collect();
2752
2753        // Should fail - deflated leaf_count changes tree structure
2754        assert!(
2755            multi_proof
2756                .verify_multi_inclusion(&mut hasher, &elements, &root)
2757                .is_err(),
2758            "Should reject proof with deflated leaf_count"
2759        );
2760    }
2761
2762    #[test]
2763    fn test_multi_proof_mismatched_element_count() {
2764        // Provide more or fewer elements than the proof was generated for
2765        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2766
2767        let mut builder = Builder::<Sha256>::new(digests.len());
2768        for digest in &digests {
2769            builder.add(digest);
2770        }
2771        let tree = builder.build();
2772        let root = tree.root();
2773        let mut hasher = Sha256::default();
2774
2775        // Generate proof for 2 positions
2776        let positions = [0, 3];
2777        let multi_proof = tree.multi_proof(&positions).unwrap();
2778
2779        // Try to verify with only 1 element (too few)
2780        let too_few = [(digests[0], 0u32)];
2781        assert!(
2782            multi_proof
2783                .verify_multi_inclusion(&mut hasher, &too_few, &root)
2784                .is_err(),
2785            "Should reject when fewer elements provided than proof was generated for"
2786        );
2787
2788        // Try to verify with 3 elements (too many)
2789        let too_many = [(digests[0], 0u32), (digests[3], 3), (digests[5], 5)];
2790        assert!(
2791            multi_proof
2792                .verify_multi_inclusion(&mut hasher, &too_many, &root)
2793                .is_err(),
2794            "Should reject when more elements provided than proof was generated for"
2795        );
2796    }
2797
2798    #[test]
2799    fn test_multi_proof_swapped_siblings() {
2800        // Swap the order of siblings in the proof
2801        let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2802
2803        let mut builder = Builder::<Sha256>::new(digests.len());
2804        for digest in &digests {
2805            builder.add(digest);
2806        }
2807        let tree = builder.build();
2808        let root = tree.root();
2809        let mut hasher = Sha256::default();
2810
2811        // Generate valid proof with multiple siblings
2812        let positions = [0, 5];
2813        let mut multi_proof = tree.multi_proof(&positions).unwrap();
2814
2815        // Ensure we have at least 2 siblings to swap
2816        if multi_proof.siblings.len() >= 2 {
2817            // Swap first two siblings
2818            multi_proof.siblings.swap(0, 1);
2819
2820            let elements: Vec<(Digest, u32)> = positions
2821                .iter()
2822                .map(|&p| (digests[p as usize], p))
2823                .collect();
2824
2825            assert!(
2826                multi_proof
2827                    .verify_multi_inclusion(&mut hasher, &elements, &root)
2828                    .is_err(),
2829                "Should reject proof with swapped siblings"
2830            );
2831        }
2832    }
2833
2834    #[test]
2835    fn test_multi_proof_dos_large_leaf_count() {
2836        // Attacker sets massive leaf_count trying to cause DoS via memory allocation
2837        // The verify function should NOT allocate proportional to leaf_count
2838        let digests: Vec<Digest> = (0..4u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2839
2840        let mut builder = Builder::<Sha256>::new(digests.len());
2841        for digest in &digests {
2842            builder.add(digest);
2843        }
2844        let tree = builder.build();
2845        let root = tree.root();
2846        let mut hasher = Sha256::default();
2847
2848        // Generate valid proof
2849        let positions = [0, 2];
2850        let mut multi_proof = tree.multi_proof(&positions).unwrap();
2851
2852        // Set massive leaf_count (attacker trying to exhaust memory)
2853        multi_proof.leaf_count = u32::MAX;
2854
2855        let elements: Vec<(Digest, u32)> = positions
2856            .iter()
2857            .map(|&p| (digests[p as usize], p))
2858            .collect();
2859
2860        // This should fail quickly without allocating massive memory
2861        // The function is O(elements * levels), not O(leaf_count)
2862        let result = multi_proof.verify_multi_inclusion(&mut hasher, &elements, &root);
2863        assert!(result.is_err(), "Should reject malicious large leaf_count");
2864    }
2865
2866    #[cfg(feature = "arbitrary")]
2867    mod conformance {
2868        use super::*;
2869        use commonware_codec::conformance::CodecConformance;
2870        use commonware_cryptography::sha256::Digest as Sha256Digest;
2871
2872        commonware_conformance::conformance_tests! {
2873            CodecConformance<RangeProof<Sha256Digest>>,
2874            CodecConformance<Bounds<Sha256Digest>>,
2875            CodecConformance<Proof<Sha256Digest>>,
2876        }
2877    }
2878}