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)]
11#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
12pub struct MmrPath {
13 forest: Forest,
15
16 position: usize,
18
19 merkle_path: MerklePath,
22}
23
24impl MmrPath {
25 pub fn new(forest: Forest, position: usize, merkle_path: MerklePath) -> Self {
27 Self { forest, position, merkle_path }
28 }
29
30 pub fn forest(&self) -> Forest {
32 self.forest
33 }
34
35 pub fn position(&self) -> usize {
37 self.position
38 }
39
40 pub fn merkle_path(&self) -> &MerklePath {
43 &self.merkle_path
44 }
45
46 pub fn relative_pos(&self) -> usize {
49 self.forest
50 .leaf_relative_position(self.position)
51 .expect("position must be part of the forest")
52 }
53
54 pub fn peak_index(&self) -> usize {
56 self.forest.tree_index(self.position)
57 }
58
59 pub fn with_forest(&self, target_forest: Forest) -> Result<MmrPath, MmrError> {
70 if target_forest.num_leaves() <= self.position {
72 return Err(MmrError::PositionNotFound(self.position));
73 }
74
75 if target_forest > self.forest {
77 return Err(MmrError::ForestOutOfBounds(
78 target_forest.num_leaves(),
79 self.forest.num_leaves(),
80 ));
81 }
82
83 let target_path_len = target_forest
85 .leaf_to_corresponding_tree(self.position)
86 .expect("position is in target forest") as usize;
87
88 let trimmed_nodes: Vec<_> =
90 self.merkle_path.nodes().iter().take(target_path_len).copied().collect();
91 let trimmed_path = MerklePath::new(trimmed_nodes);
92
93 Ok(MmrPath::new(target_forest, self.position, trimmed_path))
94 }
95}
96
97#[derive(Debug, Clone, PartialEq)]
98#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
99pub struct MmrProof {
100 path: MmrPath,
102
103 leaf: Word,
105}
106
107impl MmrProof {
108 pub fn new(path: MmrPath, leaf: Word) -> Self {
110 Self { path, leaf }
111 }
112
113 pub fn path(&self) -> &MmrPath {
115 &self.path
116 }
117
118 pub fn leaf(&self) -> Word {
120 self.leaf
121 }
122
123 pub fn forest(&self) -> Forest {
125 self.path.forest()
126 }
127
128 pub fn position(&self) -> usize {
130 self.path.position()
131 }
132
133 pub fn merkle_path(&self) -> &MerklePath {
136 self.path.merkle_path()
137 }
138
139 pub fn relative_pos(&self) -> usize {
142 self.path.relative_pos()
143 }
144
145 pub fn peak_index(&self) -> usize {
147 self.path.peak_index()
148 }
149
150 pub fn with_forest(&self, target_forest: Forest) -> Result<MmrProof, MmrError> {
161 let adjusted_path = self.path.with_forest(target_forest)?;
162 Ok(MmrProof::new(adjusted_path, self.leaf))
163 }
164}
165
166#[cfg(test)]
170mod tests {
171 use super::{MerklePath, MmrPath, MmrProof};
172 use crate::{
173 Word,
174 merkle::{
175 int_to_node,
176 mmr::{Mmr, forest::Forest},
177 },
178 };
179
180 #[test]
181 fn test_peak_index() {
182 let forest = Forest::new(11);
184
185 for position in 0..8 {
187 let proof = make_dummy_proof(forest, position);
188 assert_eq!(proof.peak_index(), 0);
189 }
190
191 let forest = Forest::new(11);
193
194 for position in 0..8 {
196 let proof = make_dummy_proof(forest, position);
197 assert_eq!(proof.peak_index(), 0);
198 }
199
200 for position in 8..10 {
202 let proof = make_dummy_proof(forest, position);
203 assert_eq!(proof.peak_index(), 1);
204 }
205
206 let proof = make_dummy_proof(forest, 10);
208 assert_eq!(proof.peak_index(), 2);
209
210 let forest = Forest::new(7);
212
213 for position in 0..4 {
215 let proof = make_dummy_proof(forest, position);
216 assert_eq!(proof.peak_index(), 0);
217 }
218
219 for position in 4..6 {
221 let proof = make_dummy_proof(forest, position);
222 assert_eq!(proof.peak_index(), 1);
223 }
224
225 let proof = make_dummy_proof(forest, 6);
227 assert_eq!(proof.peak_index(), 2);
228 }
229
230 fn make_dummy_proof(forest: Forest, position: usize) -> MmrProof {
231 let path = MmrPath::new(forest, position, MerklePath::default());
232 MmrProof::new(path, Word::empty())
233 }
234
235 #[test]
236 fn test_mmr_proof_with_forest() {
237 let mut small_mmr = Mmr::new();
239 for i in 0..5 {
240 small_mmr.add(int_to_node(i));
241 }
242 let small_forest = small_mmr.forest();
243
244 let mut large_mmr = small_mmr.clone();
246 for i in 5..10 {
247 large_mmr.add(int_to_node(i));
248 }
249
250 let large_proof = large_mmr.open(2).unwrap();
252 let small_path_len = small_forest.leaf_to_corresponding_tree(2).unwrap() as u8;
253
254 assert!(large_proof.merkle_path().depth() > small_path_len);
256
257 let adjusted_proof = large_proof.with_forest(small_forest).unwrap();
259 assert_eq!(large_proof.merkle_path().depth() - adjusted_proof.merkle_path().depth(), 1);
260
261 let peak_idx = adjusted_proof.peak_index();
263 let relative_pos = adjusted_proof.relative_pos();
264 let computed_root = adjusted_proof
265 .merkle_path()
266 .compute_root(relative_pos as u64, adjusted_proof.leaf())
267 .unwrap();
268 assert_eq!(computed_root, small_mmr.peaks().peaks()[peak_idx]);
269 }
270
271 #[test]
272 fn test_mmr_path_with_forest_errors() {
273 let mut mmr = Mmr::new();
275 for i in 0..7 {
276 mmr.add(int_to_node(i));
277 }
278 let proof = mmr.open(2).unwrap();
279 let path = proof.path();
280
281 let small_forest = Forest::new(2);
283 assert!(path.with_forest(small_forest).is_err());
284
285 let large_forest = Forest::new(15);
287 assert!(path.with_forest(large_forest).is_err());
288
289 assert!(path.with_forest(mmr.forest()).is_ok());
291 }
292}