From 670e48380a4ed1a1f4360a27cdda1a7e2431fa1f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Jun 2021 13:26:22 +0200 Subject: [PATCH] Finish recursive verifier --- src/fri/recursive_verifier.rs | 154 +++++++++++++++++----------------- src/gadgets/polynomial.rs | 4 + src/plonk_challenger.rs | 25 +++++- 3 files changed, 100 insertions(+), 83 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 9eb1a1c0..a424dee0 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -58,81 +58,78 @@ impl, const D: usize> CircuitBuilder { proof: &FriProofTarget, challenger: &mut RecursiveChallenger, config: &FriConfig, - ) -> Result<()> { + ) { let mut inputs = challenger.get_hash(self).elements.to_vec(); inputs.push(proof.pow_witness); let hash = self.hash_n_to_m(inputs, 1, false)[0]; - self.assert_trailing_zeros::<64>(hash, config.proof_of_work_bits); - - Ok(()) + self.assert_trailing_zeros::<2>(hash, config.proof_of_work_bits); } - // pub fn verify_fri_proof( - // purported_degree_log: usize, - // // Openings of the PLONK polynomials. - // os: &OpeningSet, - // // Point at which the PLONK polynomials are opened. - // zeta: F::Extension, - // // Scaling factor to combine polynomials. - // alpha: F::Extension, - // initial_merkle_roots: &[Hash], - // proof: &FriProof, - // challenger: &mut Challenger, - // config: &FriConfig, - // ) -> Result<()> { - // let total_arities = config.reduction_arity_bits.iter().sum::(); - // ensure!( - // purported_degree_log - // == log2_strict(proof.final_poly.len()) + total_arities - config.rate_bits, - // "Final polynomial has wrong degree." - // ); - // - // // Size of the LDE domain. - // let n = proof.final_poly.len() << total_arities; - // - // // Recover the random betas used in the FRI reductions. - // let betas = proof - // .commit_phase_merkle_roots - // .iter() - // .map(|root| { - // challenger.observe_hash(root); - // challenger.get_extension_challenge() - // }) - // .collect::>(); - // challenger.observe_extension_elements(&proof.final_poly.coeffs); - // - // // Check PoW. - // fri_verify_proof_of_work(proof, challenger, config)?; - // - // // Check that parameters are coherent. - // ensure!( - // config.num_query_rounds == proof.query_round_proofs.len(), - // "Number of query rounds does not match config." - // ); - // ensure!( - // !config.reduction_arity_bits.is_empty(), - // "Number of reductions should be non-zero." - // ); - // - // for round_proof in &proof.query_round_proofs { - // fri_verifier_query_round( - // os, - // zeta, - // alpha, - // initial_merkle_roots, - // &proof, - // challenger, - // n, - // &betas, - // round_proof, - // config, - // )?; - // } - // - // Ok(()) - // } - // + pub fn verify_fri_proof( + &mut self, + purported_degree_log: usize, + // Openings of the PLONK polynomials. + os: &OpeningSetTarget, + // Point at which the PLONK polynomials are opened. + zeta: ExtensionTarget, + // Scaling factor to combine polynomials. + alpha: ExtensionTarget, + initial_merkle_roots: &[HashTarget], + proof: &FriProofTarget, + challenger: &mut RecursiveChallenger, + config: &FriConfig, + ) { + let total_arities = config.reduction_arity_bits.iter().sum::(); + debug_assert_eq!( + purported_degree_log, + log2_strict(proof.final_poly.len()) + total_arities - config.rate_bits, + "Final polynomial has wrong degree." + ); + + // Size of the LDE domain. + let n = proof.final_poly.len() << total_arities; + + // Recover the random betas used in the FRI reductions. + let betas = proof + .commit_phase_merkle_roots + .iter() + .map(|root| { + challenger.observe_hash(root); + challenger.get_extension_challenge(self) + }) + .collect::>(); + challenger.observe_extension_elements(&proof.final_poly.0); + + // Check PoW. + self.fri_verify_proof_of_work(proof, challenger, config); + + // Check that parameters are coherent. + debug_assert_eq!( + config.num_query_rounds, + proof.query_round_proofs.len(), + "Number of query rounds does not match config." + ); + debug_assert!( + !config.reduction_arity_bits.is_empty(), + "Number of reductions should be non-zero." + ); + + for round_proof in &proof.query_round_proofs { + self.fri_verifier_query_round( + os, + zeta, + alpha, + initial_merkle_roots, + &proof, + challenger, + n, + &betas, + round_proof, + config, + ); + } + } fn fri_verify_initial_proof( &mut self, @@ -265,7 +262,7 @@ impl, const D: usize> CircuitBuilder { betas: &[ExtensionTarget], round_proof: &FriQueryRoundTarget, config: &FriConfig, - ) -> Result<()> { + ) { let n_log = log2_strict(n); let mut evaluations: Vec>> = Vec::new(); // TODO: Do we need to range check `x_index` to a target smaller than `p`? @@ -312,14 +309,15 @@ impl, const D: usize> CircuitBuilder { 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 (low_x_index, high_x_index) = self.split_low_high(x_index, arity_bits); + // TODO: Uncomment this. // evals.insert(x_index & (arity - 1), e_x); - // evaluations.push(evals); - // self.verify_merkle_proof( - // flatten_target(&evaluations[i]), - // x_index >> arity_bits, - // proof.commit_phase_merkle_roots[i], - // &round_proof.steps[i].merkle_proof, - // )?; + evaluations.push(evals); + self.verify_merkle_proof( + flatten_target(&evaluations[i]), + high_x_index, + proof.commit_phase_merkle_roots[i], + &round_proof.steps[i].merkle_proof, + ); if i > 0 { // Update the point x to x^arity. @@ -349,7 +347,5 @@ impl, const D: usize> CircuitBuilder { // to the one sent by the prover. let eval = proof.final_poly.eval_scalar(self, subgroup_x); self.assert_equal_extension(eval, purported_eval); - - Ok(()) } } diff --git a/src/gadgets/polynomial.rs b/src/gadgets/polynomial.rs index 543be834..07bc1952 100644 --- a/src/gadgets/polynomial.rs +++ b/src/gadgets/polynomial.rs @@ -6,6 +6,10 @@ use crate::target::Target; pub struct PolynomialCoeffsExtTarget(pub Vec>); impl PolynomialCoeffsExtTarget { + pub fn len(&self) -> usize { + self.0.len() + } + pub fn eval_scalar>( &self, builder: &mut CircuitBuilder, diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index bcb2c8cd..b24bbde8 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -1,9 +1,11 @@ use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::hash::{permute, SPONGE_RATE, SPONGE_WIDTH}; use crate::proof::{Hash, HashTarget, OpeningSet}; use crate::target::Target; +use std::convert::TryInto; /// Observes prover messages, and generates challenges by hashing the transcript. #[derive(Clone)] @@ -41,9 +43,7 @@ impl Challenger { where F: Extendable, { - for &e in &element.to_basefield_array() { - self.observe_element(e); - } + self.observe_elements(&element.to_basefield_array()); } pub fn observe_elements(&mut self, elements: &[F]) { @@ -177,7 +177,7 @@ impl Default for Challenger { } /// A recursive version of `Challenger`. -pub(crate) struct RecursiveChallenger { +pub struct RecursiveChallenger { sponge_state: [Target; SPONGE_WIDTH], input_buffer: Vec, output_buffer: Vec, @@ -212,6 +212,16 @@ impl RecursiveChallenger { self.observe_elements(&hash.elements) } + pub fn observe_extension_element(&mut self, element: ExtensionTarget) { + self.observe_elements(&element.0); + } + + pub fn observe_extension_elements(&mut self, elements: &[ExtensionTarget]) { + for &element in elements { + self.observe_extension_element(element); + } + } + pub(crate) fn get_challenge, const D: usize>( &mut self, builder: &mut CircuitBuilder, @@ -269,6 +279,13 @@ impl RecursiveChallenger { } } + pub fn get_extension_challenge, const D: usize>( + &mut self, + builder: &mut CircuitBuilder, + ) -> ExtensionTarget { + self.get_n_challenges(builder, D).try_into().unwrap() + } + /// Absorb any buffered inputs. After calling this, the input buffer will be empty. fn absorb_buffered_inputs, const D: usize>( &mut self,