From 64ad8783eb1c385a82fd94e7f15e22d5708c5dbd Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 7 Oct 2021 22:19:26 +0200 Subject: [PATCH 1/4] Fix path compression --- src/hash/path_compression.rs | 64 +++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/src/hash/path_compression.rs b/src/hash/path_compression.rs index f6e876d9..9136e0ea 100644 --- a/src/hash/path_compression.rs +++ b/src/hash/path_compression.rs @@ -22,7 +22,9 @@ pub(crate) fn compress_merkle_proofs( let mut known = vec![false; 2 * num_leaves]; for &i in indices { // The leaves are known. - known[i + num_leaves] = true; + for j in 0..(height - cap_height) { + known[(i + num_leaves) >> j] = true; + } } // For each proof collect all the unknown proof elements. for (&i, p) in indices.iter().zip(proofs) { @@ -66,31 +68,41 @@ pub(crate) fn decompress_merkle_proofs( // Observe the leaves. seen.insert(i + num_leaves, hash_or_noop(v.to_vec())); } - // For every index, go up the tree by querying `seen` to get node values, or if they are unknown - // get them from the compressed proof. - for (&i, p) in leaves_indices.iter().zip(compressed_proofs) { - let mut compressed_siblings = p.siblings.into_iter(); - let mut decompressed_proof = MerkleProof { - siblings: Vec::new(), - }; - let mut index = i + num_leaves; - let mut current_digest = seen[&index]; - for _ in 0..height - cap_height { + let mut proofs = compressed_proofs + .iter() + .map(|p| p.siblings.iter()) + .collect::>(); + for depth in 0..height - cap_height { + for (&i, p) in leaves_indices.iter().zip(proofs.iter_mut()) { + let index = (i + num_leaves) >> depth; let sibling_index = index ^ 1; - // Get the value of the sibling node by querying it or getting it from the proof. + // dbg!(i, depth, index, sibling_index); let h = *seen .entry(sibling_index) - .or_insert_with(|| compressed_siblings.next().unwrap()); - decompressed_proof.siblings.push(h); - // Update the current digest to the value of the parent. - current_digest = if index.is_even() { + .or_insert_with(|| *p.next().unwrap()); + seen.insert(sibling_index, h); + let current_digest = seen[&index]; + let current_digest = if index.is_even() { compress(current_digest, h) } else { compress(h, current_digest) }; - // Observe the parent. + seen.insert(index >> 1, current_digest); + } + } + // For every index, go up the tree by querying `seen` to get node values, or if they are unknown + // get them from the compressed proof. + for (&i, p) in leaves_indices.iter().zip(compressed_proofs) { + let mut decompressed_proof = MerkleProof { + siblings: Vec::new(), + }; + let mut index = i + num_leaves; + for _ in 0..height - cap_height { + let sibling_index = index ^ 1; + // dbg!(index, sibling_index); + let h = seen[&sibling_index]; + decompressed_proof.siblings.push(h); index >>= 1; - seen.insert(index, current_digest); } decompressed_proofs.push(decompressed_proof); @@ -111,17 +123,29 @@ mod tests { #[test] fn test_path_compression() { type F = CrandallField; - let h = 10; - let cap_height = 3; + let h = 5; + let cap_height = 0; let vs = (0..1 << h).map(|_| vec![F::rand()]).collect::>(); let mt = MerkleTree::new(vs.clone(), cap_height); let mut rng = thread_rng(); let k = rng.gen_range(1..=1 << h); + let k = 8; let indices = (0..k).map(|_| rng.gen_range(0..1 << h)).collect::>(); + let indices = [14, 8, 15, 2, 20, 3, 7, 30]; let proofs = indices.iter().map(|&i| mt.prove(i)).collect::>(); let compressed_proofs = compress_merkle_proofs(cap_height, &indices, &proofs); + // for p in &compressed_proofs { + // dbg!(&p.siblings.len()); + // } + // println!( + // "{}", + // compressed_proofs + // .iter() + // .map(|p| p.siblings.len()) + // .sum::() + // ); let decompressed_proofs = decompress_merkle_proofs( &indices.iter().map(|&i| vs[i].clone()).collect::>(), &indices, From e531eda576106fa53295ef7e32549b64b2a1c6e0 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 7 Oct 2021 22:32:58 +0200 Subject: [PATCH 2/4] Cleaning --- src/hash/path_compression.rs | 37 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/hash/path_compression.rs b/src/hash/path_compression.rs index 9136e0ea..060101f6 100644 --- a/src/hash/path_compression.rs +++ b/src/hash/path_compression.rs @@ -21,7 +21,7 @@ pub(crate) fn compress_merkle_proofs( // children at indices `2i` and `2i +1` its parent at index `floor(i ∕ 2)`. let mut known = vec![false; 2 * num_leaves]; for &i in indices { - // The leaves are known. + // The branch from a leaf to the cap is known. for j in 0..(height - cap_height) { known[(i + num_leaves) >> j] = true; } @@ -68,30 +68,31 @@ pub(crate) fn decompress_merkle_proofs( // Observe the leaves. seen.insert(i + num_leaves, hash_or_noop(v.to_vec())); } - let mut proofs = compressed_proofs + + // Iterators over the siblings. + let mut siblings = compressed_proofs .iter() .map(|p| p.siblings.iter()) .collect::>(); + // Fill the `seen` map from the bottom of the tree to the top. for depth in 0..height - cap_height { - for (&i, p) in leaves_indices.iter().zip(proofs.iter_mut()) { + for (&i, p) in leaves_indices.iter().zip(siblings.iter_mut()) { let index = (i + num_leaves) >> depth; + let current_hash = seen[&index]; let sibling_index = index ^ 1; - // dbg!(i, depth, index, sibling_index); - let h = *seen + let sibling_hash = *seen .entry(sibling_index) .or_insert_with(|| *p.next().unwrap()); - seen.insert(sibling_index, h); - let current_digest = seen[&index]; + seen.insert(sibling_index, sibling_hash); let current_digest = if index.is_even() { - compress(current_digest, h) + compress(current_hash, sibling_hash) } else { - compress(h, current_digest) + compress(sibling_hash, current_hash) }; seen.insert(index >> 1, current_digest); } } - // For every index, go up the tree by querying `seen` to get node values, or if they are unknown - // get them from the compressed proof. + // For every index, go up the tree by querying `seen` to get node values. for (&i, p) in leaves_indices.iter().zip(compressed_proofs) { let mut decompressed_proof = MerkleProof { siblings: Vec::new(), @@ -123,29 +124,17 @@ mod tests { #[test] fn test_path_compression() { type F = CrandallField; - let h = 5; + let h = 10; let cap_height = 0; let vs = (0..1 << h).map(|_| vec![F::rand()]).collect::>(); let mt = MerkleTree::new(vs.clone(), cap_height); let mut rng = thread_rng(); let k = rng.gen_range(1..=1 << h); - let k = 8; let indices = (0..k).map(|_| rng.gen_range(0..1 << h)).collect::>(); - let indices = [14, 8, 15, 2, 20, 3, 7, 30]; let proofs = indices.iter().map(|&i| mt.prove(i)).collect::>(); let compressed_proofs = compress_merkle_proofs(cap_height, &indices, &proofs); - // for p in &compressed_proofs { - // dbg!(&p.siblings.len()); - // } - // println!( - // "{}", - // compressed_proofs - // .iter() - // .map(|p| p.siblings.len()) - // .sum::() - // ); let decompressed_proofs = decompress_merkle_proofs( &indices.iter().map(|&i| vs[i].clone()).collect::>(), &indices, From 64d386051bf6e2c84c292c045e6a02b72e4b622c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 7 Oct 2021 22:41:30 +0200 Subject: [PATCH 3/4] More cleaning --- src/hash/path_compression.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hash/path_compression.rs b/src/hash/path_compression.rs index 060101f6..bad35a64 100644 --- a/src/hash/path_compression.rs +++ b/src/hash/path_compression.rs @@ -74,7 +74,7 @@ pub(crate) fn decompress_merkle_proofs( .iter() .map(|p| p.siblings.iter()) .collect::>(); - // Fill the `seen` map from the bottom of the tree to the top. + // Fill the `seen` map from the bottom of the tree to the cap. for depth in 0..height - cap_height { for (&i, p) in leaves_indices.iter().zip(siblings.iter_mut()) { let index = (i + num_leaves) >> depth; @@ -93,14 +93,13 @@ pub(crate) fn decompress_merkle_proofs( } } // For every index, go up the tree by querying `seen` to get node values. - for (&i, p) in leaves_indices.iter().zip(compressed_proofs) { + for &i in leaves_indices { let mut decompressed_proof = MerkleProof { siblings: Vec::new(), }; let mut index = i + num_leaves; for _ in 0..height - cap_height { let sibling_index = index ^ 1; - // dbg!(index, sibling_index); let h = seen[&sibling_index]; decompressed_proof.siblings.push(h); index >>= 1; @@ -125,7 +124,7 @@ mod tests { fn test_path_compression() { type F = CrandallField; let h = 10; - let cap_height = 0; + let cap_height = 3; let vs = (0..1 << h).map(|_| vec![F::rand()]).collect::>(); let mt = MerkleTree::new(vs.clone(), cap_height); From bc95563f43aa51a692744f262c0cca7048c20379 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 8 Oct 2021 08:15:55 +0200 Subject: [PATCH 4/4] PR feedback --- src/hash/path_compression.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/hash/path_compression.rs b/src/hash/path_compression.rs index bad35a64..481eb163 100644 --- a/src/hash/path_compression.rs +++ b/src/hash/path_compression.rs @@ -21,7 +21,7 @@ pub(crate) fn compress_merkle_proofs( // children at indices `2i` and `2i +1` its parent at index `floor(i ∕ 2)`. let mut known = vec![false; 2 * num_leaves]; for &i in indices { - // The branch from a leaf to the cap is known. + // The path from a leaf to the cap is known. for j in 0..(height - cap_height) { known[(i + num_leaves) >> j] = true; } @@ -75,21 +75,20 @@ pub(crate) fn decompress_merkle_proofs( .map(|p| p.siblings.iter()) .collect::>(); // Fill the `seen` map from the bottom of the tree to the cap. - for depth in 0..height - cap_height { + for layer_height in 0..height - cap_height { for (&i, p) in leaves_indices.iter().zip(siblings.iter_mut()) { - let index = (i + num_leaves) >> depth; + let index = (i + num_leaves) >> layer_height; let current_hash = seen[&index]; let sibling_index = index ^ 1; let sibling_hash = *seen .entry(sibling_index) .or_insert_with(|| *p.next().unwrap()); - seen.insert(sibling_index, sibling_hash); - let current_digest = if index.is_even() { + let parent_hash = if index.is_even() { compress(current_hash, sibling_hash) } else { compress(sibling_hash, current_hash) }; - seen.insert(index >> 1, current_digest); + seen.insert(index >> 1, parent_hash); } } // For every index, go up the tree by querying `seen` to get node values.