1use crate::mmr::{
62 hasher::Hasher as HasherTrait,
63 iterator::{pos_to_height, PeakIterator},
64 storage::Storage as StorageTrait,
65 Error, Location, Position, StandardHasher,
66};
67use commonware_cryptography::Hasher as CHasher;
68use futures::future::try_join_all;
69use std::collections::HashMap;
70use tracing::debug;
71
72pub struct Hasher<'a, H: CHasher> {
80 hasher: &'a mut StandardHasher<H>,
81 height: u32,
82
83 grafted_digests: HashMap<Position, H::Digest>,
85}
86
87impl<'a, H: CHasher> Hasher<'a, H> {
88 pub fn new(hasher: &'a mut StandardHasher<H>, height: u32) -> Self {
89 Self {
90 hasher,
91 height,
92 grafted_digests: HashMap::new(),
93 }
94 }
95
96 pub const fn standard(&mut self) -> &mut StandardHasher<H> {
98 self.hasher
99 }
100
101 pub(crate) async fn load_grafted_digests(
111 &mut self,
112 leaves: &[Location],
113 mmr: &impl StorageTrait<H::Digest>,
114 ) -> Result<(), Error> {
115 let leaf_positions: Vec<Position> = leaves
117 .iter()
118 .map(|&loc| Position::try_from(loc))
119 .collect::<Result<_, _>>()?;
120
121 let futures = leaf_positions
123 .iter()
124 .map(|&pos| mmr.get_node(self.destination_pos(pos)));
125 let digests = try_join_all(futures).await?;
126
127 for (i, digest) in digests.iter().enumerate() {
129 if digest.is_none() {
130 return Err(Error::MissingGraftedDigest(leaves[i]));
131 }
132 }
133
134 for (pos, digest) in leaf_positions.into_iter().zip(digests) {
136 self.grafted_digests.insert(pos, digest.unwrap());
137 }
138
139 Ok(())
140 }
141
142 fn destination_pos(&self, pos: Position) -> Position {
145 destination_pos(pos, self.height)
146 }
147}
148
149pub struct HasherFork<'a, H: CHasher> {
152 hasher: StandardHasher<H>,
153 height: u32,
154 grafted_digests: &'a HashMap<Position, H::Digest>,
155}
156
157fn destination_pos(peak_node_pos: Position, height: u32) -> Position {
164 let peak_node_pos = *peak_node_pos;
165 let leading_zeros = (peak_node_pos + 1).leading_zeros();
166 assert!(leading_zeros >= height, "destination_pos > u64::MAX");
167 let mut peak_pos = u64::MAX >> leading_zeros;
168 let mut base_pos = u64::MAX >> (leading_zeros - height);
169 let mut peak_height = peak_pos.trailing_ones() - 1;
170 let mut base_height = peak_height + height;
171 peak_pos -= 1;
172 base_pos -= 1;
173
174 while base_height >= height {
175 if peak_pos == peak_node_pos {
176 break;
177 }
178
179 let left_pos = peak_pos - (1 << peak_height);
180 if left_pos < peak_node_pos {
181 peak_pos -= 1;
182 base_pos -= 1;
183 } else {
184 peak_pos = left_pos;
185 base_pos -= 1 << base_height;
186 }
187
188 peak_height -= 1;
189 base_height -= 1;
190 }
191
192 Position::new(base_pos)
193}
194
195pub(super) fn source_pos(base_node_pos: Position, height: u32) -> Option<Position> {
198 if pos_to_height(base_node_pos) < height {
199 return None;
201 }
202
203 let leading_zeros = (base_node_pos + 1).leading_zeros();
204 let mut base_pos = u64::MAX >> leading_zeros;
205 let mut peak_pos = u64::MAX >> (leading_zeros + height);
206 let mut base_height = base_pos.trailing_ones() - 1;
207 let mut peak_height = base_height - height;
208 base_pos -= 1;
209 peak_pos -= 1;
210
211 while base_pos != base_node_pos {
212 let left_pos = base_pos - (1 << base_height);
213 if left_pos < base_node_pos {
214 base_pos -= 1;
215 peak_pos -= 1;
216 } else {
217 base_pos = left_pos;
218 peak_pos -= 1 << peak_height;
219 }
220
221 base_height -= 1;
222 peak_height -= 1;
223 }
224
225 Some(Position::new(peak_pos))
226}
227
228impl<H: CHasher> HasherTrait<H::Digest> for Hasher<'_, H> {
229 type Inner = H;
230
231 fn leaf_digest(&mut self, pos: Position, element: &[u8]) -> H::Digest {
237 let grafted_digest = self.grafted_digests.get(&pos);
238 let Some(grafted_digest) = grafted_digest else {
239 panic!("missing grafted digest for leaf_pos {pos} - load_grafted_digests must be called first");
240 };
241
242 self.hasher.update_with_element(element);
245 self.hasher.update_with_digest(grafted_digest);
246
247 self.hasher.finalize()
248 }
249
250 fn fork(&self) -> impl HasherTrait<H::Digest> {
251 HasherFork::<H> {
252 hasher: StandardHasher::new(),
253 height: self.height,
254 grafted_digests: &self.grafted_digests,
255 }
256 }
257
258 fn node_digest(
259 &mut self,
260 pos: Position,
261 left_digest: &H::Digest,
262 right_digest: &H::Digest,
263 ) -> H::Digest {
264 self.hasher
265 .node_digest(self.destination_pos(pos), left_digest, right_digest)
266 }
267
268 fn root<'a>(
269 &mut self,
270 size: Position,
271 peak_digests: impl Iterator<Item = &'a H::Digest>,
272 ) -> H::Digest {
273 let dest_pos = self.destination_pos(size);
274 self.hasher.root(dest_pos, peak_digests)
275 }
276
277 fn digest(&mut self, data: &[u8]) -> H::Digest {
278 self.hasher.digest(data)
279 }
280
281 fn inner(&mut self) -> &mut H {
282 self.hasher.inner()
283 }
284}
285
286impl<H: CHasher> HasherTrait<H::Digest> for HasherFork<'_, H> {
287 type Inner = H;
288
289 fn leaf_digest(&mut self, pos: Position, element: &[u8]) -> H::Digest {
295 let grafted_digest = self.grafted_digests.get(&pos);
296 let Some(grafted_digest) = grafted_digest else {
297 panic!("missing grafted digest for leaf_pos {pos} - load_grafted_digests must be called first");
298 };
299
300 self.hasher.update_with_element(element);
303 self.hasher.update_with_digest(grafted_digest);
304
305 self.hasher.finalize()
306 }
307
308 fn fork(&self) -> impl HasherTrait<H::Digest> {
309 HasherFork::<H> {
310 hasher: StandardHasher::<H>::new(),
311 height: self.height,
312 grafted_digests: self.grafted_digests,
313 }
314 }
315
316 fn node_digest(
317 &mut self,
318 pos: Position,
319 left_digest: &H::Digest,
320 right_digest: &H::Digest,
321 ) -> H::Digest {
322 self.hasher
323 .node_digest(destination_pos(pos, self.height), left_digest, right_digest)
324 }
325
326 fn root<'a>(
327 &mut self,
328 size: Position,
329 peak_digests: impl Iterator<Item = &'a H::Digest>,
330 ) -> H::Digest {
331 let dest_pos = destination_pos(size, self.height);
332 self.hasher.root(dest_pos, peak_digests)
333 }
334
335 fn digest(&mut self, data: &[u8]) -> H::Digest {
336 self.hasher.digest(data)
337 }
338
339 fn inner(&mut self) -> &mut H {
340 self.hasher.inner()
341 }
342}
343
344pub struct Verifier<'a, H: CHasher> {
346 hasher: StandardHasher<H>,
347 height: u32,
348
349 elements: Vec<&'a [u8]>,
351
352 loc: Location,
354}
355
356impl<'a, H: CHasher> Verifier<'a, H> {
357 pub fn new(height: u32, loc: Location, elements: Vec<&'a [u8]>) -> Self {
363 assert!(loc.is_valid(), "location {loc} > MAX_LOCATION");
364 Self {
365 hasher: StandardHasher::new(),
366 height,
367 elements,
368 loc,
369 }
370 }
371
372 pub const fn standard(&mut self) -> &mut StandardHasher<H> {
373 &mut self.hasher
374 }
375}
376
377impl<H: CHasher> HasherTrait<H::Digest> for Verifier<'_, H> {
378 type Inner = H;
379
380 fn leaf_digest(&mut self, pos: Position, element: &[u8]) -> H::Digest {
381 self.hasher.leaf_digest(pos, element)
382 }
383
384 fn fork(&self) -> impl HasherTrait<H::Digest> {
385 Verifier::<H> {
386 hasher: StandardHasher::new(),
387 height: self.height,
388 elements: self.elements.clone(),
389 loc: self.loc,
390 }
391 }
392
393 fn node_digest(
394 &mut self,
395 pos: Position,
396 left_digest: &H::Digest,
397 right_digest: &H::Digest,
398 ) -> H::Digest {
399 let digest = self.hasher.node_digest(pos, left_digest, right_digest);
400 if pos_to_height(pos) != self.height {
401 return digest;
403 }
404
405 let source_pos = source_pos(pos, self.height);
408 let Some(source_pos) = source_pos else {
409 debug!(?pos, "no grafting source pos");
411 return digest;
412 };
413 let Ok(index) = Location::try_from(source_pos) else {
414 debug!(?source_pos, "grafting source pos is not a leaf");
416 return digest;
417 };
418 if index < self.loc {
419 debug!(
421 ?index,
422 ?self.loc,
423 "grafting index is negative"
424 );
425 return digest;
426 };
427 let index = index - self.loc;
428 if index >= self.elements.len() as u64 {
429 debug!(
431 ?index,
432 len = self.elements.len(),
433 "grafting index is out of bounds"
434 );
435 return digest;
436 }
437 self.hasher
438 .update_with_element(self.elements[*index as usize]);
439 self.hasher.update_with_digest(&digest);
440
441 self.hasher.finalize()
442 }
443
444 fn root<'a>(
445 &mut self,
446 size: Position,
447 peak_digests: impl Iterator<Item = &'a H::Digest>,
448 ) -> H::Digest {
449 self.hasher.root(size, peak_digests)
450 }
451
452 fn digest(&mut self, data: &[u8]) -> H::Digest {
453 self.hasher.digest(data)
454 }
455
456 fn inner(&mut self) -> &mut H {
457 self.hasher.inner()
458 }
459}
460
461pub struct Storage<'a, H: CHasher, S1: StorageTrait<H::Digest>, S2: StorageTrait<H::Digest>> {
464 peak_tree: &'a S1,
465 base_mmr: &'a S2,
466 height: u32,
467
468 _marker: std::marker::PhantomData<H>,
469}
470
471impl<'a, H: CHasher, S1: StorageTrait<H::Digest>, S2: StorageTrait<H::Digest>>
472 Storage<'a, H, S1, S2>
473{
474 pub const fn new(peak_tree: &'a S1, base_mmr: &'a S2, height: u32) -> Self {
476 Self {
477 peak_tree,
478 base_mmr,
479 height,
480 _marker: std::marker::PhantomData,
481 }
482 }
483
484 pub async fn root(&self, hasher: &mut StandardHasher<H>) -> Result<H::Digest, Error> {
485 let size = self.size();
486 let peak_futures = PeakIterator::new(size).map(|(peak_pos, _)| self.get_node(peak_pos));
487 let peaks = try_join_all(peak_futures).await?;
488 let unwrapped_peaks = peaks.iter().map(|p| {
489 p.as_ref()
490 .expect("peak should be non-none, are the trees unaligned?")
491 });
492 let digest = hasher.root(self.base_mmr.size(), unwrapped_peaks);
493
494 Ok(digest)
495 }
496}
497
498impl<H: CHasher, S1: StorageTrait<H::Digest>, S2: StorageTrait<H::Digest>> StorageTrait<H::Digest>
499 for Storage<'_, H, S1, S2>
500{
501 fn size(&self) -> Position {
502 self.base_mmr.size()
503 }
504
505 async fn get_node(&self, pos: Position) -> Result<Option<H::Digest>, Error> {
506 let height = pos_to_height(pos);
507 if height < self.height {
508 return self.base_mmr.get_node(pos).await;
509 }
510
511 let source_pos = source_pos(pos, self.height);
512 let Some(source_pos) = source_pos else {
513 return Ok(None);
514 };
515
516 self.peak_tree.get_node(source_pos).await
517 }
518}
519
520#[cfg(test)]
521mod tests {
522 use super::*;
523 use crate::mmr::{
524 mem::CleanMmr,
525 stability::{build_test_mmr, ROOTS},
526 verification, Position, StandardHasher,
527 };
528 use commonware_cryptography::{Hasher as CHasher, Sha256};
529 use commonware_macros::test_traced;
530 use commonware_runtime::{deterministic, Runner};
531 use commonware_utils::hex;
532
533 #[test]
534 fn test_leaf_digest_sha256() {
535 test_leaf_digest::<Sha256>();
536 }
537
538 #[test]
539 fn test_node_digest_sha256() {
540 test_node_digest::<Sha256>();
541 }
542
543 #[test]
544 fn test_root_sha256() {
545 test_root::<Sha256>();
546 }
547
548 fn test_digest<H: CHasher>(value: u8) -> H::Digest {
549 let mut hasher = H::new();
550 hasher.update(&[value]);
551 hasher.finalize()
552 }
553
554 fn test_leaf_digest<H: CHasher>() {
555 let executor = deterministic::Runner::default();
556 executor.start(|_| async move {
557 let mut mmr_hasher: StandardHasher<H> = StandardHasher::new();
558 let digest1 = test_digest::<H>(1);
560 let digest2 = test_digest::<H>(2);
561
562 let out = mmr_hasher.leaf_digest(Position::new(0), &digest1);
563 assert_ne!(out, test_digest::<H>(0), "hash should be non-zero");
564
565 let mut out2 = mmr_hasher.leaf_digest(Position::new(0), &digest1);
566 assert_eq!(out, out2, "hash should be re-computed consistently");
567
568 out2 = mmr_hasher.leaf_digest(Position::new(1), &digest1);
569 assert_ne!(out, out2, "hash should change with different pos");
570
571 out2 = mmr_hasher.leaf_digest(Position::new(0), &digest2);
572 assert_ne!(out, out2, "hash should change with different input digest");
573 });
574 }
575
576 fn test_node_digest<H: CHasher>() {
577 let mut mmr_hasher: StandardHasher<H> = StandardHasher::new();
578 let d1 = test_digest::<H>(1);
581 let d2 = test_digest::<H>(2);
582 let d3 = test_digest::<H>(3);
583
584 let out = mmr_hasher.node_digest(Position::new(0), &d1, &d2);
585 assert_ne!(out, test_digest::<H>(0), "hash should be non-zero");
586
587 let mut out2 = mmr_hasher.node_digest(Position::new(0), &d1, &d2);
588 assert_eq!(out, out2, "hash should be re-computed consistently");
589
590 out2 = mmr_hasher.node_digest(Position::new(1), &d1, &d2);
591 assert_ne!(out, out2, "hash should change with different pos");
592
593 out2 = mmr_hasher.node_digest(Position::new(0), &d3, &d2);
594 assert_ne!(
595 out, out2,
596 "hash should change with different first input hash"
597 );
598
599 out2 = mmr_hasher.node_digest(Position::new(0), &d1, &d3);
600 assert_ne!(
601 out, out2,
602 "hash should change with different second input hash"
603 );
604
605 out2 = mmr_hasher.node_digest(Position::new(0), &d2, &d1);
606 assert_ne!(
607 out, out2,
608 "hash should change when swapping order of inputs"
609 );
610 }
611
612 fn test_root<H: CHasher>() {
613 let mut mmr_hasher: StandardHasher<H> = StandardHasher::new();
614 let d1 = test_digest::<H>(1);
616 let d2 = test_digest::<H>(2);
617 let d3 = test_digest::<H>(3);
618 let d4 = test_digest::<H>(4);
619
620 let empty_vec: Vec<H::Digest> = Vec::new();
621 let empty_out = mmr_hasher.root(Position::new(0), empty_vec.iter());
622 assert_ne!(
623 empty_out,
624 test_digest::<H>(0),
625 "root of empty MMR should be non-zero"
626 );
627
628 let digests = [d1, d2, d3, d4];
629 let out = mmr_hasher.root(Position::new(10), digests.iter());
630 assert_ne!(out, test_digest::<H>(0), "root should be non-zero");
631 assert_ne!(out, empty_out, "root should differ from empty MMR");
632
633 let mut out2 = mmr_hasher.root(Position::new(10), digests.iter());
634 assert_eq!(out, out2, "root should be computed consistently");
635
636 out2 = mmr_hasher.root(Position::new(11), digests.iter());
637 assert_ne!(out, out2, "root should change with different position");
638
639 let digests = [d1, d2, d4, d3];
640 out2 = mmr_hasher.root(Position::new(10), digests.iter());
641 assert_ne!(out, out2, "root should change with different digest order");
642
643 let digests = [d1, d2, d3];
644 out2 = mmr_hasher.root(Position::new(10), digests.iter());
645 assert_ne!(
646 out, out2,
647 "root should change with different number of hashes"
648 );
649 }
650
651 #[test]
654 fn test_hasher_dest_source_pos_conversion() {
655 for grafting_height in 1..10 {
656 for pos in 0..10000 {
657 let pos = Position::new(pos);
658 let dest_pos = destination_pos(pos, grafting_height);
659 let source_pos = source_pos(dest_pos, grafting_height).unwrap();
660 assert_eq!(pos, source_pos);
661 }
662 }
663 }
664
665 #[test]
666 fn test_hasher_source_dest_pos_conversion() {
667 for grafting_height in 1..10 {
668 for pos in 0..10000 {
669 let pos = Position::new(pos);
670 if pos_to_height(pos) < grafting_height {
671 assert!(source_pos(pos, grafting_height).is_none());
674 continue;
675 }
676 let source_pos = source_pos(pos, grafting_height).unwrap();
677 let dest_pos = destination_pos(source_pos, grafting_height);
678 assert_eq!(pos, dest_pos);
679 }
680 }
681 }
682
683 #[test]
684 fn test_hasher_grafting() {
685 let executor = deterministic::Runner::default();
686 executor.start(|_| async move {
687 let mut standard: StandardHasher<Sha256> = StandardHasher::new();
688 let mmr = CleanMmr::new(&mut standard);
689 let base_mmr = build_test_mmr(&mut standard, mmr);
690 let root = *base_mmr.root();
691 let expected_root = ROOTS[199];
692 assert_eq!(&hex(&root), expected_root);
693
694 let mut hasher: Hasher<'_, Sha256> = Hasher::new(&mut standard, 0);
695 hasher
696 .load_grafted_digests(
697 &(0..199).map(Location::new_unchecked).collect::<Vec<_>>(),
698 &base_mmr,
699 )
700 .await
701 .unwrap();
702
703 {
704 assert_eq!(hasher.destination_pos(Position::new(0)), Position::new(0));
710 let rand_leaf_pos = Position::new(1234234);
711 assert_eq!(hasher.destination_pos(rand_leaf_pos), rand_leaf_pos);
712
713 let mmr = CleanMmr::new(&mut hasher);
714 let peak_mmr = build_test_mmr(&mut hasher, mmr);
715 let root = *peak_mmr.root();
716 assert!(hex(&root) != expected_root);
718 }
719
720 let base_mmr = build_test_mmr(&mut standard, base_mmr);
723 {
724 let mut hasher: Hasher<'_, Sha256> = Hasher::new(&mut standard, 1);
725 hasher
726 .load_grafted_digests(
727 &(0..199).map(Location::new_unchecked).collect::<Vec<_>>(),
728 &base_mmr,
729 )
730 .await
731 .unwrap();
732
733 assert_eq!(
736 hasher.destination_pos(Position::try_from(Location::new_unchecked(0)).unwrap()),
737 Position::new(2)
738 );
739 assert_eq!(
740 hasher.destination_pos(Position::try_from(Location::new_unchecked(1)).unwrap()),
741 Position::new(5)
742 );
743 assert_eq!(
744 hasher.destination_pos(Position::try_from(Location::new_unchecked(2)).unwrap()),
745 Position::new(9)
746 );
747 assert_eq!(
748 hasher.destination_pos(Position::try_from(Location::new_unchecked(3)).unwrap()),
749 Position::new(12)
750 );
751 assert_eq!(
752 hasher.destination_pos(Position::try_from(Location::new_unchecked(4)).unwrap()),
753 Position::new(17)
754 );
755
756 let mmr = CleanMmr::new(&mut hasher);
757 let peak_mmr = build_test_mmr(&mut hasher, mmr);
758 let root = *peak_mmr.root();
759 assert!(hex(&root) != expected_root);
761 }
762
763 let hasher: Hasher<'_, Sha256> = Hasher::new(&mut standard, 2);
765 assert_eq!(
766 hasher.destination_pos(Position::try_from(Location::new_unchecked(0)).unwrap()),
767 Position::new(6)
768 );
769 assert_eq!(
770 hasher.destination_pos(Position::try_from(Location::new_unchecked(1)).unwrap()),
771 Position::new(13)
772 );
773
774 let hasher: Hasher<'_, Sha256> = Hasher::new(&mut standard, 3);
776 assert_eq!(
777 hasher.destination_pos(Position::try_from(Location::new_unchecked(0)).unwrap()),
778 Position::new(14)
779 );
780 });
781 }
782
783 #[test_traced]
785 fn test_hasher_grafted_storage() {
786 let executor = deterministic::Runner::default();
787 const GRAFTING_HEIGHT: u32 = 1;
788 executor.start(|_| async move {
789 let b1 = Sha256::fill(0x01);
790 let b2 = Sha256::fill(0x02);
791 let b3 = Sha256::fill(0x03);
792 let b4 = Sha256::fill(0x04);
793 let mut standard: StandardHasher<Sha256> = StandardHasher::new();
794
795 let mut base_mmr = CleanMmr::new(&mut standard);
797 base_mmr.add(&mut standard, &b1);
798 base_mmr.add(&mut standard, &b2);
799 base_mmr.add(&mut standard, &b3);
800 base_mmr.add(&mut standard, &b4);
801
802 let p1 = Sha256::fill(0xF1);
803 let p2 = Sha256::fill(0xF2);
804
805 let mut peak_tree = CleanMmr::new(&mut standard);
808 {
809 let mut grafter = Hasher::new(&mut standard, GRAFTING_HEIGHT);
810 grafter
811 .load_grafted_digests(
812 &[Location::new_unchecked(0), Location::new_unchecked(1)],
813 &base_mmr,
814 )
815 .await
816 .unwrap();
817 peak_tree.add(&mut grafter, &p1);
818 peak_tree.add(&mut grafter, &p2);
819 }
820
821 let peak_root = *peak_tree.root();
822 let base_root = *base_mmr.root();
823 assert_ne!(peak_root, base_root);
824
825 {
826 let grafted_mmr = Storage::new(&peak_tree, &base_mmr, GRAFTING_HEIGHT);
827 assert_eq!(grafted_mmr.size(), base_mmr.size());
828
829 let grafted_storage_root = grafted_mmr.root(&mut standard).await.unwrap();
830 assert_ne!(grafted_storage_root, base_root);
831
832 assert_ne!(grafted_storage_root, peak_root);
836
837 {
840 let loc = Location::new_unchecked(0);
841 let proof = verification::range_proof(&grafted_mmr, loc..loc + 1)
842 .await
843 .unwrap();
844
845 let mut verifier = Verifier::<Sha256>::new(
846 GRAFTING_HEIGHT,
847 Location::new_unchecked(0),
848 vec![&p1],
849 );
850 assert!(proof.verify_element_inclusion(
851 &mut verifier,
852 &b1,
853 loc,
854 &grafted_storage_root
855 ));
856
857 let loc = Location::new_unchecked(1);
858 let proof = verification::range_proof(&grafted_mmr, loc..loc + 1)
859 .await
860 .unwrap();
861 assert!(proof.verify_element_inclusion(
862 &mut verifier,
863 &b2,
864 loc,
865 &grafted_storage_root
866 ));
867
868 let loc = Location::new_unchecked(2);
869 let proof = verification::range_proof(&grafted_mmr, loc..loc + 1)
870 .await
871 .unwrap();
872 let mut verifier = Verifier::<Sha256>::new(
873 GRAFTING_HEIGHT,
874 Location::new_unchecked(1),
875 vec![&p2],
876 );
877 assert!(proof.verify_element_inclusion(
878 &mut verifier,
879 &b3,
880 loc,
881 &grafted_storage_root
882 ));
883
884 let loc = Location::new_unchecked(3);
885 let proof = verification::range_proof(&grafted_mmr, loc..loc + 1)
886 .await
887 .unwrap();
888 assert!(proof.verify_element_inclusion(
889 &mut verifier,
890 &b4,
891 loc,
892 &grafted_storage_root
893 ));
894 }
895
896 {
898 let loc = Location::new_unchecked(3);
900 let proof = verification::range_proof(&grafted_mmr, loc..loc + 1)
901 .await
902 .unwrap();
903 let mut verifier = Verifier::<Sha256>::new(
904 GRAFTING_HEIGHT,
905 Location::new_unchecked(1),
906 vec![&p2],
907 );
908 assert!(proof.verify_element_inclusion(
909 &mut verifier,
910 &b4,
911 loc,
912 &grafted_storage_root
913 ));
914
915 assert!(!proof.verify_element_inclusion(
917 &mut verifier,
918 &b3,
919 loc,
920 &grafted_storage_root
921 ));
922
923 assert!(!proof.verify_element_inclusion(&mut verifier, &b4, loc, &peak_root));
925
926 assert!(!proof.verify_element_inclusion(
928 &mut verifier,
929 &b4,
930 loc + 1,
931 &grafted_storage_root
932 ));
933
934 let mut verifier = Verifier::<Sha256>::new(
936 GRAFTING_HEIGHT,
937 Location::new_unchecked(0),
938 vec![&p1],
939 );
940 assert!(!proof.verify_element_inclusion(
941 &mut verifier,
942 &b4,
943 loc,
944 &grafted_storage_root
945 ));
946
947 let mut verifier = Verifier::<Sha256>::new(
949 GRAFTING_HEIGHT,
950 Location::new_unchecked(2),
951 vec![&p2],
952 );
953 assert!(!proof.verify_element_inclusion(
954 &mut verifier,
955 &b4,
956 loc,
957 &grafted_storage_root
958 ));
959 }
960
961 {
963 let proof = verification::range_proof(
965 &grafted_mmr,
966 Location::new_unchecked(0)..Location::new_unchecked(4),
967 )
968 .await
969 .unwrap();
970 let range = vec![&b1, &b2, &b3, &b4];
971 let mut verifier = Verifier::<Sha256>::new(
972 GRAFTING_HEIGHT,
973 Location::new_unchecked(0),
974 vec![&p1, &p2],
975 );
976 assert!(proof.verify_range_inclusion(
977 &mut verifier,
978 &range,
979 Location::new_unchecked(0),
980 &grafted_storage_root
981 ));
982
983 let mut verifier = Verifier::<Sha256>::new(
985 GRAFTING_HEIGHT,
986 Location::new_unchecked(0),
987 vec![&p1],
988 );
989 assert!(!proof.verify_range_inclusion(
990 &mut verifier,
991 &range,
992 Location::new_unchecked(0),
993 &grafted_storage_root
994 ));
995 }
996 }
997
998 let b5 = Sha256::fill(0x05);
1001 base_mmr.add(&mut standard, &b5);
1002
1003 let grafted_mmr = Storage::new(&peak_tree, &base_mmr, GRAFTING_HEIGHT);
1004 assert_eq!(grafted_mmr.size(), base_mmr.size());
1005
1006 let grafted_storage_root = grafted_mmr.root(&mut standard).await.unwrap();
1009 let loc = Location::new_unchecked(0);
1010 let proof = verification::range_proof(&grafted_mmr, loc..loc + 1)
1011 .await
1012 .unwrap();
1013
1014 let mut verifier = Verifier::<Sha256>::new(GRAFTING_HEIGHT, loc, vec![&p1]);
1015 assert!(proof.verify_element_inclusion(&mut verifier, &b1, loc, &grafted_storage_root));
1016
1017 let mut verifier = Verifier::<Sha256>::new(GRAFTING_HEIGHT, loc, vec![]);
1018 let loc = Location::new_unchecked(4);
1019 let proof = verification::range_proof(&grafted_mmr, loc..loc + 1)
1020 .await
1021 .unwrap();
1022 assert!(proof.verify_element_inclusion(&mut verifier, &b5, loc, &grafted_storage_root));
1023 });
1024 }
1025}