miden_crypto/merkle/mmr/
proof.rs1use alloc::vec::Vec;
3
4use super::{super::MerklePath, MmrError, forest::Forest};
5use crate::Word;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct MmrPath {
12 forest: Forest,
14
15 position: usize,
17
18 merkle_path: MerklePath,
21}
22
23impl MmrPath {
24 pub fn new(forest: Forest, position: usize, merkle_path: MerklePath) -> Self {
26 Self { forest, position, merkle_path }
27 }
28
29 pub fn forest(&self) -> Forest {
31 self.forest
32 }
33
34 pub fn position(&self) -> usize {
36 self.position
37 }
38
39 pub fn merkle_path(&self) -> &MerklePath {
42 &self.merkle_path
43 }
44
45 pub fn relative_pos(&self) -> usize {
48 self.forest
49 .leaf_relative_position(self.position)
50 .expect("position must be part of the forest")
51 }
52
53 pub fn peak_index(&self) -> usize {
55 self.forest.tree_index(self.position)
56 }
57
58 pub fn with_forest(&self, target_forest: Forest) -> Result<MmrPath, MmrError> {
69 if target_forest.num_leaves() <= self.position {
71 return Err(MmrError::PositionNotFound(self.position));
72 }
73
74 if target_forest > self.forest {
76 return Err(MmrError::ForestOutOfBounds(
77 target_forest.num_leaves(),
78 self.forest.num_leaves(),
79 ));
80 }
81
82 let target_path_len = target_forest
84 .leaf_to_corresponding_tree(self.position)
85 .expect("position is in target forest") as usize;
86
87 let trimmed_nodes: Vec<_> =
89 self.merkle_path.nodes().iter().take(target_path_len).copied().collect();
90 let trimmed_path = MerklePath::new(trimmed_nodes);
91
92 Ok(MmrPath::new(target_forest, self.position, trimmed_path))
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub struct MmrProof {
98 path: MmrPath,
100
101 leaf: Word,
103}
104
105impl MmrProof {
106 pub fn new(path: MmrPath, leaf: Word) -> Self {
108 Self { path, leaf }
109 }
110
111 pub fn path(&self) -> &MmrPath {
113 &self.path
114 }
115
116 pub fn leaf(&self) -> Word {
118 self.leaf
119 }
120
121 pub fn forest(&self) -> Forest {
123 self.path.forest()
124 }
125
126 pub fn position(&self) -> usize {
128 self.path.position()
129 }
130
131 pub fn merkle_path(&self) -> &MerklePath {
134 self.path.merkle_path()
135 }
136
137 pub fn relative_pos(&self) -> usize {
140 self.path.relative_pos()
141 }
142
143 pub fn peak_index(&self) -> usize {
145 self.path.peak_index()
146 }
147
148 pub fn with_forest(&self, target_forest: Forest) -> Result<MmrProof, MmrError> {
159 let adjusted_path = self.path.with_forest(target_forest)?;
160 Ok(MmrProof::new(adjusted_path, self.leaf))
161 }
162}
163
164#[cfg(test)]
168mod tests {
169 use super::{MerklePath, MmrPath, MmrProof};
170 use crate::{
171 Word,
172 merkle::{
173 int_to_node,
174 mmr::{Mmr, forest::Forest},
175 },
176 };
177
178 #[test]
179 fn test_peak_index() {
180 let forest = Forest::new(11).unwrap();
182
183 for position in 0..8 {
185 let proof = make_dummy_proof(forest, position);
186 assert_eq!(proof.peak_index(), 0);
187 }
188
189 let forest = Forest::new(11).unwrap();
191
192 for position in 0..8 {
194 let proof = make_dummy_proof(forest, position);
195 assert_eq!(proof.peak_index(), 0);
196 }
197
198 for position in 8..10 {
200 let proof = make_dummy_proof(forest, position);
201 assert_eq!(proof.peak_index(), 1);
202 }
203
204 let proof = make_dummy_proof(forest, 10);
206 assert_eq!(proof.peak_index(), 2);
207
208 let forest = Forest::new(7).unwrap();
210
211 for position in 0..4 {
213 let proof = make_dummy_proof(forest, position);
214 assert_eq!(proof.peak_index(), 0);
215 }
216
217 for position in 4..6 {
219 let proof = make_dummy_proof(forest, position);
220 assert_eq!(proof.peak_index(), 1);
221 }
222
223 let proof = make_dummy_proof(forest, 6);
225 assert_eq!(proof.peak_index(), 2);
226 }
227
228 fn make_dummy_proof(forest: Forest, position: usize) -> MmrProof {
229 let path = MmrPath::new(forest, position, MerklePath::default());
230 MmrProof::new(path, Word::empty())
231 }
232
233 #[test]
234 fn test_mmr_proof_with_forest() {
235 let mut small_mmr = Mmr::new();
237 for i in 0..5 {
238 small_mmr.add(int_to_node(i)).unwrap();
239 }
240 let small_forest = small_mmr.forest();
241
242 let mut large_mmr = small_mmr.clone();
244 for i in 5..10 {
245 large_mmr.add(int_to_node(i)).unwrap();
246 }
247
248 let large_proof = large_mmr.open(2).unwrap();
250 let small_path_len = small_forest.leaf_to_corresponding_tree(2).unwrap() as u8;
251
252 assert!(large_proof.merkle_path().depth() > small_path_len);
254
255 let adjusted_proof = large_proof.with_forest(small_forest).unwrap();
257 assert_eq!(large_proof.merkle_path().depth() - adjusted_proof.merkle_path().depth(), 1);
258
259 let peak_idx = adjusted_proof.peak_index();
261 let relative_pos = adjusted_proof.relative_pos();
262 let computed_root = adjusted_proof
263 .merkle_path()
264 .compute_root(relative_pos as u64, adjusted_proof.leaf())
265 .unwrap();
266 assert_eq!(computed_root, small_mmr.peaks().peaks()[peak_idx]);
267 }
268
269 #[test]
270 fn test_mmr_path_with_forest_errors() {
271 let mut mmr = Mmr::new();
273 for i in 0..7 {
274 mmr.add(int_to_node(i)).unwrap();
275 }
276 let proof = mmr.open(2).unwrap();
277 let path = proof.path();
278
279 let small_forest = Forest::new(2).unwrap();
281 assert!(path.with_forest(small_forest).is_err());
282
283 let large_forest = Forest::new(15).unwrap();
285 assert!(path.with_forest(large_forest).is_err());
286
287 assert!(path.with_forest(mmr.forest()).is_ok());
289 }
290}