1use super::cid::Cid;
10use super::diff::DiffPage;
11use super::error::{Diff, Error};
12use super::key;
13use super::node::Node;
14use super::range::{RangeCursor, RangePage};
15#[cfg(feature = "async-store")]
16use super::store::AsyncStore;
17use super::store::Store;
18use super::tree::Tree;
19#[cfg(feature = "async-store")]
20use super::AsyncProlly;
21use super::Prolly;
22use serde::{Deserialize, Serialize};
23use sha2::{Digest, Sha256};
24use std::collections::{HashMap, HashSet};
25
26const PROOF_BUNDLE_VERSION: u64 = 1;
27const PROOF_BUNDLE_KIND_KEY: u8 = 1;
28const PROOF_BUNDLE_KIND_MULTI_KEY: u8 = 2;
29const PROOF_BUNDLE_KIND_RANGE: u8 = 3;
30const PROOF_BUNDLE_KIND_RANGE_PAGE: u8 = 4;
31const PROOF_BUNDLE_KIND_DIFF_PAGE: u8 = 5;
32const AUTHENTICATED_PROOF_ENVELOPE_VERSION: u64 = 1;
33const AUTHENTICATED_PROOF_ENVELOPE_ALGORITHM_HMAC_SHA256: &str = "hmac-sha256";
34const AUTHENTICATED_PROOF_ENVELOPE_DOMAIN: &[u8] = b"trail.prolly.authenticated-proof-envelope.v1";
35
36#[derive(Serialize, Deserialize)]
37struct ProofBundleWire {
38 version: u64,
39 kind: u8,
40 root: Option<Vec<u8>>,
41 keys: Vec<Vec<u8>>,
42 #[serde(default, skip_serializing_if = "Option::is_none")]
43 start: Option<Vec<u8>>,
44 #[serde(default, skip_serializing_if = "Option::is_none")]
45 end: Option<Vec<u8>>,
46 #[serde(default, skip_serializing_if = "Option::is_none")]
47 after: Option<Vec<u8>>,
48 path_node_bytes: Vec<Vec<u8>>,
49}
50
51#[derive(Serialize, Deserialize)]
52struct AuthenticatedProofEnvelopeSigningWire {
53 version: u64,
54 algorithm: String,
55 key_id: Vec<u8>,
56 proof_bundle: Vec<u8>,
57 context: Vec<u8>,
58 issued_at_millis: Option<u64>,
59 expires_at_millis: Option<u64>,
60 nonce: Vec<u8>,
61}
62
63#[derive(Serialize, Deserialize)]
64struct AuthenticatedProofEnvelopeWire {
65 version: u64,
66 algorithm: String,
67 key_id: Vec<u8>,
68 proof_bundle: Vec<u8>,
69 context: Vec<u8>,
70 issued_at_millis: Option<u64>,
71 expires_at_millis: Option<u64>,
72 nonce: Vec<u8>,
73 signature: Vec<u8>,
74}
75
76#[derive(Serialize, Deserialize)]
77struct DiffPageProofBundleWire {
78 version: u64,
79 kind: u8,
80 requested_end: Option<Vec<u8>>,
81 limit: u64,
82 base_range_page_proof: Vec<u8>,
83 other_range_page_proof: Vec<u8>,
84 #[serde(default, skip_serializing_if = "Option::is_none")]
85 lookahead_base_key_proof: Option<Vec<u8>>,
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 lookahead_other_key_proof: Option<Vec<u8>>,
88}
89
90#[derive(Clone, Debug, PartialEq)]
92pub struct KeyProof {
93 pub root: Option<Cid>,
95 pub key: Vec<u8>,
97 pub path: Vec<Node>,
99}
100
101#[derive(Clone, Debug, PartialEq, Eq)]
103pub struct KeyProofVerification {
104 pub valid: bool,
106 pub root: Option<Cid>,
108 pub key: Vec<u8>,
110 pub value: Option<Vec<u8>>,
113}
114
115#[derive(Clone, Debug, PartialEq)]
121pub struct MultiKeyProof {
122 pub root: Option<Cid>,
125 pub keys: Vec<Vec<u8>>,
127 pub path: Vec<Node>,
130}
131
132#[derive(Clone, Debug, PartialEq, Eq)]
134pub struct MultiKeyProofVerification {
135 pub valid: bool,
137 pub root: Option<Cid>,
139 pub results: Vec<KeyProofVerification>,
141}
142
143#[derive(Clone, Debug, PartialEq)]
149pub struct RangeProof {
150 pub root: Option<Cid>,
153 pub start: Vec<u8>,
155 pub end: Option<Vec<u8>>,
157 pub path: Vec<Node>,
159}
160
161#[derive(Clone, Debug, PartialEq)]
167pub struct RangePageProof {
168 pub root: Option<Cid>,
171 pub after: Option<Vec<u8>>,
174 pub end: Option<Vec<u8>>,
176 pub path: Vec<Node>,
178}
179
180#[derive(Clone, Debug, PartialEq)]
182pub struct ProvedRangePage {
183 pub page: RangePage,
186 pub proof: RangePageProof,
189}
190
191#[derive(Clone, Debug, PartialEq)]
198pub struct DiffPageProof {
199 pub base: RangePageProof,
201 pub other: RangePageProof,
203 pub lookahead_base: Option<KeyProof>,
206 pub lookahead_other: Option<KeyProof>,
209 pub requested_end: Option<Vec<u8>>,
211 pub limit: usize,
213}
214
215#[derive(Clone, Debug, PartialEq)]
217pub struct ProvedDiffPage {
218 pub page: DiffPage,
221 pub proof: DiffPageProof,
224}
225
226#[derive(Clone, Debug, PartialEq, Eq)]
234pub struct AuthenticatedProofEnvelope {
235 pub algorithm: String,
237 pub key_id: Vec<u8>,
239 pub proof_bundle: Vec<u8>,
242 pub context: Vec<u8>,
245 pub issued_at_millis: Option<u64>,
247 pub expires_at_millis: Option<u64>,
249 pub nonce: Vec<u8>,
251 pub signature: Vec<u8>,
253}
254
255#[derive(Clone, Debug, PartialEq, Eq)]
257pub struct AuthenticatedProofEnvelopeVerification {
258 pub valid: bool,
261 pub signature_valid: bool,
264 pub time_valid: bool,
267 pub not_yet_valid: bool,
269 pub expired: bool,
272 pub algorithm: String,
274 pub key_id: Vec<u8>,
276 pub proof_bundle: Vec<u8>,
278 pub context: Vec<u8>,
280 pub issued_at_millis: Option<u64>,
282 pub expires_at_millis: Option<u64>,
284 pub nonce: Vec<u8>,
286}
287
288#[derive(Clone, Copy, Debug, PartialEq, Eq)]
290pub enum ProofBundleKind {
291 Key,
293 MultiKey,
295 Range,
297 RangePage,
299 DiffPage,
301}
302
303impl ProofBundleKind {
304 pub fn as_str(self) -> &'static str {
306 match self {
307 ProofBundleKind::Key => "key",
308 ProofBundleKind::MultiKey => "multi_key",
309 ProofBundleKind::Range => "range",
310 ProofBundleKind::RangePage => "range_page",
311 ProofBundleKind::DiffPage => "diff_page",
312 }
313 }
314}
315
316#[derive(Clone, Debug, PartialEq, Eq)]
322pub struct ProofBundleSummary {
323 pub version: u64,
325 pub kind: ProofBundleKind,
327 pub root: Option<Cid>,
329 pub other_root: Option<Cid>,
331 pub key_count: usize,
333 pub path_node_count: usize,
336 pub start: Option<Vec<u8>>,
338 pub end: Option<Vec<u8>>,
340 pub after: Option<Vec<u8>>,
342 pub requested_end: Option<Vec<u8>>,
344 pub limit: Option<usize>,
346 pub has_lookahead: bool,
348}
349
350#[derive(Clone, Debug, PartialEq, Eq)]
357pub struct ProofBundleVerification {
358 pub summary: ProofBundleSummary,
360 pub valid: bool,
362 pub exists_count: usize,
364 pub absence_count: usize,
366 pub entry_count: usize,
368 pub diff_count: usize,
370 pub next_cursor: Option<RangeCursor>,
372}
373
374#[derive(Clone, Debug, PartialEq, Eq)]
381pub struct AuthenticatedProofBundleVerification {
382 pub valid: bool,
384 pub envelope: AuthenticatedProofEnvelopeVerification,
386 pub proof: Option<ProofBundleVerification>,
388 pub proof_error: Option<String>,
390}
391
392#[derive(Clone, Debug, PartialEq, Eq)]
394pub struct RangeProofVerification {
395 pub valid: bool,
397 pub root: Option<Cid>,
399 pub start: Vec<u8>,
401 pub end: Option<Vec<u8>>,
403 pub entries: Vec<(Vec<u8>, Vec<u8>)>,
405}
406
407#[derive(Clone, Debug, PartialEq, Eq)]
409pub struct RangePageProofVerification {
410 pub valid: bool,
413 pub root: Option<Cid>,
415 pub after: Option<Vec<u8>>,
417 pub end: Option<Vec<u8>>,
419 pub entries: Vec<(Vec<u8>, Vec<u8>)>,
421}
422
423#[derive(Clone, Debug, PartialEq, Eq)]
425pub struct DiffPageProofVerification {
426 pub valid: bool,
429 pub base_valid: bool,
431 pub other_valid: bool,
433 pub lookahead_valid: bool,
436 pub base_root: Option<Cid>,
438 pub other_root: Option<Cid>,
440 pub after: Option<Vec<u8>>,
442 pub requested_end: Option<Vec<u8>>,
444 pub proof_end: Option<Vec<u8>>,
448 pub limit: usize,
450 pub diffs: Vec<Diff>,
452 pub next_cursor: Option<RangeCursor>,
454}
455
456impl KeyProofVerification {
457 pub fn exists(&self) -> bool {
459 self.valid && self.value.is_some()
460 }
461
462 pub fn is_absence(&self) -> bool {
464 self.valid && self.value.is_none()
465 }
466}
467
468impl MultiKeyProofVerification {
469 pub fn all_valid(&self) -> bool {
471 self.valid && self.results.iter().all(|result| result.valid)
472 }
473}
474
475impl RangeProofVerification {
476 pub fn is_empty(&self) -> bool {
478 self.valid && self.entries.is_empty()
479 }
480}
481
482impl RangePageProofVerification {
483 pub fn is_empty(&self) -> bool {
485 self.valid && self.entries.is_empty()
486 }
487}
488
489impl DiffPageProofVerification {
490 pub fn is_empty(&self) -> bool {
492 self.valid && self.diffs.is_empty()
493 }
494}
495
496impl AuthenticatedProofEnvelope {
497 pub fn to_bytes(&self) -> Result<Vec<u8>, Error> {
499 authenticated_proof_envelope_to_bytes(self)
500 }
501
502 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
505 authenticated_proof_envelope_from_bytes(bytes)
506 }
507
508 pub fn verify(
511 &self,
512 secret: &[u8],
513 now_millis: Option<u64>,
514 ) -> AuthenticatedProofEnvelopeVerification {
515 verify_authenticated_proof_envelope(self, secret, now_millis)
516 }
517}
518
519impl ProofBundleSummary {
520 pub fn kind_name(&self) -> &'static str {
522 self.kind.as_str()
523 }
524}
525
526impl ProofBundleVerification {
527 pub fn kind_name(&self) -> &'static str {
529 self.summary.kind_name()
530 }
531}
532
533impl KeyProof {
534 pub fn verify(&self) -> KeyProofVerification {
536 verify_key_proof(self)
537 }
538
539 pub fn path_node_bytes(&self) -> Vec<Vec<u8>> {
541 self.path.iter().map(Node::to_bytes).collect()
542 }
543
544 pub fn from_node_bytes(
546 root: Option<Cid>,
547 key: impl Into<Vec<u8>>,
548 path_node_bytes: Vec<Vec<u8>>,
549 ) -> Result<Self, Error> {
550 let path = path_node_bytes
551 .iter()
552 .map(|bytes| Node::from_bytes(bytes))
553 .collect::<Result<Vec<_>, _>>()?;
554 Ok(Self {
555 root,
556 key: key.into(),
557 path,
558 })
559 }
560
561 pub fn to_bundle_bytes(&self) -> Result<Vec<u8>, Error> {
563 proof_bundle_to_bytes(ProofBundleWire {
564 version: PROOF_BUNDLE_VERSION,
565 kind: PROOF_BUNDLE_KIND_KEY,
566 root: self.root.as_ref().map(|cid| cid.as_bytes().to_vec()),
567 keys: vec![self.key.clone()],
568 start: None,
569 end: None,
570 after: None,
571 path_node_bytes: self.path_node_bytes(),
572 })
573 }
574
575 pub fn from_bundle_bytes(bytes: &[u8]) -> Result<Self, Error> {
577 let wire = proof_bundle_from_bytes(bytes)?;
578 if wire.kind != PROOF_BUNDLE_KIND_KEY {
579 return Err(proof_bundle_deserialize("proof bundle is not a key proof"));
580 }
581 if wire.keys.len() != 1 {
582 return Err(proof_bundle_deserialize(
583 "key proof bundle must contain exactly one key",
584 ));
585 }
586 Self::from_node_bytes(
587 cid_from_bundle_root(wire.root)?,
588 wire.keys.into_iter().next().unwrap(),
589 wire.path_node_bytes,
590 )
591 }
592}
593
594impl MultiKeyProof {
595 pub fn verify(&self) -> MultiKeyProofVerification {
597 verify_multi_key_proof(self)
598 }
599
600 pub fn path_node_bytes(&self) -> Vec<Vec<u8>> {
602 self.path.iter().map(Node::to_bytes).collect()
603 }
604
605 pub fn from_node_bytes(
607 root: Option<Cid>,
608 keys: Vec<Vec<u8>>,
609 path_node_bytes: Vec<Vec<u8>>,
610 ) -> Result<Self, Error> {
611 let path = path_node_bytes
612 .iter()
613 .map(|bytes| Node::from_bytes(bytes))
614 .collect::<Result<Vec<_>, _>>()?;
615 Ok(Self { root, keys, path })
616 }
617
618 pub fn to_bundle_bytes(&self) -> Result<Vec<u8>, Error> {
620 proof_bundle_to_bytes(ProofBundleWire {
621 version: PROOF_BUNDLE_VERSION,
622 kind: PROOF_BUNDLE_KIND_MULTI_KEY,
623 root: self.root.as_ref().map(|cid| cid.as_bytes().to_vec()),
624 keys: self.keys.clone(),
625 start: None,
626 end: None,
627 after: None,
628 path_node_bytes: self.path_node_bytes(),
629 })
630 }
631
632 pub fn from_bundle_bytes(bytes: &[u8]) -> Result<Self, Error> {
634 let wire = proof_bundle_from_bytes(bytes)?;
635 if wire.kind != PROOF_BUNDLE_KIND_MULTI_KEY {
636 return Err(proof_bundle_deserialize(
637 "proof bundle is not a multi-key proof",
638 ));
639 }
640 Self::from_node_bytes(
641 cid_from_bundle_root(wire.root)?,
642 wire.keys,
643 wire.path_node_bytes,
644 )
645 }
646}
647
648impl RangeProof {
649 pub fn verify(&self) -> RangeProofVerification {
651 verify_range_proof(self)
652 }
653
654 pub fn path_node_bytes(&self) -> Vec<Vec<u8>> {
656 self.path.iter().map(Node::to_bytes).collect()
657 }
658
659 pub fn from_node_bytes(
661 root: Option<Cid>,
662 start: impl Into<Vec<u8>>,
663 end: Option<Vec<u8>>,
664 path_node_bytes: Vec<Vec<u8>>,
665 ) -> Result<Self, Error> {
666 let path = path_node_bytes
667 .iter()
668 .map(|bytes| Node::from_bytes(bytes))
669 .collect::<Result<Vec<_>, _>>()?;
670 Ok(Self {
671 root,
672 start: start.into(),
673 end,
674 path,
675 })
676 }
677
678 pub fn to_bundle_bytes(&self) -> Result<Vec<u8>, Error> {
680 proof_bundle_to_bytes(ProofBundleWire {
681 version: PROOF_BUNDLE_VERSION,
682 kind: PROOF_BUNDLE_KIND_RANGE,
683 root: self.root.as_ref().map(|cid| cid.as_bytes().to_vec()),
684 keys: Vec::new(),
685 start: Some(self.start.clone()),
686 end: self.end.clone(),
687 after: None,
688 path_node_bytes: self.path_node_bytes(),
689 })
690 }
691
692 pub fn from_bundle_bytes(bytes: &[u8]) -> Result<Self, Error> {
694 let wire = proof_bundle_from_bytes(bytes)?;
695 if wire.kind != PROOF_BUNDLE_KIND_RANGE {
696 return Err(proof_bundle_deserialize(
697 "proof bundle is not a range proof",
698 ));
699 }
700 let Some(start) = wire.start else {
701 return Err(proof_bundle_deserialize(
702 "range proof bundle must contain a start key",
703 ));
704 };
705 Self::from_node_bytes(
706 cid_from_bundle_root(wire.root)?,
707 start,
708 wire.end,
709 wire.path_node_bytes,
710 )
711 }
712}
713
714impl RangePageProof {
715 pub fn verify(&self) -> RangePageProofVerification {
717 verify_range_page_proof(self)
718 }
719
720 pub fn path_node_bytes(&self) -> Vec<Vec<u8>> {
722 self.path.iter().map(Node::to_bytes).collect()
723 }
724
725 pub fn from_node_bytes(
727 root: Option<Cid>,
728 after: Option<Vec<u8>>,
729 end: Option<Vec<u8>>,
730 path_node_bytes: Vec<Vec<u8>>,
731 ) -> Result<Self, Error> {
732 let path = path_node_bytes
733 .iter()
734 .map(|bytes| Node::from_bytes(bytes))
735 .collect::<Result<Vec<_>, _>>()?;
736 Ok(Self {
737 root,
738 after,
739 end,
740 path,
741 })
742 }
743
744 pub fn to_bundle_bytes(&self) -> Result<Vec<u8>, Error> {
746 proof_bundle_to_bytes(ProofBundleWire {
747 version: PROOF_BUNDLE_VERSION,
748 kind: PROOF_BUNDLE_KIND_RANGE_PAGE,
749 root: self.root.as_ref().map(|cid| cid.as_bytes().to_vec()),
750 keys: Vec::new(),
751 start: None,
752 end: self.end.clone(),
753 after: self.after.clone(),
754 path_node_bytes: self.path_node_bytes(),
755 })
756 }
757
758 pub fn from_bundle_bytes(bytes: &[u8]) -> Result<Self, Error> {
760 let wire = proof_bundle_from_bytes(bytes)?;
761 if wire.kind != PROOF_BUNDLE_KIND_RANGE_PAGE {
762 return Err(proof_bundle_deserialize(
763 "proof bundle is not a range page proof",
764 ));
765 }
766 Self::from_node_bytes(
767 cid_from_bundle_root(wire.root)?,
768 wire.after,
769 wire.end,
770 wire.path_node_bytes,
771 )
772 }
773}
774
775impl DiffPageProof {
776 pub fn verify(&self) -> DiffPageProofVerification {
778 verify_diff_page_proof(self)
779 }
780
781 pub fn to_bundle_bytes(&self) -> Result<Vec<u8>, Error> {
784 let limit = u64::try_from(self.limit)
785 .map_err(|_| Error::Serialize("diff page proof limit is too large".to_string()))?;
786 let base_range_page_proof = self.base.to_bundle_bytes()?;
787 let other_range_page_proof = self.other.to_bundle_bytes()?;
788 let lookahead_base_key_proof = self
789 .lookahead_base
790 .as_ref()
791 .map(KeyProof::to_bundle_bytes)
792 .transpose()?;
793 let lookahead_other_key_proof = self
794 .lookahead_other
795 .as_ref()
796 .map(KeyProof::to_bundle_bytes)
797 .transpose()?;
798
799 serde_cbor::ser::to_vec_packed(&DiffPageProofBundleWire {
800 version: PROOF_BUNDLE_VERSION,
801 kind: PROOF_BUNDLE_KIND_DIFF_PAGE,
802 requested_end: self.requested_end.clone(),
803 limit,
804 base_range_page_proof,
805 other_range_page_proof,
806 lookahead_base_key_proof,
807 lookahead_other_key_proof,
808 })
809 .map_err(|err| Error::Serialize(err.to_string()))
810 }
811
812 pub fn from_bundle_bytes(bytes: &[u8]) -> Result<Self, Error> {
814 let wire = diff_page_proof_bundle_from_bytes(bytes)?;
815 let limit = usize::try_from(wire.limit)
816 .map_err(|_| proof_bundle_deserialize("diff page proof bundle limit is too large"))?;
817
818 Ok(Self {
819 base: RangePageProof::from_bundle_bytes(&wire.base_range_page_proof)?,
820 other: RangePageProof::from_bundle_bytes(&wire.other_range_page_proof)?,
821 lookahead_base: wire
822 .lookahead_base_key_proof
823 .map(|proof| KeyProof::from_bundle_bytes(&proof))
824 .transpose()?,
825 lookahead_other: wire
826 .lookahead_other_key_proof
827 .map(|proof| KeyProof::from_bundle_bytes(&proof))
828 .transpose()?,
829 requested_end: wire.requested_end,
830 limit,
831 })
832 }
833}
834
835impl<S: Store> Prolly<S> {
836 pub fn prove_key(&self, tree: &Tree, key: &[u8]) -> Result<KeyProof, Error> {
841 let mut path = Vec::new();
842
843 let Some(root_cid) = &tree.root else {
844 return Ok(KeyProof {
845 root: None,
846 key: key.to_vec(),
847 path,
848 });
849 };
850
851 let mut cid = root_cid.clone();
852 loop {
853 let node = self.load(&cid)?;
854 let is_leaf = node.leaf;
855 let child_index = path_child_index(&node, key);
856 path.push(node.clone());
857
858 if is_leaf {
859 break;
860 }
861
862 let Some(child_bytes) = node.vals.get(child_index) else {
863 return Err(Error::InvalidNode);
864 };
865 cid = cid_from_child_bytes(child_bytes).ok_or(Error::InvalidNode)?;
866 }
867
868 Ok(KeyProof {
869 root: Some(root_cid.clone()),
870 key: key.to_vec(),
871 path,
872 })
873 }
874
875 pub fn prove_keys<K: AsRef<[u8]>>(
881 &self,
882 tree: &Tree,
883 keys: &[K],
884 ) -> Result<MultiKeyProof, Error> {
885 let keys = keys
886 .iter()
887 .map(|key| key.as_ref().to_vec())
888 .collect::<Vec<_>>();
889 let mut path = Vec::new();
890
891 let Some(root_cid) = &tree.root else {
892 return Ok(MultiKeyProof {
893 root: None,
894 keys,
895 path,
896 });
897 };
898
899 if keys.is_empty() {
900 return Ok(MultiKeyProof {
901 root: Some(root_cid.clone()),
902 keys,
903 path,
904 });
905 }
906
907 let mut seen = HashSet::new();
908 for key in &keys {
909 let key_proof = self.prove_key(tree, key)?;
910 for node in key_proof.path {
911 let cid = node.cid();
912 if seen.insert(cid) {
913 path.push(node);
914 }
915 }
916 }
917
918 Ok(MultiKeyProof {
919 root: Some(root_cid.clone()),
920 keys,
921 path,
922 })
923 }
924
925 pub fn prove_range(
930 &self,
931 tree: &Tree,
932 start: &[u8],
933 end: Option<&[u8]>,
934 ) -> Result<RangeProof, Error> {
935 let mut path = Vec::new();
936
937 let Some(root_cid) = &tree.root else {
938 return Ok(RangeProof {
939 root: None,
940 start: start.to_vec(),
941 end: end.map(<[u8]>::to_vec),
942 path,
943 });
944 };
945
946 if range_is_empty_by_bounds(start, end) {
947 return Ok(RangeProof {
948 root: Some(root_cid.clone()),
949 start: start.to_vec(),
950 end: end.map(<[u8]>::to_vec),
951 path,
952 });
953 }
954
955 let mut seen = HashSet::new();
956 self.collect_range_proof_nodes(root_cid, start, end, &mut seen, &mut path)?;
957
958 Ok(RangeProof {
959 root: Some(root_cid.clone()),
960 start: start.to_vec(),
961 end: end.map(<[u8]>::to_vec),
962 path,
963 })
964 }
965
966 pub fn prove_prefix(&self, tree: &Tree, prefix: &[u8]) -> Result<RangeProof, Error> {
972 let (start, end) = key::prefix_range(prefix);
973 self.prove_range(tree, &start, end.as_deref())
974 }
975
976 pub fn prove_range_page(
982 &self,
983 tree: &Tree,
984 cursor: &RangeCursor,
985 end: Option<&[u8]>,
986 limit: usize,
987 ) -> Result<ProvedRangePage, Error> {
988 let after = cursor.after().map(<[u8]>::to_vec);
989
990 if limit == 0 {
991 let proof_end = after.clone().or_else(|| Some(Vec::new()));
992 return Ok(ProvedRangePage {
993 page: RangePage {
994 entries: Vec::new(),
995 next_cursor: Some(cursor.clone()),
996 },
997 proof: RangePageProof {
998 root: tree.root.clone(),
999 after,
1000 end: proof_end,
1001 path: Vec::new(),
1002 },
1003 });
1004 }
1005
1006 let mut iter = self.range_from_cursor(tree, cursor, end)?;
1007 let mut entries = Vec::with_capacity(limit);
1008
1009 for _ in 0..limit {
1010 let Some(item) = iter.next() else {
1011 let proof = self.prove_range_page_window(tree, after.as_deref(), end)?;
1012 return Ok(ProvedRangePage {
1013 page: RangePage {
1014 entries,
1015 next_cursor: None,
1016 },
1017 proof,
1018 });
1019 };
1020 entries.push(item?);
1021 }
1022
1023 let lookahead = iter.next().transpose()?;
1024 let proof_end = lookahead
1025 .as_ref()
1026 .map(|(key, _)| key.clone())
1027 .or_else(|| end.map(<[u8]>::to_vec));
1028 let proof = self.prove_range_page_window(tree, after.as_deref(), proof_end.as_deref())?;
1029 let next_cursor = lookahead.as_ref().and_then(|_| {
1030 entries
1031 .last()
1032 .map(|(key, _)| RangeCursor::after_key(key.clone()))
1033 });
1034
1035 Ok(ProvedRangePage {
1036 page: RangePage {
1037 entries,
1038 next_cursor,
1039 },
1040 proof,
1041 })
1042 }
1043
1044 pub fn prove_diff_page(
1050 &self,
1051 base: &Tree,
1052 other: &Tree,
1053 cursor: &RangeCursor,
1054 end: Option<&[u8]>,
1055 limit: usize,
1056 ) -> Result<ProvedDiffPage, Error> {
1057 let after = cursor.after().map(<[u8]>::to_vec);
1058
1059 if limit == 0 {
1060 let proof_end = after.clone().or_else(|| Some(Vec::new()));
1061 return Ok(ProvedDiffPage {
1062 page: DiffPage {
1063 diffs: Vec::new(),
1064 next_cursor: Some(cursor.clone()),
1065 },
1066 proof: DiffPageProof {
1067 base: RangePageProof {
1068 root: base.root.clone(),
1069 after: after.clone(),
1070 end: proof_end.clone(),
1071 path: Vec::new(),
1072 },
1073 other: RangePageProof {
1074 root: other.root.clone(),
1075 after,
1076 end: proof_end,
1077 path: Vec::new(),
1078 },
1079 lookahead_base: None,
1080 lookahead_other: None,
1081 requested_end: end.map(<[u8]>::to_vec),
1082 limit,
1083 },
1084 });
1085 }
1086
1087 let mut all_diffs = self.diff_from_cursor(base, other, cursor, end)?;
1088 let has_more = all_diffs.len() > limit;
1089 let lookahead_key = has_more.then(|| all_diffs[limit].key().to_vec());
1090 if has_more {
1091 all_diffs.truncate(limit);
1092 }
1093
1094 let next_cursor = if has_more {
1095 all_diffs
1096 .last()
1097 .map(|diff| RangeCursor::after_key(diff.key().to_vec()))
1098 } else {
1099 None
1100 };
1101 let proof_end = lookahead_key.clone().or_else(|| end.map(<[u8]>::to_vec));
1102 let lookahead_base = lookahead_key
1103 .as_ref()
1104 .map(|key| self.prove_key(base, key))
1105 .transpose()?;
1106 let lookahead_other = lookahead_key
1107 .as_ref()
1108 .map(|key| self.prove_key(other, key))
1109 .transpose()?;
1110
1111 Ok(ProvedDiffPage {
1112 page: DiffPage {
1113 diffs: all_diffs,
1114 next_cursor,
1115 },
1116 proof: DiffPageProof {
1117 base: self.prove_range_page_window(base, after.as_deref(), proof_end.as_deref())?,
1118 other: self.prove_range_page_window(
1119 other,
1120 after.as_deref(),
1121 proof_end.as_deref(),
1122 )?,
1123 lookahead_base,
1124 lookahead_other,
1125 requested_end: end.map(<[u8]>::to_vec),
1126 limit,
1127 },
1128 })
1129 }
1130
1131 fn prove_range_page_window(
1132 &self,
1133 tree: &Tree,
1134 after: Option<&[u8]>,
1135 end: Option<&[u8]>,
1136 ) -> Result<RangePageProof, Error> {
1137 let Some(root_cid) = &tree.root else {
1138 return Ok(RangePageProof {
1139 root: None,
1140 after: after.map(<[u8]>::to_vec),
1141 end: end.map(<[u8]>::to_vec),
1142 path: Vec::new(),
1143 });
1144 };
1145
1146 if page_range_is_empty_by_bounds(after, end) {
1147 return Ok(RangePageProof {
1148 root: Some(root_cid.clone()),
1149 after: after.map(<[u8]>::to_vec),
1150 end: end.map(<[u8]>::to_vec),
1151 path: Vec::new(),
1152 });
1153 }
1154
1155 let mut seen = HashSet::new();
1156 let mut path = Vec::new();
1157 self.collect_range_page_proof_nodes(root_cid, after, end, &mut seen, &mut path)?;
1158
1159 Ok(RangePageProof {
1160 root: Some(root_cid.clone()),
1161 after: after.map(<[u8]>::to_vec),
1162 end: end.map(<[u8]>::to_vec),
1163 path,
1164 })
1165 }
1166
1167 fn collect_range_proof_nodes(
1168 &self,
1169 cid: &Cid,
1170 start: &[u8],
1171 end: Option<&[u8]>,
1172 seen: &mut HashSet<Cid>,
1173 path: &mut Vec<Node>,
1174 ) -> Result<(), Error> {
1175 let node = self.load(cid)?;
1176 if !seen.insert(cid.clone()) {
1177 return Ok(());
1178 }
1179 path.push(node.clone());
1180
1181 if node.leaf {
1182 return Ok(());
1183 }
1184
1185 for idx in overlapping_child_index_range(&node, start, end) {
1186 let child_start = node.keys[idx].as_slice();
1187 let child_end = child_span_end(&node, idx, None);
1188 if !span_overlaps_range(child_start, child_end, start, end) {
1189 if range_ends_before_or_at(end, child_start) {
1190 break;
1191 }
1192 continue;
1193 }
1194 let child_cid = cid_from_child_bytes(node.vals.get(idx).ok_or(Error::InvalidNode)?)
1195 .ok_or(Error::InvalidNode)?;
1196 self.collect_range_proof_nodes(&child_cid, start, end, seen, path)?;
1197 }
1198
1199 Ok(())
1200 }
1201
1202 fn collect_range_page_proof_nodes(
1203 &self,
1204 cid: &Cid,
1205 after: Option<&[u8]>,
1206 end: Option<&[u8]>,
1207 seen: &mut HashSet<Cid>,
1208 path: &mut Vec<Node>,
1209 ) -> Result<(), Error> {
1210 let node = self.load(cid)?;
1211 if !seen.insert(cid.clone()) {
1212 return Ok(());
1213 }
1214 path.push(node.clone());
1215
1216 if node.leaf {
1217 return Ok(());
1218 }
1219
1220 let traversal_start = after.unwrap_or(&[]);
1221 for idx in overlapping_child_index_range(&node, traversal_start, end) {
1222 let child_start = node.keys[idx].as_slice();
1223 let child_end = child_span_end(&node, idx, None);
1224 if !span_overlaps_page_range(child_start, child_end, after, end) {
1225 if range_ends_before_or_at(end, child_start) {
1226 break;
1227 }
1228 continue;
1229 }
1230 let child_cid = cid_from_child_bytes(node.vals.get(idx).ok_or(Error::InvalidNode)?)
1231 .ok_or(Error::InvalidNode)?;
1232 self.collect_range_page_proof_nodes(&child_cid, after, end, seen, path)?;
1233 }
1234
1235 Ok(())
1236 }
1237}
1238
1239#[cfg(feature = "async-store")]
1240impl<S> AsyncProlly<S>
1241where
1242 S: AsyncStore,
1243 S::Error: Send + Sync,
1244{
1245 pub async fn prove_key(&self, tree: &Tree, key: &[u8]) -> Result<KeyProof, Error> {
1250 let mut path = Vec::new();
1251
1252 let Some(root_cid) = &tree.root else {
1253 return Ok(KeyProof {
1254 root: None,
1255 key: key.to_vec(),
1256 path,
1257 });
1258 };
1259
1260 let mut cid = root_cid.clone();
1261 loop {
1262 let node = self.load_arc(&cid).await?;
1263 let is_leaf = node.leaf;
1264 let child_index = path_child_index(&node, key);
1265 path.push((*node).clone());
1266
1267 if is_leaf {
1268 break;
1269 }
1270
1271 let Some(child_bytes) = node.vals.get(child_index) else {
1272 return Err(Error::InvalidNode);
1273 };
1274 cid = cid_from_child_bytes(child_bytes).ok_or(Error::InvalidNode)?;
1275 }
1276
1277 Ok(KeyProof {
1278 root: Some(root_cid.clone()),
1279 key: key.to_vec(),
1280 path,
1281 })
1282 }
1283
1284 pub async fn prove_keys<K: AsRef<[u8]>>(
1290 &self,
1291 tree: &Tree,
1292 keys: &[K],
1293 ) -> Result<MultiKeyProof, Error> {
1294 let keys = keys
1295 .iter()
1296 .map(|key| key.as_ref().to_vec())
1297 .collect::<Vec<_>>();
1298 let mut path = Vec::new();
1299
1300 let Some(root_cid) = &tree.root else {
1301 return Ok(MultiKeyProof {
1302 root: None,
1303 keys,
1304 path,
1305 });
1306 };
1307
1308 if keys.is_empty() {
1309 return Ok(MultiKeyProof {
1310 root: Some(root_cid.clone()),
1311 keys,
1312 path,
1313 });
1314 }
1315
1316 let mut seen = HashSet::new();
1317 for key in &keys {
1318 let key_proof = self.prove_key(tree, key).await?;
1319 for node in key_proof.path {
1320 let cid = node.cid();
1321 if seen.insert(cid) {
1322 path.push(node);
1323 }
1324 }
1325 }
1326
1327 Ok(MultiKeyProof {
1328 root: Some(root_cid.clone()),
1329 keys,
1330 path,
1331 })
1332 }
1333
1334 pub async fn prove_range(
1339 &self,
1340 tree: &Tree,
1341 start: &[u8],
1342 end: Option<&[u8]>,
1343 ) -> Result<RangeProof, Error> {
1344 let mut path = Vec::new();
1345
1346 let Some(root_cid) = &tree.root else {
1347 return Ok(RangeProof {
1348 root: None,
1349 start: start.to_vec(),
1350 end: end.map(<[u8]>::to_vec),
1351 path,
1352 });
1353 };
1354
1355 if range_is_empty_by_bounds(start, end) {
1356 return Ok(RangeProof {
1357 root: Some(root_cid.clone()),
1358 start: start.to_vec(),
1359 end: end.map(<[u8]>::to_vec),
1360 path,
1361 });
1362 }
1363
1364 let mut seen = HashSet::new();
1365 self.collect_range_proof_nodes(root_cid, start, end, &mut seen, &mut path)
1366 .await?;
1367
1368 Ok(RangeProof {
1369 root: Some(root_cid.clone()),
1370 start: start.to_vec(),
1371 end: end.map(<[u8]>::to_vec),
1372 path,
1373 })
1374 }
1375
1376 pub async fn prove_prefix(&self, tree: &Tree, prefix: &[u8]) -> Result<RangeProof, Error> {
1378 let (start, end) = key::prefix_range(prefix);
1379 self.prove_range(tree, &start, end.as_deref()).await
1380 }
1381
1382 pub async fn prove_range_page(
1384 &self,
1385 tree: &Tree,
1386 cursor: &RangeCursor,
1387 end: Option<&[u8]>,
1388 limit: usize,
1389 ) -> Result<ProvedRangePage, Error> {
1390 let after = cursor.after().map(<[u8]>::to_vec);
1391
1392 if limit == 0 {
1393 let proof_end = after.clone().or_else(|| Some(Vec::new()));
1394 return Ok(ProvedRangePage {
1395 page: RangePage {
1396 entries: Vec::new(),
1397 next_cursor: Some(cursor.clone()),
1398 },
1399 proof: RangePageProof {
1400 root: tree.root.clone(),
1401 after,
1402 end: proof_end,
1403 path: Vec::new(),
1404 },
1405 });
1406 }
1407
1408 let mut iter = self.range_from_cursor(tree, cursor, end).await?;
1409 let mut entries = Vec::with_capacity(limit);
1410
1411 for _ in 0..limit {
1412 let Some(item) = iter.next().await else {
1413 let proof = self
1414 .prove_range_page_window(tree, after.as_deref(), end)
1415 .await?;
1416 return Ok(ProvedRangePage {
1417 page: RangePage {
1418 entries,
1419 next_cursor: None,
1420 },
1421 proof,
1422 });
1423 };
1424 entries.push(item?);
1425 }
1426
1427 let lookahead = iter.next().await.transpose()?;
1428 let proof_end = lookahead
1429 .as_ref()
1430 .map(|(key, _)| key.clone())
1431 .or_else(|| end.map(<[u8]>::to_vec));
1432 let proof = self
1433 .prove_range_page_window(tree, after.as_deref(), proof_end.as_deref())
1434 .await?;
1435 let next_cursor = lookahead.as_ref().and_then(|_| {
1436 entries
1437 .last()
1438 .map(|(key, _)| RangeCursor::after_key(key.clone()))
1439 });
1440
1441 Ok(ProvedRangePage {
1442 page: RangePage {
1443 entries,
1444 next_cursor,
1445 },
1446 proof,
1447 })
1448 }
1449
1450 pub async fn prove_diff_page(
1453 &self,
1454 base: &Tree,
1455 other: &Tree,
1456 cursor: &RangeCursor,
1457 end: Option<&[u8]>,
1458 limit: usize,
1459 ) -> Result<ProvedDiffPage, Error> {
1460 let after = cursor.after().map(<[u8]>::to_vec);
1461
1462 if limit == 0 {
1463 let proof_end = after.clone().or_else(|| Some(Vec::new()));
1464 return Ok(ProvedDiffPage {
1465 page: DiffPage {
1466 diffs: Vec::new(),
1467 next_cursor: Some(cursor.clone()),
1468 },
1469 proof: DiffPageProof {
1470 base: RangePageProof {
1471 root: base.root.clone(),
1472 after: after.clone(),
1473 end: proof_end.clone(),
1474 path: Vec::new(),
1475 },
1476 other: RangePageProof {
1477 root: other.root.clone(),
1478 after,
1479 end: proof_end,
1480 path: Vec::new(),
1481 },
1482 lookahead_base: None,
1483 lookahead_other: None,
1484 requested_end: end.map(<[u8]>::to_vec),
1485 limit,
1486 },
1487 });
1488 }
1489
1490 let mut all_diffs = self.diff_from_cursor(base, other, cursor, end).await?;
1491 let has_more = all_diffs.len() > limit;
1492 let lookahead_key = has_more.then(|| all_diffs[limit].key().to_vec());
1493 if has_more {
1494 all_diffs.truncate(limit);
1495 }
1496
1497 let next_cursor = if has_more {
1498 all_diffs
1499 .last()
1500 .map(|diff| RangeCursor::after_key(diff.key().to_vec()))
1501 } else {
1502 None
1503 };
1504 let proof_end = lookahead_key.clone().or_else(|| end.map(<[u8]>::to_vec));
1505 let lookahead_base = match &lookahead_key {
1506 Some(key) => Some(self.prove_key(base, key).await?),
1507 None => None,
1508 };
1509 let lookahead_other = match &lookahead_key {
1510 Some(key) => Some(self.prove_key(other, key).await?),
1511 None => None,
1512 };
1513
1514 Ok(ProvedDiffPage {
1515 page: DiffPage {
1516 diffs: all_diffs,
1517 next_cursor,
1518 },
1519 proof: DiffPageProof {
1520 base: self
1521 .prove_range_page_window(base, after.as_deref(), proof_end.as_deref())
1522 .await?,
1523 other: self
1524 .prove_range_page_window(other, after.as_deref(), proof_end.as_deref())
1525 .await?,
1526 lookahead_base,
1527 lookahead_other,
1528 requested_end: end.map(<[u8]>::to_vec),
1529 limit,
1530 },
1531 })
1532 }
1533
1534 async fn prove_range_page_window(
1535 &self,
1536 tree: &Tree,
1537 after: Option<&[u8]>,
1538 end: Option<&[u8]>,
1539 ) -> Result<RangePageProof, Error> {
1540 let Some(root_cid) = &tree.root else {
1541 return Ok(RangePageProof {
1542 root: None,
1543 after: after.map(<[u8]>::to_vec),
1544 end: end.map(<[u8]>::to_vec),
1545 path: Vec::new(),
1546 });
1547 };
1548
1549 if page_range_is_empty_by_bounds(after, end) {
1550 return Ok(RangePageProof {
1551 root: Some(root_cid.clone()),
1552 after: after.map(<[u8]>::to_vec),
1553 end: end.map(<[u8]>::to_vec),
1554 path: Vec::new(),
1555 });
1556 }
1557
1558 let mut seen = HashSet::new();
1559 let mut path = Vec::new();
1560 self.collect_range_page_proof_nodes(root_cid, after, end, &mut seen, &mut path)
1561 .await?;
1562
1563 Ok(RangePageProof {
1564 root: Some(root_cid.clone()),
1565 after: after.map(<[u8]>::to_vec),
1566 end: end.map(<[u8]>::to_vec),
1567 path,
1568 })
1569 }
1570
1571 async fn collect_range_proof_nodes(
1572 &self,
1573 cid: &Cid,
1574 start: &[u8],
1575 end: Option<&[u8]>,
1576 seen: &mut HashSet<Cid>,
1577 path: &mut Vec<Node>,
1578 ) -> Result<(), Error> {
1579 let mut stack = vec![cid.clone()];
1580 while let Some(cid) = stack.pop() {
1581 if !seen.insert(cid.clone()) {
1582 continue;
1583 }
1584 let node = self.load_arc(&cid).await?;
1585 path.push((*node).clone());
1586
1587 if node.leaf {
1588 continue;
1589 }
1590
1591 let mut child_cids = Vec::new();
1592 for idx in overlapping_child_index_range(&node, start, end) {
1593 let child_start = node.keys[idx].as_slice();
1594 let child_end = child_span_end(&node, idx, None);
1595 if !span_overlaps_range(child_start, child_end, start, end) {
1596 if range_ends_before_or_at(end, child_start) {
1597 break;
1598 }
1599 continue;
1600 }
1601 child_cids.push(
1602 cid_from_child_bytes(node.vals.get(idx).ok_or(Error::InvalidNode)?)
1603 .ok_or(Error::InvalidNode)?,
1604 );
1605 }
1606 child_cids.reverse();
1607 stack.extend(child_cids);
1608 }
1609
1610 Ok(())
1611 }
1612
1613 async fn collect_range_page_proof_nodes(
1614 &self,
1615 cid: &Cid,
1616 after: Option<&[u8]>,
1617 end: Option<&[u8]>,
1618 seen: &mut HashSet<Cid>,
1619 path: &mut Vec<Node>,
1620 ) -> Result<(), Error> {
1621 let mut stack = vec![cid.clone()];
1622 while let Some(cid) = stack.pop() {
1623 if !seen.insert(cid.clone()) {
1624 continue;
1625 }
1626 let node = self.load_arc(&cid).await?;
1627 path.push((*node).clone());
1628
1629 if node.leaf {
1630 continue;
1631 }
1632
1633 let traversal_start = after.unwrap_or(&[]);
1634 let mut child_cids = Vec::new();
1635 for idx in overlapping_child_index_range(&node, traversal_start, end) {
1636 let child_start = node.keys[idx].as_slice();
1637 let child_end = child_span_end(&node, idx, None);
1638 if !span_overlaps_page_range(child_start, child_end, after, end) {
1639 if range_ends_before_or_at(end, child_start) {
1640 break;
1641 }
1642 continue;
1643 }
1644 child_cids.push(
1645 cid_from_child_bytes(node.vals.get(idx).ok_or(Error::InvalidNode)?)
1646 .ok_or(Error::InvalidNode)?,
1647 );
1648 }
1649 child_cids.reverse();
1650 stack.extend(child_cids);
1651 }
1652
1653 Ok(())
1654 }
1655}
1656
1657pub fn verify_key_proof(proof: &KeyProof) -> KeyProofVerification {
1659 let valid = proof_is_consistent(proof);
1660 let value = if valid {
1661 verified_leaf_value(proof.path.last(), &proof.key)
1662 } else {
1663 None
1664 };
1665
1666 KeyProofVerification {
1667 valid,
1668 root: proof.root.clone(),
1669 key: proof.key.clone(),
1670 value,
1671 }
1672}
1673
1674pub fn verify_multi_key_proof(proof: &MultiKeyProof) -> MultiKeyProofVerification {
1676 let mut results = proof
1677 .keys
1678 .iter()
1679 .map(|key| KeyProofVerification {
1680 valid: false,
1681 root: proof.root.clone(),
1682 key: key.clone(),
1683 value: None,
1684 })
1685 .collect::<Vec<_>>();
1686
1687 let node_map = match proof_node_map(proof) {
1688 Some(node_map) => node_map,
1689 None => {
1690 return MultiKeyProofVerification {
1691 valid: false,
1692 root: proof.root.clone(),
1693 results,
1694 };
1695 }
1696 };
1697
1698 match &proof.root {
1699 None => {
1700 let valid = proof.path.is_empty();
1701 for result in &mut results {
1702 result.valid = valid;
1703 }
1704 MultiKeyProofVerification {
1705 valid,
1706 root: proof.root.clone(),
1707 results,
1708 }
1709 }
1710 Some(root) if proof.keys.is_empty() => {
1711 let valid = proof.path.is_empty() || node_map.contains_key(root);
1712 MultiKeyProofVerification {
1713 valid,
1714 root: proof.root.clone(),
1715 results,
1716 }
1717 }
1718 Some(root) => {
1719 let mut all_valid = true;
1720 for result in &mut results {
1721 match verified_value_from_node_set(root, &result.key, &node_map) {
1722 Some(value) => {
1723 result.valid = true;
1724 result.value = value;
1725 }
1726 None => {
1727 all_valid = false;
1728 }
1729 }
1730 }
1731 MultiKeyProofVerification {
1732 valid: all_valid,
1733 root: proof.root.clone(),
1734 results,
1735 }
1736 }
1737 }
1738}
1739
1740pub fn verify_range_proof(proof: &RangeProof) -> RangeProofVerification {
1742 let mut entries = Vec::new();
1743
1744 if range_is_empty_by_bounds(&proof.start, proof.end.as_deref()) {
1745 return RangeProofVerification {
1746 valid: proof.path.is_empty(),
1747 root: proof.root.clone(),
1748 start: proof.start.clone(),
1749 end: proof.end.clone(),
1750 entries,
1751 };
1752 }
1753
1754 let node_map = match range_proof_node_map(proof) {
1755 Some(node_map) => node_map,
1756 None => {
1757 return RangeProofVerification {
1758 valid: false,
1759 root: proof.root.clone(),
1760 start: proof.start.clone(),
1761 end: proof.end.clone(),
1762 entries,
1763 };
1764 }
1765 };
1766
1767 let valid = match &proof.root {
1768 None => proof.path.is_empty(),
1769 Some(root) => {
1770 let mut stack = HashSet::new();
1771 verify_range_node(
1772 root,
1773 &proof.start,
1774 proof.end.as_deref(),
1775 &node_map,
1776 &mut stack,
1777 &mut entries,
1778 )
1779 }
1780 };
1781
1782 if !valid {
1783 entries.clear();
1784 }
1785
1786 RangeProofVerification {
1787 valid,
1788 root: proof.root.clone(),
1789 start: proof.start.clone(),
1790 end: proof.end.clone(),
1791 entries,
1792 }
1793}
1794
1795pub fn verify_range_page_proof(proof: &RangePageProof) -> RangePageProofVerification {
1797 let mut entries = Vec::new();
1798
1799 if page_range_is_empty_by_bounds(proof.after.as_deref(), proof.end.as_deref()) {
1800 return RangePageProofVerification {
1801 valid: proof.path.is_empty(),
1802 root: proof.root.clone(),
1803 after: proof.after.clone(),
1804 end: proof.end.clone(),
1805 entries,
1806 };
1807 }
1808
1809 let node_map = match range_page_proof_node_map(proof) {
1810 Some(node_map) => node_map,
1811 None => {
1812 return RangePageProofVerification {
1813 valid: false,
1814 root: proof.root.clone(),
1815 after: proof.after.clone(),
1816 end: proof.end.clone(),
1817 entries,
1818 };
1819 }
1820 };
1821
1822 let valid = match &proof.root {
1823 None => proof.path.is_empty(),
1824 Some(root) => {
1825 let mut stack = HashSet::new();
1826 verify_range_page_node(
1827 root,
1828 proof.after.as_deref(),
1829 proof.end.as_deref(),
1830 &node_map,
1831 &mut stack,
1832 &mut entries,
1833 )
1834 }
1835 };
1836
1837 if !valid {
1838 entries.clear();
1839 }
1840
1841 RangePageProofVerification {
1842 valid,
1843 root: proof.root.clone(),
1844 after: proof.after.clone(),
1845 end: proof.end.clone(),
1846 entries,
1847 }
1848}
1849
1850pub fn verify_diff_page_proof(proof: &DiffPageProof) -> DiffPageProofVerification {
1852 let base = verify_range_page_proof(&proof.base);
1853 let other = verify_range_page_proof(&proof.other);
1854 let same_bounds = proof.base.after == proof.other.after && proof.base.end == proof.other.end;
1855 let after = proof.base.after.clone();
1856 let proof_end = proof.base.end.clone();
1857 let mut diffs = Vec::new();
1858
1859 let mut lookahead_valid = false;
1860 let mut next_cursor = None;
1861 let mut valid = base.valid && other.valid && same_bounds;
1862
1863 if valid {
1864 diffs = diff_verified_entries(&base.entries, &other.entries);
1865 match (&proof.lookahead_base, &proof.lookahead_other) {
1866 (Some(base_lookahead), Some(other_lookahead)) => {
1867 let base_lookahead = verify_key_proof(base_lookahead);
1868 let other_lookahead = verify_key_proof(other_lookahead);
1869 lookahead_valid = verify_diff_page_lookahead(
1870 &base_lookahead,
1871 &other_lookahead,
1872 after.as_deref(),
1873 proof.requested_end.as_deref(),
1874 proof_end.as_deref(),
1875 );
1876 valid = valid && lookahead_valid && proof.limit > 0 && diffs.len() == proof.limit;
1877 if valid {
1878 next_cursor = diffs
1879 .last()
1880 .map(|diff| RangeCursor::after_key(diff.key().to_vec()));
1881 }
1882 }
1883 (None, None) => {
1884 lookahead_valid = true;
1885 if proof.limit == 0 {
1886 valid = valid && diffs.is_empty();
1887 if valid {
1888 next_cursor = Some(
1889 after
1890 .clone()
1891 .map(RangeCursor::after_key)
1892 .unwrap_or_else(RangeCursor::start),
1893 );
1894 }
1895 } else {
1896 valid = valid && proof_end == proof.requested_end && diffs.len() <= proof.limit;
1897 }
1898 }
1899 _ => {
1900 valid = false;
1901 }
1902 }
1903 }
1904
1905 if !valid {
1906 diffs.clear();
1907 next_cursor = None;
1908 }
1909
1910 DiffPageProofVerification {
1911 valid,
1912 base_valid: base.valid,
1913 other_valid: other.valid,
1914 lookahead_valid,
1915 base_root: base.root,
1916 other_root: other.root,
1917 after,
1918 requested_end: proof.requested_end.clone(),
1919 proof_end,
1920 limit: proof.limit,
1921 diffs,
1922 next_cursor,
1923 }
1924}
1925
1926pub fn inspect_proof_bundle(bytes: &[u8]) -> Result<ProofBundleSummary, Error> {
1933 match proof_bundle_from_bytes(bytes) {
1934 Ok(wire) => proof_bundle_summary_from_wire(wire),
1935 Err(primary_error) => match diff_page_proof_bundle_from_bytes(bytes) {
1936 Ok(wire) => diff_page_proof_bundle_summary_from_wire(wire),
1937 Err(_) => Err(primary_error),
1938 },
1939 }
1940}
1941
1942pub fn verify_proof_bundle(bytes: &[u8]) -> Result<ProofBundleVerification, Error> {
1948 let summary = inspect_proof_bundle(bytes)?;
1949 match summary.kind {
1950 ProofBundleKind::Key => {
1951 let verified = KeyProof::from_bundle_bytes(bytes)?.verify();
1952 Ok(ProofBundleVerification {
1953 summary,
1954 valid: verified.valid,
1955 exists_count: usize::from(verified.exists()),
1956 absence_count: usize::from(verified.is_absence()),
1957 entry_count: 0,
1958 diff_count: 0,
1959 next_cursor: None,
1960 })
1961 }
1962 ProofBundleKind::MultiKey => {
1963 let verified = MultiKeyProof::from_bundle_bytes(bytes)?.verify();
1964 let (exists_count, absence_count) = if verified.valid {
1965 (
1966 verified
1967 .results
1968 .iter()
1969 .filter(|result| result.exists())
1970 .count(),
1971 verified
1972 .results
1973 .iter()
1974 .filter(|result| result.is_absence())
1975 .count(),
1976 )
1977 } else {
1978 (0, 0)
1979 };
1980 Ok(ProofBundleVerification {
1981 summary,
1982 valid: verified.valid,
1983 exists_count,
1984 absence_count,
1985 entry_count: 0,
1986 diff_count: 0,
1987 next_cursor: None,
1988 })
1989 }
1990 ProofBundleKind::Range => {
1991 let verified = RangeProof::from_bundle_bytes(bytes)?.verify();
1992 Ok(ProofBundleVerification {
1993 summary,
1994 valid: verified.valid,
1995 exists_count: 0,
1996 absence_count: 0,
1997 entry_count: if verified.valid {
1998 verified.entries.len()
1999 } else {
2000 0
2001 },
2002 diff_count: 0,
2003 next_cursor: None,
2004 })
2005 }
2006 ProofBundleKind::RangePage => {
2007 let verified = RangePageProof::from_bundle_bytes(bytes)?.verify();
2008 Ok(ProofBundleVerification {
2009 summary,
2010 valid: verified.valid,
2011 exists_count: 0,
2012 absence_count: 0,
2013 entry_count: if verified.valid {
2014 verified.entries.len()
2015 } else {
2016 0
2017 },
2018 diff_count: 0,
2019 next_cursor: None,
2020 })
2021 }
2022 ProofBundleKind::DiffPage => {
2023 let verified = DiffPageProof::from_bundle_bytes(bytes)?.verify();
2024 Ok(ProofBundleVerification {
2025 summary,
2026 valid: verified.valid,
2027 exists_count: 0,
2028 absence_count: 0,
2029 entry_count: 0,
2030 diff_count: if verified.valid {
2031 verified.diffs.len()
2032 } else {
2033 0
2034 },
2035 next_cursor: verified.next_cursor,
2036 })
2037 }
2038 }
2039}
2040
2041pub fn sign_proof_bundle_hmac_sha256(
2043 proof_bundle: impl Into<Vec<u8>>,
2044 key_id: impl Into<Vec<u8>>,
2045 secret: &[u8],
2046 context: impl Into<Vec<u8>>,
2047 issued_at_millis: Option<u64>,
2048 expires_at_millis: Option<u64>,
2049 nonce: impl Into<Vec<u8>>,
2050) -> Result<AuthenticatedProofEnvelope, Error> {
2051 let envelope = AuthenticatedProofEnvelope {
2052 algorithm: AUTHENTICATED_PROOF_ENVELOPE_ALGORITHM_HMAC_SHA256.to_string(),
2053 key_id: key_id.into(),
2054 proof_bundle: proof_bundle.into(),
2055 context: context.into(),
2056 issued_at_millis,
2057 expires_at_millis,
2058 nonce: nonce.into(),
2059 signature: Vec::new(),
2060 };
2061 let signature = hmac_sha256(
2062 secret,
2063 &authenticated_proof_envelope_signing_bytes(&envelope)?,
2064 );
2065 Ok(AuthenticatedProofEnvelope {
2066 signature: signature.to_vec(),
2067 ..envelope
2068 })
2069}
2070
2071pub fn verify_authenticated_proof_envelope(
2076 envelope: &AuthenticatedProofEnvelope,
2077 secret: &[u8],
2078 now_millis: Option<u64>,
2079) -> AuthenticatedProofEnvelopeVerification {
2080 let algorithm_supported =
2081 envelope.algorithm == AUTHENTICATED_PROOF_ENVELOPE_ALGORITHM_HMAC_SHA256;
2082 let signature_valid = algorithm_supported
2083 && authenticated_proof_envelope_signing_bytes(envelope)
2084 .map(|bytes| {
2085 let expected = hmac_sha256(secret, &bytes);
2086 constant_time_eq(&expected, &envelope.signature)
2087 })
2088 .unwrap_or(false);
2089 let (not_yet_valid, expired) = match now_millis {
2090 Some(now) => (
2091 envelope
2092 .issued_at_millis
2093 .is_some_and(|issued_at| issued_at > now),
2094 envelope
2095 .expires_at_millis
2096 .is_some_and(|expires_at| expires_at <= now),
2097 ),
2098 None => (false, false),
2099 };
2100 let time_valid = !not_yet_valid && !expired;
2101
2102 AuthenticatedProofEnvelopeVerification {
2103 valid: signature_valid && time_valid,
2104 signature_valid,
2105 time_valid,
2106 not_yet_valid,
2107 expired,
2108 algorithm: envelope.algorithm.clone(),
2109 key_id: envelope.key_id.clone(),
2110 proof_bundle: envelope.proof_bundle.clone(),
2111 context: envelope.context.clone(),
2112 issued_at_millis: envelope.issued_at_millis,
2113 expires_at_millis: envelope.expires_at_millis,
2114 nonce: envelope.nonce.clone(),
2115 }
2116}
2117
2118pub fn verify_authenticated_proof_bundle(
2127 envelope_bytes: &[u8],
2128 secret: &[u8],
2129 now_millis: Option<u64>,
2130) -> Result<AuthenticatedProofBundleVerification, Error> {
2131 let envelope = AuthenticatedProofEnvelope::from_bytes(envelope_bytes)?;
2132 let envelope = verify_authenticated_proof_envelope(&envelope, secret, now_millis);
2133
2134 if !envelope.valid {
2135 return Ok(AuthenticatedProofBundleVerification {
2136 valid: false,
2137 envelope,
2138 proof: None,
2139 proof_error: None,
2140 });
2141 }
2142
2143 match verify_proof_bundle(&envelope.proof_bundle) {
2144 Ok(proof) => Ok(AuthenticatedProofBundleVerification {
2145 valid: proof.valid,
2146 envelope,
2147 proof: Some(proof),
2148 proof_error: None,
2149 }),
2150 Err(err) => Ok(AuthenticatedProofBundleVerification {
2151 valid: false,
2152 envelope,
2153 proof: None,
2154 proof_error: Some(err.to_string()),
2155 }),
2156 }
2157}
2158
2159fn proof_node_map(proof: &MultiKeyProof) -> Option<HashMap<Cid, &Node>> {
2160 let mut node_map = HashMap::with_capacity(proof.path.len());
2161 for node in &proof.path {
2162 if !node_shape_is_valid(node) {
2163 return None;
2164 }
2165 node_map.insert(node.cid(), node);
2166 }
2167 Some(node_map)
2168}
2169
2170fn range_proof_node_map(proof: &RangeProof) -> Option<HashMap<Cid, &Node>> {
2171 let mut node_map = HashMap::with_capacity(proof.path.len());
2172 for node in &proof.path {
2173 if !node_shape_is_valid(node) {
2174 return None;
2175 }
2176 node_map.insert(node.cid(), node);
2177 }
2178 Some(node_map)
2179}
2180
2181fn range_page_proof_node_map(proof: &RangePageProof) -> Option<HashMap<Cid, &Node>> {
2182 let mut node_map = HashMap::with_capacity(proof.path.len());
2183 for node in &proof.path {
2184 if !node_shape_is_valid(node) {
2185 return None;
2186 }
2187 node_map.insert(node.cid(), node);
2188 }
2189 Some(node_map)
2190}
2191
2192fn diff_verified_entries(base: &[(Vec<u8>, Vec<u8>)], other: &[(Vec<u8>, Vec<u8>)]) -> Vec<Diff> {
2193 let mut diffs = Vec::new();
2194 let mut base_idx = 0;
2195 let mut other_idx = 0;
2196
2197 while base_idx < base.len() && other_idx < other.len() {
2198 let (base_key, base_value) = &base[base_idx];
2199 let (other_key, other_value) = &other[other_idx];
2200 match base_key.cmp(other_key) {
2201 std::cmp::Ordering::Less => {
2202 diffs.push(Diff::Removed {
2203 key: base_key.clone(),
2204 val: base_value.clone(),
2205 });
2206 base_idx += 1;
2207 }
2208 std::cmp::Ordering::Greater => {
2209 diffs.push(Diff::Added {
2210 key: other_key.clone(),
2211 val: other_value.clone(),
2212 });
2213 other_idx += 1;
2214 }
2215 std::cmp::Ordering::Equal => {
2216 if base_value != other_value {
2217 diffs.push(Diff::Changed {
2218 key: base_key.clone(),
2219 old: base_value.clone(),
2220 new: other_value.clone(),
2221 });
2222 }
2223 base_idx += 1;
2224 other_idx += 1;
2225 }
2226 }
2227 }
2228
2229 for (key, value) in &base[base_idx..] {
2230 diffs.push(Diff::Removed {
2231 key: key.clone(),
2232 val: value.clone(),
2233 });
2234 }
2235 for (key, value) in &other[other_idx..] {
2236 diffs.push(Diff::Added {
2237 key: key.clone(),
2238 val: value.clone(),
2239 });
2240 }
2241
2242 diffs
2243}
2244
2245fn verify_diff_page_lookahead(
2246 base: &KeyProofVerification,
2247 other: &KeyProofVerification,
2248 after: Option<&[u8]>,
2249 requested_end: Option<&[u8]>,
2250 proof_end: Option<&[u8]>,
2251) -> bool {
2252 if !base.valid || !other.valid || base.key != other.key {
2253 return false;
2254 }
2255 let key = base.key.as_slice();
2256 if proof_end != Some(key) || !key_in_page_range(key, after, requested_end) {
2257 return false;
2258 }
2259 match (&base.value, &other.value) {
2260 (None, None) => false,
2261 (Some(left), Some(right)) => left != right,
2262 _ => true,
2263 }
2264}
2265
2266fn verify_range_node(
2267 cid: &Cid,
2268 start: &[u8],
2269 end: Option<&[u8]>,
2270 node_map: &HashMap<Cid, &Node>,
2271 stack: &mut HashSet<Cid>,
2272 entries: &mut Vec<(Vec<u8>, Vec<u8>)>,
2273) -> bool {
2274 if !stack.insert(cid.clone()) {
2275 return false;
2276 }
2277
2278 let Some(node) = node_map.get(cid).copied() else {
2279 stack.remove(cid);
2280 return false;
2281 };
2282
2283 if node.leaf {
2284 for (key, value) in node.keys.iter().zip(&node.vals) {
2285 if key_in_range(key, start, end) {
2286 entries.push((key.clone(), value.clone()));
2287 }
2288 }
2289 stack.remove(cid);
2290 return true;
2291 }
2292
2293 for idx in overlapping_child_index_range(node, start, end) {
2294 let child_start = node.keys[idx].as_slice();
2295 let child_end = child_span_end(node, idx, None);
2296 if !span_overlaps_range(child_start, child_end, start, end) {
2297 if range_ends_before_or_at(end, child_start) {
2298 break;
2299 }
2300 continue;
2301 }
2302
2303 let Some(child_cid) = node
2304 .vals
2305 .get(idx)
2306 .and_then(|bytes| cid_from_child_bytes(bytes))
2307 else {
2308 stack.remove(cid);
2309 return false;
2310 };
2311 let Some(child) = node_map.get(&child_cid).copied() else {
2312 stack.remove(cid);
2313 return false;
2314 };
2315 if node.level != child.level.saturating_add(1) {
2316 stack.remove(cid);
2317 return false;
2318 }
2319 if !verify_range_node(&child_cid, start, end, node_map, stack, entries) {
2320 stack.remove(cid);
2321 return false;
2322 }
2323 }
2324
2325 stack.remove(cid);
2326 true
2327}
2328
2329fn verify_range_page_node(
2330 cid: &Cid,
2331 after: Option<&[u8]>,
2332 end: Option<&[u8]>,
2333 node_map: &HashMap<Cid, &Node>,
2334 stack: &mut HashSet<Cid>,
2335 entries: &mut Vec<(Vec<u8>, Vec<u8>)>,
2336) -> bool {
2337 if !stack.insert(cid.clone()) {
2338 return false;
2339 }
2340
2341 let Some(node) = node_map.get(cid).copied() else {
2342 stack.remove(cid);
2343 return false;
2344 };
2345
2346 if node.leaf {
2347 for (key, value) in node.keys.iter().zip(&node.vals) {
2348 if key_in_page_range(key, after, end) {
2349 entries.push((key.clone(), value.clone()));
2350 }
2351 }
2352 stack.remove(cid);
2353 return true;
2354 }
2355
2356 let traversal_start = after.unwrap_or(&[]);
2357 for idx in overlapping_child_index_range(node, traversal_start, end) {
2358 let child_start = node.keys[idx].as_slice();
2359 let child_end = child_span_end(node, idx, None);
2360 if !span_overlaps_page_range(child_start, child_end, after, end) {
2361 if range_ends_before_or_at(end, child_start) {
2362 break;
2363 }
2364 continue;
2365 }
2366
2367 let Some(child_cid) = node
2368 .vals
2369 .get(idx)
2370 .and_then(|bytes| cid_from_child_bytes(bytes))
2371 else {
2372 stack.remove(cid);
2373 return false;
2374 };
2375 let Some(child) = node_map.get(&child_cid).copied() else {
2376 stack.remove(cid);
2377 return false;
2378 };
2379 if node.level != child.level.saturating_add(1) {
2380 stack.remove(cid);
2381 return false;
2382 }
2383 if !verify_range_page_node(&child_cid, after, end, node_map, stack, entries) {
2384 stack.remove(cid);
2385 return false;
2386 }
2387 }
2388
2389 stack.remove(cid);
2390 true
2391}
2392
2393fn verified_value_from_node_set(
2394 root: &Cid,
2395 key: &[u8],
2396 node_map: &HashMap<Cid, &Node>,
2397) -> Option<Option<Vec<u8>>> {
2398 let mut cid = root.clone();
2399 let mut visited = HashSet::new();
2400
2401 for _ in 0..=node_map.len() {
2402 if !visited.insert(cid.clone()) {
2403 return None;
2404 }
2405
2406 let node = *node_map.get(&cid)?;
2407 if node.leaf {
2408 return Some(verified_leaf_value(Some(node), key));
2409 }
2410
2411 let child_index = path_child_index(node, key);
2412 let child_cid = cid_from_child_bytes(node.vals.get(child_index)?)?;
2413 let child = *node_map.get(&child_cid)?;
2414 if node.level != child.level.saturating_add(1) {
2415 return None;
2416 }
2417 cid = child_cid;
2418 }
2419
2420 None
2421}
2422
2423fn proof_is_consistent(proof: &KeyProof) -> bool {
2424 match (&proof.root, proof.path.as_slice()) {
2425 (None, []) => return true,
2426 (None, _) | (Some(_), []) => return false,
2427 (Some(root), [first, ..]) if &first.cid() != root => return false,
2428 _ => {}
2429 }
2430
2431 for (depth, node) in proof.path.iter().enumerate() {
2432 if !node_shape_is_valid(node) {
2433 return false;
2434 }
2435
2436 let is_last = depth + 1 == proof.path.len();
2437 if is_last {
2438 return node.leaf;
2439 }
2440
2441 if node.leaf {
2442 return false;
2443 }
2444
2445 let next = &proof.path[depth + 1];
2446 if node.level != next.level.saturating_add(1) {
2447 return false;
2448 }
2449
2450 let child_index = path_child_index(node, &proof.key);
2451 let Some(child_bytes) = node.vals.get(child_index) else {
2452 return false;
2453 };
2454 let Some(child_cid) = cid_from_child_bytes(child_bytes) else {
2455 return false;
2456 };
2457 if next.cid() != child_cid {
2458 return false;
2459 }
2460 }
2461
2462 false
2463}
2464
2465fn verified_leaf_value(leaf: Option<&Node>, key: &[u8]) -> Option<Vec<u8>> {
2466 let leaf = leaf?;
2467 if !leaf.leaf {
2468 return None;
2469 }
2470 match leaf.search(key) {
2471 Ok(index) => leaf.vals.get(index).cloned(),
2472 Err(_) => None,
2473 }
2474}
2475
2476fn node_shape_is_valid(node: &Node) -> bool {
2477 if node.keys.is_empty() || node.keys.len() != node.vals.len() {
2478 return false;
2479 }
2480
2481 if !node.keys.windows(2).all(|window| window[0] < window[1]) {
2482 return false;
2483 }
2484
2485 node.leaf || node.vals.iter().all(|value| value.len() == 32)
2486}
2487
2488fn path_child_index(node: &Node, key: &[u8]) -> usize {
2489 node.keys
2490 .partition_point(|candidate| candidate.as_slice() <= key)
2491 .saturating_sub(1)
2492}
2493
2494fn overlapping_child_index_range(
2495 node: &Node,
2496 range_start: &[u8],
2497 range_end: Option<&[u8]>,
2498) -> std::ops::Range<usize> {
2499 let start = node
2500 .keys
2501 .partition_point(|candidate| candidate.as_slice() < range_start)
2502 .saturating_sub(1);
2503 let end = range_end.map_or(node.len(), |end| {
2504 node.keys
2505 .partition_point(|candidate| candidate.as_slice() < end)
2506 });
2507 start..end.max(start).min(node.len())
2508}
2509
2510fn child_span_end<'a>(node: &'a Node, idx: usize, span_end: Option<&'a [u8]>) -> Option<&'a [u8]> {
2511 node.keys.get(idx + 1).map(Vec::as_slice).or(span_end)
2512}
2513
2514fn span_overlaps_range(
2515 span_start: &[u8],
2516 span_end: Option<&[u8]>,
2517 range_start: &[u8],
2518 range_end: Option<&[u8]>,
2519) -> bool {
2520 !span_ends_before_or_at(span_end, range_start)
2521 && !range_ends_before_or_at(range_end, span_start)
2522}
2523
2524fn span_ends_before_or_at(end: Option<&[u8]>, start: &[u8]) -> bool {
2525 end.is_some_and(|end| end <= start)
2526}
2527
2528fn range_ends_before_or_at(end: Option<&[u8]>, start: &[u8]) -> bool {
2529 end.is_some_and(|end| end <= start)
2530}
2531
2532fn range_is_empty_by_bounds(start: &[u8], end: Option<&[u8]>) -> bool {
2533 end.is_some_and(|end| end <= start)
2534}
2535
2536fn page_range_is_empty_by_bounds(after: Option<&[u8]>, end: Option<&[u8]>) -> bool {
2537 match (after, end) {
2538 (Some(after), Some(end)) => end <= after,
2539 (None, Some(end)) => end.is_empty(),
2540 _ => false,
2541 }
2542}
2543
2544fn key_in_range(key: &[u8], start: &[u8], end: Option<&[u8]>) -> bool {
2545 key >= start
2546 && match end {
2547 Some(end) => key < end,
2548 None => true,
2549 }
2550}
2551
2552fn key_in_page_range(key: &[u8], after: Option<&[u8]>, end: Option<&[u8]>) -> bool {
2553 after.map_or(true, |after| key > after)
2554 && match end {
2555 Some(end) => key < end,
2556 None => true,
2557 }
2558}
2559
2560fn span_overlaps_page_range(
2561 span_start: &[u8],
2562 span_end: Option<&[u8]>,
2563 after: Option<&[u8]>,
2564 end: Option<&[u8]>,
2565) -> bool {
2566 !after.is_some_and(|after| span_ends_before_or_at(span_end, after))
2567 && !range_ends_before_or_at(end, span_start)
2568}
2569
2570fn cid_from_child_bytes(bytes: &[u8]) -> Option<Cid> {
2571 bytes.try_into().ok().map(Cid)
2572}
2573
2574fn proof_bundle_to_bytes(wire: ProofBundleWire) -> Result<Vec<u8>, Error> {
2575 serde_cbor::ser::to_vec_packed(&wire).map_err(|err| Error::Serialize(err.to_string()))
2576}
2577
2578fn proof_bundle_from_bytes(bytes: &[u8]) -> Result<ProofBundleWire, Error> {
2579 let wire: ProofBundleWire =
2580 serde_cbor::from_slice(bytes).map_err(|err| Error::Deserialize(err.to_string()))?;
2581 if wire.version != PROOF_BUNDLE_VERSION {
2582 return Err(proof_bundle_deserialize(format!(
2583 "unsupported proof bundle version {}",
2584 wire.version
2585 )));
2586 }
2587 match wire.kind {
2588 PROOF_BUNDLE_KIND_KEY
2589 | PROOF_BUNDLE_KIND_MULTI_KEY
2590 | PROOF_BUNDLE_KIND_RANGE
2591 | PROOF_BUNDLE_KIND_RANGE_PAGE => Ok(wire),
2592 other => Err(proof_bundle_deserialize(format!(
2593 "unsupported proof bundle kind {other}"
2594 ))),
2595 }
2596}
2597
2598fn diff_page_proof_bundle_from_bytes(bytes: &[u8]) -> Result<DiffPageProofBundleWire, Error> {
2599 let wire: DiffPageProofBundleWire =
2600 serde_cbor::from_slice(bytes).map_err(|err| Error::Deserialize(err.to_string()))?;
2601 if wire.version != PROOF_BUNDLE_VERSION {
2602 return Err(proof_bundle_deserialize(format!(
2603 "unsupported diff page proof bundle version {}",
2604 wire.version
2605 )));
2606 }
2607 if wire.kind != PROOF_BUNDLE_KIND_DIFF_PAGE {
2608 return Err(proof_bundle_deserialize(
2609 "proof bundle is not a diff page proof",
2610 ));
2611 }
2612 Ok(wire)
2613}
2614
2615fn proof_bundle_summary_from_wire(wire: ProofBundleWire) -> Result<ProofBundleSummary, Error> {
2616 Ok(ProofBundleSummary {
2617 version: wire.version,
2618 kind: proof_bundle_kind_from_u8(wire.kind)?,
2619 root: cid_from_bundle_root(wire.root)?,
2620 other_root: None,
2621 key_count: wire.keys.len(),
2622 path_node_count: wire.path_node_bytes.len(),
2623 start: wire.start,
2624 end: wire.end,
2625 after: wire.after,
2626 requested_end: None,
2627 limit: None,
2628 has_lookahead: false,
2629 })
2630}
2631
2632fn diff_page_proof_bundle_summary_from_wire(
2633 wire: DiffPageProofBundleWire,
2634) -> Result<ProofBundleSummary, Error> {
2635 let limit = usize::try_from(wire.limit)
2636 .map_err(|_| proof_bundle_deserialize("diff page proof bundle limit is too large"))?;
2637 let base = proof_bundle_from_bytes(&wire.base_range_page_proof)?;
2638 if base.kind != PROOF_BUNDLE_KIND_RANGE_PAGE {
2639 return Err(proof_bundle_deserialize(
2640 "diff page proof base proof must be a range page proof",
2641 ));
2642 }
2643 let other = proof_bundle_from_bytes(&wire.other_range_page_proof)?;
2644 if other.kind != PROOF_BUNDLE_KIND_RANGE_PAGE {
2645 return Err(proof_bundle_deserialize(
2646 "diff page proof other proof must be a range page proof",
2647 ));
2648 }
2649
2650 let mut path_node_count = base.path_node_bytes.len() + other.path_node_bytes.len();
2651 let mut has_lookahead = false;
2652 if let Some(lookahead) = &wire.lookahead_base_key_proof {
2653 let lookahead = proof_bundle_from_bytes(lookahead)?;
2654 if lookahead.kind != PROOF_BUNDLE_KIND_KEY {
2655 return Err(proof_bundle_deserialize(
2656 "diff page proof base lookahead must be a key proof",
2657 ));
2658 }
2659 path_node_count += lookahead.path_node_bytes.len();
2660 has_lookahead = true;
2661 }
2662 if let Some(lookahead) = &wire.lookahead_other_key_proof {
2663 let lookahead = proof_bundle_from_bytes(lookahead)?;
2664 if lookahead.kind != PROOF_BUNDLE_KIND_KEY {
2665 return Err(proof_bundle_deserialize(
2666 "diff page proof other lookahead must be a key proof",
2667 ));
2668 }
2669 path_node_count += lookahead.path_node_bytes.len();
2670 has_lookahead = true;
2671 }
2672
2673 Ok(ProofBundleSummary {
2674 version: wire.version,
2675 kind: ProofBundleKind::DiffPage,
2676 root: cid_from_bundle_root(base.root)?,
2677 other_root: cid_from_bundle_root(other.root)?,
2678 key_count: 0,
2679 path_node_count,
2680 start: None,
2681 end: base.end,
2682 after: base.after,
2683 requested_end: wire.requested_end,
2684 limit: Some(limit),
2685 has_lookahead,
2686 })
2687}
2688
2689fn proof_bundle_kind_from_u8(kind: u8) -> Result<ProofBundleKind, Error> {
2690 match kind {
2691 PROOF_BUNDLE_KIND_KEY => Ok(ProofBundleKind::Key),
2692 PROOF_BUNDLE_KIND_MULTI_KEY => Ok(ProofBundleKind::MultiKey),
2693 PROOF_BUNDLE_KIND_RANGE => Ok(ProofBundleKind::Range),
2694 PROOF_BUNDLE_KIND_RANGE_PAGE => Ok(ProofBundleKind::RangePage),
2695 PROOF_BUNDLE_KIND_DIFF_PAGE => Ok(ProofBundleKind::DiffPage),
2696 other => Err(proof_bundle_deserialize(format!(
2697 "unsupported proof bundle kind {other}"
2698 ))),
2699 }
2700}
2701
2702fn cid_from_bundle_root(root: Option<Vec<u8>>) -> Result<Option<Cid>, Error> {
2703 root.map(|bytes| {
2704 bytes
2705 .try_into()
2706 .map(Cid)
2707 .map_err(|_| proof_bundle_deserialize("proof bundle root CID must be 32 bytes"))
2708 })
2709 .transpose()
2710}
2711
2712fn proof_bundle_deserialize(message: impl Into<String>) -> Error {
2713 Error::Deserialize(format!("invalid proof bundle: {}", message.into()))
2714}
2715
2716fn authenticated_proof_envelope_to_bytes(
2717 envelope: &AuthenticatedProofEnvelope,
2718) -> Result<Vec<u8>, Error> {
2719 serde_cbor::ser::to_vec_packed(&AuthenticatedProofEnvelopeWire {
2720 version: AUTHENTICATED_PROOF_ENVELOPE_VERSION,
2721 algorithm: envelope.algorithm.clone(),
2722 key_id: envelope.key_id.clone(),
2723 proof_bundle: envelope.proof_bundle.clone(),
2724 context: envelope.context.clone(),
2725 issued_at_millis: envelope.issued_at_millis,
2726 expires_at_millis: envelope.expires_at_millis,
2727 nonce: envelope.nonce.clone(),
2728 signature: envelope.signature.clone(),
2729 })
2730 .map_err(|err| Error::Serialize(err.to_string()))
2731}
2732
2733fn authenticated_proof_envelope_from_bytes(
2734 bytes: &[u8],
2735) -> Result<AuthenticatedProofEnvelope, Error> {
2736 let wire: AuthenticatedProofEnvelopeWire =
2737 serde_cbor::from_slice(bytes).map_err(|err| Error::Deserialize(err.to_string()))?;
2738 if wire.version != AUTHENTICATED_PROOF_ENVELOPE_VERSION {
2739 return Err(authenticated_proof_envelope_deserialize(format!(
2740 "unsupported envelope version {}",
2741 wire.version
2742 )));
2743 }
2744 if wire.algorithm != AUTHENTICATED_PROOF_ENVELOPE_ALGORITHM_HMAC_SHA256 {
2745 return Err(authenticated_proof_envelope_deserialize(format!(
2746 "unsupported envelope algorithm {}",
2747 wire.algorithm
2748 )));
2749 }
2750 if wire.signature.len() != 32 {
2751 return Err(authenticated_proof_envelope_deserialize(
2752 "HMAC-SHA256 signature must be 32 bytes",
2753 ));
2754 }
2755 Ok(AuthenticatedProofEnvelope {
2756 algorithm: wire.algorithm,
2757 key_id: wire.key_id,
2758 proof_bundle: wire.proof_bundle,
2759 context: wire.context,
2760 issued_at_millis: wire.issued_at_millis,
2761 expires_at_millis: wire.expires_at_millis,
2762 nonce: wire.nonce,
2763 signature: wire.signature,
2764 })
2765}
2766
2767fn authenticated_proof_envelope_signing_bytes(
2768 envelope: &AuthenticatedProofEnvelope,
2769) -> Result<Vec<u8>, Error> {
2770 let mut bytes = AUTHENTICATED_PROOF_ENVELOPE_DOMAIN.to_vec();
2771 bytes.push(0);
2772 let payload = serde_cbor::ser::to_vec_packed(&AuthenticatedProofEnvelopeSigningWire {
2773 version: AUTHENTICATED_PROOF_ENVELOPE_VERSION,
2774 algorithm: envelope.algorithm.clone(),
2775 key_id: envelope.key_id.clone(),
2776 proof_bundle: envelope.proof_bundle.clone(),
2777 context: envelope.context.clone(),
2778 issued_at_millis: envelope.issued_at_millis,
2779 expires_at_millis: envelope.expires_at_millis,
2780 nonce: envelope.nonce.clone(),
2781 })
2782 .map_err(|err| Error::Serialize(err.to_string()))?;
2783 bytes.extend(payload);
2784 Ok(bytes)
2785}
2786
2787fn authenticated_proof_envelope_deserialize(message: impl Into<String>) -> Error {
2788 Error::Deserialize(format!(
2789 "invalid authenticated proof envelope: {}",
2790 message.into()
2791 ))
2792}
2793
2794fn hmac_sha256(secret: &[u8], message: &[u8]) -> [u8; 32] {
2795 const BLOCK_SIZE: usize = 64;
2796
2797 let mut key_block = [0u8; BLOCK_SIZE];
2798 if secret.len() > BLOCK_SIZE {
2799 let digest = Sha256::digest(secret);
2800 key_block[..digest.len()].copy_from_slice(&digest);
2801 } else {
2802 key_block[..secret.len()].copy_from_slice(secret);
2803 }
2804
2805 let mut inner_pad = [0x36u8; BLOCK_SIZE];
2806 let mut outer_pad = [0x5cu8; BLOCK_SIZE];
2807 for idx in 0..BLOCK_SIZE {
2808 inner_pad[idx] ^= key_block[idx];
2809 outer_pad[idx] ^= key_block[idx];
2810 }
2811
2812 let mut inner = Sha256::new();
2813 inner.update(inner_pad);
2814 inner.update(message);
2815 let inner_digest = inner.finalize();
2816
2817 let mut outer = Sha256::new();
2818 outer.update(outer_pad);
2819 outer.update(inner_digest);
2820 outer.finalize().into()
2821}
2822
2823fn constant_time_eq(left: &[u8], right: &[u8]) -> bool {
2824 if left.len() != right.len() {
2825 return false;
2826 }
2827 let mut diff = 0u8;
2828 for (&left_byte, &right_byte) in left.iter().zip(right) {
2829 diff |= left_byte ^ right_byte;
2830 }
2831 diff == 0
2832}