1use crate::{HashBuilder, Nibbles, RlpNode, TrieNode};
9use alloc::vec::Vec;
10use alloy_primitives::{keccak256, map::B256Map, Bytes, B256};
11use alloy_rlp::Decodable;
12
13const KEY_NIBBLES: usize = B256::len_bytes() * 2;
14
15const MAX_PROOF_NODES: usize = 2 * (KEY_NIBBLES + 1);
18
19struct RangeProofVerifier<'a> {
21 range: ProofRange,
23 nodes: ProofNodes<'a>,
25 frontier: ProofFrontier,
27 next: Option<Nibbles>,
29}
30
31impl<'a> RangeProofVerifier<'a> {
32 fn new(
34 left: B256,
35 right: B256,
36 proof: &'a [Bytes],
37 frontier: ProofFrontier,
38 ) -> Result<Self, RangeProofErrorKind> {
39 Ok(Self {
40 range: ProofRange::new(left, right),
41 nodes: ProofNodes::new(proof)?,
42 frontier,
43 next: None,
44 })
45 }
46
47 fn verify(mut self, root: B256) -> Result<Option<B256>, RangeProofErrorKind> {
50 self.visit_reference(Nibbles::new(), &RlpNode::word_rlp(&root))?;
51
52 let got = self.frontier.root()?;
53 if got != root {
54 return Err(RangeProofErrorKind::RootMismatch { expected: root, got })
55 }
56 Ok(self.next.as_ref().map(TriePath::lowest_key))
57 }
58
59 fn visit_reference(
62 &mut self,
63 prefix: Nibbles,
64 reference: &RlpNode,
65 ) -> Result<(), RangeProofErrorKind> {
66 match self.range.subtree_relation(&prefix)? {
67 SubtreeRelation::OutsideLeft => self.add_outside_reference(prefix, reference),
68 SubtreeRelation::OutsideRight => {
69 self.note_next(prefix);
70 self.add_outside_reference(prefix, reference)
71 }
72 SubtreeRelation::Inside => Ok(()),
73 SubtreeRelation::Boundary => {
74 let node = self.nodes.resolve(prefix, reference)?;
75 self.visit_node(node, prefix)
76 }
77 }
78 }
79
80 fn visit_node(&mut self, node: TrieNode, prefix: Nibbles) -> Result<(), RangeProofErrorKind> {
82 match node {
83 TrieNode::EmptyRoot => Ok(()),
84 TrieNode::Leaf(leaf) => {
85 let path = prefix.descend_leaf(&leaf.key)?;
86 match self.range.key_relation(&path) {
87 KeyRelation::Before => self.frontier.push_leaf(path, leaf.value),
88 KeyRelation::Inside => {}
89 KeyRelation::After => {
90 self.note_next(path);
91 self.frontier.push_leaf(path, leaf.value);
92 }
93 }
94 Ok(())
95 }
96 TrieNode::Extension(extension) => {
97 self.visit_reference(prefix.descend_extension(&extension.key)?, &extension.child)
98 }
99 TrieNode::Branch(branch) => {
100 for (nibble, child) in branch
101 .as_ref()
102 .children()
103 .filter_map(|(nibble, child)| child.map(|child| (nibble, child)))
104 {
105 self.visit_reference(prefix.descend_child(nibble)?, child)?;
106 }
107 Ok(())
108 }
109 }
110 }
111
112 fn add_outside_reference(
114 &mut self,
115 prefix: Nibbles,
116 reference: &RlpNode,
117 ) -> Result<(), RangeProofErrorKind> {
118 if let Some(hash) = reference.as_hash() {
119 self.frontier.push_subtree(prefix, hash);
120 return Ok(())
121 }
122 self.add_outside_node(TrieNode::decode(&mut reference.as_slice())?, prefix)
123 }
124
125 fn add_outside_node(
127 &mut self,
128 node: TrieNode,
129 prefix: Nibbles,
130 ) -> Result<(), RangeProofErrorKind> {
131 match node {
132 TrieNode::EmptyRoot => Ok(()),
133 TrieNode::Leaf(leaf) => {
134 let path = prefix.descend_leaf(&leaf.key)?;
135 self.frontier.push_leaf(path, leaf.value);
136 Ok(())
137 }
138 TrieNode::Extension(extension) => self
139 .add_outside_reference(prefix.descend_extension(&extension.key)?, &extension.child),
140 TrieNode::Branch(branch) => {
141 for (nibble, child) in branch
142 .as_ref()
143 .children()
144 .filter_map(|(nibble, child)| child.map(|child| (nibble, child)))
145 {
146 self.add_outside_reference(prefix.descend_child(nibble)?, child)?;
147 }
148 Ok(())
149 }
150 }
151 }
152
153 fn note_next(&mut self, path: Nibbles) {
155 if self.next.is_none_or(|next| path < next) {
156 self.next = Some(path);
157 }
158 }
159}
160
161struct ProofRange {
163 left: Nibbles,
165 right: Nibbles,
167}
168
169impl ProofRange {
170 fn new(left: B256, right: B256) -> Self {
172 Self { left: Nibbles::unpack(left), right: Nibbles::unpack(right) }
173 }
174
175 fn subtree_relation(&self, prefix: &Nibbles) -> Result<SubtreeRelation, RangeProofErrorKind> {
177 if prefix.len() > KEY_NIBBLES {
178 return Err(RangeProofErrorKind::PathTooLong { path: *prefix })
179 }
180 let left = self.left.slice(..prefix.len());
181 let right = self.right.slice(..prefix.len());
182
183 Ok(if *prefix < left {
184 SubtreeRelation::OutsideLeft
185 } else if *prefix > right {
186 SubtreeRelation::OutsideRight
187 } else if *prefix > left && *prefix < right {
188 SubtreeRelation::Inside
189 } else {
190 SubtreeRelation::Boundary
191 })
192 }
193
194 fn key_relation(&self, path: &Nibbles) -> KeyRelation {
196 if path < &self.left {
197 KeyRelation::Before
198 } else if path > &self.right {
199 KeyRelation::After
200 } else {
201 KeyRelation::Inside
202 }
203 }
204}
205
206#[derive(Clone, Copy, Debug, PartialEq, Eq)]
209enum SubtreeRelation {
210 OutsideLeft,
212 OutsideRight,
214 Boundary,
216 Inside,
218}
219
220#[derive(Clone, Copy, Debug, PartialEq, Eq)]
222enum KeyRelation {
223 Before,
225 Inside,
227 After,
229}
230
231struct ProofNodes<'a>(B256Map<&'a [u8]>);
233
234impl<'a> ProofNodes<'a> {
235 fn new(proof: &'a [Bytes]) -> Result<Self, RangeProofErrorKind> {
238 if proof.len() > MAX_PROOF_NODES {
239 return Err(RangeProofErrorKind::TooManyProofNodes { count: proof.len() })
240 }
241 Ok(Self(proof.iter().map(|node| (keccak256(node), node.as_ref())).collect()))
242 }
243
244 fn resolve(&self, path: Nibbles, reference: &RlpNode) -> Result<TrieNode, RangeProofErrorKind> {
246 let Some(hash) = reference.as_hash() else {
247 return Ok(TrieNode::decode(&mut reference.as_slice())?)
248 };
249 let node = self.0.get(&hash).ok_or(RangeProofErrorKind::MissingProofNode { path })?;
250 Ok(TrieNode::decode(&mut &node[..])?)
251 }
252}
253
254#[derive(Default)]
256struct ProofFrontier(Vec<FrontierEntry>);
257
258impl ProofFrontier {
259 fn from_leaves<I, V>(
261 origin: B256,
262 leaves: I,
263 ) -> Result<(Self, Option<B256>), RangeProofErrorKind>
264 where
265 I: IntoIterator<Item = (B256, V)>,
266 V: Into<Vec<u8>>,
267 {
268 let mut frontier = Self::default();
269 let mut previous = None;
270
271 for (key, value) in leaves {
272 let value = value.into();
273 if key < origin {
274 return Err(RangeProofErrorKind::LeafBeforeOrigin { key, origin })
275 }
276 if previous.is_some_and(|previous| key <= previous) {
277 return Err(RangeProofErrorKind::NonMonotonicLeaves)
278 }
279 if value.is_empty() {
280 return Err(RangeProofErrorKind::EmptyLeafValue { key })
281 }
282 previous = Some(key);
283 frontier.push_leaf(Nibbles::unpack(key), value);
284 }
285
286 Ok((frontier, previous))
287 }
288
289 fn push_leaf(&mut self, path: Nibbles, value: Vec<u8>) {
291 debug_assert_eq!(path.len(), KEY_NIBBLES);
292 self.0.push(FrontierEntry::Leaf { path, value });
293 }
294
295 fn push_subtree(&mut self, path: Nibbles, hash: B256) {
297 debug_assert!(path.len() <= KEY_NIBBLES);
298 self.0.push(FrontierEntry::Subtree { path, hash });
299 }
300
301 fn root(mut self) -> Result<B256, RangeProofErrorKind> {
303 self.0.sort_unstable_by_key(FrontierEntry::path);
306 let mut builder = HashBuilder::default();
307 let mut previous = None;
308
309 for entry in self.0 {
310 let path = entry.path();
311 if previous.is_some_and(|previous| path <= previous) {
312 return Err(RangeProofErrorKind::DuplicateFrontierPath { path })
313 }
314 previous = Some(path);
315 match entry {
316 FrontierEntry::Leaf { path, value } => builder.add_leaf(path, &value),
317 FrontierEntry::Subtree { path, hash } => builder.add_branch(path, hash, false),
318 }
319 }
320 Ok(builder.root())
321 }
322}
323
324#[derive(Clone, Debug)]
327enum FrontierEntry {
328 Leaf { path: Nibbles, value: Vec<u8> },
330 Subtree { path: Nibbles, hash: B256 },
332}
333
334impl FrontierEntry {
335 const fn path(&self) -> Nibbles {
337 match self {
338 Self::Leaf { path, .. } | Self::Subtree { path, .. } => *path,
339 }
340 }
341}
342
343#[derive(Debug, thiserror::Error)]
347#[error(transparent)]
348pub struct RangeProofError(#[from] RangeProofErrorKind);
349
350#[derive(Debug, thiserror::Error, PartialEq, Eq)]
351enum RangeProofErrorKind {
352 #[error("range leaves are not strictly increasing")]
354 NonMonotonicLeaves,
355 #[error("range leaf {key} precedes origin {origin}")]
357 LeafBeforeOrigin {
358 key: B256,
360 origin: B256,
362 },
363 #[error("range leaf {key} has an empty value")]
365 EmptyLeafValue {
366 key: B256,
368 },
369 #[error("missing proof node at path {path:?}")]
371 MissingProofNode {
372 path: Nibbles,
374 },
375 #[error("range proof has {count} nodes, more than two boundary paths can reference")]
377 TooManyProofNodes {
378 count: usize,
380 },
381 #[error("extension node at path {path:?} has an empty key")]
383 EmptyExtensionKey {
384 path: Nibbles,
386 },
387 #[error("proof path {path:?} exceeds hashed key length")]
389 PathTooLong {
390 path: Nibbles,
392 },
393 #[error("leaf path {path:?} does not resolve to a hashed key")]
395 InvalidLeafPath {
396 path: Nibbles,
398 },
399 #[error("duplicate range-proof frontier path {path:?}")]
401 DuplicateFrontierPath {
402 path: Nibbles,
404 },
405 #[error("range proof root mismatch: expected {expected}, got {got}")]
407 RootMismatch {
408 expected: B256,
410 got: B256,
412 },
413 #[error(transparent)]
415 Rlp(#[from] alloy_rlp::Error),
416}
417
418pub fn verify_range_proof<I, V>(
430 root: B256,
431 origin: B256,
432 limit: B256,
433 leaves: I,
434 proof: &[Bytes],
435) -> Result<Option<B256>, RangeProofError>
436where
437 I: IntoIterator<Item = (B256, V)>,
438 V: Into<Vec<u8>>,
439{
440 let (frontier, last_key) = ProofFrontier::from_leaves(origin, leaves)?;
441
442 if proof.is_empty() {
444 let got = frontier.root()?;
445 if got != root {
446 return Err(RangeProofErrorKind::RootMismatch { expected: root, got }.into())
447 }
448 return Ok(None)
449 }
450
451 RangeProofVerifier::new(origin, last_key.unwrap_or(limit), proof, frontier)?
452 .verify(root)
453 .map_err(Into::into)
454}
455
456trait TriePath: Sized {
459 fn lowest_key(&self) -> B256;
461
462 fn descend_extension(self, key: &Nibbles) -> Result<Self, RangeProofErrorKind>;
464
465 fn descend_child(self, nibble: u8) -> Result<Self, RangeProofErrorKind>;
467
468 fn descend_leaf(self, key: &Nibbles) -> Result<Self, RangeProofErrorKind>;
470
471 fn join_checked(self, key: &Nibbles) -> Result<Self, RangeProofErrorKind>;
473}
474
475impl TriePath for Nibbles {
476 fn lowest_key(&self) -> B256 {
478 B256::right_padding_from(&self.pack())
479 }
480
481 fn descend_extension(self, key: &Nibbles) -> Result<Self, RangeProofErrorKind> {
483 if key.is_empty() {
484 return Err(RangeProofErrorKind::EmptyExtensionKey { path: self })
485 }
486 self.join_checked(key)
487 }
488
489 fn descend_child(self, nibble: u8) -> Result<Self, RangeProofErrorKind> {
491 if self.len() >= KEY_NIBBLES {
492 return Err(RangeProofErrorKind::PathTooLong { path: self })
493 }
494 let mut path = self;
495 path.push(nibble);
496 Ok(path)
497 }
498
499 fn descend_leaf(self, key: &Nibbles) -> Result<Self, RangeProofErrorKind> {
501 let path = self.join_checked(key)?;
502 if path.len() != KEY_NIBBLES {
503 return Err(RangeProofErrorKind::InvalidLeafPath { path })
504 }
505 Ok(path)
506 }
507
508 fn join_checked(self, key: &Nibbles) -> Result<Self, RangeProofErrorKind> {
510 if self.len() + key.len() > KEY_NIBBLES {
511 return Err(RangeProofErrorKind::PathTooLong { path: self })
512 }
513 Ok(self.join(key))
514 }
515}
516
517#[cfg(test)]
518mod tests {
519 use super::*;
520 use crate::{proof::ProofRetainer, BranchNode, ExtensionNode, TrieMask, EMPTY_ROOT_HASH};
521 use alloc::{vec, vec::Vec};
522
523 const MAX_HASH: B256 = B256::repeat_byte(0xff);
524
525 fn verify_range_proof<I, V>(
526 root: B256,
527 origin: B256,
528 leaves: I,
529 proof: &[Bytes],
530 ) -> Result<Option<B256>, RangeProofErrorKind>
531 where
532 I: IntoIterator<Item = (B256, V)>,
533 V: Into<Vec<u8>>,
534 {
535 super::verify_range_proof(root, origin, MAX_HASH, leaves, proof).map_err(|error| error.0)
536 }
537
538 fn key(value: u64) -> B256 {
539 B256::left_padding_from(&value.to_be_bytes())
540 }
541
542 fn encode_node(node: &TrieNode) -> Bytes {
543 alloy_rlp::encode(node).into()
544 }
545
546 fn no_leaves() -> Vec<(B256, Vec<u8>)> {
547 Vec::new()
548 }
549
550 fn value(byte: u8) -> Vec<u8> {
551 vec![byte; 64]
552 }
553
554 fn build_proof(leaves: &[(B256, Vec<u8>)], targets: &[B256]) -> (B256, Vec<Bytes>) {
555 let targets = targets.iter().copied().map(Nibbles::unpack).collect();
556 let mut builder = HashBuilder::default().with_proof_retainer(ProofRetainer::new(targets));
557 for (key, value) in leaves {
558 builder.add_leaf(Nibbles::unpack(*key), value);
559 }
560 let root = builder.root();
561 let proof = builder
562 .take_proof_nodes()
563 .into_nodes_sorted()
564 .into_iter()
565 .map(|(_, node)| node)
566 .collect();
567 (root, proof)
568 }
569
570 #[test]
571 fn partial_range_authenticates_and_reports_the_next_key() {
572 let leaves =
573 vec![(key(1), value(1)), (key(2), value(2)), (key(3), value(3)), (key(4), value(4))];
574 let (root, proof) = build_proof(&leaves, &[key(2), key(3)]);
575
576 assert_eq!(
577 verify_range_proof(root, key(2), leaves[1..3].to_vec(), &proof).unwrap(),
578 Some(key(4))
579 );
580 }
581
582 #[test]
584 fn unexpanded_right_subtree_reports_a_prefix_bound() {
585 let right = |tail: u8| {
586 let mut key = B256::ZERO;
587 key.0[0] = 0x40;
588 key.0[31] = tail;
589 key
590 };
591 let leaves = vec![
592 (key(1), value(1)),
593 (key(2), value(2)),
594 (right(1), value(3)),
595 (right(2), value(4)),
596 ];
597 let (root, proof) = build_proof(&leaves, &[key(1), key(2)]);
598
599 assert_eq!(
600 verify_range_proof(root, key(1), leaves[..2].to_vec(), &proof).unwrap(),
601 Some(B256::right_padding_from(&[0x40]))
602 );
603 }
604
605 #[test]
606 fn inline_outside_nodes_are_reconstructed() {
607 let leaves =
608 vec![(key(1), vec![1]), (key(2), vec![2]), (key(3), vec![3]), (key(4), vec![4])];
609 let (root, proof) = build_proof(&leaves, &[key(2), key(3)]);
610
611 assert_eq!(
612 verify_range_proof(root, key(2), leaves[1..3].to_vec(), &proof).unwrap(),
613 Some(key(4))
614 );
615 }
616
617 #[test]
618 fn unused_proof_nodes_are_accepted() {
619 let leaves =
620 vec![(key(1), value(1)), (key(2), value(2)), (key(3), value(3)), (key(4), value(4))];
621 let (root, mut proof) = build_proof(&leaves, &[key(2), key(3)]);
622 proof.push(Bytes::from_static(&[alloy_rlp::EMPTY_STRING_CODE]));
623
624 assert_eq!(
625 verify_range_proof(root, key(2), leaves[1..3].to_vec(), &proof).unwrap(),
626 Some(key(4))
627 );
628 }
629
630 #[test]
631 fn proof_node_count_is_bounded() {
632 let leaves =
633 vec![(key(1), value(1)), (key(2), value(2)), (key(3), value(3)), (key(4), value(4))];
634 let (root, mut proof) = build_proof(&leaves, &[key(2), key(3)]);
635 proof.resize(MAX_PROOF_NODES, Bytes::from_static(&[alloy_rlp::EMPTY_STRING_CODE]));
636
637 assert_eq!(
638 verify_range_proof(root, key(2), leaves[1..3].to_vec(), &proof),
639 Ok(Some(key(4)))
640 );
641
642 proof.push(Bytes::from_static(&[alloy_rlp::EMPTY_STRING_CODE]));
643
644 assert_eq!(
645 verify_range_proof(root, key(2), leaves[1..3].to_vec(), &proof),
646 Err(RangeProofErrorKind::TooManyProofNodes { count: MAX_PROOF_NODES + 1 })
647 );
648 }
649
650 #[test]
652 fn node_paths_are_bounded_before_they_overflow_a_key() {
653 let dangling = RlpNode::word_rlp(&B256::repeat_byte(0xaa));
654
655 let overlong = encode_node(&TrieNode::Extension(ExtensionNode::new(
657 Nibbles::unpack(key(1)),
658 dangling.clone(),
659 )));
660 let branch = encode_node(&TrieNode::Branch(BranchNode::new(
661 vec![RlpNode::word_rlp(&keccak256(&overlong))],
662 TrieMask::new(1),
663 )));
664 let proof = vec![branch.clone(), overlong];
665
666 assert!(matches!(
667 verify_range_proof(keccak256(&branch), key(1), no_leaves(), &proof),
668 Err(RangeProofErrorKind::PathTooLong { .. })
669 ));
670
671 let deep_branch =
673 encode_node(&TrieNode::Branch(BranchNode::new(vec![dangling], TrieMask::new(1))));
674 let reach = encode_node(&TrieNode::Extension(ExtensionNode::new(
675 Nibbles::unpack(key(1)),
676 RlpNode::word_rlp(&keccak256(&deep_branch)),
677 )));
678 let proof = vec![reach.clone(), deep_branch];
679
680 assert!(matches!(
681 verify_range_proof(keccak256(&reach), key(1), no_leaves(), &proof),
682 Err(RangeProofErrorKind::PathTooLong { .. })
683 ));
684 }
685
686 #[test]
688 fn oversized_compact_keys_are_rejected() {
689 for (flag, len) in [(0x00, 33), (0x1a, 32), (0x20, 33), (0x3a, 32)] {
692 let compact_key = [&[flag][..], &[0xab; 33][..len]].concat();
693 let mut node = Vec::new();
694 alloy_rlp::encode_list::<_, [u8]>(&[&compact_key[..], &[0xaa; 32]], &mut node);
695 let node = Bytes::from(node);
696
697 assert_eq!(
698 verify_range_proof(keccak256(&node), key(1), no_leaves(), &[node]),
699 Err(RangeProofErrorKind::Rlp(alloy_rlp::Error::Custom("trie node key too long"))),
700 "flag {flag:#04x}"
701 );
702 }
703 }
704
705 #[test]
707 fn empty_extension_keys_are_rejected() {
708 let empty_key = Nibbles::new();
709 let mut proof = Vec::new();
710 let mut child = RlpNode::word_rlp(&B256::repeat_byte(0xaa));
711
712 for _ in 0..64 {
713 let node = encode_node(&TrieNode::Extension(ExtensionNode::new(empty_key, child)));
714 child = RlpNode::word_rlp(&keccak256(&node));
715 proof.push(node);
716 }
717 let root = keccak256(proof.last().unwrap());
718
719 assert!(matches!(
720 verify_range_proof(root, key(1), no_leaves(), &proof),
721 Err(RangeProofErrorKind::EmptyExtensionKey { .. })
722 ));
723 }
724
725 #[test]
726 fn missing_boundary_node_is_rejected() {
727 let leaves =
728 vec![(key(1), value(1)), (key(2), value(2)), (key(3), value(3)), (key(4), value(4))];
729 let (root, _) = build_proof(&leaves, &[key(2), key(3)]);
730 let unrelated = [Bytes::from_static(&[alloy_rlp::EMPTY_STRING_CODE])];
731
732 assert!(matches!(
733 verify_range_proof(root, key(2), leaves[1..3].to_vec(), &unrelated),
734 Err(RangeProofErrorKind::MissingProofNode { .. })
735 ));
736 }
737
738 #[test]
739 fn boundary_proof_can_authenticate_an_exhausted_range() {
740 let leaves =
741 vec![(key(1), value(1)), (key(2), value(2)), (key(3), value(3)), (key(4), value(4))];
742 let (root, proof) = build_proof(&leaves, &[key(2), key(4)]);
743
744 assert_eq!(verify_range_proof(root, key(2), leaves[1..].to_vec(), &proof).unwrap(), None);
745 }
746
747 #[test]
748 fn proof_free_full_trie_is_exhausted() {
749 let leaves = vec![(key(1), value(1)), (key(2), value(2)), (key(3), value(3))];
750 let (root, _) = build_proof(&leaves, &[]);
751
752 assert_eq!(verify_range_proof(root, B256::ZERO, leaves, &[]).unwrap(), None);
753 }
754
755 #[test]
756 fn omitted_interior_leaf_changes_root() {
757 let leaves =
758 vec![(key(1), value(1)), (key(2), value(2)), (key(3), value(3)), (key(4), value(4))];
759 let (root, proof) = build_proof(&leaves, &[key(2), key(4)]);
760 let returned = vec![(key(2), value(2)), (key(4), value(4))];
761
762 assert!(matches!(
763 verify_range_proof(root, key(2), returned, &proof),
764 Err(RangeProofErrorKind::RootMismatch { .. })
765 ));
766 }
767
768 #[test]
769 fn mutated_leaf_changes_root() {
770 let leaves = vec![(key(1), value(1)), (key(2), value(2)), (key(3), value(3))];
771 let (root, proof) = build_proof(&leaves, &[key(2), key(3)]);
772 let returned = vec![(key(2), value(9)), (key(3), value(3))];
773
774 assert!(matches!(
775 verify_range_proof(root, key(2), returned, &proof),
776 Err(RangeProofErrorKind::RootMismatch { .. })
777 ));
778 }
779
780 #[test]
781 fn empty_tail_is_authenticated() {
782 let leaves = vec![(key(1), value(1)), (key(2), value(2))];
783 let (root, proof) = build_proof(&leaves, &[key(3)]);
784
785 assert_eq!(
786 verify_range_proof(root, key(3), core::iter::empty::<(B256, Vec<u8>)>(), &proof)
787 .unwrap(),
788 None
789 );
790 }
791
792 #[test]
793 fn empty_range_cannot_hide_a_right_leaf() {
794 let leaves = vec![(key(1), value(1)), (key(3), value(3))];
795 let (root, proof) = build_proof(&leaves, &[key(2)]);
796
797 assert!(matches!(
798 verify_range_proof(root, key(2), core::iter::empty::<(B256, Vec<u8>)>(), &proof,),
799 Err(RangeProofErrorKind::RootMismatch { .. })
800 ));
801 }
802
803 #[test]
804 fn empty_interval_is_authenticated_through_its_limit() {
805 let leaves = vec![(key(1), value(1)), (key(3), value(3))];
806 let (root, proof) = build_proof(&leaves, &[key(2)]);
807
808 assert_eq!(
809 super::verify_range_proof(root, key(2), key(2), no_leaves(), &proof).unwrap(),
810 Some(key(3))
811 );
812 }
813
814 #[test]
815 fn rejects_non_monotonic_leaves_and_leaves_before_origin() {
816 let leaves = vec![(key(2), value(2)), (key(1), value(1))];
817
818 assert_eq!(
819 verify_range_proof(B256::ZERO, B256::ZERO, leaves, &[]),
820 Err(RangeProofErrorKind::NonMonotonicLeaves)
821 );
822 assert!(matches!(
823 verify_range_proof(B256::ZERO, key(2), [(key(1), value(1))], &[],),
824 Err(RangeProofErrorKind::LeafBeforeOrigin { .. })
825 ));
826 assert_eq!(
827 verify_range_proof(B256::ZERO, B256::ZERO, [(key(1), Vec::new())], &[]),
828 Err(RangeProofErrorKind::EmptyLeafValue { key: key(1) })
829 );
830 }
831
832 #[test]
833 fn empty_root_accepts_only_an_empty_range() {
834 assert_eq!(
835 verify_range_proof(
836 EMPTY_ROOT_HASH,
837 B256::ZERO,
838 core::iter::empty::<(B256, Vec<u8>)>(),
839 &[]
840 )
841 .unwrap(),
842 None
843 );
844 assert!(matches!(
845 verify_range_proof(EMPTY_ROOT_HASH, B256::ZERO, [(key(1), value(1))], &[],),
846 Err(RangeProofErrorKind::RootMismatch { .. })
847 ));
848 assert!(
849 verify_range_proof(EMPTY_ROOT_HASH, B256::ZERO, no_leaves(), &[Bytes::new()]).is_err()
850 );
851 }
852}