ark-r1cs-std/crypto-primitives/src/merkle_tree/mod.rs
crypto-primitives/src/merkle_tree/mod.rsRaw
1use crate::crh::FixedLengthCRH;
2use algebra::bytes::ToBytes;
3use crate::Error;
4use std::{fmt, rc::Rc};
5
6
7#[cfg(feature = "r1cs")]
8pub mod constraints;
9
10pub trait MerkleTreeConfig {
11 const HEIGHT: usize;
12 type H: FixedLengthCRH;
13}
14
15/// Stores the hashes of a particular path (in order) from leaf to root.
16/// Our path `is_left_child()` if the boolean in `path` is true.
17#[derive(Derivative)]
18#[derivative(
19 Clone(bound = "P: MerkleTreeConfig"),
20 Debug(bound = "P: MerkleTreeConfig, <P::H as FixedLengthCRH>::Output: fmt::Debug")
21)]
22pub struct MerkleTreePath<P: MerkleTreeConfig> {
23 pub(crate) path: Vec<(<P::H as FixedLengthCRH>::Output, <P::H as FixedLengthCRH>::Output)>,
24}
25
26pub type MerkleTreeParams<P> = <<P as MerkleTreeConfig>::H as FixedLengthCRH>::Parameters;
27pub type MerkleTreeDigest<P> = <<P as MerkleTreeConfig>::H as FixedLengthCRH>::Output;
28
29
30impl<P: MerkleTreeConfig> Default for MerkleTreePath<P> {
31 fn default() -> Self {
32 let mut path = Vec::with_capacity(P::HEIGHT as usize);
33 for _i in 1..P::HEIGHT as usize {
34 path.push((<P::H as FixedLengthCRH>::Output::default(), <P::H as FixedLengthCRH>::Output::default()));
35 }
36 Self {
37 path,
38 }
39 }
40}
41
42impl<P: MerkleTreeConfig> MerkleTreePath<P> {
43 pub fn verify<L: ToBytes>(
44 &self,
45 parameters: &<P::H as FixedLengthCRH>::Parameters,
46 root_hash: &<P::H as FixedLengthCRH>::Output,
47 leaf: &L,
48 ) -> Result<bool, Error> {
49 if self.path.len() != (P::HEIGHT - 1) as usize {
50 return Ok(false);
51 }
52 // Check that the given leaf matches the leaf in the membership proof.
53 let mut buffer = [0u8; 128];
54
55 if !self.path.is_empty() {
56 let claimed_leaf_hash = hash_leaf::<P::H, L>(parameters, leaf, &mut buffer)?;
57
58 // Check if leaf is one of the bottom-most siblings.
59 if claimed_leaf_hash != self.path[0].0 && claimed_leaf_hash != self.path[0].1 {
60 return Ok(false);
61 };
62
63 let mut prev = claimed_leaf_hash;
64 // Check levels between leaf level and root.
65 for &(ref hash, ref sibling_hash) in &self.path {
66 // Check if the previous hash matches the correct current hash.
67 if &prev != hash && &prev != sibling_hash {
68 return Ok(false);
69 };
70 prev = hash_inner_node::<P::H>(parameters, hash, sibling_hash, &mut buffer)?;
71 }
72
73 if root_hash != &prev {
74 return Ok(false);
75 }
76 Ok(true)
77 } else {
78 Ok(false)
79 }
80 }
81}
82
83pub struct MerkleHashTree<P: MerkleTreeConfig> {
84 tree: Vec<<P::H as FixedLengthCRH>::Output>,
85 padding_tree: Vec<(<P::H as FixedLengthCRH>::Output, <P::H as FixedLengthCRH>::Output)>,
86 parameters: Rc<<P::H as FixedLengthCRH>::Parameters>,
87 root: Option<<P::H as FixedLengthCRH>::Output>,
88}
89
90impl<P: MerkleTreeConfig> MerkleHashTree<P> {
91 pub const HEIGHT: u8 = P::HEIGHT as u8;
92
93 pub fn blank(parameters: Rc<<P::H as FixedLengthCRH>::Parameters>) -> Self {
94 MerkleHashTree {
95 tree: Vec::new(),
96 padding_tree: Vec::new(),
97 root: None,
98 parameters,
99 }
100 }
101
102 pub fn new<L: ToBytes>(parameters: Rc<<P::H as FixedLengthCRH>::Parameters>, leaves: &[L]) -> Result<Self, Error> {
103 let new_time = start_timer!(|| "MerkleTree::New");
104
105 let last_level_size = leaves.len().next_power_of_two();
106 let tree_size = 2 * last_level_size - 1;
107 let tree_height = tree_height(tree_size);
108 assert!(tree_height as u8 <= Self::HEIGHT);
109
110 // Initialize the merkle tree.
111 let mut tree = Vec::with_capacity(tree_size);
112 let empty_hash = hash_empty::<P::H>(¶meters)?;
113 for _ in 0..tree_size {
114 tree.push(empty_hash.clone());
115 }
116
117 // Compute the starting indices for each level of the tree.
118 let mut index = 0;
119 let mut level_indices = Vec::with_capacity(tree_height);
120 for _ in 0..tree_height {
121 level_indices.push(index);
122 index = left_child(index);
123 }
124
125 // Compute and store the hash values for each leaf.
126 let last_level_index = level_indices.pop().unwrap();
127 let mut buffer = [0u8; 128];
128 for (i, leaf) in leaves.iter().enumerate() {
129 tree[last_level_index + i] = hash_leaf::<P::H, _>(¶meters, leaf, &mut buffer)?;
130 }
131
132 // Compute the hash values for every node in the tree.
133 let mut upper_bound = last_level_index;
134 let mut buffer = [0u8; 128];
135 level_indices.reverse();
136 for &start_index in &level_indices {
137 // Iterate over the current level.
138 for current_index in start_index..upper_bound {
139 let left_index = left_child(current_index);
140 let right_index = right_child(current_index);
141
142 // Compute Hash(left || right).
143 tree[current_index] = hash_inner_node::<P::H>(
144 ¶meters,
145 &tree[left_index],
146 &tree[right_index],
147 &mut buffer,
148 )?;
149 }
150 upper_bound = start_index;
151 }
152 // Finished computing actual tree.
153 // Now, we compute the dummy nodes until we hit our HEIGHT goal.
154 let mut cur_height = tree_height;
155 let mut padding_tree = Vec::new();
156 let mut cur_hash = tree[0].clone();
157 while cur_height < (Self::HEIGHT - 1) as usize {
158 cur_hash = hash_inner_node::<P::H>(¶meters, &cur_hash, &empty_hash, &mut buffer)?;
159 padding_tree.push((cur_hash.clone(), empty_hash.clone()));
160 cur_height += 1;
161 }
162
163 let root_hash = hash_inner_node::<P::H>(¶meters, &cur_hash, &empty_hash, &mut buffer)?;
164
165 end_timer!(new_time);
166
167 Ok(MerkleHashTree {
168 tree,
169 padding_tree,
170 parameters,
171 root: Some(root_hash),
172 })
173 }
174
175 #[inline]
176 pub fn root(&self) -> <P::H as FixedLengthCRH>::Output {
177 self.root.clone().unwrap()
178 }
179
180 pub fn generate_proof<L: ToBytes>(
181 &self,
182 index: usize,
183 leaf: &L,
184 ) -> Result<MerkleTreePath<P>, Error> {
185 let prove_time = start_timer!(|| "MerkleTree::GenProof");
186 let mut path = Vec::new();
187
188 let mut buffer = [0u8; 128];
189 let leaf_hash = hash_leaf::<P::H, _>(&self.parameters, leaf, &mut buffer)?;
190 let tree_height = tree_height(self.tree.len());
191 let tree_index = convert_index_to_last_level(index, tree_height);
192 let empty_hash = hash_empty::<P::H>(&self.parameters)?;
193
194 // Check that the given index corresponds to the correct leaf.
195 if leaf_hash != self.tree[tree_index] {
196 Err(MerkleTreeError::IncorrectLeafIndex(tree_index))?
197 }
198
199 // Iterate from the leaf up to the root, storing all intermediate hash values.
200 let mut current_node = tree_index;
201 while !is_root(current_node) {
202 let sibling_node = sibling(current_node).unwrap();
203 let (curr_hash, sibling_hash) = (
204 self.tree[current_node].clone(),
205 self.tree[sibling_node].clone(),
206 );
207 if is_left_child(current_node) {
208 path.push((curr_hash, sibling_hash));
209 } else {
210 path.push((sibling_hash, curr_hash));
211 }
212 current_node = parent(current_node).unwrap();
213 }
214
215 // Store the root node. Set boolean as true for consistency with digest
216 // location.
217 assert!(path.len() < Self::HEIGHT as usize);
218 if path.len() != (Self::HEIGHT - 1) as usize {
219 path.push((self.tree[0].clone(), empty_hash));
220 for &(ref hash, ref sibling_hash) in &self.padding_tree {
221 path.push((hash.clone(), sibling_hash.clone()));
222 }
223 }
224 end_timer!(prove_time);
225 if path.len() != (Self::HEIGHT - 1) as usize {
226 Err(MerkleTreeError::IncorrectPathLength(path.len()))?
227 } else {
228 Ok(MerkleTreePath {
229 path,
230 })
231 }
232 }
233}
234
235#[derive(Debug)]
236pub enum MerkleTreeError {
237 IncorrectLeafIndex(usize),
238 IncorrectPathLength(usize),
239}
240
241impl std::fmt::Display for MerkleTreeError {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 let msg = match self {
244 MerkleTreeError::IncorrectLeafIndex(index) => format!("incorrect leaf index: {}", index),
245 MerkleTreeError::IncorrectPathLength(len) => format!("incorrect path length: {}", len),
246 };
247 write!(f, "{}", msg)
248 }
249}
250
251impl std::error::Error for MerkleTreeError {
252 #[inline]
253 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
254 None
255 }
256}
257
258/// Returns the log2 value of the given number.
259#[inline]
260fn log2(number: usize) -> usize {
261 (number as f64).log2() as usize
262}
263
264/// Returns the height of the tree, given the size of the tree.
265#[inline]
266fn tree_height(tree_size: usize) -> usize {
267 log2(tree_size + 1)
268}
269
270/// Returns true iff the index represents the root.
271#[inline]
272fn is_root(index: usize) -> bool {
273 index == 0
274}
275
276/// Returns the index of the left child, given an index.
277#[inline]
278fn left_child(index: usize) -> usize {
279 2 * index + 1
280}
281
282/// Returns the index of the right child, given an index.
283#[inline]
284fn right_child(index: usize) -> usize {
285 2 * index + 2
286}
287
288/// Returns the index of the sibling, given an index.
289#[inline]
290fn sibling(index: usize) -> Option<usize> {
291 if index == 0 {
292 None
293 } else if is_left_child(index) {
294 Some(index + 1)
295 } else {
296 Some(index - 1)
297 }
298}
299
300/// Returns true iff the given index represents a left child.
301#[inline]
302fn is_left_child(index: usize) -> bool {
303 index % 2 == 1
304}
305
306/// Returns the index of the parent, given an index.
307#[inline]
308fn parent(index: usize) -> Option<usize> {
309 if index > 0 {
310 Some((index - 1) >> 1)
311 } else {
312 None
313 }
314}
315
316#[inline]
317fn convert_index_to_last_level(index: usize, tree_height: usize) -> usize {
318 index + (1 << (tree_height - 1)) - 1
319}
320
321/// Returns the output hash, given a left and right hash value.
322pub(crate) fn hash_inner_node<H: FixedLengthCRH>(
323 parameters: &H::Parameters,
324 left: &H::Output,
325 right: &H::Output,
326 buffer: &mut [u8],
327) -> Result<H::Output, Error> {
328 use std::io::Cursor;
329 let mut writer = Cursor::new(buffer);
330 // Construct left input.
331 left.write(&mut writer)?;
332
333 // Construct right input.
334 right.write(&mut writer)?;
335
336 let buffer = writer.into_inner();
337 H::evaluate(parameters, &buffer[..(H::INPUT_SIZE_BITS / 8)])
338}
339
340/// Returns the hash of a leaf.
341pub(crate) fn hash_leaf<H: FixedLengthCRH, L: ToBytes>(
342 parameters: &H::Parameters,
343 leaf: &L,
344 buffer: &mut [u8],
345) -> Result<H::Output, Error> {
346 use std::io::Cursor;
347 let mut writer = Cursor::new(buffer);
348 leaf.write(&mut writer)?;
349
350 let buffer = writer.into_inner();
351 H::evaluate(parameters, &buffer[..(H::INPUT_SIZE_BITS / 8)])
352}
353
354pub(crate) fn hash_empty<H: FixedLengthCRH>(
355 parameters: &H::Parameters,
356) -> Result<H::Output, Error> {
357 let empty_buffer = vec![0u8; H::INPUT_SIZE_BITS / 8];
358 H::evaluate(parameters, &empty_buffer)
359}
360
361
362#[cfg(test)]
363mod test {
364 use crate::{crh::{pedersen::*, *}, merkle_tree::*};
365 use algebra::curves::jubjub::JubJubAffine as JubJub;
366 use rand::SeedableRng;
367 use rand_xorshift::XorShiftRng;
368
369 #[derive(Clone)]
370 pub(super) struct Window4x256;
371 impl PedersenWindow for Window4x256 {
372 const WINDOW_SIZE: usize = 4;
373 const NUM_WINDOWS: usize = 256;
374 }
375
376
377 type H = PedersenCRH<JubJub, Window4x256>;
378
379 struct JubJubMerkleTreeParams;
380
381 impl MerkleTreeConfig for JubJubMerkleTreeParams {
382 const HEIGHT: usize = 32;
383 type H = H;
384 }
385 type JubJubMerkleTree = MerkleHashTree<JubJubMerkleTreeParams>;
386
387
388 fn generate_merkle_tree<L: ToBytes + Clone + Eq>(leaves: &[L]) -> () {
389 let mut rng = XorShiftRng::seed_from_u64(9174123u64);
390
391 let crh_parameters = Rc::new(H::setup(&mut rng).unwrap());
392 let tree = JubJubMerkleTree::new(crh_parameters.clone(), &leaves).unwrap();
393 let root = tree.root();
394 for (i, leaf) in leaves.iter().enumerate() {
395 let proof = tree.generate_proof(i, &leaf).unwrap();
396 assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap());
397 }
398 }
399
400 #[test]
401 fn good_root_test() {
402 let mut leaves = Vec::new();
403 for i in 0..4u8 {
404 leaves.push([i, i, i, i, i, i, i, i]);
405 }
406 generate_merkle_tree(&leaves);
407 let mut leaves = Vec::new();
408 for i in 0..100u8 {
409 leaves.push([i, i, i, i, i, i, i, i]);
410 }
411 generate_merkle_tree(&leaves);
412 }
413
414 fn bad_merkle_tree_verify<L: ToBytes + Clone + Eq>(leaves: &[L]) -> () {
415 use algebra::groups::Group;
416 let mut rng = XorShiftRng::seed_from_u64(13423423u64);
417
418 let crh_parameters = Rc::new(H::setup(&mut rng).unwrap());
419 let tree = JubJubMerkleTree::new(crh_parameters.clone(), &leaves).unwrap();
420 let root = JubJub::zero();
421 for (i, leaf) in leaves.iter().enumerate() {
422 let proof = tree.generate_proof(i, &leaf).unwrap();
423 assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap());
424 }
425 }
426
427 #[should_panic]
428 #[test]
429 fn bad_root_test() {
430 let mut leaves = Vec::new();
431 for i in 0..4u8 {
432 leaves.push([i, i, i, i, i, i, i, i]);
433 }
434 generate_merkle_tree(&leaves);
435 let mut leaves = Vec::new();
436 for i in 0..100u8 {
437 leaves.push([i, i, i, i, i, i, i, i]);
438 }
439 bad_merkle_tree_verify(&leaves);
440 }
441}