Tweak Merkle proof API and make it public (#588)

- Add `_to_cap` to existing methods for clarity
- Add variants which deal with Merkle roots instead of caps
- Simplify `verify_merkle_proof_to_cap` - it can call `verify_merkle_proof_to_cap_with_cap_index`
- Make them all public except `verify_merkle_proof_to_cap_with_cap_index`, which is pretty niche
This commit is contained in:
Daniel Lubarov 2022-06-27 20:39:47 -07:00 committed by GitHub
parent e3834a5335
commit dec0765fb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 33 deletions

View File

@ -208,7 +208,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
with_context!(
self,
&format!("verify {}'th initial Merkle proof", i),
self.verify_merkle_proof_with_cap_index::<H>(
self.verify_merkle_proof_to_cap_with_cap_index::<H>(
evals.clone(),
x_index_bits,
cap_index,
@ -351,7 +351,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
with_context!(
self,
"verify FRI round Merkle proof.",
self.verify_merkle_proof_with_cap_index::<C::Hasher>(
self.verify_merkle_proof_to_cap_with_cap_index::<C::Hasher>(
flatten_target(evals),
&coset_index_bits,
cap_index,

View File

@ -8,7 +8,7 @@ use crate::fri::proof::{FriChallenges, FriInitialTreeProof, FriProof, FriQueryRo
use crate::fri::structure::{FriBatchInfo, FriInstanceInfo, FriOpenings};
use crate::fri::{FriConfig, FriParams};
use crate::hash::hash_types::RichField;
use crate::hash::merkle_proofs::verify_merkle_proof;
use crate::hash::merkle_proofs::verify_merkle_proof_to_cap;
use crate::hash::merkle_tree::MerkleCap;
use crate::plonk::config::{GenericConfig, Hasher};
use crate::util::reducing::ReducingFactor;
@ -116,7 +116,7 @@ where
[(); H::HASH_SIZE]:,
{
for ((evals, merkle_proof), cap) in proof.evals_proofs.iter().zip(initial_merkle_caps) {
verify_merkle_proof::<F, H>(evals.clone(), x_index, cap, merkle_proof)?;
verify_merkle_proof_to_cap::<F, H>(evals.clone(), x_index, cap, merkle_proof)?;
}
Ok(())
@ -224,7 +224,7 @@ where
challenges.fri_betas[i],
);
verify_merkle_proof::<F, C::Hasher>(
verify_merkle_proof_to_cap::<F, C::Hasher>(
flatten(evals),
coset_index,
&proof.commit_phase_merkle_caps[i],

View File

@ -13,7 +13,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// bit of the integer, with little-endian ordering.
/// Verifies that the decomposition is correct by using `k` `BaseSum<2>` gates
/// with `k` such that `k * num_routed_wires >= num_bits`.
pub(crate) fn split_le(&mut self, integer: Target, num_bits: usize) -> Vec<BoolTarget> {
pub fn split_le(&mut self, integer: Target, num_bits: usize) -> Vec<BoolTarget> {
if num_bits == 0 {
return Vec::new();
}

View File

@ -23,9 +23,24 @@ pub struct MerkleProofTarget {
pub siblings: Vec<HashOutTarget>,
}
/// Verifies that the given leaf data is present at the given index in the Merkle tree with the
/// given root.
pub fn verify_merkle_proof<F: RichField, H: Hasher<F>>(
leaf_data: Vec<F>,
leaf_index: usize,
merkle_root: H::Hash,
proof: &MerkleProof<F, H>,
) -> Result<()>
where
[(); H::HASH_SIZE]:,
{
let merkle_cap = MerkleCap(vec![merkle_root]);
verify_merkle_proof_to_cap(leaf_data, leaf_index, &merkle_cap, proof)
}
/// Verifies that the given leaf data is present at the given index in the Merkle tree with the
/// given cap.
pub(crate) fn verify_merkle_proof<F: RichField, H: Hasher<F>>(
pub fn verify_merkle_proof_to_cap<F: RichField, H: Hasher<F>>(
leaf_data: Vec<F>,
leaf_index: usize,
merkle_cap: &MerkleCap<F, H>,
@ -55,37 +70,40 @@ where
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Verifies that the given leaf data is present at the given index in the Merkle tree with the
/// given cap. The index is given by it's little-endian bits.
#[cfg(test)]
pub(crate) fn verify_merkle_proof<H: AlgebraicHasher<F>>(
/// given root. The index is given by its little-endian bits.
pub fn verify_merkle_proof<H: AlgebraicHasher<F>>(
&mut self,
leaf_data: Vec<Target>,
leaf_index_bits: &[BoolTarget],
merkle_root: HashOutTarget,
proof: &MerkleProofTarget,
) {
let merkle_cap = MerkleCapTarget(vec![merkle_root]);
self.verify_merkle_proof_to_cap::<H>(leaf_data, leaf_index_bits, &merkle_cap, proof);
}
/// Verifies that the given leaf data is present at the given index in the Merkle tree with the
/// given cap. The index is given by its little-endian bits.
pub fn verify_merkle_proof_to_cap<H: AlgebraicHasher<F>>(
&mut self,
leaf_data: Vec<Target>,
leaf_index_bits: &[BoolTarget],
merkle_cap: &MerkleCapTarget,
proof: &MerkleProofTarget,
) {
let zero = self.zero();
let mut state: HashOutTarget = self.hash_or_noop::<H>(leaf_data);
for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) {
let mut perm_inputs = [zero; SPONGE_WIDTH];
perm_inputs[..4].copy_from_slice(&state.elements);
perm_inputs[4..8].copy_from_slice(&sibling.elements);
let outputs = self.permute_swapped::<H>(perm_inputs, bit);
state = HashOutTarget::from_vec(outputs[0..4].to_vec());
}
let index = self.le_sum(leaf_index_bits[proof.siblings.len()..].iter().copied());
for i in 0..4 {
let result =
self.random_access(index, merkle_cap.0.iter().map(|h| h.elements[i]).collect());
self.connect(result, state.elements[i]);
}
let cap_index = self.le_sum(leaf_index_bits[proof.siblings.len()..].iter().copied());
self.verify_merkle_proof_to_cap_with_cap_index::<H>(
leaf_data,
leaf_index_bits,
cap_index,
merkle_cap,
proof,
);
}
/// Same as `verify_merkle_proof` but with the final "cap index" as extra parameter.
pub(crate) fn verify_merkle_proof_with_cap_index<H: AlgebraicHasher<F>>(
/// Same as `verify_merkle_proof_to_cap`, except with the final "cap index" as separate parameter,
/// rather than being contained in `leaf_index_bits`.
pub(crate) fn verify_merkle_proof_to_cap_with_cap_index<H: AlgebraicHasher<F>>(
&mut self,
leaf_data: Vec<Target>,
leaf_index_bits: &[BoolTarget],
@ -176,7 +194,7 @@ mod tests {
pw.set_target(data[j], tree.leaves[i][j]);
}
builder.verify_merkle_proof::<<C as GenericConfig<D>>::InnerHasher>(
builder.verify_merkle_proof_to_cap::<<C as GenericConfig<D>>::InnerHasher>(
data, &i_bits, &cap_t, &proof_t,
);

View File

@ -209,7 +209,7 @@ mod tests {
use plonky2_field::extension::Extendable;
use super::*;
use crate::hash::merkle_proofs::verify_merkle_proof;
use crate::hash::merkle_proofs::verify_merkle_proof_to_cap;
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
fn random_data<F: RichField>(n: usize, k: usize) -> Vec<Vec<F>> {
@ -226,7 +226,7 @@ mod tests {
let tree = MerkleTree::<F, C::Hasher>::new(leaves.clone(), cap_height);
for (i, leaf) in leaves.into_iter().enumerate() {
let proof = tree.prove(i);
verify_merkle_proof(leaf, i, &tree.cap, &proof)?;
verify_merkle_proof_to_cap(leaf, i, &tree.cap, &proof)?;
}
Ok(())
}