mmr_crypto_primitives/merkle_tree/
mod.rs1#![allow(clippy::needless_range_loop)]
2
3use crate::crh::TwoToOneCRHScheme;
5use crate::{CRHScheme, Error};
6use ark_ff::ToBytes;
7use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write};
8use ark_std::borrow::Borrow;
9use ark_std::hash::Hash;
10use ark_std::vec::Vec;
11
12#[cfg(test)]
13mod tests;
14
15#[cfg(feature = "r1cs")]
16pub mod constraints;
17
18pub trait DigestConverter<From, To: ?Sized> {
21 type TargetType: Borrow<To>;
22 fn convert(item: From) -> Result<Self::TargetType, Error>;
23}
24
25pub struct IdentityDigestConverter<T> {
27 _prev_layer_digest: T,
28}
29
30impl<T> DigestConverter<T, T> for IdentityDigestConverter<T> {
31 type TargetType = T;
32 fn convert(item: T) -> Result<T, Error> {
33 Ok(item)
34 }
35}
36
37pub struct ByteDigestConverter<T: CanonicalSerialize + ToBytes> {
40 _prev_layer_digest: T,
41}
42
43impl<T: CanonicalSerialize + ToBytes> DigestConverter<T, [u8]> for ByteDigestConverter<T> {
44 type TargetType = Vec<u8>;
45
46 fn convert(item: T) -> Result<Self::TargetType, Error> {
47 Ok(crate::to_unchecked_bytes!(item)?)
49 }
50}
51
52pub trait Config {
58 type Leaf: ?Sized; type LeafDigest: ToBytes
61 + Clone
62 + Eq
63 + core::fmt::Debug
64 + Hash
65 + Default
66 + CanonicalSerialize
67 + CanonicalDeserialize;
68 type LeafInnerDigestConverter: DigestConverter<
70 Self::LeafDigest,
71 <Self::TwoToOneHash as TwoToOneCRHScheme>::Input,
72 >;
73 type InnerDigest: ToBytes
75 + Clone
76 + Eq
77 + core::fmt::Debug
78 + Hash
79 + Default
80 + CanonicalSerialize
81 + CanonicalDeserialize;
82
83 type LeafHash: CRHScheme<Input = Self::Leaf, Output = Self::LeafDigest>;
90 type TwoToOneHash: TwoToOneCRHScheme<Output = Self::InnerDigest>;
92}
93
94pub type TwoToOneParam<P> = <<P as Config>::TwoToOneHash as TwoToOneCRHScheme>::Parameters;
95pub type LeafParam<P> = <<P as Config>::LeafHash as CRHScheme>::Parameters;
96
97#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
110#[derivative(
111 Clone(bound = "P: Config"),
112 Debug(bound = "P: Config"),
113 Default(bound = "P: Config")
114)]
115pub struct Path<P: Config> {
116 pub leaf_sibling_hash: P::LeafDigest,
117 pub auth_path: Vec<P::InnerDigest>,
119 pub leaf_index: usize,
121}
122
123impl<P: Config> Path<P> {
124 #[allow(unused)] fn position_list(&'_ self) -> impl '_ + Iterator<Item = bool> {
130 (0..self.auth_path.len() + 1)
131 .map(move |i| ((self.leaf_index >> i) & 1) != 0)
132 .rev()
133 }
134}
135
136impl<P: Config> Path<P> {
137 pub fn verify<L: Borrow<P::Leaf>>(
142 &self,
143 leaf_hash_params: &LeafParam<P>,
144 two_to_one_params: &TwoToOneParam<P>,
145 root_hash: &P::InnerDigest,
146 leaf: L,
147 ) -> Result<bool, crate::Error> {
148 let claimed_leaf_hash = P::LeafHash::evaluate(&leaf_hash_params, leaf)?;
150 let (left_child, right_child) =
152 select_left_right_child(self.leaf_index, &claimed_leaf_hash, &self.leaf_sibling_hash)?;
153
154 let left_child = P::LeafInnerDigestConverter::convert(left_child)?;
156 let right_child = P::LeafInnerDigestConverter::convert(right_child)?;
157
158 let mut curr_path_node =
159 P::TwoToOneHash::evaluate(&two_to_one_params, left_child, right_child)?;
160
161 let mut index = self.leaf_index;
163 index >>= 1;
164
165 for level in (0..self.auth_path.len()).rev() {
167 let (left, right) =
169 select_left_right_child(index, &curr_path_node, &self.auth_path[level])?;
170 curr_path_node = P::TwoToOneHash::compress(&two_to_one_params, &left, &right)?;
172 index >>= 1;
173 }
174
175 if &curr_path_node != root_hash {
177 return Ok(false);
178 }
179
180 Ok(true)
181 }
182}
183
184fn select_left_right_child<L: Clone>(
192 index: usize,
193 computed_hash: &L,
194 sibling_hash: &L,
195) -> Result<(L, L), crate::Error> {
196 let is_left = index & 1 == 0;
197 let mut left_child = computed_hash;
198 let mut right_child = sibling_hash;
199 if !is_left {
200 core::mem::swap(&mut left_child, &mut right_child);
201 }
202 Ok((left_child.clone(), right_child.clone()))
203}
204
205#[derive(Derivative)]
213#[derivative(Clone(bound = "P: Config"))]
214pub struct MerkleTree<P: Config> {
215 non_leaf_nodes: Vec<P::InnerDigest>,
218 leaf_nodes: Vec<P::LeafDigest>,
220 two_to_one_hash_param: TwoToOneParam<P>,
222 leaf_hash_param: LeafParam<P>,
224 height: usize,
226}
227
228impl<P: Config> MerkleTree<P> {
229 pub fn blank(
232 leaf_hash_param: &LeafParam<P>,
233 two_to_one_hash_param: &TwoToOneParam<P>,
234 height: usize,
235 ) -> Result<Self, crate::Error> {
236 let leaves_digest = vec![P::LeafDigest::default(); 1 << (height - 1)];
238 Self::new_with_leaf_digest(leaf_hash_param, two_to_one_hash_param, leaves_digest)
239 }
240
241 pub fn new<L: Borrow<P::Leaf>>(
243 leaf_hash_param: &LeafParam<P>,
244 two_to_one_hash_param: &TwoToOneParam<P>,
245 leaves: impl IntoIterator<Item = L>,
246 ) -> Result<Self, crate::Error> {
247 let mut leaves_digests = Vec::new();
248
249 for leaf in leaves.into_iter() {
251 leaves_digests.push(P::LeafHash::evaluate(leaf_hash_param, leaf)?)
252 }
253
254 Self::new_with_leaf_digest(leaf_hash_param, two_to_one_hash_param, leaves_digests)
255 }
256
257 pub fn new_with_leaf_digest(
258 leaf_hash_param: &LeafParam<P>,
259 two_to_one_hash_param: &TwoToOneParam<P>,
260 leaves_digest: Vec<P::LeafDigest>,
261 ) -> Result<Self, crate::Error> {
262 let leaf_nodes_size = leaves_digest.len();
263 assert!(
264 leaf_nodes_size.is_power_of_two() && leaf_nodes_size > 1,
265 "`leaves.len() should be power of two and greater than one"
266 );
267 let non_leaf_nodes_size = leaf_nodes_size - 1;
268
269 let tree_height = tree_height(leaf_nodes_size);
270
271 let hash_of_empty: P::InnerDigest = P::InnerDigest::default();
272
273 let mut non_leaf_nodes: Vec<P::InnerDigest> = (0..non_leaf_nodes_size)
275 .map(|_| hash_of_empty.clone())
276 .collect();
277
278 let mut index = 0;
280 let mut level_indices = Vec::with_capacity(tree_height - 1);
281 for _ in 0..(tree_height - 1) {
282 level_indices.push(index);
283 index = left_child(index);
284 }
285
286 {
288 let start_index = level_indices.pop().unwrap();
289 let upper_bound = left_child(start_index);
290 for current_index in start_index..upper_bound {
291 let left_leaf_index = left_child(current_index) - upper_bound;
295 let right_leaf_index = right_child(current_index) - upper_bound;
296 non_leaf_nodes[current_index] = P::TwoToOneHash::evaluate(
298 &two_to_one_hash_param,
299 P::LeafInnerDigestConverter::convert(leaves_digest[left_leaf_index].clone())?,
300 P::LeafInnerDigestConverter::convert(leaves_digest[right_leaf_index].clone())?,
301 )?
302 }
303 }
304
305 level_indices.reverse();
307 for &start_index in &level_indices {
308 let upper_bound = left_child(start_index);
310 for current_index in start_index..upper_bound {
311 let left_index = left_child(current_index);
312 let right_index = right_child(current_index);
313 non_leaf_nodes[current_index] = P::TwoToOneHash::compress(
314 &two_to_one_hash_param,
315 non_leaf_nodes[left_index].clone(),
316 non_leaf_nodes[right_index].clone(),
317 )?
318 }
319 }
320
321 Ok(MerkleTree {
322 leaf_nodes: leaves_digest,
323 non_leaf_nodes,
324 height: tree_height,
325 leaf_hash_param: leaf_hash_param.clone(),
326 two_to_one_hash_param: two_to_one_hash_param.clone(),
327 })
328 }
329
330 pub fn root(&self) -> P::InnerDigest {
332 self.non_leaf_nodes[0].clone()
333 }
334
335 pub fn height(&self) -> usize {
337 self.height
338 }
339
340 pub fn generate_proof(&self, index: usize) -> Result<Path<P>, crate::Error> {
342 let tree_height = tree_height(self.leaf_nodes.len());
344
345 let leaf_index_in_tree = convert_index_to_last_level(index, tree_height);
347 let leaf_sibling_hash = if index & 1 == 0 {
348 self.leaf_nodes[index + 1].clone()
350 } else {
351 self.leaf_nodes[index - 1].clone()
353 };
354
355 let mut path = Vec::with_capacity(tree_height - 2);
357 let mut current_node = parent(leaf_index_in_tree).unwrap();
359 while !is_root(current_node) {
360 let sibling_node = sibling(current_node).unwrap();
361 path.push(self.non_leaf_nodes[sibling_node].clone());
362 current_node = parent(current_node).unwrap();
363 }
364
365 debug_assert_eq!(path.len(), tree_height - 2);
366
367 path.reverse();
369
370 Ok(Path {
371 leaf_index: index,
372 auth_path: path,
373 leaf_sibling_hash,
374 })
375 }
376
377 fn updated_path<T: Borrow<P::Leaf>>(
380 &self,
381 index: usize,
382 new_leaf: T,
383 ) -> Result<(P::LeafDigest, Vec<P::InnerDigest>), crate::Error> {
384 let new_leaf_hash: P::LeafDigest = P::LeafHash::evaluate(&self.leaf_hash_param, new_leaf)?;
386
387 let (leaf_left, leaf_right) = if index & 1 == 0 {
389 (&new_leaf_hash, &self.leaf_nodes[index + 1])
391 } else {
392 (&self.leaf_nodes[index - 1], &new_leaf_hash)
393 };
394
395 let mut path_bottom_to_top = Vec::with_capacity(self.height - 1);
397 {
398 path_bottom_to_top.push(P::TwoToOneHash::evaluate(
399 &self.two_to_one_hash_param,
400 P::LeafInnerDigestConverter::convert(leaf_left.clone())?,
401 P::LeafInnerDigestConverter::convert(leaf_right.clone())?,
402 )?);
403 }
404
405 let leaf_index_in_tree = convert_index_to_last_level(index, self.height);
407 let mut prev_index = parent(leaf_index_in_tree).unwrap();
408 while !is_root(prev_index) {
409 let (left_child, right_child) = if is_left_child(prev_index) {
410 (
411 path_bottom_to_top.last().unwrap(),
412 &self.non_leaf_nodes[sibling(prev_index).unwrap()],
413 )
414 } else {
415 (
416 &self.non_leaf_nodes[sibling(prev_index).unwrap()],
417 path_bottom_to_top.last().unwrap(),
418 )
419 };
420 let evaluated =
421 P::TwoToOneHash::compress(&self.two_to_one_hash_param, left_child, right_child)?;
422 path_bottom_to_top.push(evaluated);
423 prev_index = parent(prev_index).unwrap();
424 }
425
426 debug_assert_eq!(path_bottom_to_top.len(), self.height - 1);
427 let path_top_to_bottom: Vec<_> = path_bottom_to_top.into_iter().rev().collect();
428 Ok((new_leaf_hash, path_top_to_bottom))
429 }
430
431 pub fn update(&mut self, index: usize, new_leaf: &P::Leaf) -> Result<(), crate::Error> {
443 assert!(index < self.leaf_nodes.len(), "index out of range");
444 let (updated_leaf_hash, mut updated_path) = self.updated_path(index, new_leaf)?;
445 self.leaf_nodes[index] = updated_leaf_hash;
446 let mut curr_index = convert_index_to_last_level(index, self.height);
447 for _ in 0..self.height - 1 {
448 curr_index = parent(curr_index).unwrap();
449 self.non_leaf_nodes[curr_index] = updated_path.pop().unwrap();
450 }
451 Ok(())
452 }
453
454 pub fn check_update<T: Borrow<P::Leaf>>(
458 &mut self,
459 index: usize,
460 new_leaf: &P::Leaf,
461 asserted_new_root: &P::InnerDigest,
462 ) -> Result<bool, crate::Error> {
463 let new_leaf = new_leaf.borrow();
464 assert!(index < self.leaf_nodes.len(), "index out of range");
465 let (updated_leaf_hash, mut updated_path) = self.updated_path(index, new_leaf)?;
466 if &updated_path[0] != asserted_new_root {
467 return Ok(false);
468 }
469 self.leaf_nodes[index] = updated_leaf_hash;
470 let mut curr_index = convert_index_to_last_level(index, self.height);
471 for _ in 0..self.height - 1 {
472 curr_index = parent(curr_index).unwrap();
473 self.non_leaf_nodes[curr_index] = updated_path.pop().unwrap();
474 }
475 Ok(true)
476 }
477}
478
479#[inline]
481fn tree_height(num_leaves: usize) -> usize {
482 if num_leaves == 1 {
483 return 1;
484 }
485
486 (ark_std::log2(num_leaves) as usize) + 1
487}
488#[inline]
490fn is_root(index: usize) -> bool {
491 index == 0
492}
493
494#[inline]
496fn left_child(index: usize) -> usize {
497 2 * index + 1
498}
499
500#[inline]
502fn right_child(index: usize) -> usize {
503 2 * index + 2
504}
505
506#[inline]
508fn sibling(index: usize) -> Option<usize> {
509 if index == 0 {
510 None
511 } else if is_left_child(index) {
512 Some(index + 1)
513 } else {
514 Some(index - 1)
515 }
516}
517
518#[inline]
520fn is_left_child(index: usize) -> bool {
521 index % 2 == 1
522}
523
524#[inline]
526fn parent(index: usize) -> Option<usize> {
527 if index > 0 {
528 Some((index - 1) >> 1)
529 } else {
530 None
531 }
532}
533
534#[inline]
535fn convert_index_to_last_level(index: usize, tree_height: usize) -> usize {
536 index + (1 << (tree_height - 1)) - 1
537}