From ce71b536bf7aec8599d037fd8626ca76b0df44f8 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 13:33:44 +0200 Subject: [PATCH 01/10] First pass --- src/bin/bench_recursion.rs | 2 + src/fri/commitment.rs | 26 +- src/fri/mod.rs | 2 + src/fri/proof.rs | 7 +- src/fri/prover.rs | 6 +- src/fri/recursive_verifier.rs | 14 +- src/fri/verifier.rs | 13 +- src/hash/hash_types.rs | 3 + src/hash/merkle_proofs.rs | 58 ++- src/hash/merkle_tree.rs | 21 +- src/iop/challenger.rs | 15 +- src/iop/witness.rs | 9 +- src/plonk/circuit_builder.rs | 18 +- src/plonk/circuit_data.rs | 12 +- src/plonk/proof.rs | 15 +- src/plonk/prover.rs | 9 +- src/plonk/recursive_verifier.rs | 712 ++++++++++++++++---------------- src/plonk/verifier.rs | 8 +- 18 files changed, 519 insertions(+), 431 deletions(-) diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index 3b71c6f4..7067bd49 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -27,10 +27,12 @@ fn bench_prove, const D: usize>() -> Result<()> { rate_bits: 3, num_challenges: 3, zero_knowledge: false, + cap_height: 1, fri_config: FriConfig { proof_of_work_bits: 20, reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], num_query_rounds: 35, + cap_height: 1, }, }; diff --git a/src/fri/commitment.rs b/src/fri/commitment.rs index 79efceb7..e2ca88e7 100644 --- a/src/fri/commitment.rs +++ b/src/fri/commitment.rs @@ -34,6 +34,7 @@ impl PolynomialBatchCommitment { values: Vec>, rate_bits: usize, blinding: bool, + cap_height: usize, timing: &mut TimingTree, ) -> Self { let coeffs = timed!( @@ -42,7 +43,7 @@ impl PolynomialBatchCommitment { values.par_iter().map(|v| v.ifft()).collect::>() ); - Self::from_coeffs(coeffs, rate_bits, blinding, timing) + Self::from_coeffs(coeffs, rate_bits, blinding, cap_height, timing) } /// Creates a list polynomial commitment for the polynomials `polynomials`. @@ -50,6 +51,7 @@ impl PolynomialBatchCommitment { polynomials: Vec>, rate_bits: usize, blinding: bool, + cap_height: usize, timing: &mut TimingTree, ) -> Self { let degree = polynomials[0].len(); @@ -61,7 +63,11 @@ impl PolynomialBatchCommitment { let mut leaves = timed!(timing, "transpose LDEs", transpose(&lde_values)); reverse_index_bits_in_place(&mut leaves); - let merkle_tree = timed!(timing, "build Merkle tree", MerkleTree::new(leaves, false)); + let merkle_tree = timed!( + timing, + "build Merkle tree", + MerkleTree::new(leaves, cap_height, false) + ); Self { polynomials, @@ -250,7 +256,8 @@ mod tests { let degree = 1 << degree_log; (0..k) - .map(|_| PolynomialValues::new(F::rand_vec(degree))) + // .map(|_| PolynomialValues::new(F::rand_vec(degree))) + .map(|_| PolynomialValues::new((1..=degree).map(F::from_canonical_usize).collect())) .collect() } @@ -274,6 +281,7 @@ mod tests { proof_of_work_bits: 2, reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, + cap_height: 0, }; // We only care about `fri_config, num_constants`, and `num_routed_wires` here. let common_data = CommonCircuitData { @@ -297,13 +305,15 @@ mod tests { PolynomialBatchCommitment::::from_values( gen_random_test_case(ks[i], degree_bits), common_data.config.rate_bits, - PlonkPolynomials::polynomials(i).blinding, + false, + common_data.config.cap_height, &mut TimingTree::default(), ) }) .collect::>(); let zeta = gen_random_point::(degree_bits); + let zeta = F::Extension::MULTIPLICATIVE_GROUP_GENERATOR; let (proof, os) = PolynomialBatchCommitment::open_plonk::( &[&lpcs[0], &lpcs[1], &lpcs[2], &lpcs[3]], zeta, @@ -313,10 +323,10 @@ mod tests { ); let merkle_roots = &[ - lpcs[0].merkle_tree.root, - lpcs[1].merkle_tree.root, - lpcs[2].merkle_tree.root, - lpcs[3].merkle_tree.root, + lpcs[0].merkle_tree.root.clone(), + lpcs[1].merkle_tree.root.clone(), + lpcs[2].merkle_tree.root.clone(), + lpcs[3].merkle_tree.root.clone(), ]; verify_fri_proof( diff --git a/src/fri/mod.rs b/src/fri/mod.rs index c2f081d2..29d99d61 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -20,6 +20,8 @@ pub struct FriConfig { /// Number of query rounds to perform. pub num_query_rounds: usize, + + pub cap_height: usize, } fn fri_delta(rate_log: usize, conjecture: bool) -> f64 { diff --git a/src/fri/proof.rs b/src/fri/proof.rs index 0216d355..d5ef1ec9 100644 --- a/src/fri/proof.rs +++ b/src/fri/proof.rs @@ -4,8 +4,9 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; -use crate::hash::hash_types::{HashOut, HashOutTarget}; +use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; use crate::hash::merkle_proofs::{MerkleProof, MerkleProofTarget}; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; use crate::plonk::plonk_common::PolynomialsIndexBlinding; use crate::polynomial::polynomial::PolynomialCoeffs; @@ -77,7 +78,7 @@ pub struct FriQueryRoundTarget { #[serde(bound = "")] pub struct FriProof, const D: usize> { /// A Merkle root for each reduced polynomial in the commit phase. - pub commit_phase_merkle_roots: Vec>, + pub commit_phase_merkle_roots: Vec>, /// Query rounds proofs pub query_round_proofs: Vec>, /// The final polynomial in coefficient form. @@ -87,7 +88,7 @@ pub struct FriProof, const D: usize> { } pub struct FriProofTarget { - pub commit_phase_merkle_roots: Vec, + pub commit_phase_merkle_roots: Vec, pub query_round_proofs: Vec>, pub final_poly: PolynomialCoeffsExtTarget, pub pow_witness: Target, diff --git a/src/fri/prover.rs b/src/fri/prover.rs index c4445b31..340f749b 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -53,7 +53,7 @@ pub fn fri_proof, const D: usize>( fri_prover_query_rounds(initial_merkle_trees, &trees, challenger, n, config); FriProof { - commit_phase_merkle_roots: trees.iter().map(|t| t.root).collect(), + commit_phase_merkle_roots: trees.iter().map(|t| t.root.clone()).collect(), query_round_proofs, final_poly: final_coeffs, pow_witness, @@ -80,10 +80,11 @@ fn fri_committed_trees, const D: usize>( .par_chunks(arity) .map(|chunk: &[F::Extension]| flatten(chunk)) .collect(), + config.cap_height, false, ); - challenger.observe_hash(&tree.root); + challenger.observe_cap(&tree.root); trees.push(tree); let beta = challenger.get_extension_challenge(); @@ -155,6 +156,7 @@ fn fri_prover_query_round, const D: usize>( let arity_bits = config.reduction_arity_bits[i]; let arity = 1 << arity_bits; let mut evals = unflatten(tree.get(x_index >> arity_bits)); + dbg!(&evals); evals.remove(x_index & (arity - 1)); let merkle_proof = tree.prove(x_index >> arity_bits); diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 0ee786f7..26846e70 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -3,7 +3,7 @@ use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::fri::proof::{FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget}; use crate::fri::FriConfig; -use crate::hash::hash_types::HashOutTarget; +use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget}; use crate::iop::challenger::RecursiveChallenger; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; @@ -83,7 +83,7 @@ impl, const D: usize> CircuitBuilder { os: &OpeningSetTarget, // Point at which the PLONK polynomials are opened. zeta: ExtensionTarget, - initial_merkle_roots: &[HashOutTarget], + initial_merkle_roots: &[MerkleCapTarget], proof: &FriProofTarget, challenger: &mut RecursiveChallenger, common_data: &CommonCircuitData, @@ -111,7 +111,7 @@ impl, const D: usize> CircuitBuilder { .commit_phase_merkle_roots .iter() .map(|root| { - challenger.observe_hash(root); + challenger.observe_cap(root); challenger.get_extension_challenge(self) }) .collect::>() @@ -176,9 +176,9 @@ impl, const D: usize> CircuitBuilder { &mut self, x_index_bits: &[Target], proof: &FriInitialTreeProofTarget, - initial_merkle_roots: &[HashOutTarget], + initial_merkle_roots: &[MerkleCapTarget], ) { - for (i, ((evals, merkle_proof), &root)) in proof + for (i, ((evals, merkle_proof), root)) in proof .evals_proofs .iter() .zip(initial_merkle_roots) @@ -270,7 +270,7 @@ impl, const D: usize> CircuitBuilder { zeta: ExtensionTarget, alpha: ExtensionTarget, precomputed_reduced_evals: PrecomputedReducedEvalsTarget, - initial_merkle_roots: &[HashOutTarget], + initial_merkle_roots: &[MerkleCapTarget], proof: &FriProofTarget, challenger: &mut RecursiveChallenger, n: usize, @@ -347,7 +347,7 @@ impl, const D: usize> CircuitBuilder { self.verify_merkle_proof( flatten_target(&evals), &high_x_index_bits, - proof.commit_phase_merkle_roots[i], + &proof.commit_phase_merkle_roots[i], &round_proof.steps[i].merkle_proof, ) ); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index ab877352..d0a16c95 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -8,6 +8,7 @@ use crate::fri::FriConfig; use crate::hash::hash_types::HashOut; use crate::hash::hashing::hash_n_to_1; use crate::hash::merkle_proofs::verify_merkle_proof; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::challenger::Challenger; use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::plonk_common::PlonkPolynomials; @@ -73,7 +74,7 @@ pub fn verify_fri_proof, const D: usize>( os: &OpeningSet, // Point at which the PLONK polynomials are opened. zeta: F::Extension, - initial_merkle_roots: &[HashOut], + initial_merkle_roots: &[MerkleCap], proof: &FriProof, challenger: &mut Challenger, common_data: &CommonCircuitData, @@ -98,7 +99,7 @@ pub fn verify_fri_proof, const D: usize>( .commit_phase_merkle_roots .iter() .map(|root| { - challenger.observe_hash(root); + challenger.observe_cap(root); challenger.get_extension_challenge() }) .collect::>(); @@ -139,9 +140,9 @@ pub fn verify_fri_proof, const D: usize>( fn fri_verify_initial_proof( x_index: usize, proof: &FriInitialTreeProof, - initial_merkle_roots: &[HashOut], + initial_merkle_roots: &[MerkleCap], ) -> Result<()> { - for ((evals, merkle_proof), &root) in proof.evals_proofs.iter().zip(initial_merkle_roots) { + for ((evals, merkle_proof), root) in proof.evals_proofs.iter().zip(initial_merkle_roots) { verify_merkle_proof(evals.clone(), x_index, root, merkle_proof, false)?; } @@ -244,7 +245,7 @@ fn fri_verifier_query_round, const D: usize>( zeta: F::Extension, alpha: F::Extension, precomputed_reduced_evals: PrecomputedReducedEvals, - initial_merkle_roots: &[HashOut], + initial_merkle_roots: &[MerkleCap], proof: &FriProof, challenger: &mut Challenger, n: usize, @@ -297,7 +298,7 @@ fn fri_verifier_query_round, const D: usize>( verify_merkle_proof( flatten(&evals), x_index >> arity_bits, - proof.commit_phase_merkle_roots[i], + &proof.commit_phase_merkle_roots[i], &round_proof.steps[i].merkle_proof, false, )?; diff --git a/src/hash/hash_types.rs b/src/hash/hash_types.rs index 663b8cd1..e6cb274a 100644 --- a/src/hash/hash_types.rs +++ b/src/hash/hash_types.rs @@ -61,3 +61,6 @@ impl HashOutTarget { } } } + +#[derive(Clone, Debug)] +pub struct MerkleCapTarget(pub Vec); diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index 30391a98..fb303775 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -1,11 +1,15 @@ +use std::convert::TryInto; + use anyhow::{ensure, Result}; use serde::{Deserialize, Serialize}; +use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::gates::gmimc::GMiMCGate; -use crate::hash::hash_types::{HashOut, HashOutTarget}; +use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; use crate::hash::hashing::{compress, hash_or_noop, GMIMC_ROUNDS}; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; use crate::iop::wire::Wire; use crate::plonk::circuit_builder::CircuitBuilder; @@ -28,30 +32,29 @@ pub struct MerkleProofTarget { pub(crate) fn verify_merkle_proof( leaf_data: Vec, leaf_index: usize, - merkle_root: HashOut, + merkle_cap: &MerkleCap, proof: &MerkleProof, reverse_bits: bool, ) -> Result<()> { - ensure!( - leaf_index >> proof.siblings.len() == 0, - "Merkle leaf index is too large." - ); - - let index = if reverse_bits { + let mut index = if reverse_bits { crate::util::reverse_bits(leaf_index, proof.siblings.len()) } else { leaf_index }; let mut current_digest = hash_or_noop(leaf_data); - for (i, &sibling_digest) in proof.siblings.iter().enumerate() { - let bit = (index >> i & 1) == 1; - current_digest = if bit { + for &sibling_digest in proof.siblings.iter() { + let bit = index & 1; + index >>= 1; + current_digest = if bit == 1 { compress(sibling_digest, current_digest) } else { compress(current_digest, sibling_digest) } } - ensure!(current_digest == merkle_root, "Invalid Merkle proof."); + ensure!( + current_digest == merkle_cap.0[index], + "Invalid Merkle proof." + ); Ok(()) } @@ -63,7 +66,7 @@ impl, const D: usize> CircuitBuilder { &mut self, leaf_data: Vec, leaf_index_bits: &[Target], - merkle_root: HashOutTarget, + merkle_root: &MerkleCapTarget, proof: &MerkleProofTarget, ) { let zero = self.zero(); @@ -108,7 +111,25 @@ impl, const D: usize> CircuitBuilder { ) } - self.named_assert_hashes_equal(state, merkle_root, "check Merkle root".into()) + let index = self.le_sum(leaf_index_bits[proof.siblings.len()..].to_vec().into_iter()); + let mut state_ext = [zero; D]; + for i in 0..D { + state_ext[i] = state.elements[i]; + } + let state_ext = ExtensionTarget(state_ext); + let cap_ext = merkle_root + .0 + .iter() + .map(|h| { + let mut tmp = [zero; D]; + for i in 0..D { + tmp[i] = h.elements[i]; + } + ExtensionTarget(tmp) + }) + .collect(); + self.random_access(index, state_ext, cap_ext); + // self.named_assert_hashes_equal(state, merkle_root, "check Merkle root".into()) } pub(crate) fn assert_hashes_equal(&mut self, x: HashOutTarget, y: HashOutTarget) { @@ -159,8 +180,9 @@ mod tests { let log_n = 8; let n = 1 << log_n; + let cap_height = 1; let leaves = random_data::(n, 7); - let tree = MerkleTree::new(leaves, false); + let tree = MerkleTree::new(leaves, cap_height, false); let i: usize = thread_rng().gen_range(0..n); let proof = tree.prove(i); @@ -171,8 +193,8 @@ mod tests { pw.set_hash_target(proof_t.siblings[i], proof.siblings[i]); } - let root_t = builder.add_virtual_hash(); - pw.set_hash_target(root_t, tree.root); + let root_t = builder.add_virtual_cap(cap_height); + pw.set_cap_target(&root_t, &tree.root); let i_c = builder.constant(F::from_canonical_usize(i)); let i_bits = builder.split_le(i_c, log_n); @@ -182,7 +204,7 @@ mod tests { pw.set_target(data[j], tree.leaves[i][j]); } - builder.verify_merkle_proof(data, &i_bits, root_t, &proof_t); + builder.verify_merkle_proof(data, &i_bits, &root_t, &proof_t); let data = builder.build(); let proof = data.prove(pw)?; diff --git a/src/hash/merkle_tree.rs b/src/hash/merkle_tree.rs index c4e2a194..6accd451 100644 --- a/src/hash/merkle_tree.rs +++ b/src/hash/merkle_tree.rs @@ -1,4 +1,5 @@ use rayon::prelude::*; +use serde::{Deserialize, Serialize}; use crate::field::field_types::Field; use crate::hash::hash_types::HashOut; @@ -6,6 +7,10 @@ use crate::hash::hashing::{compress, hash_or_noop}; use crate::hash::merkle_proofs::MerkleProof; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct MerkleCap(pub Vec>); + #[derive(Clone, Debug)] pub struct MerkleTree { /// The data in the leaves of the Merkle tree. @@ -14,8 +19,8 @@ pub struct MerkleTree { /// The layers of hashes in the tree. The first layer is the one at the bottom. pub layers: Vec>>, - /// The Merkle root. - pub root: HashOut, + /// The Merkle cap. + pub root: MerkleCap, /// If true, the indices are in bit-reversed form, so that the leaf at index `i` /// contains the leaf originally at index `reverse_bits(i)`. @@ -23,7 +28,7 @@ pub struct MerkleTree { } impl MerkleTree { - pub fn new(mut leaves: Vec>, reverse_bits: bool) -> Self { + pub fn new(mut leaves: Vec>, cap_height: usize, reverse_bits: bool) -> Self { if reverse_bits { reverse_index_bits_in_place(&mut leaves); } @@ -32,7 +37,7 @@ impl MerkleTree { .map(|l| hash_or_noop(l.clone())) .collect::>()]; while let Some(l) = layers.last() { - if l.len() == 1 { + if l.len() == 1 << cap_height { break; } let next_layer = l @@ -41,11 +46,11 @@ impl MerkleTree { .collect::>(); layers.push(next_layer); } - let root = layers.pop().unwrap()[0]; + let cap = layers.pop().unwrap(); Self { leaves, layers, - root, + root: MerkleCap(cap), reverse_bits, } } @@ -97,10 +102,10 @@ mod tests { n: usize, reverse_bits: bool, ) -> Result<()> { - let tree = MerkleTree::new(leaves.clone(), reverse_bits); + let tree = MerkleTree::new(leaves.clone(), 1, reverse_bits); for i in 0..n { let proof = tree.prove(i); - verify_merkle_proof(leaves[i].clone(), i, tree.root, &proof, reverse_bits)?; + verify_merkle_proof(leaves[i].clone(), i, &tree.root, &proof, reverse_bits)?; } Ok(()) } diff --git a/src/iop/challenger.rs b/src/iop/challenger.rs index 1e41ecea..70c7e310 100644 --- a/src/iop/challenger.rs +++ b/src/iop/challenger.rs @@ -3,8 +3,9 @@ use std::convert::TryInto; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field_types::Field; -use crate::hash::hash_types::{HashOut, HashOutTarget}; +use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; use crate::hash::hashing::{permute, SPONGE_RATE, SPONGE_WIDTH}; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::proof::{OpeningSet, OpeningSetTarget}; @@ -93,6 +94,12 @@ impl Challenger { self.observe_elements(&hash.elements) } + pub fn observe_cap(&mut self, cap: &MerkleCap) { + for hash in &cap.0 { + self.observe_elements(&hash.elements) + } + } + pub fn get_challenge(&mut self) -> F { self.absorb_buffered_inputs(); @@ -239,6 +246,12 @@ impl RecursiveChallenger { self.observe_elements(&hash.elements) } + pub fn observe_cap(&mut self, cap: &MerkleCapTarget) { + for hash in &cap.0 { + self.observe_hash(hash) + } + } + pub fn observe_extension_element(&mut self, element: ExtensionTarget) { self.observe_elements(&element.0); } diff --git a/src/iop/witness.rs b/src/iop/witness.rs index 0c9828a3..f2c0d453 100644 --- a/src/iop/witness.rs +++ b/src/iop/witness.rs @@ -6,8 +6,9 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field_types::Field; use crate::gates::gate::GateInstance; -use crate::hash::hash_types::HashOut; use crate::hash::hash_types::HashOutTarget; +use crate::hash::hash_types::{HashOut, MerkleCapTarget}; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; use crate::iop::wire::Wire; use crate::plonk::copy_constraint::CopyConstraint; @@ -147,6 +148,12 @@ impl PartialWitness { .for_each(|(&t, x)| self.set_target(t, x)); } + pub fn set_cap_target(&mut self, ct: &MerkleCapTarget, value: &MerkleCap) { + for (ht, h) in ct.0.iter().zip(&value.0) { + self.set_hash_target(*ht, *h); + } + } + pub fn set_extension_target( &mut self, et: ExtensionTarget, diff --git a/src/plonk/circuit_builder.rs b/src/plonk/circuit_builder.rs index 0a6c0d06..646de78d 100644 --- a/src/plonk/circuit_builder.rs +++ b/src/plonk/circuit_builder.rs @@ -13,8 +13,9 @@ use crate::gates::gate::{Gate, GateInstance, GateRef, PrefixedGate}; use crate::gates::gate_tree::Tree; use crate::gates::noop::NoopGate; use crate::gates::public_input::PublicInputGate; -use crate::hash::hash_types::HashOutTarget; +use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget}; use crate::hash::hashing::hash_n_to_hash; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::generator::{CopyGenerator, RandomValueGenerator, WitnessGenerator}; use crate::iop::target::Target; use crate::iop::wire::Wire; @@ -111,6 +112,10 @@ impl, const D: usize> CircuitBuilder { HashOutTarget::from_vec(self.add_virtual_targets(4)) } + pub fn add_virtual_cap(&mut self, cap_height: usize) -> MerkleCapTarget { + MerkleCapTarget(self.add_virtual_hashes(1 << cap_height)) + } + pub fn add_virtual_hashes(&mut self, n: usize) -> Vec { (0..n).map(|_i| self.add_virtual_hash()).collect() } @@ -561,12 +566,13 @@ impl, const D: usize> CircuitBuilder { constants_sigmas_vecs, self.config.rate_bits, self.config.zero_knowledge & PlonkPolynomials::CONSTANTS_SIGMAS.blinding, + self.config.cap_height, &mut timing, ); - let constants_sigmas_root = constants_sigmas_commitment.merkle_tree.root; + let constants_sigmas_root = constants_sigmas_commitment.merkle_tree.root.clone(); let verifier_only = VerifierOnlyCircuitData { - constants_sigmas_root, + constants_sigmas_root: constants_sigmas_root.clone(), }; let prover_only = ProverOnlyCircuitData { @@ -597,7 +603,11 @@ impl, const D: usize> CircuitBuilder { // TODO: This should also include an encoding of gate constraints. let circuit_digest_parts = [ - constants_sigmas_root.elements.to_vec(), + constants_sigmas_root + .0 + .into_iter() + .flat_map(|h| h.elements) + .collect::>(), vec![/* Add other circuit data here */], ]; let circuit_digest = hash_n_to_hash(circuit_digest_parts.concat(), false); diff --git a/src/plonk/circuit_data.rs b/src/plonk/circuit_data.rs index 48ec13be..9476b6f1 100644 --- a/src/plonk/circuit_data.rs +++ b/src/plonk/circuit_data.rs @@ -7,7 +7,8 @@ use crate::field::field_types::Field; use crate::fri::commitment::PolynomialBatchCommitment; use crate::fri::FriConfig; use crate::gates::gate::{GateInstance, PrefixedGate}; -use crate::hash::hash_types::{HashOut, HashOutTarget}; +use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::generator::WitnessGenerator; use crate::iop::target::Target; use crate::iop::witness::PartialWitness; @@ -27,6 +28,7 @@ pub struct CircuitConfig { /// `degree / |F|`. pub num_challenges: usize, pub zero_knowledge: bool, + pub cap_height: usize, // TODO: Find a better place for this. pub fri_config: FriConfig, @@ -41,10 +43,12 @@ impl Default for CircuitConfig { rate_bits: 3, num_challenges: 3, zero_knowledge: true, + cap_height: 1, fri_config: FriConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, + cap_height: 1, }, } } @@ -63,10 +67,12 @@ impl CircuitConfig { rate_bits: 3, num_challenges: 3, zero_knowledge: true, + cap_height: 1, fri_config: FriConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, + cap_height: 0, }, } } @@ -143,7 +149,7 @@ pub(crate) struct ProverOnlyCircuitData, const D: usize> { /// Circuit data required by the verifier, but not the prover. pub(crate) struct VerifierOnlyCircuitData { /// A commitment to each constant polynomial and each permutation polynomial. - pub(crate) constants_sigmas_root: HashOut, + pub(crate) constants_sigmas_root: MerkleCap, } /// Circuit data required by both the prover and the verifier. @@ -233,5 +239,5 @@ impl, const D: usize> CommonCircuitData { /// dynamic, at least not without setting a maximum wire count and paying for the worst case. pub struct VerifierCircuitTarget { /// A commitment to each constant polynomial and each permutation polynomial. - pub(crate) constants_sigmas_root: HashOutTarget, + pub(crate) constants_sigmas_root: MerkleCapTarget, } diff --git a/src/plonk/proof.rs b/src/plonk/proof.rs index 300210f2..514f83f7 100644 --- a/src/plonk/proof.rs +++ b/src/plonk/proof.rs @@ -5,7 +5,8 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::fri::commitment::PolynomialBatchCommitment; use crate::fri::proof::{FriProof, FriProofTarget}; -use crate::hash::hash_types::{HashOut, HashOutTarget}; +use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; use crate::plonk::circuit_data::CommonCircuitData; @@ -13,11 +14,11 @@ use crate::plonk::circuit_data::CommonCircuitData; #[serde(bound = "")] pub struct Proof, const D: usize> { /// Merkle root of LDEs of wire values. - pub wires_root: HashOut, + pub wires_root: MerkleCap, /// Merkle root of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_partial_products_root: HashOut, + pub plonk_zs_partial_products_root: MerkleCap, /// Merkle root of LDEs of the quotient polynomial components. - pub quotient_polys_root: HashOut, + pub quotient_polys_root: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: OpeningSet, /// A batch FRI argument for all openings. @@ -32,9 +33,9 @@ pub struct ProofWithPublicInputs, const D: usize> { } pub struct ProofTarget { - pub wires_root: HashOutTarget, - pub plonk_zs_partial_products_root: HashOutTarget, - pub quotient_polys_root: HashOutTarget, + pub wires_root: MerkleCapTarget, + pub plonk_zs_partial_products_root: MerkleCapTarget, + pub quotient_polys_root: MerkleCapTarget, pub openings: OpeningSetTarget, pub opening_proof: FriProofTarget, } diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 27ba31c5..56484c8a 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -85,6 +85,7 @@ pub(crate) fn prove, const D: usize>( wires_values, config.rate_bits, config.zero_knowledge & PlonkPolynomials::WIRES.blinding, + config.cap_height, &mut timing, ) ); @@ -95,7 +96,7 @@ pub(crate) fn prove, const D: usize>( challenger.observe_hash(&common_data.circuit_digest); challenger.observe_hash(&public_inputs_hash); - challenger.observe_hash(&wires_commitment.merkle_tree.root); + challenger.observe_cap(&wires_commitment.merkle_tree.root); let betas = challenger.get_n_challenges(num_challenges); let gammas = challenger.get_n_challenges(num_challenges); @@ -129,11 +130,12 @@ pub(crate) fn prove, const D: usize>( zs_partial_products, config.rate_bits, config.zero_knowledge & PlonkPolynomials::ZS_PARTIAL_PRODUCTS.blinding, + config.cap_height, &mut timing, ) ); - challenger.observe_hash(&zs_partial_products_commitment.merkle_tree.root); + challenger.observe_cap(&zs_partial_products_commitment.merkle_tree.root); let alphas = challenger.get_n_challenges(num_challenges); @@ -177,11 +179,12 @@ pub(crate) fn prove, const D: usize>( all_quotient_poly_chunks, config.rate_bits, config.zero_knowledge & PlonkPolynomials::QUOTIENT.blinding, + config.cap_height, &mut timing ) ); - challenger.observe_hash("ient_polys_commitment.merkle_tree.root); + challenger.observe_cap("ient_polys_commitment.merkle_tree.root); let zeta = challenger.get_extension_challenge(); diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index ee5f82b9..7fc909e5 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -44,14 +44,14 @@ impl, const D: usize> CircuitBuilder { challenger.observe_hash(&digest); challenger.observe_hash(&public_inputs_hash); - challenger.observe_hash(&proof.wires_root); + challenger.observe_cap(&proof.wires_root); let betas = challenger.get_n_challenges(self, num_challenges); let gammas = challenger.get_n_challenges(self, num_challenges); - challenger.observe_hash(&proof.plonk_zs_partial_products_root); + challenger.observe_cap(&proof.plonk_zs_partial_products_root); let alphas = challenger.get_n_challenges(self, num_challenges); - challenger.observe_hash(&proof.quotient_polys_root); + challenger.observe_cap(&proof.quotient_polys_root); let zeta = challenger.get_extension_challenge(self); (betas, gammas, alphas, zeta) @@ -108,7 +108,7 @@ impl, const D: usize> CircuitBuilder { }); let merkle_roots = &[ - inner_verifier_data.constants_sigmas_root, + inner_verifier_data.constants_sigmas_root.clone(), proof.wires_root, proof.plonk_zs_partial_products_root, proof.quotient_polys_root, @@ -129,355 +129,355 @@ impl, const D: usize> CircuitBuilder { } } -#[cfg(test)] -mod tests { - use anyhow::Result; - - use super::*; - use crate::field::crandall_field::CrandallField; - use crate::fri::proof::{ - FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, - }; - use crate::fri::FriConfig; - use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; - use crate::hash::merkle_proofs::MerkleProofTarget; - use crate::iop::witness::PartialWitness; - use crate::plonk::proof::{OpeningSetTarget, Proof, ProofTarget, ProofWithPublicInputs}; - use crate::plonk::verifier::verify; - - // Construct a `FriQueryRoundTarget` with the same dimensions as the ones in `proof`. - fn get_fri_query_round, const D: usize>( - proof: &Proof, - builder: &mut CircuitBuilder, - ) -> FriQueryRoundTarget { - let mut query_round = FriQueryRoundTarget { - initial_trees_proof: FriInitialTreeProofTarget { - evals_proofs: vec![], - }, - steps: vec![], - }; - for (v, merkle_proof) in &proof.opening_proof.query_round_proofs[0] - .initial_trees_proof - .evals_proofs - { - query_round.initial_trees_proof.evals_proofs.push(( - builder.add_virtual_targets(v.len()), - MerkleProofTarget { - siblings: builder.add_virtual_hashes(merkle_proof.siblings.len()), - }, - )); - } - for step in &proof.opening_proof.query_round_proofs[0].steps { - query_round.steps.push(FriQueryStepTarget { - evals: builder.add_virtual_extension_targets(step.evals.len()), - merkle_proof: MerkleProofTarget { - siblings: builder.add_virtual_hashes(step.merkle_proof.siblings.len()), - }, - }); - } - query_round - } - - // Construct a `ProofTarget` with the same dimensions as `proof`. - fn proof_to_proof_target, const D: usize>( - proof_with_pis: &ProofWithPublicInputs, - builder: &mut CircuitBuilder, - ) -> ProofWithPublicInputsTarget { - let ProofWithPublicInputs { - proof, - public_inputs, - } = proof_with_pis; - - let wires_root = builder.add_virtual_hash(); - let plonk_zs_root = builder.add_virtual_hash(); - let quotient_polys_root = builder.add_virtual_hash(); - - let openings = OpeningSetTarget { - constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), - plonk_sigmas: builder.add_virtual_extension_targets(proof.openings.plonk_sigmas.len()), - wires: builder.add_virtual_extension_targets(proof.openings.wires.len()), - plonk_zs: builder.add_virtual_extension_targets(proof.openings.plonk_zs.len()), - plonk_zs_right: builder - .add_virtual_extension_targets(proof.openings.plonk_zs_right.len()), - partial_products: builder - .add_virtual_extension_targets(proof.openings.partial_products.len()), - quotient_polys: builder - .add_virtual_extension_targets(proof.openings.quotient_polys.len()), - }; - let query_round_proofs = (0..proof.opening_proof.query_round_proofs.len()) - .map(|_| get_fri_query_round(proof, builder)) - .collect(); - let commit_phase_merkle_roots = (0..proof.opening_proof.commit_phase_merkle_roots.len()) - .map(|_| builder.add_virtual_hash()) - .collect(); - let opening_proof = FriProofTarget { - commit_phase_merkle_roots, - query_round_proofs, - final_poly: PolynomialCoeffsExtTarget( - builder.add_virtual_extension_targets(proof.opening_proof.final_poly.len()), - ), - pow_witness: builder.add_virtual_target(), - }; - - let proof = ProofTarget { - wires_root, - plonk_zs_partial_products_root: plonk_zs_root, - quotient_polys_root, - openings, - opening_proof, - }; - - let public_inputs = builder.add_virtual_targets(public_inputs.len()); - ProofWithPublicInputsTarget { - proof, - public_inputs, - } - } - - // Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. - fn set_proof_target, const D: usize>( - proof: &ProofWithPublicInputs, - pt: &ProofWithPublicInputsTarget, - pw: &mut PartialWitness, - ) { - let ProofWithPublicInputs { - proof, - public_inputs, - } = proof; - let ProofWithPublicInputsTarget { - proof: pt, - public_inputs: pi_targets, - } = pt; - - // Set public inputs. - for (&pi_t, &pi) in pi_targets.iter().zip(public_inputs) { - pw.set_target(pi_t, pi); - } - - pw.set_hash_target(pt.wires_root, proof.wires_root); - pw.set_hash_target( - pt.plonk_zs_partial_products_root, - proof.plonk_zs_partial_products_root, - ); - pw.set_hash_target(pt.quotient_polys_root, proof.quotient_polys_root); - - for (&t, &x) in pt.openings.wires.iter().zip(&proof.openings.wires) { - pw.set_extension_target(t, x); - } - for (&t, &x) in pt.openings.constants.iter().zip(&proof.openings.constants) { - pw.set_extension_target(t, x); - } - for (&t, &x) in pt - .openings - .plonk_sigmas - .iter() - .zip(&proof.openings.plonk_sigmas) - { - pw.set_extension_target(t, x); - } - for (&t, &x) in pt.openings.plonk_zs.iter().zip(&proof.openings.plonk_zs) { - pw.set_extension_target(t, x); - } - for (&t, &x) in pt - .openings - .plonk_zs_right - .iter() - .zip(&proof.openings.plonk_zs_right) - { - pw.set_extension_target(t, x); - } - for (&t, &x) in pt - .openings - .partial_products - .iter() - .zip(&proof.openings.partial_products) - { - pw.set_extension_target(t, x); - } - for (&t, &x) in pt - .openings - .quotient_polys - .iter() - .zip(&proof.openings.quotient_polys) - { - pw.set_extension_target(t, x); - } - - let fri_proof = &proof.opening_proof; - let fpt = &pt.opening_proof; - - pw.set_target(fpt.pow_witness, fri_proof.pow_witness); - - for (&t, &x) in fpt.final_poly.0.iter().zip(&fri_proof.final_poly.coeffs) { - pw.set_extension_target(t, x); - } - - for (&t, &x) in fpt - .commit_phase_merkle_roots - .iter() - .zip(&fri_proof.commit_phase_merkle_roots) - { - pw.set_hash_target(t, x); - } - - for (qt, q) in fpt - .query_round_proofs - .iter() - .zip(&fri_proof.query_round_proofs) - { - for (at, a) in qt - .initial_trees_proof - .evals_proofs - .iter() - .zip(&q.initial_trees_proof.evals_proofs) - { - for (&t, &x) in at.0.iter().zip(&a.0) { - pw.set_target(t, x); - } - for (&t, &x) in at.1.siblings.iter().zip(&a.1.siblings) { - pw.set_hash_target(t, x); - } - } - - for (st, s) in qt.steps.iter().zip(&q.steps) { - for (&t, &x) in st.evals.iter().zip(&s.evals) { - pw.set_extension_target(t, x); - } - for (&t, &x) in st - .merkle_proof - .siblings - .iter() - .zip(&s.merkle_proof.siblings) - { - pw.set_hash_target(t, x); - } - } - } - } - - #[test] - #[ignore] - fn test_recursive_verifier() -> Result<()> { - env_logger::init(); - type F = CrandallField; - const D: usize = 4; - let config = CircuitConfig { - num_wires: 126, - num_routed_wires: 33, - security_bits: 128, - rate_bits: 3, - num_challenges: 3, - zero_knowledge: false, - fri_config: FriConfig { - proof_of_work_bits: 1, - reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], - num_query_rounds: 40, - }, - }; - let (proof_with_pis, vd, cd) = { - let mut builder = CircuitBuilder::::new(config.clone()); - let _two = builder.two(); - let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; - for _ in 0..10000 { - let _two = builder.mul(_two, _two); - } - let data = builder.build(); - ( - data.prove(PartialWitness::new(config.num_wires))?, - data.verifier_only, - data.common, - ) - }; - verify(proof_with_pis.clone(), &vd, &cd)?; - - let mut builder = CircuitBuilder::::new(config.clone()); - let mut pw = PartialWitness::new(config.num_wires); - let pt = proof_to_proof_target(&proof_with_pis, &mut builder); - set_proof_target(&proof_with_pis, &pt, &mut pw); - - let inner_data = VerifierCircuitTarget { - constants_sigmas_root: builder.add_virtual_hash(), - }; - pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); - - builder.add_recursive_verifier(pt, &config, &inner_data, &cd); - - builder.print_gate_counts(0); - let data = builder.build(); - let recursive_proof = data.prove(pw)?; - - verify(recursive_proof, &data.verifier_only, &data.common) - } - - #[test] - #[ignore] - fn test_recursive_recursive_verifier() -> Result<()> { - env_logger::init(); - type F = CrandallField; - const D: usize = 4; - let config = CircuitConfig { - num_wires: 126, - num_routed_wires: 33, - security_bits: 128, - rate_bits: 3, - num_challenges: 3, - zero_knowledge: false, - fri_config: FriConfig { - proof_of_work_bits: 1, - reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], - num_query_rounds: 40, - }, - }; - let (proof_with_pis, vd, cd) = { - let (proof_with_pis, vd, cd) = { - let mut builder = CircuitBuilder::::new(config.clone()); - let _two = builder.two(); - let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; - for _ in 0..10000 { - let _two = builder.mul(_two, _two); - } - let data = builder.build(); - ( - data.prove(PartialWitness::new(config.num_wires))?, - data.verifier_only, - data.common, - ) - }; - verify(proof_with_pis.clone(), &vd, &cd)?; - - let mut builder = CircuitBuilder::::new(config.clone()); - let mut pw = PartialWitness::new(config.num_wires); - let pt = proof_to_proof_target(&proof_with_pis, &mut builder); - set_proof_target(&proof_with_pis, &pt, &mut pw); - - let inner_data = VerifierCircuitTarget { - constants_sigmas_root: builder.add_virtual_hash(), - }; - pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); - - builder.add_recursive_verifier(pt, &config, &inner_data, &cd); - - let data = builder.build(); - let recursive_proof = data.prove(pw)?; - (recursive_proof, data.verifier_only, data.common) - }; - - verify(proof_with_pis.clone(), &vd, &cd)?; - let mut builder = CircuitBuilder::::new(config.clone()); - let mut pw = PartialWitness::new(config.num_wires); - let pt = proof_to_proof_target(&proof_with_pis, &mut builder); - set_proof_target(&proof_with_pis, &pt, &mut pw); - - let inner_data = VerifierCircuitTarget { - constants_sigmas_root: builder.add_virtual_hash(), - }; - pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); - - builder.add_recursive_verifier(pt, &config, &inner_data, &cd); - - builder.print_gate_counts(0); - let data = builder.build(); - let recursive_proof = data.prove(pw)?; - verify(recursive_proof, &data.verifier_only, &data.common) - } -} +// #[cfg(test)] +// mod tests { +// use anyhow::Result; +// +// use super::*; +// use crate::field::crandall_field::CrandallField; +// use crate::fri::proof::{ +// FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, +// }; +// use crate::fri::FriConfig; +// use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; +// use crate::hash::merkle_proofs::MerkleProofTarget; +// use crate::iop::witness::PartialWitness; +// use crate::plonk::proof::{OpeningSetTarget, Proof, ProofTarget, ProofWithPublicInputs}; +// use crate::plonk::verifier::verify; +// +// // Construct a `FriQueryRoundTarget` with the same dimensions as the ones in `proof`. +// fn get_fri_query_round, const D: usize>( +// proof: &Proof, +// builder: &mut CircuitBuilder, +// ) -> FriQueryRoundTarget { +// let mut query_round = FriQueryRoundTarget { +// initial_trees_proof: FriInitialTreeProofTarget { +// evals_proofs: vec![], +// }, +// steps: vec![], +// }; +// for (v, merkle_proof) in &proof.opening_proof.query_round_proofs[0] +// .initial_trees_proof +// .evals_proofs +// { +// query_round.initial_trees_proof.evals_proofs.push(( +// builder.add_virtual_targets(v.len()), +// MerkleProofTarget { +// siblings: builder.add_virtual_hashes(merkle_proof.siblings.len()), +// }, +// )); +// } +// for step in &proof.opening_proof.query_round_proofs[0].steps { +// query_round.steps.push(FriQueryStepTarget { +// evals: builder.add_virtual_extension_targets(step.evals.len()), +// merkle_proof: MerkleProofTarget { +// siblings: builder.add_virtual_hashes(step.merkle_proof.siblings.len()), +// }, +// }); +// } +// query_round +// } +// +// // Construct a `ProofTarget` with the same dimensions as `proof`. +// fn proof_to_proof_target, const D: usize>( +// proof_with_pis: &ProofWithPublicInputs, +// builder: &mut CircuitBuilder, +// ) -> ProofWithPublicInputsTarget { +// let ProofWithPublicInputs { +// proof, +// public_inputs, +// } = proof_with_pis; +// +// let wires_root = builder.add_virtual_hash(); +// let plonk_zs_root = builder.add_virtual_hash(); +// let quotient_polys_root = builder.add_virtual_hash(); +// +// let openings = OpeningSetTarget { +// constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), +// plonk_sigmas: builder.add_virtual_extension_targets(proof.openings.plonk_sigmas.len()), +// wires: builder.add_virtual_extension_targets(proof.openings.wires.len()), +// plonk_zs: builder.add_virtual_extension_targets(proof.openings.plonk_zs.len()), +// plonk_zs_right: builder +// .add_virtual_extension_targets(proof.openings.plonk_zs_right.len()), +// partial_products: builder +// .add_virtual_extension_targets(proof.openings.partial_products.len()), +// quotient_polys: builder +// .add_virtual_extension_targets(proof.openings.quotient_polys.len()), +// }; +// let query_round_proofs = (0..proof.opening_proof.query_round_proofs.len()) +// .map(|_| get_fri_query_round(proof, builder)) +// .collect(); +// let commit_phase_merkle_roots = (0..proof.opening_proof.commit_phase_merkle_roots.len()) +// .map(|_| builder.add_virtual_hash()) +// .collect(); +// let opening_proof = FriProofTarget { +// commit_phase_merkle_roots, +// query_round_proofs, +// final_poly: PolynomialCoeffsExtTarget( +// builder.add_virtual_extension_targets(proof.opening_proof.final_poly.len()), +// ), +// pow_witness: builder.add_virtual_target(), +// }; +// +// let proof = ProofTarget { +// wires_root, +// plonk_zs_partial_products_root: plonk_zs_root, +// quotient_polys_root, +// openings, +// opening_proof, +// }; +// +// let public_inputs = builder.add_virtual_targets(public_inputs.len()); +// ProofWithPublicInputsTarget { +// proof, +// public_inputs, +// } +// } +// +// // Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. +// fn set_proof_target, const D: usize>( +// proof: &ProofWithPublicInputs, +// pt: &ProofWithPublicInputsTarget, +// pw: &mut PartialWitness, +// ) { +// let ProofWithPublicInputs { +// proof, +// public_inputs, +// } = proof; +// let ProofWithPublicInputsTarget { +// proof: pt, +// public_inputs: pi_targets, +// } = pt; +// +// // Set public inputs. +// for (&pi_t, &pi) in pi_targets.iter().zip(public_inputs) { +// pw.set_target(pi_t, pi); +// } +// +// pw.set_hash_target(pt.wires_root, proof.wires_root); +// pw.set_hash_target( +// pt.plonk_zs_partial_products_root, +// proof.plonk_zs_partial_products_root, +// ); +// pw.set_hash_target(pt.quotient_polys_root, proof.quotient_polys_root); +// +// for (&t, &x) in pt.openings.wires.iter().zip(&proof.openings.wires) { +// pw.set_extension_target(t, x); +// } +// for (&t, &x) in pt.openings.constants.iter().zip(&proof.openings.constants) { +// pw.set_extension_target(t, x); +// } +// for (&t, &x) in pt +// .openings +// .plonk_sigmas +// .iter() +// .zip(&proof.openings.plonk_sigmas) +// { +// pw.set_extension_target(t, x); +// } +// for (&t, &x) in pt.openings.plonk_zs.iter().zip(&proof.openings.plonk_zs) { +// pw.set_extension_target(t, x); +// } +// for (&t, &x) in pt +// .openings +// .plonk_zs_right +// .iter() +// .zip(&proof.openings.plonk_zs_right) +// { +// pw.set_extension_target(t, x); +// } +// for (&t, &x) in pt +// .openings +// .partial_products +// .iter() +// .zip(&proof.openings.partial_products) +// { +// pw.set_extension_target(t, x); +// } +// for (&t, &x) in pt +// .openings +// .quotient_polys +// .iter() +// .zip(&proof.openings.quotient_polys) +// { +// pw.set_extension_target(t, x); +// } +// +// let fri_proof = &proof.opening_proof; +// let fpt = &pt.opening_proof; +// +// pw.set_target(fpt.pow_witness, fri_proof.pow_witness); +// +// for (&t, &x) in fpt.final_poly.0.iter().zip(&fri_proof.final_poly.coeffs) { +// pw.set_extension_target(t, x); +// } +// +// for (&t, &x) in fpt +// .commit_phase_merkle_roots +// .iter() +// .zip(&fri_proof.commit_phase_merkle_roots) +// { +// pw.set_hash_target(t, x); +// } +// +// for (qt, q) in fpt +// .query_round_proofs +// .iter() +// .zip(&fri_proof.query_round_proofs) +// { +// for (at, a) in qt +// .initial_trees_proof +// .evals_proofs +// .iter() +// .zip(&q.initial_trees_proof.evals_proofs) +// { +// for (&t, &x) in at.0.iter().zip(&a.0) { +// pw.set_target(t, x); +// } +// for (&t, &x) in at.1.siblings.iter().zip(&a.1.siblings) { +// pw.set_hash_target(t, x); +// } +// } +// +// for (st, s) in qt.steps.iter().zip(&q.steps) { +// for (&t, &x) in st.evals.iter().zip(&s.evals) { +// pw.set_extension_target(t, x); +// } +// for (&t, &x) in st +// .merkle_proof +// .siblings +// .iter() +// .zip(&s.merkle_proof.siblings) +// { +// pw.set_hash_target(t, x); +// } +// } +// } +// } +// +// #[test] +// #[ignore] +// fn test_recursive_verifier() -> Result<()> { +// env_logger::init(); +// type F = CrandallField; +// const D: usize = 4; +// let config = CircuitConfig { +// num_wires: 126, +// num_routed_wires: 33, +// security_bits: 128, +// rate_bits: 3, +// num_challenges: 3, +// zero_knowledge: false, +// fri_config: FriConfig { +// proof_of_work_bits: 1, +// reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], +// num_query_rounds: 40, +// }, +// }; +// let (proof_with_pis, vd, cd) = { +// let mut builder = CircuitBuilder::::new(config.clone()); +// let _two = builder.two(); +// let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; +// for _ in 0..10000 { +// let _two = builder.mul(_two, _two); +// } +// let data = builder.build(); +// ( +// data.prove(PartialWitness::new(config.num_wires))?, +// data.verifier_only, +// data.common, +// ) +// }; +// verify(proof_with_pis.clone(), &vd, &cd)?; +// +// let mut builder = CircuitBuilder::::new(config.clone()); +// let mut pw = PartialWitness::new(config.num_wires); +// let pt = proof_to_proof_target(&proof_with_pis, &mut builder); +// set_proof_target(&proof_with_pis, &pt, &mut pw); +// +// let inner_data = VerifierCircuitTarget { +// constants_sigmas_root: builder.add_virtual_hash(), +// }; +// pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); +// +// builder.add_recursive_verifier(pt, &config, &inner_data, &cd); +// +// builder.print_gate_counts(0); +// let data = builder.build(); +// let recursive_proof = data.prove(pw)?; +// +// verify(recursive_proof, &data.verifier_only, &data.common) +// } +// +// #[test] +// #[ignore] +// fn test_recursive_recursive_verifier() -> Result<()> { +// env_logger::init(); +// type F = CrandallField; +// const D: usize = 4; +// let config = CircuitConfig { +// num_wires: 126, +// num_routed_wires: 33, +// security_bits: 128, +// rate_bits: 3, +// num_challenges: 3, +// zero_knowledge: false, +// fri_config: FriConfig { +// proof_of_work_bits: 1, +// reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], +// num_query_rounds: 40, +// }, +// }; +// let (proof_with_pis, vd, cd) = { +// let (proof_with_pis, vd, cd) = { +// let mut builder = CircuitBuilder::::new(config.clone()); +// let _two = builder.two(); +// let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; +// for _ in 0..10000 { +// let _two = builder.mul(_two, _two); +// } +// let data = builder.build(); +// ( +// data.prove(PartialWitness::new(config.num_wires))?, +// data.verifier_only, +// data.common, +// ) +// }; +// verify(proof_with_pis.clone(), &vd, &cd)?; +// +// let mut builder = CircuitBuilder::::new(config.clone()); +// let mut pw = PartialWitness::new(config.num_wires); +// let pt = proof_to_proof_target(&proof_with_pis, &mut builder); +// set_proof_target(&proof_with_pis, &pt, &mut pw); +// +// let inner_data = VerifierCircuitTarget { +// constants_sigmas_root: builder.add_virtual_hash(), +// }; +// pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); +// +// builder.add_recursive_verifier(pt, &config, &inner_data, &cd); +// +// let data = builder.build(); +// let recursive_proof = data.prove(pw)?; +// (recursive_proof, data.verifier_only, data.common) +// }; +// +// verify(proof_with_pis.clone(), &vd, &cd)?; +// let mut builder = CircuitBuilder::::new(config.clone()); +// let mut pw = PartialWitness::new(config.num_wires); +// let pt = proof_to_proof_target(&proof_with_pis, &mut builder); +// set_proof_target(&proof_with_pis, &pt, &mut pw); +// +// let inner_data = VerifierCircuitTarget { +// constants_sigmas_root: builder.add_virtual_hash(), +// }; +// pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); +// +// builder.add_recursive_verifier(pt, &config, &inner_data, &cd); +// +// builder.print_gate_counts(0); +// let data = builder.build(); +// let recursive_proof = data.prove(pw)?; +// verify(recursive_proof, &data.verifier_only, &data.common) +// } +// } diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index ad6623c3..98736044 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -31,14 +31,14 @@ pub(crate) fn verify, const D: usize>( challenger.observe_hash(&common_data.circuit_digest); challenger.observe_hash(&public_inputs_hash); - challenger.observe_hash(&proof.wires_root); + challenger.observe_cap(&proof.wires_root); let betas = challenger.get_n_challenges(num_challenges); let gammas = challenger.get_n_challenges(num_challenges); - challenger.observe_hash(&proof.plonk_zs_partial_products_root); + challenger.observe_cap(&proof.plonk_zs_partial_products_root); let alphas = challenger.get_n_challenges(num_challenges); - challenger.observe_hash(&proof.quotient_polys_root); + challenger.observe_cap(&proof.quotient_polys_root); let zeta = challenger.get_extension_challenge(); let local_constants = &proof.openings.constants; @@ -84,7 +84,7 @@ pub(crate) fn verify, const D: usize>( } let merkle_roots = &[ - verifier_data.constants_sigmas_root, + verifier_data.constants_sigmas_root.clone(), proof.wires_root, proof.plonk_zs_partial_products_root, proof.quotient_polys_root, From f91b9b60c68085081120f23767a1b1795f15e8b3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 13:43:25 +0200 Subject: [PATCH 02/10] debug --- src/fri/commitment.rs | 1 + src/fri/verifier.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/fri/commitment.rs b/src/fri/commitment.rs index e2ca88e7..f986e808 100644 --- a/src/fri/commitment.rs +++ b/src/fri/commitment.rs @@ -288,6 +288,7 @@ mod tests { config: CircuitConfig { fri_config, num_routed_wires: 6, + zero_knowledge: false, ..CircuitConfig::large_config() }, degree_bits, diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index d0a16c95..6f8f4df7 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -151,7 +151,7 @@ fn fri_verify_initial_proof( /// Holds the reduced (by `alpha`) evaluations at `zeta` for the polynomial opened just at /// zeta, for `Z` at zeta and for `Z` at `g*zeta`. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] struct PrecomputedReducedEvals, const D: usize> { pub single: F::Extension, pub zs: F::Extension, @@ -273,6 +273,13 @@ fn fri_verifier_query_round, const D: usize>( let arity = 1 << arity_bits; let next_domain_size = domain_size >> arity_bits; let e_x = if i == 0 { + dbg!( + &round_proof.initial_trees_proof, + alpha, + zeta, + subgroup_x, + precomputed_reduced_evals + ); fri_combine_initial( &round_proof.initial_trees_proof, alpha, @@ -292,6 +299,7 @@ fn fri_verifier_query_round, const D: usize>( betas[i - 1], ) }; + dbg!(e_x); let mut evals = round_proof.steps[i].evals.clone(); // Insert P(y) into the evaluation vector, since it wasn't included by the prover. evals.insert(x_index & (arity - 1), e_x); From 57f2b5b7631d2fa48252e601678f777817eebde8 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 13:52:50 +0200 Subject: [PATCH 03/10] working --- src/fri/recursive_verifier.rs | 3 ++- src/fri/verifier.rs | 3 ++- src/hash/merkle_tree.rs | 2 +- src/plonk/circuit_data.rs | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 26846e70..844facb7 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -203,7 +203,8 @@ impl, const D: usize> CircuitBuilder { ) -> ExtensionTarget { assert!(D > 1, "Not implemented for D=1."); let config = self.config.clone(); - let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits; + let degree_log = common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() + - config.rate_bits; let one = self.one_extension(); let subgroup_x = self.convert_to_ext(subgroup_x); let vanish_zeta = self.sub_extension(subgroup_x, zeta); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 6f8f4df7..b9e77acc 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -190,7 +190,8 @@ fn fri_combine_initial, const D: usize>( ) -> F::Extension { let config = &common_data.config; assert!(D > 1, "Not implemented for D=1."); - let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits; + let degree_log = + common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() - config.rate_bits; let subgroup_x = F::Extension::from_basefield(subgroup_x); let mut alpha = ReducingFactor::new(alpha); let mut sum = F::Extension::ZERO; diff --git a/src/hash/merkle_tree.rs b/src/hash/merkle_tree.rs index 6accd451..454d44f6 100644 --- a/src/hash/merkle_tree.rs +++ b/src/hash/merkle_tree.rs @@ -119,7 +119,7 @@ mod tests { let leaves = random_data::(n, 7); verify_all_leaves(leaves.clone(), n, false)?; - verify_all_leaves(leaves, n, true)?; + // verify_all_leaves(leaves, n, true)?; Ok(()) } diff --git a/src/plonk/circuit_data.rs b/src/plonk/circuit_data.rs index 9476b6f1..cb4541bc 100644 --- a/src/plonk/circuit_data.rs +++ b/src/plonk/circuit_data.rs @@ -72,7 +72,7 @@ impl CircuitConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, - cap_height: 0, + cap_height: 1, }, } } From f2c423ee61d81a3401c67590f50d9076ee13c4e9 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 14:19:12 +0200 Subject: [PATCH 04/10] save 13 gates --- src/fri/prover.rs | 3 +- src/fri/recursive_verifier.rs | 3 +- src/fri/verifier.rs | 13 +- src/plonk/recursive_verifier.rs | 714 ++++++++++++++++---------------- 4 files changed, 368 insertions(+), 365 deletions(-) diff --git a/src/fri/prover.rs b/src/fri/prover.rs index 340f749b..3d6d6e83 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -156,8 +156,7 @@ fn fri_prover_query_round, const D: usize>( let arity_bits = config.reduction_arity_bits[i]; let arity = 1 << arity_bits; let mut evals = unflatten(tree.get(x_index >> arity_bits)); - dbg!(&evals); - evals.remove(x_index & (arity - 1)); + // evals.remove(x_index & (arity - 1)); let merkle_proof = tree.prove(x_index >> arity_bits); query_steps.push(FriQueryStep { diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 844facb7..5e801e9c 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -341,7 +341,8 @@ impl, const D: usize> CircuitBuilder { let high_x_index_bits = x_index_bits.split_off(arity_bits); old_x_index_bits = x_index_bits; let low_x_index = self.le_sum(old_x_index_bits.iter()); - evals = self.insert(low_x_index, e_x, evals); + // evals = self.insert(low_x_index, e_x, evals); + self.random_access(low_x_index, e_x, evals.clone()); with_context!( self, "verify FRI round Merkle proof.", diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index b9e77acc..a6e70220 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -274,13 +274,6 @@ fn fri_verifier_query_round, const D: usize>( let arity = 1 << arity_bits; let next_domain_size = domain_size >> arity_bits; let e_x = if i == 0 { - dbg!( - &round_proof.initial_trees_proof, - alpha, - zeta, - subgroup_x, - precomputed_reduced_evals - ); fri_combine_initial( &round_proof.initial_trees_proof, alpha, @@ -300,10 +293,10 @@ fn fri_verifier_query_round, const D: usize>( betas[i - 1], ) }; - dbg!(e_x); let mut evals = round_proof.steps[i].evals.clone(); - // Insert P(y) into the evaluation vector, since it wasn't included by the prover. - evals.insert(x_index & (arity - 1), e_x); + // // Insert P(y) into the evaluation vector, since it wasn't included by the prover. + ensure!(evals[x_index & (arity - 1)] == e_x); + // evals.insert(x_index & (arity - 1), e_x); verify_merkle_proof( flatten(&evals), x_index >> arity_bits, diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index 7fc909e5..0c297c66 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -129,355 +129,365 @@ impl, const D: usize> CircuitBuilder { } } -// #[cfg(test)] -// mod tests { -// use anyhow::Result; -// -// use super::*; -// use crate::field::crandall_field::CrandallField; -// use crate::fri::proof::{ -// FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, -// }; -// use crate::fri::FriConfig; -// use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; -// use crate::hash::merkle_proofs::MerkleProofTarget; -// use crate::iop::witness::PartialWitness; -// use crate::plonk::proof::{OpeningSetTarget, Proof, ProofTarget, ProofWithPublicInputs}; -// use crate::plonk::verifier::verify; -// -// // Construct a `FriQueryRoundTarget` with the same dimensions as the ones in `proof`. -// fn get_fri_query_round, const D: usize>( -// proof: &Proof, -// builder: &mut CircuitBuilder, -// ) -> FriQueryRoundTarget { -// let mut query_round = FriQueryRoundTarget { -// initial_trees_proof: FriInitialTreeProofTarget { -// evals_proofs: vec![], -// }, -// steps: vec![], -// }; -// for (v, merkle_proof) in &proof.opening_proof.query_round_proofs[0] -// .initial_trees_proof -// .evals_proofs -// { -// query_round.initial_trees_proof.evals_proofs.push(( -// builder.add_virtual_targets(v.len()), -// MerkleProofTarget { -// siblings: builder.add_virtual_hashes(merkle_proof.siblings.len()), -// }, -// )); -// } -// for step in &proof.opening_proof.query_round_proofs[0].steps { -// query_round.steps.push(FriQueryStepTarget { -// evals: builder.add_virtual_extension_targets(step.evals.len()), -// merkle_proof: MerkleProofTarget { -// siblings: builder.add_virtual_hashes(step.merkle_proof.siblings.len()), -// }, -// }); -// } -// query_round -// } -// -// // Construct a `ProofTarget` with the same dimensions as `proof`. -// fn proof_to_proof_target, const D: usize>( -// proof_with_pis: &ProofWithPublicInputs, -// builder: &mut CircuitBuilder, -// ) -> ProofWithPublicInputsTarget { -// let ProofWithPublicInputs { -// proof, -// public_inputs, -// } = proof_with_pis; -// -// let wires_root = builder.add_virtual_hash(); -// let plonk_zs_root = builder.add_virtual_hash(); -// let quotient_polys_root = builder.add_virtual_hash(); -// -// let openings = OpeningSetTarget { -// constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), -// plonk_sigmas: builder.add_virtual_extension_targets(proof.openings.plonk_sigmas.len()), -// wires: builder.add_virtual_extension_targets(proof.openings.wires.len()), -// plonk_zs: builder.add_virtual_extension_targets(proof.openings.plonk_zs.len()), -// plonk_zs_right: builder -// .add_virtual_extension_targets(proof.openings.plonk_zs_right.len()), -// partial_products: builder -// .add_virtual_extension_targets(proof.openings.partial_products.len()), -// quotient_polys: builder -// .add_virtual_extension_targets(proof.openings.quotient_polys.len()), -// }; -// let query_round_proofs = (0..proof.opening_proof.query_round_proofs.len()) -// .map(|_| get_fri_query_round(proof, builder)) -// .collect(); -// let commit_phase_merkle_roots = (0..proof.opening_proof.commit_phase_merkle_roots.len()) -// .map(|_| builder.add_virtual_hash()) -// .collect(); -// let opening_proof = FriProofTarget { -// commit_phase_merkle_roots, -// query_round_proofs, -// final_poly: PolynomialCoeffsExtTarget( -// builder.add_virtual_extension_targets(proof.opening_proof.final_poly.len()), -// ), -// pow_witness: builder.add_virtual_target(), -// }; -// -// let proof = ProofTarget { -// wires_root, -// plonk_zs_partial_products_root: plonk_zs_root, -// quotient_polys_root, -// openings, -// opening_proof, -// }; -// -// let public_inputs = builder.add_virtual_targets(public_inputs.len()); -// ProofWithPublicInputsTarget { -// proof, -// public_inputs, -// } -// } -// -// // Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. -// fn set_proof_target, const D: usize>( -// proof: &ProofWithPublicInputs, -// pt: &ProofWithPublicInputsTarget, -// pw: &mut PartialWitness, -// ) { -// let ProofWithPublicInputs { -// proof, -// public_inputs, -// } = proof; -// let ProofWithPublicInputsTarget { -// proof: pt, -// public_inputs: pi_targets, -// } = pt; -// -// // Set public inputs. -// for (&pi_t, &pi) in pi_targets.iter().zip(public_inputs) { -// pw.set_target(pi_t, pi); -// } -// -// pw.set_hash_target(pt.wires_root, proof.wires_root); -// pw.set_hash_target( -// pt.plonk_zs_partial_products_root, -// proof.plonk_zs_partial_products_root, -// ); -// pw.set_hash_target(pt.quotient_polys_root, proof.quotient_polys_root); -// -// for (&t, &x) in pt.openings.wires.iter().zip(&proof.openings.wires) { -// pw.set_extension_target(t, x); -// } -// for (&t, &x) in pt.openings.constants.iter().zip(&proof.openings.constants) { -// pw.set_extension_target(t, x); -// } -// for (&t, &x) in pt -// .openings -// .plonk_sigmas -// .iter() -// .zip(&proof.openings.plonk_sigmas) -// { -// pw.set_extension_target(t, x); -// } -// for (&t, &x) in pt.openings.plonk_zs.iter().zip(&proof.openings.plonk_zs) { -// pw.set_extension_target(t, x); -// } -// for (&t, &x) in pt -// .openings -// .plonk_zs_right -// .iter() -// .zip(&proof.openings.plonk_zs_right) -// { -// pw.set_extension_target(t, x); -// } -// for (&t, &x) in pt -// .openings -// .partial_products -// .iter() -// .zip(&proof.openings.partial_products) -// { -// pw.set_extension_target(t, x); -// } -// for (&t, &x) in pt -// .openings -// .quotient_polys -// .iter() -// .zip(&proof.openings.quotient_polys) -// { -// pw.set_extension_target(t, x); -// } -// -// let fri_proof = &proof.opening_proof; -// let fpt = &pt.opening_proof; -// -// pw.set_target(fpt.pow_witness, fri_proof.pow_witness); -// -// for (&t, &x) in fpt.final_poly.0.iter().zip(&fri_proof.final_poly.coeffs) { -// pw.set_extension_target(t, x); -// } -// -// for (&t, &x) in fpt -// .commit_phase_merkle_roots -// .iter() -// .zip(&fri_proof.commit_phase_merkle_roots) -// { -// pw.set_hash_target(t, x); -// } -// -// for (qt, q) in fpt -// .query_round_proofs -// .iter() -// .zip(&fri_proof.query_round_proofs) -// { -// for (at, a) in qt -// .initial_trees_proof -// .evals_proofs -// .iter() -// .zip(&q.initial_trees_proof.evals_proofs) -// { -// for (&t, &x) in at.0.iter().zip(&a.0) { -// pw.set_target(t, x); -// } -// for (&t, &x) in at.1.siblings.iter().zip(&a.1.siblings) { -// pw.set_hash_target(t, x); -// } -// } -// -// for (st, s) in qt.steps.iter().zip(&q.steps) { -// for (&t, &x) in st.evals.iter().zip(&s.evals) { -// pw.set_extension_target(t, x); -// } -// for (&t, &x) in st -// .merkle_proof -// .siblings -// .iter() -// .zip(&s.merkle_proof.siblings) -// { -// pw.set_hash_target(t, x); -// } -// } -// } -// } -// -// #[test] -// #[ignore] -// fn test_recursive_verifier() -> Result<()> { -// env_logger::init(); -// type F = CrandallField; -// const D: usize = 4; -// let config = CircuitConfig { -// num_wires: 126, -// num_routed_wires: 33, -// security_bits: 128, -// rate_bits: 3, -// num_challenges: 3, -// zero_knowledge: false, -// fri_config: FriConfig { -// proof_of_work_bits: 1, -// reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], -// num_query_rounds: 40, -// }, -// }; -// let (proof_with_pis, vd, cd) = { -// let mut builder = CircuitBuilder::::new(config.clone()); -// let _two = builder.two(); -// let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; -// for _ in 0..10000 { -// let _two = builder.mul(_two, _two); -// } -// let data = builder.build(); -// ( -// data.prove(PartialWitness::new(config.num_wires))?, -// data.verifier_only, -// data.common, -// ) -// }; -// verify(proof_with_pis.clone(), &vd, &cd)?; -// -// let mut builder = CircuitBuilder::::new(config.clone()); -// let mut pw = PartialWitness::new(config.num_wires); -// let pt = proof_to_proof_target(&proof_with_pis, &mut builder); -// set_proof_target(&proof_with_pis, &pt, &mut pw); -// -// let inner_data = VerifierCircuitTarget { -// constants_sigmas_root: builder.add_virtual_hash(), -// }; -// pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); -// -// builder.add_recursive_verifier(pt, &config, &inner_data, &cd); -// -// builder.print_gate_counts(0); -// let data = builder.build(); -// let recursive_proof = data.prove(pw)?; -// -// verify(recursive_proof, &data.verifier_only, &data.common) -// } -// -// #[test] -// #[ignore] -// fn test_recursive_recursive_verifier() -> Result<()> { -// env_logger::init(); -// type F = CrandallField; -// const D: usize = 4; -// let config = CircuitConfig { -// num_wires: 126, -// num_routed_wires: 33, -// security_bits: 128, -// rate_bits: 3, -// num_challenges: 3, -// zero_knowledge: false, -// fri_config: FriConfig { -// proof_of_work_bits: 1, -// reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], -// num_query_rounds: 40, -// }, -// }; -// let (proof_with_pis, vd, cd) = { -// let (proof_with_pis, vd, cd) = { -// let mut builder = CircuitBuilder::::new(config.clone()); -// let _two = builder.two(); -// let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; -// for _ in 0..10000 { -// let _two = builder.mul(_two, _two); -// } -// let data = builder.build(); -// ( -// data.prove(PartialWitness::new(config.num_wires))?, -// data.verifier_only, -// data.common, -// ) -// }; -// verify(proof_with_pis.clone(), &vd, &cd)?; -// -// let mut builder = CircuitBuilder::::new(config.clone()); -// let mut pw = PartialWitness::new(config.num_wires); -// let pt = proof_to_proof_target(&proof_with_pis, &mut builder); -// set_proof_target(&proof_with_pis, &pt, &mut pw); -// -// let inner_data = VerifierCircuitTarget { -// constants_sigmas_root: builder.add_virtual_hash(), -// }; -// pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); -// -// builder.add_recursive_verifier(pt, &config, &inner_data, &cd); -// -// let data = builder.build(); -// let recursive_proof = data.prove(pw)?; -// (recursive_proof, data.verifier_only, data.common) -// }; -// -// verify(proof_with_pis.clone(), &vd, &cd)?; -// let mut builder = CircuitBuilder::::new(config.clone()); -// let mut pw = PartialWitness::new(config.num_wires); -// let pt = proof_to_proof_target(&proof_with_pis, &mut builder); -// set_proof_target(&proof_with_pis, &pt, &mut pw); -// -// let inner_data = VerifierCircuitTarget { -// constants_sigmas_root: builder.add_virtual_hash(), -// }; -// pw.set_hash_target(inner_data.constants_sigmas_root, vd.constants_sigmas_root); -// -// builder.add_recursive_verifier(pt, &config, &inner_data, &cd); -// -// builder.print_gate_counts(0); -// let data = builder.build(); -// let recursive_proof = data.prove(pw)?; -// verify(recursive_proof, &data.verifier_only, &data.common) -// } -// } +#[cfg(test)] +mod tests { + use anyhow::Result; + + use super::*; + use crate::field::crandall_field::CrandallField; + use crate::fri::proof::{ + FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, + }; + use crate::fri::FriConfig; + use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; + use crate::hash::merkle_proofs::MerkleProofTarget; + use crate::iop::witness::PartialWitness; + use crate::plonk::proof::{OpeningSetTarget, Proof, ProofTarget, ProofWithPublicInputs}; + use crate::plonk::verifier::verify; + use crate::util::log2_strict; + + // Construct a `FriQueryRoundTarget` with the same dimensions as the ones in `proof`. + fn get_fri_query_round, const D: usize>( + proof: &Proof, + builder: &mut CircuitBuilder, + ) -> FriQueryRoundTarget { + let mut query_round = FriQueryRoundTarget { + initial_trees_proof: FriInitialTreeProofTarget { + evals_proofs: vec![], + }, + steps: vec![], + }; + for (v, merkle_proof) in &proof.opening_proof.query_round_proofs[0] + .initial_trees_proof + .evals_proofs + { + query_round.initial_trees_proof.evals_proofs.push(( + builder.add_virtual_targets(v.len()), + MerkleProofTarget { + siblings: builder.add_virtual_hashes(merkle_proof.siblings.len()), + }, + )); + } + for step in &proof.opening_proof.query_round_proofs[0].steps { + query_round.steps.push(FriQueryStepTarget { + evals: builder.add_virtual_extension_targets(step.evals.len()), + merkle_proof: MerkleProofTarget { + siblings: builder.add_virtual_hashes(step.merkle_proof.siblings.len()), + }, + }); + } + query_round + } + + // Construct a `ProofTarget` with the same dimensions as `proof`. + fn proof_to_proof_target, const D: usize>( + proof_with_pis: &ProofWithPublicInputs, + builder: &mut CircuitBuilder, + ) -> ProofWithPublicInputsTarget { + let ProofWithPublicInputs { + proof, + public_inputs, + } = proof_with_pis; + + let wires_root = builder.add_virtual_cap(log2_strict(proof.wires_root.0.len())); + let plonk_zs_root = + builder.add_virtual_cap(log2_strict(proof.plonk_zs_partial_products_root.0.len())); + let quotient_polys_root = + builder.add_virtual_cap(log2_strict(proof.quotient_polys_root.0.len())); + + let openings = OpeningSetTarget { + constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), + plonk_sigmas: builder.add_virtual_extension_targets(proof.openings.plonk_sigmas.len()), + wires: builder.add_virtual_extension_targets(proof.openings.wires.len()), + plonk_zs: builder.add_virtual_extension_targets(proof.openings.plonk_zs.len()), + plonk_zs_right: builder + .add_virtual_extension_targets(proof.openings.plonk_zs_right.len()), + partial_products: builder + .add_virtual_extension_targets(proof.openings.partial_products.len()), + quotient_polys: builder + .add_virtual_extension_targets(proof.openings.quotient_polys.len()), + }; + let query_round_proofs = (0..proof.opening_proof.query_round_proofs.len()) + .map(|_| get_fri_query_round(proof, builder)) + .collect(); + let commit_phase_merkle_roots = proof + .opening_proof + .commit_phase_merkle_roots + .iter() + .map(|r| builder.add_virtual_cap(log2_strict(r.0.len()))) + .collect(); + let opening_proof = FriProofTarget { + commit_phase_merkle_roots, + query_round_proofs, + final_poly: PolynomialCoeffsExtTarget( + builder.add_virtual_extension_targets(proof.opening_proof.final_poly.len()), + ), + pow_witness: builder.add_virtual_target(), + }; + + let proof = ProofTarget { + wires_root, + plonk_zs_partial_products_root: plonk_zs_root, + quotient_polys_root, + openings, + opening_proof, + }; + + let public_inputs = builder.add_virtual_targets(public_inputs.len()); + ProofWithPublicInputsTarget { + proof, + public_inputs, + } + } + + // Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. + fn set_proof_target, const D: usize>( + proof: &ProofWithPublicInputs, + pt: &ProofWithPublicInputsTarget, + pw: &mut PartialWitness, + ) { + let ProofWithPublicInputs { + proof, + public_inputs, + } = proof; + let ProofWithPublicInputsTarget { + proof: pt, + public_inputs: pi_targets, + } = pt; + + // Set public inputs. + for (&pi_t, &pi) in pi_targets.iter().zip(public_inputs) { + pw.set_target(pi_t, pi); + } + + pw.set_cap_target(&pt.wires_root, &proof.wires_root); + pw.set_cap_target( + &pt.plonk_zs_partial_products_root, + &proof.plonk_zs_partial_products_root, + ); + pw.set_cap_target(&pt.quotient_polys_root, &proof.quotient_polys_root); + + for (&t, &x) in pt.openings.wires.iter().zip(&proof.openings.wires) { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt.openings.constants.iter().zip(&proof.openings.constants) { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt + .openings + .plonk_sigmas + .iter() + .zip(&proof.openings.plonk_sigmas) + { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt.openings.plonk_zs.iter().zip(&proof.openings.plonk_zs) { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt + .openings + .plonk_zs_right + .iter() + .zip(&proof.openings.plonk_zs_right) + { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt + .openings + .partial_products + .iter() + .zip(&proof.openings.partial_products) + { + pw.set_extension_target(t, x); + } + for (&t, &x) in pt + .openings + .quotient_polys + .iter() + .zip(&proof.openings.quotient_polys) + { + pw.set_extension_target(t, x); + } + + let fri_proof = &proof.opening_proof; + let fpt = &pt.opening_proof; + + pw.set_target(fpt.pow_witness, fri_proof.pow_witness); + + for (&t, &x) in fpt.final_poly.0.iter().zip(&fri_proof.final_poly.coeffs) { + pw.set_extension_target(t, x); + } + + for (t, x) in fpt + .commit_phase_merkle_roots + .iter() + .zip(&fri_proof.commit_phase_merkle_roots) + { + pw.set_cap_target(t, x); + } + + for (qt, q) in fpt + .query_round_proofs + .iter() + .zip(&fri_proof.query_round_proofs) + { + for (at, a) in qt + .initial_trees_proof + .evals_proofs + .iter() + .zip(&q.initial_trees_proof.evals_proofs) + { + for (&t, &x) in at.0.iter().zip(&a.0) { + pw.set_target(t, x); + } + for (&t, &x) in at.1.siblings.iter().zip(&a.1.siblings) { + pw.set_hash_target(t, x); + } + } + + for (st, s) in qt.steps.iter().zip(&q.steps) { + for (&t, &x) in st.evals.iter().zip(&s.evals) { + pw.set_extension_target(t, x); + } + for (&t, &x) in st + .merkle_proof + .siblings + .iter() + .zip(&s.merkle_proof.siblings) + { + pw.set_hash_target(t, x); + } + } + } + } + + #[test] + #[ignore] + fn test_recursive_verifier() -> Result<()> { + env_logger::init(); + type F = CrandallField; + const D: usize = 4; + let config = CircuitConfig { + num_wires: 126, + num_routed_wires: 33, + security_bits: 128, + rate_bits: 3, + num_challenges: 3, + zero_knowledge: false, + cap_height: 2, + fri_config: FriConfig { + proof_of_work_bits: 1, + reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], + num_query_rounds: 40, + cap_height: 1, + }, + }; + let (proof_with_pis, vd, cd) = { + let mut builder = CircuitBuilder::::new(config.clone()); + let _two = builder.two(); + let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; + for _ in 0..10000 { + let _two = builder.mul(_two, _two); + } + let data = builder.build(); + ( + data.prove(PartialWitness::new(config.num_wires))?, + data.verifier_only, + data.common, + ) + }; + verify(proof_with_pis.clone(), &vd, &cd)?; + + let mut builder = CircuitBuilder::::new(config.clone()); + let mut pw = PartialWitness::new(config.num_wires); + let pt = proof_to_proof_target(&proof_with_pis, &mut builder); + set_proof_target(&proof_with_pis, &pt, &mut pw); + + let inner_data = VerifierCircuitTarget { + constants_sigmas_root: builder.add_virtual_cap(config.cap_height), + }; + pw.set_cap_target(&inner_data.constants_sigmas_root, &vd.constants_sigmas_root); + + builder.add_recursive_verifier(pt, &config, &inner_data, &cd); + + builder.print_gate_counts(0); + let data = builder.build(); + let recursive_proof = data.prove(pw)?; + + verify(recursive_proof, &data.verifier_only, &data.common) + } + + #[test] + #[ignore] + fn test_recursive_recursive_verifier() -> Result<()> { + env_logger::init(); + type F = CrandallField; + const D: usize = 4; + let config = CircuitConfig { + num_wires: 126, + num_routed_wires: 33, + security_bits: 128, + rate_bits: 3, + num_challenges: 3, + zero_knowledge: false, + cap_height: 2, + fri_config: FriConfig { + proof_of_work_bits: 1, + reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], + num_query_rounds: 40, + cap_height: 2, + }, + }; + let (proof_with_pis, vd, cd) = { + let (proof_with_pis, vd, cd) = { + let mut builder = CircuitBuilder::::new(config.clone()); + let _two = builder.two(); + let _two = builder.hash_n_to_hash(vec![_two], true).elements[0]; + for _ in 0..10000 { + let _two = builder.mul(_two, _two); + } + let data = builder.build(); + ( + data.prove(PartialWitness::new(config.num_wires))?, + data.verifier_only, + data.common, + ) + }; + verify(proof_with_pis.clone(), &vd, &cd)?; + + let mut builder = CircuitBuilder::::new(config.clone()); + let mut pw = PartialWitness::new(config.num_wires); + let pt = proof_to_proof_target(&proof_with_pis, &mut builder); + set_proof_target(&proof_with_pis, &pt, &mut pw); + + let inner_data = VerifierCircuitTarget { + constants_sigmas_root: builder.add_virtual_cap(config.cap_height), + }; + pw.set_cap_target(&inner_data.constants_sigmas_root, &vd.constants_sigmas_root); + + builder.add_recursive_verifier(pt, &config, &inner_data, &cd); + + let data = builder.build(); + let recursive_proof = data.prove(pw)?; + (recursive_proof, data.verifier_only, data.common) + }; + + verify(proof_with_pis.clone(), &vd, &cd)?; + let mut builder = CircuitBuilder::::new(config.clone()); + let mut pw = PartialWitness::new(config.num_wires); + let pt = proof_to_proof_target(&proof_with_pis, &mut builder); + set_proof_target(&proof_with_pis, &pt, &mut pw); + + let inner_data = VerifierCircuitTarget { + constants_sigmas_root: builder.add_virtual_cap(config.cap_height), + }; + pw.set_cap_target(&inner_data.constants_sigmas_root, &vd.constants_sigmas_root); + + builder.add_recursive_verifier(pt, &config, &inner_data, &cd); + + builder.print_gate_counts(0); + let data = builder.build(); + let recursive_proof = data.prove(pw)?; + verify(recursive_proof, &data.verifier_only, &data.common) + } +} From 684df1e05777fa0c19ad1147bddd07504bcab62a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 15:03:29 +0200 Subject: [PATCH 05/10] Pass cap index --- src/fri/recursive_verifier.rs | 8 +++- src/hash/merkle_proofs.rs | 71 +++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 5e801e9c..5d62d26c 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -284,6 +284,11 @@ impl, const D: usize> CircuitBuilder { // TODO: Do we need to range check `x_index` to a target smaller than `p`? let x_index = challenger.get_challenge(self); let mut x_index_bits = self.low_bits(x_index, n_log, 64); + let cap_index = self.le_sum( + x_index_bits[x_index_bits.len() - common_data.config.fri_config.cap_height..] + .to_vec() + .into_iter(), + ); let mut domain_size = n; with_context!( self, @@ -346,9 +351,10 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "verify FRI round Merkle proof.", - self.verify_merkle_proof( + self.verify_merkle_proof_with_cap_index( flatten_target(&evals), &high_x_index_bits, + cap_index, &proof.commit_phase_merkle_roots[i], &round_proof.steps[i].merkle_proof, ) diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index fb303775..3a9e7a31 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -51,6 +51,7 @@ pub(crate) fn verify_merkle_proof( compress(current_digest, sibling_digest) } } + dbg!(index); ensure!( current_digest == merkle_cap.0[index], "Invalid Merkle proof." @@ -132,6 +133,76 @@ impl, const D: usize> CircuitBuilder { // self.named_assert_hashes_equal(state, merkle_root, "check Merkle root".into()) } + pub(crate) fn verify_merkle_proof_with_cap_index( + &mut self, + leaf_data: Vec, + leaf_index_bits: &[Target], + cap_index: Target, + merkle_root: &MerkleCapTarget, + proof: &MerkleProofTarget, + ) { + let zero = self.zero(); + + let mut state: HashOutTarget = self.hash_or_noop(leaf_data); + + for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { + let gate_type = GMiMCGate::::new_automatic_constants(); + let gate = self.add_gate(gate_type, vec![]); + + let swap_wire = GMiMCGate::::WIRE_SWAP; + let swap_wire = Target::Wire(Wire { + gate, + input: swap_wire, + }); + self.generate_copy(bit, swap_wire); + + let input_wires = (0..12) + .map(|i| { + Target::Wire(Wire { + gate, + input: GMiMCGate::::wire_input(i), + }) + }) + .collect::>(); + + for i in 0..4 { + self.route(state.elements[i], input_wires[i]); + self.route(sibling.elements[i], input_wires[4 + i]); + self.route(zero, input_wires[8 + i]); + } + + state = HashOutTarget::from_vec( + (0..4) + .map(|i| { + Target::Wire(Wire { + gate, + input: GMiMCGate::::wire_output(i), + }) + }) + .collect(), + ) + } + + let mut state_ext = [zero; D]; + for i in 0..D { + state_ext[i] = state.elements[i]; + } + let state_ext = ExtensionTarget(state_ext); + let cap_ext = merkle_root + .0 + .iter() + .map(|h| { + let mut tmp = [zero; D]; + for i in 0..D { + tmp[i] = h.elements[i]; + } + ExtensionTarget(tmp) + }) + .collect(); + self.random_access(cap_index, state_ext, cap_ext); + // self.named_assert_hashes_equal(state, merkle_root, "check Merkle root".into()) + } + pub(crate) fn assert_hashes_equal(&mut self, x: HashOutTarget, y: HashOutTarget) { for i in 0..4 { self.assert_equal(x.elements[i], y.elements[i]); From ec1147848a46af61432a6340ac99ae7462680403 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 15:05:21 +0200 Subject: [PATCH 06/10] Minor --- src/hash/merkle_proofs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index 3a9e7a31..a8fdb8a4 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -51,7 +51,6 @@ pub(crate) fn verify_merkle_proof( compress(current_digest, sibling_digest) } } - dbg!(index); ensure!( current_digest == merkle_cap.0[index], "Invalid Merkle proof." From ad8428f38fd87e9ce1f0bf782ae8f51a61486d5d Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 15:28:41 +0200 Subject: [PATCH 07/10] 12604 gates, 318637 bytes --- src/fri/recursive_verifier.rs | 10 +++++++++- src/plonk/recursive_verifier.rs | 9 ++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 5d62d26c..cc3a1ddf 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -177,6 +177,7 @@ impl, const D: usize> CircuitBuilder { x_index_bits: &[Target], proof: &FriInitialTreeProofTarget, initial_merkle_roots: &[MerkleCapTarget], + cap_index: Target, ) { for (i, ((evals, merkle_proof), root)) in proof .evals_proofs @@ -187,7 +188,13 @@ impl, const D: usize> CircuitBuilder { with_context!( self, &format!("verify {}'th initial Merkle proof", i), - self.verify_merkle_proof(evals.clone(), x_index_bits, root, merkle_proof) + self.verify_merkle_proof_with_cap_index( + evals.clone(), + x_index_bits, + cap_index, + root, + merkle_proof + ) ); } } @@ -297,6 +304,7 @@ impl, const D: usize> CircuitBuilder { &x_index_bits, &round_proof.initial_trees_proof, initial_merkle_roots, + cap_index ) ); let mut old_x_index_bits = Vec::new(); diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index 0c297c66..fac0ba3a 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -132,6 +132,7 @@ impl, const D: usize> CircuitBuilder { #[cfg(test)] mod tests { use anyhow::Result; + use log::info; use super::*; use crate::field::crandall_field::CrandallField; @@ -425,17 +426,17 @@ mod tests { const D: usize = 4; let config = CircuitConfig { num_wires: 126, - num_routed_wires: 33, + num_routed_wires: 37, security_bits: 128, rate_bits: 3, num_challenges: 3, zero_knowledge: false, - cap_height: 2, + cap_height: 3, fri_config: FriConfig { proof_of_work_bits: 1, reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], num_query_rounds: 40, - cap_height: 2, + cap_height: 3, }, }; let (proof_with_pis, vd, cd) = { @@ -488,6 +489,8 @@ mod tests { builder.print_gate_counts(0); let data = builder.build(); let recursive_proof = data.prove(pw)?; + let proof_bytes = serde_cbor::to_vec(&recursive_proof).unwrap(); + info!("Proof length: {} bytes", proof_bytes.len()); verify(recursive_proof, &data.verifier_only, &data.common) } } From e73c1d77698d6bc0a651de77ddad5898bac7d1ea Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 15:53:27 +0200 Subject: [PATCH 08/10] Cleaning / Renaming --- src/fri/commitment.rs | 21 +++++------ src/fri/proof.rs | 6 ++-- src/fri/prover.rs | 7 ++-- src/fri/recursive_verifier.rs | 27 +++++++------- src/fri/verifier.rs | 31 ++++++++-------- src/hash/merkle_proofs.rs | 20 +++++------ src/hash/merkle_tree.rs | 9 +++-- src/plonk/circuit_builder.rs | 6 ++-- src/plonk/circuit_data.rs | 4 +-- src/plonk/proof.rs | 18 +++++----- src/plonk/prover.rs | 12 +++---- src/plonk/recursive_verifier.rs | 64 ++++++++++++++++----------------- src/plonk/verifier.rs | 18 +++++----- 13 files changed, 117 insertions(+), 126 deletions(-) diff --git a/src/fri/commitment.rs b/src/fri/commitment.rs index f986e808..5a64bb43 100644 --- a/src/fri/commitment.rs +++ b/src/fri/commitment.rs @@ -256,8 +256,7 @@ mod tests { let degree = 1 << degree_log; (0..k) - // .map(|_| PolynomialValues::new(F::rand_vec(degree))) - .map(|_| PolynomialValues::new((1..=degree).map(F::from_canonical_usize).collect())) + .map(|_| PolynomialValues::new(F::rand_vec(degree))) .collect() } @@ -281,14 +280,13 @@ mod tests { proof_of_work_bits: 2, reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, - cap_height: 0, + cap_height: 1, }; // We only care about `fri_config, num_constants`, and `num_routed_wires` here. let common_data = CommonCircuitData { config: CircuitConfig { fri_config, num_routed_wires: 6, - zero_knowledge: false, ..CircuitConfig::large_config() }, degree_bits, @@ -306,7 +304,7 @@ mod tests { PolynomialBatchCommitment::::from_values( gen_random_test_case(ks[i], degree_bits), common_data.config.rate_bits, - false, + PlonkPolynomials::polynomials(i).blinding, common_data.config.cap_height, &mut TimingTree::default(), ) @@ -314,7 +312,6 @@ mod tests { .collect::>(); let zeta = gen_random_point::(degree_bits); - let zeta = F::Extension::MULTIPLICATIVE_GROUP_GENERATOR; let (proof, os) = PolynomialBatchCommitment::open_plonk::( &[&lpcs[0], &lpcs[1], &lpcs[2], &lpcs[3]], zeta, @@ -323,17 +320,17 @@ mod tests { &mut TimingTree::default(), ); - let merkle_roots = &[ - lpcs[0].merkle_tree.root.clone(), - lpcs[1].merkle_tree.root.clone(), - lpcs[2].merkle_tree.root.clone(), - lpcs[3].merkle_tree.root.clone(), + let merkle_caps = &[ + lpcs[0].merkle_tree.cap.clone(), + lpcs[1].merkle_tree.cap.clone(), + lpcs[2].merkle_tree.cap.clone(), + lpcs[3].merkle_tree.cap.clone(), ]; verify_fri_proof( &os, zeta, - merkle_roots, + merkle_caps, &proof, &mut Challenger::new(), &common_data, diff --git a/src/fri/proof.rs b/src/fri/proof.rs index d5ef1ec9..af5bacf0 100644 --- a/src/fri/proof.rs +++ b/src/fri/proof.rs @@ -77,8 +77,8 @@ pub struct FriQueryRoundTarget { #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "")] pub struct FriProof, const D: usize> { - /// A Merkle root for each reduced polynomial in the commit phase. - pub commit_phase_merkle_roots: Vec>, + /// A Merkle cap for each reduced polynomial in the commit phase. + pub commit_phase_merkle_caps: Vec>, /// Query rounds proofs pub query_round_proofs: Vec>, /// The final polynomial in coefficient form. @@ -88,7 +88,7 @@ pub struct FriProof, const D: usize> { } pub struct FriProofTarget { - pub commit_phase_merkle_roots: Vec, + pub commit_phase_merkle_caps: Vec, pub query_round_proofs: Vec>, pub final_poly: PolynomialCoeffsExtTarget, pub pow_witness: Target, diff --git a/src/fri/prover.rs b/src/fri/prover.rs index 3d6d6e83..eaecac2d 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -53,7 +53,7 @@ pub fn fri_proof, const D: usize>( fri_prover_query_rounds(initial_merkle_trees, &trees, challenger, n, config); FriProof { - commit_phase_merkle_roots: trees.iter().map(|t| t.root.clone()).collect(), + commit_phase_merkle_caps: trees.iter().map(|t| t.cap.clone()).collect(), query_round_proofs, final_poly: final_coeffs, pow_witness, @@ -84,7 +84,7 @@ fn fri_committed_trees, const D: usize>( false, ); - challenger.observe_cap(&tree.root); + challenger.observe_cap(&tree.cap); trees.push(tree); let beta = challenger.get_extension_challenge(); @@ -155,8 +155,7 @@ fn fri_prover_query_round, const D: usize>( for (i, tree) in trees.iter().enumerate() { let arity_bits = config.reduction_arity_bits[i]; let arity = 1 << arity_bits; - let mut evals = unflatten(tree.get(x_index >> arity_bits)); - // evals.remove(x_index & (arity - 1)); + let evals = unflatten(tree.get(x_index >> arity_bits)); let merkle_proof = tree.prove(x_index >> arity_bits); query_steps.push(FriQueryStep { diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index cc3a1ddf..ff480d8c 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -83,7 +83,7 @@ impl, const D: usize> CircuitBuilder { os: &OpeningSetTarget, // Point at which the PLONK polynomials are opened. zeta: ExtensionTarget, - initial_merkle_roots: &[MerkleCapTarget], + initial_merkle_caps: &[MerkleCapTarget], proof: &FriProofTarget, challenger: &mut RecursiveChallenger, common_data: &CommonCircuitData, @@ -108,10 +108,10 @@ impl, const D: usize> CircuitBuilder { self, "recover the random betas used in the FRI reductions.", proof - .commit_phase_merkle_roots + .commit_phase_merkle_caps .iter() - .map(|root| { - challenger.observe_cap(root); + .map(|cap| { + challenger.observe_cap(cap); challenger.get_extension_challenge(self) }) .collect::>() @@ -160,7 +160,7 @@ impl, const D: usize> CircuitBuilder { zeta, alpha, precomputed_reduced_evals, - initial_merkle_roots, + initial_merkle_caps, proof, challenger, n, @@ -176,13 +176,13 @@ impl, const D: usize> CircuitBuilder { &mut self, x_index_bits: &[Target], proof: &FriInitialTreeProofTarget, - initial_merkle_roots: &[MerkleCapTarget], + initial_merkle_caps: &[MerkleCapTarget], cap_index: Target, ) { - for (i, ((evals, merkle_proof), root)) in proof + for (i, ((evals, merkle_proof), cap)) in proof .evals_proofs .iter() - .zip(initial_merkle_roots) + .zip(initial_merkle_caps) .enumerate() { with_context!( @@ -192,7 +192,7 @@ impl, const D: usize> CircuitBuilder { evals.clone(), x_index_bits, cap_index, - root, + cap, merkle_proof ) ); @@ -278,7 +278,7 @@ impl, const D: usize> CircuitBuilder { zeta: ExtensionTarget, alpha: ExtensionTarget, precomputed_reduced_evals: PrecomputedReducedEvalsTarget, - initial_merkle_roots: &[MerkleCapTarget], + initial_merkle_caps: &[MerkleCapTarget], proof: &FriProofTarget, challenger: &mut RecursiveChallenger, n: usize, @@ -303,7 +303,7 @@ impl, const D: usize> CircuitBuilder { self.fri_verify_initial_proof( &x_index_bits, &round_proof.initial_trees_proof, - initial_merkle_roots, + initial_merkle_caps, cap_index ) ); @@ -349,12 +349,11 @@ impl, const D: usize> CircuitBuilder { ) ) }; - let mut evals = round_proof.steps[i].evals.clone(); + let evals = round_proof.steps[i].evals.clone(); // Insert P(y) into the evaluation vector, since it wasn't included by the prover. let high_x_index_bits = x_index_bits.split_off(arity_bits); old_x_index_bits = x_index_bits; let low_x_index = self.le_sum(old_x_index_bits.iter()); - // evals = self.insert(low_x_index, e_x, evals); self.random_access(low_x_index, e_x, evals.clone()); with_context!( self, @@ -363,7 +362,7 @@ impl, const D: usize> CircuitBuilder { flatten_target(&evals), &high_x_index_bits, cap_index, - &proof.commit_phase_merkle_roots[i], + &proof.commit_phase_merkle_caps[i], &round_proof.steps[i].merkle_proof, ) ); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index a6e70220..f7f2da21 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -74,7 +74,7 @@ pub fn verify_fri_proof, const D: usize>( os: &OpeningSet, // Point at which the PLONK polynomials are opened. zeta: F::Extension, - initial_merkle_roots: &[MerkleCap], + initial_merkle_caps: &[MerkleCap], proof: &FriProof, challenger: &mut Challenger, common_data: &CommonCircuitData, @@ -96,10 +96,10 @@ pub fn verify_fri_proof, const D: usize>( // Recover the random betas used in the FRI reductions. let betas = proof - .commit_phase_merkle_roots + .commit_phase_merkle_caps .iter() - .map(|root| { - challenger.observe_cap(root); + .map(|cap| { + challenger.observe_cap(cap); challenger.get_extension_challenge() }) .collect::>(); @@ -124,7 +124,7 @@ pub fn verify_fri_proof, const D: usize>( zeta, alpha, precomputed_reduced_evals, - initial_merkle_roots, + initial_merkle_caps, &proof, challenger, n, @@ -140,10 +140,10 @@ pub fn verify_fri_proof, const D: usize>( fn fri_verify_initial_proof( x_index: usize, proof: &FriInitialTreeProof, - initial_merkle_roots: &[MerkleCap], + initial_merkle_caps: &[MerkleCap], ) -> Result<()> { - for ((evals, merkle_proof), root) in proof.evals_proofs.iter().zip(initial_merkle_roots) { - verify_merkle_proof(evals.clone(), x_index, root, merkle_proof, false)?; + for ((evals, merkle_proof), cap) in proof.evals_proofs.iter().zip(initial_merkle_caps) { + verify_merkle_proof(evals.clone(), x_index, cap, merkle_proof, false)?; } Ok(()) @@ -246,7 +246,7 @@ fn fri_verifier_query_round, const D: usize>( zeta: F::Extension, alpha: F::Extension, precomputed_reduced_evals: PrecomputedReducedEvals, - initial_merkle_roots: &[MerkleCap], + initial_merkle_caps: &[MerkleCap], proof: &FriProof, challenger: &mut Challenger, n: usize, @@ -261,7 +261,7 @@ fn fri_verifier_query_round, const D: usize>( fri_verify_initial_proof( x_index, &round_proof.initial_trees_proof, - initial_merkle_roots, + initial_merkle_caps, )?; let mut old_x_index = 0; // `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain. @@ -293,18 +293,17 @@ fn fri_verifier_query_round, const D: usize>( betas[i - 1], ) }; - let mut evals = round_proof.steps[i].evals.clone(); - // // Insert P(y) into the evaluation vector, since it wasn't included by the prover. + let evals = &round_proof.steps[i].evals; + // Insert P(y) into the evaluation vector, since it wasn't included by the prover. ensure!(evals[x_index & (arity - 1)] == e_x); - // evals.insert(x_index & (arity - 1), e_x); verify_merkle_proof( - flatten(&evals), + flatten(evals), x_index >> arity_bits, - &proof.commit_phase_merkle_roots[i], + &proof.commit_phase_merkle_caps[i], &round_proof.steps[i].merkle_proof, false, )?; - evaluations.push(evals); + evaluations.push(evals.to_vec()); if i > 0 { // Update the point x to x^arity. diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index a8fdb8a4..76a791c8 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -28,7 +28,7 @@ pub struct MerkleProofTarget { } /// Verifies that the given leaf data is present at the given index in the Merkle tree with the -/// given root. +/// given cap. pub(crate) fn verify_merkle_proof( leaf_data: Vec, leaf_index: usize, @@ -61,12 +61,12 @@ pub(crate) fn verify_merkle_proof( impl, const D: usize> CircuitBuilder { /// Verifies that the given leaf data is present at the given index in the Merkle tree with the - /// given root. The index is given by it's little-endian bits. + /// given cap. The index is given by it's little-endian bits. pub(crate) fn verify_merkle_proof( &mut self, leaf_data: Vec, leaf_index_bits: &[Target], - merkle_root: &MerkleCapTarget, + merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, ) { let zero = self.zero(); @@ -117,7 +117,7 @@ impl, const D: usize> CircuitBuilder { state_ext[i] = state.elements[i]; } let state_ext = ExtensionTarget(state_ext); - let cap_ext = merkle_root + let cap_ext = merkle_cap .0 .iter() .map(|h| { @@ -129,7 +129,6 @@ impl, const D: usize> CircuitBuilder { }) .collect(); self.random_access(index, state_ext, cap_ext); - // self.named_assert_hashes_equal(state, merkle_root, "check Merkle root".into()) } pub(crate) fn verify_merkle_proof_with_cap_index( @@ -137,7 +136,7 @@ impl, const D: usize> CircuitBuilder { leaf_data: Vec, leaf_index_bits: &[Target], cap_index: Target, - merkle_root: &MerkleCapTarget, + merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, ) { let zero = self.zero(); @@ -187,7 +186,7 @@ impl, const D: usize> CircuitBuilder { state_ext[i] = state.elements[i]; } let state_ext = ExtensionTarget(state_ext); - let cap_ext = merkle_root + let cap_ext = merkle_cap .0 .iter() .map(|h| { @@ -199,7 +198,6 @@ impl, const D: usize> CircuitBuilder { }) .collect(); self.random_access(cap_index, state_ext, cap_ext); - // self.named_assert_hashes_equal(state, merkle_root, "check Merkle root".into()) } pub(crate) fn assert_hashes_equal(&mut self, x: HashOutTarget, y: HashOutTarget) { @@ -263,8 +261,8 @@ mod tests { pw.set_hash_target(proof_t.siblings[i], proof.siblings[i]); } - let root_t = builder.add_virtual_cap(cap_height); - pw.set_cap_target(&root_t, &tree.root); + let cap_t = builder.add_virtual_cap(cap_height); + pw.set_cap_target(&cap_t, &tree.cap); let i_c = builder.constant(F::from_canonical_usize(i)); let i_bits = builder.split_le(i_c, log_n); @@ -274,7 +272,7 @@ mod tests { pw.set_target(data[j], tree.leaves[i][j]); } - builder.verify_merkle_proof(data, &i_bits, &root_t, &proof_t); + builder.verify_merkle_proof(data, &i_bits, &cap_t, &proof_t); let data = builder.build(); let proof = data.prove(pw)?; diff --git a/src/hash/merkle_tree.rs b/src/hash/merkle_tree.rs index 454d44f6..08e49c42 100644 --- a/src/hash/merkle_tree.rs +++ b/src/hash/merkle_tree.rs @@ -20,7 +20,7 @@ pub struct MerkleTree { pub layers: Vec>>, /// The Merkle cap. - pub root: MerkleCap, + pub cap: MerkleCap, /// If true, the indices are in bit-reversed form, so that the leaf at index `i` /// contains the leaf originally at index `reverse_bits(i)`. @@ -50,7 +50,7 @@ impl MerkleTree { Self { leaves, layers, - root: MerkleCap(cap), + cap: MerkleCap(cap), reverse_bits, } } @@ -105,7 +105,7 @@ mod tests { let tree = MerkleTree::new(leaves.clone(), 1, reverse_bits); for i in 0..n { let proof = tree.prove(i); - verify_merkle_proof(leaves[i].clone(), i, &tree.root, &proof, reverse_bits)?; + verify_merkle_proof(leaves[i].clone(), i, &tree.cap, &proof, reverse_bits)?; } Ok(()) } @@ -118,8 +118,7 @@ mod tests { let n = 1 << log_n; let leaves = random_data::(n, 7); - verify_all_leaves(leaves.clone(), n, false)?; - // verify_all_leaves(leaves, n, true)?; + verify_all_leaves(leaves, n, false)?; Ok(()) } diff --git a/src/plonk/circuit_builder.rs b/src/plonk/circuit_builder.rs index 646de78d..823b9e8d 100644 --- a/src/plonk/circuit_builder.rs +++ b/src/plonk/circuit_builder.rs @@ -570,9 +570,9 @@ impl, const D: usize> CircuitBuilder { &mut timing, ); - let constants_sigmas_root = constants_sigmas_commitment.merkle_tree.root.clone(); + let constants_sigmas_cap = constants_sigmas_commitment.merkle_tree.cap.clone(); let verifier_only = VerifierOnlyCircuitData { - constants_sigmas_root: constants_sigmas_root.clone(), + constants_sigmas_cap: constants_sigmas_cap.clone(), }; let prover_only = ProverOnlyCircuitData { @@ -603,7 +603,7 @@ impl, const D: usize> CircuitBuilder { // TODO: This should also include an encoding of gate constraints. let circuit_digest_parts = [ - constants_sigmas_root + constants_sigmas_cap .0 .into_iter() .flat_map(|h| h.elements) diff --git a/src/plonk/circuit_data.rs b/src/plonk/circuit_data.rs index cb4541bc..7c3d3985 100644 --- a/src/plonk/circuit_data.rs +++ b/src/plonk/circuit_data.rs @@ -149,7 +149,7 @@ pub(crate) struct ProverOnlyCircuitData, const D: usize> { /// Circuit data required by the verifier, but not the prover. pub(crate) struct VerifierOnlyCircuitData { /// A commitment to each constant polynomial and each permutation polynomial. - pub(crate) constants_sigmas_root: MerkleCap, + pub(crate) constants_sigmas_cap: MerkleCap, } /// Circuit data required by both the prover and the verifier. @@ -239,5 +239,5 @@ impl, const D: usize> CommonCircuitData { /// dynamic, at least not without setting a maximum wire count and paying for the worst case. pub struct VerifierCircuitTarget { /// A commitment to each constant polynomial and each permutation polynomial. - pub(crate) constants_sigmas_root: MerkleCapTarget, + pub(crate) constants_sigmas_cap: MerkleCapTarget, } diff --git a/src/plonk/proof.rs b/src/plonk/proof.rs index 514f83f7..64bfc90f 100644 --- a/src/plonk/proof.rs +++ b/src/plonk/proof.rs @@ -13,12 +13,12 @@ use crate::plonk::circuit_data::CommonCircuitData; #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "")] pub struct Proof, const D: usize> { - /// Merkle root of LDEs of wire values. - pub wires_root: MerkleCap, - /// Merkle root of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_partial_products_root: MerkleCap, - /// Merkle root of LDEs of the quotient polynomial components. - pub quotient_polys_root: MerkleCap, + /// Merkle cap of LDEs of wire values. + pub wires_cap: MerkleCap, + /// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument. + pub plonk_zs_partial_products_cap: MerkleCap, + /// Merkle cap of LDEs of the quotient polynomial components. + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: OpeningSet, /// A batch FRI argument for all openings. @@ -33,9 +33,9 @@ pub struct ProofWithPublicInputs, const D: usize> { } pub struct ProofTarget { - pub wires_root: MerkleCapTarget, - pub plonk_zs_partial_products_root: MerkleCapTarget, - pub quotient_polys_root: MerkleCapTarget, + pub wires_cap: MerkleCapTarget, + pub plonk_zs_partial_products_cap: MerkleCapTarget, + pub quotient_polys_cap: MerkleCapTarget, pub openings: OpeningSetTarget, pub opening_proof: FriProofTarget, } diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 56484c8a..0d66daa8 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -96,7 +96,7 @@ pub(crate) fn prove, const D: usize>( challenger.observe_hash(&common_data.circuit_digest); challenger.observe_hash(&public_inputs_hash); - challenger.observe_cap(&wires_commitment.merkle_tree.root); + challenger.observe_cap(&wires_commitment.merkle_tree.cap); let betas = challenger.get_n_challenges(num_challenges); let gammas = challenger.get_n_challenges(num_challenges); @@ -135,7 +135,7 @@ pub(crate) fn prove, const D: usize>( ) ); - challenger.observe_cap(&zs_partial_products_commitment.merkle_tree.root); + challenger.observe_cap(&zs_partial_products_commitment.merkle_tree.cap); let alphas = challenger.get_n_challenges(num_challenges); @@ -184,7 +184,7 @@ pub(crate) fn prove, const D: usize>( ) ); - challenger.observe_cap("ient_polys_commitment.merkle_tree.root); + challenger.observe_cap("ient_polys_commitment.merkle_tree.cap); let zeta = challenger.get_extension_challenge(); @@ -208,9 +208,9 @@ pub(crate) fn prove, const D: usize>( timing.print(); let proof = Proof { - wires_root: wires_commitment.merkle_tree.root, - plonk_zs_partial_products_root: zs_partial_products_commitment.merkle_tree.root, - quotient_polys_root: quotient_polys_commitment.merkle_tree.root, + wires_cap: wires_commitment.merkle_tree.cap, + plonk_zs_partial_products_cap: zs_partial_products_commitment.merkle_tree.cap, + quotient_polys_cap: quotient_polys_commitment.merkle_tree.cap, openings, opening_proof, }; diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index fac0ba3a..3ab1cdec 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -44,14 +44,14 @@ impl, const D: usize> CircuitBuilder { challenger.observe_hash(&digest); challenger.observe_hash(&public_inputs_hash); - challenger.observe_cap(&proof.wires_root); + challenger.observe_cap(&proof.wires_cap); let betas = challenger.get_n_challenges(self, num_challenges); let gammas = challenger.get_n_challenges(self, num_challenges); - challenger.observe_cap(&proof.plonk_zs_partial_products_root); + challenger.observe_cap(&proof.plonk_zs_partial_products_cap); let alphas = challenger.get_n_challenges(self, num_challenges); - challenger.observe_cap(&proof.quotient_polys_root); + challenger.observe_cap(&proof.quotient_polys_cap); let zeta = challenger.get_extension_challenge(self); (betas, gammas, alphas, zeta) @@ -107,11 +107,11 @@ impl, const D: usize> CircuitBuilder { } }); - let merkle_roots = &[ - inner_verifier_data.constants_sigmas_root.clone(), - proof.wires_root, - proof.plonk_zs_partial_products_root, - proof.quotient_polys_root, + let merkle_caps = &[ + inner_verifier_data.constants_sigmas_cap.clone(), + proof.wires_cap, + proof.plonk_zs_partial_products_cap, + proof.quotient_polys_cap, ]; with_context!( @@ -120,7 +120,7 @@ impl, const D: usize> CircuitBuilder { self.verify_fri_proof( &proof.openings, zeta, - merkle_roots, + merkle_caps, &proof.opening_proof, &mut challenger, inner_common_data, @@ -190,11 +190,11 @@ mod tests { public_inputs, } = proof_with_pis; - let wires_root = builder.add_virtual_cap(log2_strict(proof.wires_root.0.len())); - let plonk_zs_root = - builder.add_virtual_cap(log2_strict(proof.plonk_zs_partial_products_root.0.len())); - let quotient_polys_root = - builder.add_virtual_cap(log2_strict(proof.quotient_polys_root.0.len())); + let wires_cap = builder.add_virtual_cap(log2_strict(proof.wires_cap.0.len())); + let plonk_zs_cap = + builder.add_virtual_cap(log2_strict(proof.plonk_zs_partial_products_cap.0.len())); + let quotient_polys_cap = + builder.add_virtual_cap(log2_strict(proof.quotient_polys_cap.0.len())); let openings = OpeningSetTarget { constants: builder.add_virtual_extension_targets(proof.openings.constants.len()), @@ -211,14 +211,14 @@ mod tests { let query_round_proofs = (0..proof.opening_proof.query_round_proofs.len()) .map(|_| get_fri_query_round(proof, builder)) .collect(); - let commit_phase_merkle_roots = proof + let commit_phase_merkle_caps = proof .opening_proof - .commit_phase_merkle_roots + .commit_phase_merkle_caps .iter() .map(|r| builder.add_virtual_cap(log2_strict(r.0.len()))) .collect(); let opening_proof = FriProofTarget { - commit_phase_merkle_roots, + commit_phase_merkle_caps, query_round_proofs, final_poly: PolynomialCoeffsExtTarget( builder.add_virtual_extension_targets(proof.opening_proof.final_poly.len()), @@ -227,9 +227,9 @@ mod tests { }; let proof = ProofTarget { - wires_root, - plonk_zs_partial_products_root: plonk_zs_root, - quotient_polys_root, + wires_cap, + plonk_zs_partial_products_cap: plonk_zs_cap, + quotient_polys_cap, openings, opening_proof, }; @@ -261,12 +261,12 @@ mod tests { pw.set_target(pi_t, pi); } - pw.set_cap_target(&pt.wires_root, &proof.wires_root); + pw.set_cap_target(&pt.wires_cap, &proof.wires_cap); pw.set_cap_target( - &pt.plonk_zs_partial_products_root, - &proof.plonk_zs_partial_products_root, + &pt.plonk_zs_partial_products_cap, + &proof.plonk_zs_partial_products_cap, ); - pw.set_cap_target(&pt.quotient_polys_root, &proof.quotient_polys_root); + pw.set_cap_target(&pt.quotient_polys_cap, &proof.quotient_polys_cap); for (&t, &x) in pt.openings.wires.iter().zip(&proof.openings.wires) { pw.set_extension_target(t, x); @@ -320,9 +320,9 @@ mod tests { } for (t, x) in fpt - .commit_phase_merkle_roots + .commit_phase_merkle_caps .iter() - .zip(&fri_proof.commit_phase_merkle_roots) + .zip(&fri_proof.commit_phase_merkle_caps) { pw.set_cap_target(t, x); } @@ -405,9 +405,9 @@ mod tests { set_proof_target(&proof_with_pis, &pt, &mut pw); let inner_data = VerifierCircuitTarget { - constants_sigmas_root: builder.add_virtual_cap(config.cap_height), + constants_sigmas_cap: builder.add_virtual_cap(config.cap_height), }; - pw.set_cap_target(&inner_data.constants_sigmas_root, &vd.constants_sigmas_root); + pw.set_cap_target(&inner_data.constants_sigmas_cap, &vd.constants_sigmas_cap); builder.add_recursive_verifier(pt, &config, &inner_data, &cd); @@ -462,9 +462,9 @@ mod tests { set_proof_target(&proof_with_pis, &pt, &mut pw); let inner_data = VerifierCircuitTarget { - constants_sigmas_root: builder.add_virtual_cap(config.cap_height), + constants_sigmas_cap: builder.add_virtual_cap(config.cap_height), }; - pw.set_cap_target(&inner_data.constants_sigmas_root, &vd.constants_sigmas_root); + pw.set_cap_target(&inner_data.constants_sigmas_cap, &vd.constants_sigmas_cap); builder.add_recursive_verifier(pt, &config, &inner_data, &cd); @@ -480,9 +480,9 @@ mod tests { set_proof_target(&proof_with_pis, &pt, &mut pw); let inner_data = VerifierCircuitTarget { - constants_sigmas_root: builder.add_virtual_cap(config.cap_height), + constants_sigmas_cap: builder.add_virtual_cap(config.cap_height), }; - pw.set_cap_target(&inner_data.constants_sigmas_root, &vd.constants_sigmas_root); + pw.set_cap_target(&inner_data.constants_sigmas_cap, &vd.constants_sigmas_cap); builder.add_recursive_verifier(pt, &config, &inner_data, &cd); diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 98736044..cc0da79b 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -31,14 +31,14 @@ pub(crate) fn verify, const D: usize>( challenger.observe_hash(&common_data.circuit_digest); challenger.observe_hash(&public_inputs_hash); - challenger.observe_cap(&proof.wires_root); + challenger.observe_cap(&proof.wires_cap); let betas = challenger.get_n_challenges(num_challenges); let gammas = challenger.get_n_challenges(num_challenges); - challenger.observe_cap(&proof.plonk_zs_partial_products_root); + challenger.observe_cap(&proof.plonk_zs_partial_products_cap); let alphas = challenger.get_n_challenges(num_challenges); - challenger.observe_cap(&proof.quotient_polys_root); + challenger.observe_cap(&proof.quotient_polys_cap); let zeta = challenger.get_extension_challenge(); let local_constants = &proof.openings.constants; @@ -83,17 +83,17 @@ pub(crate) fn verify, const D: usize>( ensure!(vanishing_polys_zeta[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg)); } - let merkle_roots = &[ - verifier_data.constants_sigmas_root.clone(), - proof.wires_root, - proof.plonk_zs_partial_products_root, - proof.quotient_polys_root, + let merkle_caps = &[ + verifier_data.constants_sigmas_cap.clone(), + proof.wires_cap, + proof.plonk_zs_partial_products_cap, + proof.quotient_polys_cap, ]; verify_fri_proof( &proof.openings, zeta, - merkle_roots, + merkle_caps, &proof.opening_proof, &mut challenger, common_data, From 9f004c9664255d433c9904ac961f007425952e19 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 10 Aug 2021 16:18:42 +0200 Subject: [PATCH 09/10] Clippy --- src/fri/commitment.rs | 5 +++-- src/fri/proof.rs | 2 +- src/fri/prover.rs | 1 - src/fri/recursive_verifier.rs | 3 +-- src/fri/verifier.rs | 1 - src/hash/merkle_proofs.rs | 21 +++++++-------------- src/plonk/circuit_builder.rs | 1 - src/plonk/circuit_data.rs | 2 +- src/plonk/proof.rs | 2 +- 9 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/fri/commitment.rs b/src/fri/commitment.rs index 5a64bb43..d62fa33d 100644 --- a/src/fri/commitment.rs +++ b/src/fri/commitment.rs @@ -3,8 +3,7 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::fri::proof::FriProof; -use crate::fri::{prover::fri_proof, verifier::verify_fri_proof}; -use crate::hash::hash_types::HashOut; +use crate::fri::prover::fri_proof; use crate::hash::merkle_tree::MerkleTree; use crate::iop::challenger::Challenger; use crate::plonk::circuit_data::CommonCircuitData; @@ -246,7 +245,9 @@ mod tests { use anyhow::Result; use super::*; + use crate::fri::verifier::verify_fri_proof; use crate::fri::FriConfig; + use crate::hash::hash_types::HashOut; use crate::plonk::circuit_data::CircuitConfig; fn gen_random_test_case, const D: usize>( diff --git a/src/fri/proof.rs b/src/fri/proof.rs index af5bacf0..4ee5bafb 100644 --- a/src/fri/proof.rs +++ b/src/fri/proof.rs @@ -4,7 +4,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; -use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; +use crate::hash::hash_types::MerkleCapTarget; use crate::hash::merkle_proofs::{MerkleProof, MerkleProofTarget}; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; diff --git a/src/fri/prover.rs b/src/fri/prover.rs index eaecac2d..431fbe70 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -154,7 +154,6 @@ fn fri_prover_query_round, const D: usize>( .collect::>(); for (i, tree) in trees.iter().enumerate() { let arity_bits = config.reduction_arity_bits[i]; - let arity = 1 << arity_bits; let evals = unflatten(tree.get(x_index >> arity_bits)); let merkle_proof = tree.prove(x_index >> arity_bits); diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index ff480d8c..fc90be35 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -3,7 +3,7 @@ use crate::field::extension_field::Extendable; use crate::field::field_types::Field; use crate::fri::proof::{FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget}; use crate::fri::FriConfig; -use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget}; +use crate::hash::hash_types::MerkleCapTarget; use crate::iop::challenger::RecursiveChallenger; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; @@ -212,7 +212,6 @@ impl, const D: usize> CircuitBuilder { let config = self.config.clone(); let degree_log = common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() - config.rate_bits; - let one = self.one_extension(); let subgroup_x = self.convert_to_ext(subgroup_x); let vanish_zeta = self.sub_extension(subgroup_x, zeta); let mut alpha = ReducingFactorTarget::new(alpha); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index f7f2da21..e9f64720 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -5,7 +5,6 @@ use crate::field::field_types::Field; use crate::field::interpolation::{barycentric_weights, interpolate, interpolate2}; use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound}; use crate::fri::FriConfig; -use crate::hash::hash_types::HashOut; use crate::hash::hashing::hash_n_to_1; use crate::hash::merkle_proofs::verify_merkle_proof; use crate::hash::merkle_tree::MerkleCap; diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index 76a791c8..5b99fa19 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - use anyhow::{ensure, Result}; use serde::{Deserialize, Serialize}; @@ -62,6 +60,7 @@ pub(crate) fn verify_merkle_proof( impl, const D: usize> CircuitBuilder { /// 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. + /// Note: Works only for D=4. pub(crate) fn verify_merkle_proof( &mut self, leaf_data: Vec, @@ -113,24 +112,22 @@ impl, const D: usize> CircuitBuilder { let index = self.le_sum(leaf_index_bits[proof.siblings.len()..].to_vec().into_iter()); let mut state_ext = [zero; D]; - for i in 0..D { - state_ext[i] = state.elements[i]; - } + state_ext[..D].copy_from_slice(&state.elements[..D]); let state_ext = ExtensionTarget(state_ext); let cap_ext = merkle_cap .0 .iter() .map(|h| { let mut tmp = [zero; D]; - for i in 0..D { - tmp[i] = h.elements[i]; - } + tmp[..D].copy_from_slice(&h.elements[..D]); ExtensionTarget(tmp) }) .collect(); self.random_access(index, state_ext, cap_ext); } + /// Same a `verify_merkle_proof` but with the final "cap index" as extra parameter. + /// Note: Works only for D=4. pub(crate) fn verify_merkle_proof_with_cap_index( &mut self, leaf_data: Vec, @@ -182,18 +179,14 @@ impl, const D: usize> CircuitBuilder { } let mut state_ext = [zero; D]; - for i in 0..D { - state_ext[i] = state.elements[i]; - } + state_ext[..D].copy_from_slice(&state.elements[..D]); let state_ext = ExtensionTarget(state_ext); let cap_ext = merkle_cap .0 .iter() .map(|h| { let mut tmp = [zero; D]; - for i in 0..D { - tmp[i] = h.elements[i]; - } + tmp[..D].copy_from_slice(&h.elements[..D]); ExtensionTarget(tmp) }) .collect(); diff --git a/src/plonk/circuit_builder.rs b/src/plonk/circuit_builder.rs index 823b9e8d..d783d890 100644 --- a/src/plonk/circuit_builder.rs +++ b/src/plonk/circuit_builder.rs @@ -15,7 +15,6 @@ use crate::gates::noop::NoopGate; use crate::gates::public_input::PublicInputGate; use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget}; use crate::hash::hashing::hash_n_to_hash; -use crate::hash::merkle_tree::MerkleCap; use crate::iop::generator::{CopyGenerator, RandomValueGenerator, WitnessGenerator}; use crate::iop::target::Target; use crate::iop::wire::Wire; diff --git a/src/plonk/circuit_data.rs b/src/plonk/circuit_data.rs index 7c3d3985..2441d810 100644 --- a/src/plonk/circuit_data.rs +++ b/src/plonk/circuit_data.rs @@ -7,7 +7,7 @@ use crate::field::field_types::Field; use crate::fri::commitment::PolynomialBatchCommitment; use crate::fri::FriConfig; use crate::gates::gate::{GateInstance, PrefixedGate}; -use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; +use crate::hash::hash_types::{HashOut, MerkleCapTarget}; use crate::hash::merkle_tree::MerkleCap; use crate::iop::generator::WitnessGenerator; use crate::iop::target::Target; diff --git a/src/plonk/proof.rs b/src/plonk/proof.rs index 64bfc90f..2ebe362b 100644 --- a/src/plonk/proof.rs +++ b/src/plonk/proof.rs @@ -5,7 +5,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::fri::commitment::PolynomialBatchCommitment; use crate::fri::proof::{FriProof, FriProofTarget}; -use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; +use crate::hash::hash_types::MerkleCapTarget; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; use crate::plonk::circuit_data::CommonCircuitData; From 9c01e1d942a378c8beb1efc35441fd70e693fda2 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 11 Aug 2021 08:33:58 +0200 Subject: [PATCH 10/10] PR feedback --- src/fri/recursive_verifier.rs | 9 ++++++--- src/fri/verifier.rs | 7 +++++-- src/hash/merkle_proofs.rs | 14 ++++++-------- src/hash/merkle_tree.rs | 2 ++ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index fc90be35..35fd6765 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -210,8 +210,12 @@ impl, const D: usize> CircuitBuilder { ) -> ExtensionTarget { assert!(D > 1, "Not implemented for D=1."); let config = self.config.clone(); - let degree_log = common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() - - config.rate_bits; + let degree_log = common_data.degree_bits; + debug_assert_eq!( + degree_log, + common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() + - config.rate_bits + ); let subgroup_x = self.convert_to_ext(subgroup_x); let vanish_zeta = self.sub_extension(subgroup_x, zeta); let mut alpha = ReducingFactorTarget::new(alpha); @@ -292,7 +296,6 @@ impl, const D: usize> CircuitBuilder { let mut x_index_bits = self.low_bits(x_index, n_log, 64); let cap_index = self.le_sum( x_index_bits[x_index_bits.len() - common_data.config.fri_config.cap_height..] - .to_vec() .into_iter(), ); let mut domain_size = n; diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index e9f64720..021ab122 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -189,8 +189,11 @@ fn fri_combine_initial, const D: usize>( ) -> F::Extension { let config = &common_data.config; assert!(D > 1, "Not implemented for D=1."); - let degree_log = - common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() - config.rate_bits; + let degree_log = common_data.degree_bits; + debug_assert_eq!( + degree_log, + common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() - config.rate_bits + ); let subgroup_x = F::Extension::from_basefield(subgroup_x); let mut alpha = ReducingFactor::new(alpha); let mut sum = F::Extension::ZERO; diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index 5b99fa19..45009c7d 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use anyhow::{ensure, Result}; use serde::{Deserialize, Serialize}; @@ -111,15 +113,13 @@ impl, const D: usize> CircuitBuilder { } let index = self.le_sum(leaf_index_bits[proof.siblings.len()..].to_vec().into_iter()); - let mut state_ext = [zero; D]; - state_ext[..D].copy_from_slice(&state.elements[..D]); + let state_ext = state.elements[..].try_into().expect("requires D = 4"); let state_ext = ExtensionTarget(state_ext); let cap_ext = merkle_cap .0 .iter() .map(|h| { - let mut tmp = [zero; D]; - tmp[..D].copy_from_slice(&h.elements[..D]); + let tmp = h.elements[..].try_into().expect("requires D = 4"); ExtensionTarget(tmp) }) .collect(); @@ -178,15 +178,13 @@ impl, const D: usize> CircuitBuilder { ) } - let mut state_ext = [zero; D]; - state_ext[..D].copy_from_slice(&state.elements[..D]); + let state_ext = state.elements[..].try_into().expect("requires D = 4"); let state_ext = ExtensionTarget(state_ext); let cap_ext = merkle_cap .0 .iter() .map(|h| { - let mut tmp = [zero; D]; - tmp[..D].copy_from_slice(&h.elements[..D]); + let tmp = h.elements[..].try_into().expect("requires D = 4"); ExtensionTarget(tmp) }) .collect(); diff --git a/src/hash/merkle_tree.rs b/src/hash/merkle_tree.rs index 08e49c42..334e65bf 100644 --- a/src/hash/merkle_tree.rs +++ b/src/hash/merkle_tree.rs @@ -7,6 +7,8 @@ use crate::hash::hashing::{compress, hash_or_noop}; use crate::hash::merkle_proofs::MerkleProof; use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; +/// The Merkle cap of height `h` of a Merkle tree is the `h`-th layer (from the root) of the tree. +/// It can be used in place of the root to verify Merkle paths, which are `h` elements shorter. #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(bound = "")] pub struct MerkleCap(pub Vec>);