miden_crypto/merkle/smt/full/proof.rs
1use alloc::string::ToString;
2
3use super::{SMT_DEPTH, SmtLeaf, SmtProofError, SparseMerklePath, Word};
4use crate::{
5 merkle::InnerNodeInfo,
6 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
8
9/// A proof which can be used to assert presence (or absence) of key-value pairs
10/// in a [`super::Smt`] (Sparse Merkle Tree).
11///
12/// The proof consists of a sparse Merkle path and a leaf, which describes the node located at
13/// the base of the path.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct SmtProof {
16 /// The sparse Merkle path from the leaf to the root.
17 path: SparseMerklePath,
18 /// The leaf node containing one or more key-value pairs.
19 leaf: SmtLeaf,
20}
21
22impl SmtProof {
23 // CONSTRUCTOR
24 // --------------------------------------------------------------------------------------------
25
26 /// Returns a new instance of [`SmtProof`] instantiated from the specified path and leaf.
27 ///
28 /// # Errors
29 /// Returns an error if the path length does not match the expected [`SMT_DEPTH`],
30 /// which would make the proof invalid.
31 pub fn new(path: SparseMerklePath, leaf: SmtLeaf) -> Result<Self, SmtProofError> {
32 let depth = path.depth();
33 if depth != SMT_DEPTH {
34 return Err(SmtProofError::InvalidMerklePathLength(depth as usize));
35 }
36
37 Ok(Self { path, leaf })
38 }
39
40 /// Returns a new instance of [`SmtProof`] instantiated from the specified path and leaf.
41 ///
42 /// The length of the path is not checked. Reserved for internal use.
43 pub(in crate::merkle::smt) fn new_unchecked(path: SparseMerklePath, leaf: SmtLeaf) -> Self {
44 Self { path, leaf }
45 }
46
47 // PROOF VERIFIER
48 // --------------------------------------------------------------------------------------------
49
50 /// Verifies that a [`super::Smt`] with the specified root contains the provided key-value pair.
51 ///
52 /// # Errors
53 /// - [`SmtProofError::InvalidKeyForProof`] if the key maps to a different leaf index than this
54 /// proof's leaf.
55 /// - [`SmtProofError::ConflictingRoots`] if the computed root doesn't match the expected root.
56 /// - [`SmtProofError::ValueMismatch`] if the value doesn't match the value in the leaf.
57 pub fn verify_presence(
58 &self,
59 key: &Word,
60 value: &Word,
61 root: &Word,
62 ) -> Result<(), SmtProofError> {
63 let value_in_leaf = self.leaf.get_value(key).ok_or(SmtProofError::InvalidKeyForProof)?;
64
65 // Check root before value so that ValueMismatch implies the proof is valid
66 let computed_root = self.compute_root();
67 if computed_root != *root {
68 return Err(SmtProofError::ConflictingRoots {
69 expected_root: *root,
70 actual_root: computed_root,
71 });
72 }
73
74 if value_in_leaf != *value {
75 return Err(SmtProofError::ValueMismatch { expected: *value, actual: value_in_leaf });
76 }
77
78 Ok(())
79 }
80
81 /// Verifies that a [`super::Smt`] with the specified root does not contain any value
82 /// for the provided key (i.e., the key is unset).
83 ///
84 /// This is equivalent to calling `verify_presence(key, &EMPTY_WORD, root)`, but makes
85 /// the intent clearer.
86 ///
87 /// # Errors
88 /// - [`SmtProofError::InvalidKeyForProof`] if the key maps to a different leaf index than this
89 /// proof's leaf.
90 /// - [`SmtProofError::ConflictingRoots`] if the computed root doesn't match the expected root.
91 /// - [`SmtProofError::ValueMismatch`] if the key has a value in the tree (i.e., is not empty).
92 pub fn verify_unset(&self, key: &Word, root: &Word) -> Result<(), SmtProofError> {
93 self.verify_presence(key, &super::EMPTY_WORD, root)
94 }
95
96 /// Verifies that a specific key-value pair is not in the tree.
97 ///
98 /// This succeeds if the key exists with a different value, or if the key is unset.
99 ///
100 /// # Errors
101 /// - [`SmtProofError::InvalidKeyForProof`] if the key maps to a different leaf index than this
102 /// proof's leaf.
103 /// - [`SmtProofError::ConflictingRoots`] if the computed root doesn't match the expected root.
104 /// - [`SmtProofError::ValuePresent`] if the key-value pair exists in the tree.
105 pub fn verify_absence(
106 &self,
107 key: &Word,
108 value: &Word,
109 root: &Word,
110 ) -> Result<(), SmtProofError> {
111 match self.verify_presence(key, value, root) {
112 // The key-value pair exists - absence verification fails
113 Ok(()) => Err(SmtProofError::ValuePresent { key: *key, value: *value }),
114 // Value is different - the pair is absent, success
115 Err(SmtProofError::ValueMismatch { .. }) => Ok(()),
116 // Other errors propagate as-is
117 Err(e) => Err(e),
118 }
119 }
120
121 // PUBLIC ACCESSORS
122 // --------------------------------------------------------------------------------------------
123
124 /// Returns the value associated with the specific key according to this proof, or None if
125 /// this proof does not contain a value for the specified key.
126 ///
127 /// A key-value pair generated by using this method should pass the `verify_presence()` check.
128 pub fn get(&self, key: &Word) -> Option<Word> {
129 self.leaf.get_value(key)
130 }
131
132 /// Computes the root of a [`super::Smt`] to which this proof resolves.
133 pub fn compute_root(&self) -> Word {
134 self.path
135 .compute_root(self.leaf.index().value(), self.leaf.hash())
136 .expect("failed to compute Merkle path root")
137 }
138
139 /// Returns the proof's sparse Merkle path.
140 pub fn path(&self) -> &SparseMerklePath {
141 &self.path
142 }
143
144 /// Returns the leaf associated with the proof.
145 pub fn leaf(&self) -> &SmtLeaf {
146 &self.leaf
147 }
148
149 /// Returns an iterator over every inner node of this proof's merkle path.
150 pub fn authenticated_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
151 self.path
152 .authenticated_nodes(self.leaf.index().value(), self.leaf.hash())
153 .expect("leaf index is u64 and should be less than 2^SMT_DEPTH")
154 }
155
156 /// Consume the proof and returns its parts.
157 pub fn into_parts(self) -> (SparseMerklePath, SmtLeaf) {
158 (self.path, self.leaf)
159 }
160}
161
162impl Serializable for SmtProof {
163 fn write_into<W: ByteWriter>(&self, target: &mut W) {
164 self.path.write_into(target);
165 self.leaf.write_into(target);
166 }
167}
168
169impl Deserializable for SmtProof {
170 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
171 let path = SparseMerklePath::read_from(source)?;
172 let leaf = SmtLeaf::read_from(source)?;
173
174 Self::new(path, leaf).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
175 }
176}