1use 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
50pub const MAX_LEVELS: usize = u8::MAX as usize;
53
54#[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
69pub struct Builder<H: Hasher> {
71 hasher: H,
72 leaves: Vec<H::Digest>,
73}
74
75impl<H: Hasher> Builder<H> {
76 pub fn new(leaves: usize) -> Self {
78 Self {
79 hasher: H::new(),
80 leaves: Vec::with_capacity(leaves),
81 }
82 }
83
84 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 pub fn build(self) -> Tree<H> {
100 Tree::new(self.hasher, self.leaves)
101 }
102}
103
104#[derive(Clone, Debug)]
106pub struct Tree<H: Hasher> {
107 empty: bool,
109
110 levels: NonEmptyVec<NonEmptyVec<H::Digest>>,
112}
113
114impl<H: Hasher> Tree<H> {
115 fn new(mut hasher: H, mut leaves: Vec<H::Digest>) -> Self {
117 let mut empty = false;
122 if leaves.is_empty() {
123 leaves.push(hasher.finalize());
124 empty = true;
125 }
126
127 let mut levels = non_empty_vec![non_empty_vec![@leaves]];
129
130 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 hasher.update(&chunk[0]);
137
138 if chunk.len() == 2 {
140 hasher.update(&chunk[1]);
141 } else {
142 hasher.update(&chunk[0]);
144 };
145
146 next_level.push(hasher.finalize());
148 }
149
150 levels.push(non_empty_vec![@next_level]);
152 current_level = levels.last();
153 }
154 Self { empty, levels }
155 }
156
157 pub fn root(&self) -> H::Digest {
159 *self.levels.last().first()
160 }
161
162 pub fn proof(&self, position: u32) -> Result<Proof<H::Digest>, Error> {
167 self.multi_proof(&[position])
168 }
169
170 pub fn range_proof(&self, start: u32, end: u32) -> Result<RangeProof<H::Digest>, Error> {
177 if self.empty && start == 0 && end == 0 {
179 return Ok(RangeProof::default());
180 }
181
182 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 let mut siblings = Vec::new();
196 for (level_idx, level) in self.levels.iter().enumerate() {
197 if level.is_singleton() {
199 break;
200 }
201
202 let level_start = (start as usize) >> level_idx;
204 let level_end = (end as usize) >> level_idx;
205
206 let mut left = None;
208 if level_start % 2 == 1 {
209 left = Some(level[level_start - 1]);
211 }
212
213 let mut right = None;
215 if level_end.is_multiple_of(2) {
216 if level_end + 1 < level.len().get() {
217 right = Some(level[level_end + 1]);
219 } else {
220 right = Some(level[level_end]);
225 }
226 }
227
228 siblings.push(Bounds { left, right });
229 }
230
231 Ok(RangeProof { siblings })
232 }
233
234 pub fn multi_proof(&self, positions: &[u32]) -> Result<Proof<H::Digest>, Error> {
243 if positions.is_empty() {
245 return Err(Error::NoLeaves);
246 }
247
248 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 let sibling_positions =
257 siblings_required_for_multi_proof(leaf_count, positions.iter().copied())?;
258
259 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#[derive(Clone, Debug, Eq)]
274pub struct Bounds<D: Digest> {
275 pub left: Option<D>,
277
278 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#[derive(Clone, Debug, Eq, PartialEq)]
327pub struct RangeProof<D: Digest> {
328 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
353struct Node<D: Digest> {
355 position: usize,
356 digest: D,
357}
358
359impl<D: Digest> RangeProof<D> {
360 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 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 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 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 for bounds in self.siblings.iter() {
407 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 let mut i = 0;
421 let mut next_nodes = Vec::new();
422 if let Some(left) = &bounds.left {
423 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 while i < nodes.len() {
436 let node = &nodes[i];
438 let parent_pos = node.position / 2;
439
440 if i + 1 < nodes.len() && nodes[i + 1].position == node.position + 1 {
442 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 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 return Err(Error::UnalignedProof);
463 }
464 }
465
466 nodes = next_nodes;
467 }
468
469 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#[derive(Clone, Debug, Eq, PartialEq)]
509pub struct Proof<D: Digest> {
510 pub leaf_count: u32,
512 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 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
572const fn levels_in_tree(leaf_count: u32) -> usize {
575 (u32::BITS - (leaf_count.saturating_sub(1)).leading_zeros() + 1) as usize
576}
577
578fn siblings_required_for_multi_proof(
583 leaf_count: u32,
584 positions: impl IntoIterator<Item = u32>,
585) -> Result<BTreeSet<(usize, usize)>, Error> {
586 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 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 ¤t {
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 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 if position >= self.leaf_count {
647 return Err(Error::InvalidPosition(position));
648 }
649
650 hasher.update(&position.to_be_bytes());
652 hasher.update(leaf);
653 let mut computed = hasher.finalize();
654
655 let mut level_size = self.leaf_count as usize;
657 let mut sibling_iter = self.siblings.iter();
658
659 while level_size > 1 {
661 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 (&computed, &computed)
667 } else if position.is_multiple_of(2) {
668 let sibling = sibling_iter.next().ok_or(Error::UnalignedProof)?;
670 (&computed, sibling)
671 } else {
672 let sibling = sibling_iter.next().ok_or(Error::UnalignedProof)?;
674 (sibling, &computed)
675 };
676
677 hasher.update(left_node);
679 hasher.update(right_node);
680 computed = hasher.finalize();
681
682 position /= 2;
684 level_size = level_size.div_ceil(2);
685 }
686
687 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 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 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 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 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 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 let (left, right) = if pos % 2 == 0 {
761 let left = digest;
763
764 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 left
771 } else {
772 *sibling_iter.next().ok_or(Error::UnalignedProof)?
774 };
775 (left, right)
776 } else {
777 let right = digest;
780 let left = *sibling_iter.next().ok_or(Error::UnalignedProof)?;
781 (left, right)
782 };
783
784 hasher.update(&left);
786 hasher.update(&right);
787 next_level.push((parent_pos, hasher.finalize()));
788
789 idx += 1;
790 }
791
792 core::mem::swap(&mut current, &mut next_level);
794 next_level.clear();
795 level_size = level_size.div_ceil(2);
796 }
797
798 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 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 let mut hasher = Sha256::default();
838 for (i, leaf) in digests.iter().enumerate() {
839 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 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 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 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 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 assert!(tree.proof(n as u32).is_err());
895
896 root
898 }
899
900 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 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 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 let mut proof = tree.proof(0).unwrap();
1132
1133 proof.siblings = Vec::new();
1135
1136 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 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 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 let mut proof = tree.proof(0).unwrap();
1160
1161 proof.siblings.push(*element);
1163
1164 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 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 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 let proof = tree.proof(2).unwrap();
1187
1188 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 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 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 let proof = tree.proof(1).unwrap();
1212
1213 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 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 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 let proof = tree.proof(0).unwrap();
1235
1236 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 let txs = [b"tx1", b"tx2", b"tx3"];
1248 let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1249
1250 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 let proof = tree.proof(1).unwrap();
1259 let mut serialized = proof.encode();
1260
1261 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 let txs = [b"tx1", b"tx2", b"tx3"];
1270 let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1271
1272 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 let proof = tree.proof(1).unwrap();
1281 let mut serialized = proof.encode_mut();
1282
1283 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 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 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 let mut proof = tree.proof(2).unwrap();
1304
1305 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 let txs = [b"tx1", b"tx2", b"tx3"];
1317 let digests: Vec<Digest> = txs.iter().map(|tx| Sha256::hash(*tx)).collect();
1318
1319 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 let proof = tree.proof(2).unwrap();
1329
1330 let mut hasher = Sha256::default();
1332 assert!(proof
1333 .verify_element_inclusion(&mut hasher, &digests[2], 2, &root)
1334 .is_ok());
1335
1336 assert!(tree.proof(3).is_err());
1338
1339 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1350
1351 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 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1380
1381 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 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 let digests: Vec<Digest> = (0..7u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1403
1404 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 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 let digests: Vec<Digest> = (0..15u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1422
1423 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 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 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1455
1456 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 assert!(tree.range_proof(8, 8).is_err()); assert!(tree.range_proof(0, 8).is_err()); assert!(tree.range_proof(5, 8).is_err()); assert!(tree.range_proof(2, 1).is_err()); }
1469
1470 #[test]
1471 fn test_range_proof_tampering() {
1472 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1474
1475 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 let range_proof = tree.range_proof(2, 4).unwrap();
1485 let mut hasher = Sha256::default();
1486 let range_leaves = &digests[2..5];
1487
1488 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 assert!(range_proof
1500 .verify(&mut hasher, 2, &digests[2..4], &root)
1501 .is_err());
1502
1503 let mut tampered_proof = range_proof.clone();
1505 assert!(!tampered_proof.siblings.is_empty());
1506 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 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 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 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1562
1563 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 let range_proof = tree.range_proof(2, 4).unwrap();
1573 let mut hasher = Sha256::default();
1574 let range_leaves = &digests[2..5];
1575
1576 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1589
1590 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 let range_proof = tree.range_proof(2, 4).unwrap();
1600 let mut hasher = Sha256::default();
1601
1602 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1613
1614 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 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 assert!(!range_proof.siblings.is_empty());
1629 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1644
1645 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 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 assert!(!range_proof.siblings.is_empty());
1660 assert!(range_proof.siblings[0].left.is_some() || range_proof.siblings[0].right.is_some());
1661
1662 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1674
1675 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1692
1693 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 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 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 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 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 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 let proof = tree.range_proof(0, 0).unwrap();
1744 assert!(proof.verify(&mut hasher, 0, &digests[0..1], &root).is_ok());
1745
1746 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 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 let builder = Builder::<Sha256>::new(0);
1768 let tree = builder.build();
1769
1770 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 let builder = Builder::<Sha256>::new(0);
1780 let tree = builder.build();
1781 let root = tree.root();
1782
1783 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 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 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 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 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 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 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 for i in 1..roots.len() {
1848 assert_eq!(roots[0], roots[i]);
1849 }
1850
1851 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)] #[case::need_right_sibling(4, 4)] #[case::boundaries_both_single_children(4, 4)] #[case::full_tree(0, 16)] fn test_range_proof_bounds_usage(#[case] start: u32, #[case] count: u32) {
1863 let digests: Vec<Digest> = (0..16u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1866
1867 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 assert!(range_proof
1881 .verify(&mut hasher, start, &digests[start as usize..end], &root)
1882 .is_ok());
1883
1884 for level_idx in 0..range_proof.siblings.len() {
1886 let bounds = &range_proof.siblings[level_idx];
1887
1888 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 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 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 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 #[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 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1958
1959 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
1985
1986 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2012
2013 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 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 assert!(multi_proof.siblings.is_empty());
2036 }
2037
2038 #[test]
2039 fn test_multi_proof_adjacent_elements() {
2040 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2042
2043 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 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 let digests: Vec<Digest> = (0..16u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2069
2070 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 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 let builder = Builder::<Sha256>::new(0);
2096 let tree = builder.build();
2097
2098 assert!(matches!(tree.multi_proof(&[]), Err(Error::NoLeaves)));
2101
2102 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2113
2114 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 assert!(matches!(tree.multi_proof(&[]), Err(Error::NoLeaves)));
2123 }
2124
2125 #[test]
2126 fn test_multi_proof_duplicate_positions_error() {
2127 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2129
2130 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2152
2153 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 let positions = [5, 0, 3];
2164 let multi_proof = tree.multi_proof(&positions).unwrap();
2165
2166 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 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 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 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2230
2231 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 let positions = [0, 3, 5];
2242 let multi_proof = tree.multi_proof(&positions).unwrap();
2243
2244 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2259
2260 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 let positions = [0, 3, 5];
2271 let multi_proof = tree.multi_proof(&positions).unwrap();
2272
2273 let wrong_positions = [
2275 (digests[0], 1), (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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2288
2289 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 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2317
2318 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 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 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 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 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 let digests: Vec<Digest> = (0..16u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2363
2364 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 let individual_siblings: usize = [0u32, 1, 8, 9]
2373 .iter()
2374 .map(|&p| tree.proof(p).unwrap().siblings.len())
2375 .sum();
2376
2377 let multi_proof = tree.multi_proof(&[0, 1, 8, 9]).unwrap();
2379
2380 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2393
2394 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 let positions = [0, 3, 5];
2405 let multi_proof = tree.multi_proof(&positions).unwrap();
2406
2407 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2427
2428 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 let positions = [0, 3, 5];
2437 let multi_proof = tree.multi_proof(&positions).unwrap();
2438
2439 let mut serialized = multi_proof.encode();
2441 serialized.truncate(serialized.len() - 1);
2442
2443 assert!(Proof::<Digest>::decode_cfg(&mut serialized, &positions.len()).is_err());
2445 }
2446
2447 #[test]
2448 fn test_multi_proof_serialization_extra() {
2449 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2451
2452 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 let positions = [0, 3, 5];
2461 let multi_proof = tree.multi_proof(&positions).unwrap();
2462
2463 let mut serialized = multi_proof.encode_mut();
2465 serialized.extend_from_slice(&[0u8]);
2466
2467 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()); serialized.extend_from_slice(&1usize.encode()); 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2486
2487 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 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 let digests: Vec<Digest> = (0..8u32).map(|i| Sha256::hash(&i.to_be_bytes())).collect();
2509
2510 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 let positions = [0, 3];
2521 let multi_proof = tree.multi_proof(&positions).unwrap();
2522
2523 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 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 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 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 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 let positions = [0, 3];
2579 let multi_proof = tree.multi_proof(&positions).unwrap();
2580
2581 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 let mut hasher = Sha256::default();
2592 let default_proof = Proof::<Digest>::default();
2593
2594 let empty_elements: &[(Digest, u32)] = &[];
2596
2597 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 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 let digest = Sha256::hash(b"only_leaf");
2617
2618 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 let multi_proof = tree.multi_proof(&[0]).unwrap();
2627
2628 assert_eq!(multi_proof.leaf_count, 1);
2630
2631 assert!(
2633 multi_proof.siblings.is_empty(),
2634 "Single leaf tree should have no siblings"
2635 );
2636
2637 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 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 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 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 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 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 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 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 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 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 let positions = [0, 3];
2745 let mut multi_proof = tree.multi_proof(&positions).unwrap();
2746 multi_proof.leaf_count = 4; let elements: Vec<(Digest, u32)> = positions
2749 .iter()
2750 .map(|&p| (digests[p as usize], p))
2751 .collect();
2752
2753 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 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 let positions = [0, 3];
2777 let multi_proof = tree.multi_proof(&positions).unwrap();
2778
2779 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 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 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 let positions = [0, 5];
2813 let mut multi_proof = tree.multi_proof(&positions).unwrap();
2814
2815 if multi_proof.siblings.len() >= 2 {
2817 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 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 let positions = [0, 2];
2850 let mut multi_proof = tree.multi_proof(&positions).unwrap();
2851
2852 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 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}