From 72c2e19bc5bd76061b47fec88bc69ff88e5e7407 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 8 Jun 2021 21:23:52 -0700 Subject: [PATCH] Bit of verifier work (#54) * Bit of verifier work * Minor * next_plonk_zs now available after William's changes --- src/circuit_builder.rs | 1 - src/fri/verifier.rs | 2 +- src/gates/interpolation.rs | 15 ++---- src/plonk_challenger.rs | 4 +- src/plonk_common.rs | 100 +++++++++++++++++++++++++++++++++++ src/polynomial/commitment.rs | 2 +- src/proof.rs | 4 +- src/prover.rs | 56 ++------------------ src/verifier.rs | 34 +++++++++++- 9 files changed, 146 insertions(+), 72 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index a2c94f83..4150bb68 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -9,7 +9,6 @@ use crate::circuit_data::{ }; use crate::field::cosets::get_unique_coset_shifts; use crate::field::extension_field::Extendable; -use crate::field::field::Field; use crate::gates::constant::ConstantGate; use crate::gates::gate::{GateInstance, GateRef}; use crate::gates::noop::NoopGate; diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index e6e8cae7..24e24f64 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -167,7 +167,7 @@ fn fri_combine_initial, const D: usize>( let openings = os .constants .iter() - .chain(&os.plonk_sigmas) + .chain(&os.plonk_s_sigmas) .chain(&os.quotient_polys); let numerator = izip!(evals, openings, &mut alpha_powers) .map(|(e, &o, a)| a * (e - o)) diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index d2412967..9bf76c2c 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -21,14 +21,12 @@ use crate::witness::PartialWitness; /// to evaluate the interpolant at. It computes the interpolant and outputs its evaluation at the /// given point. #[derive(Clone, Debug)] -pub(crate) struct InterpolationGate, const D: usize> -{ +pub(crate) struct InterpolationGate, const D: usize> { num_points: usize, _phantom: PhantomData, } -impl, const D: usize> InterpolationGate -{ +impl, const D: usize> InterpolationGate { pub fn new(num_points: usize) -> GateRef { let gate = Self { num_points, @@ -95,8 +93,7 @@ impl, const D: usize> InterpolationGate } } -impl, const D: usize> Gate for InterpolationGate -{ +impl, const D: usize> Gate for InterpolationGate { fn id(&self) -> String { format!("{:?}", self, D) } @@ -193,15 +190,13 @@ impl, const D: usize> Gate for InterpolationGate } } -struct InterpolationGenerator, const D: usize> -{ +struct InterpolationGenerator, const D: usize> { gate_index: usize, gate: InterpolationGate, _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator for InterpolationGenerator -{ +impl, const D: usize> SimpleGenerator for InterpolationGenerator { fn dependencies(&self) -> Vec { let local_target = |input| { Target::Wire(Wire { diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index 69891761..fd21ee0d 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -67,7 +67,7 @@ impl Challenger { { let OpeningSet { constants, - plonk_sigmas, + plonk_s_sigmas, wires, plonk_zs, plonk_zs_right, @@ -75,7 +75,7 @@ impl Challenger { } = os; for v in &[ constants, - plonk_sigmas, + plonk_s_sigmas, wires, plonk_zs, plonk_zs_right, diff --git a/src/plonk_common.rs b/src/plonk_common.rs index 990e6ea7..e84cb340 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -1,4 +1,5 @@ use crate::circuit_builder::CircuitBuilder; +use crate::circuit_data::CommonCircuitData; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field::Field; @@ -6,6 +7,105 @@ use crate::gates::gate::GateRef; use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; +/// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random +/// linear combination of gate constraints, plus some other terms relating to the permutation +/// argument. All such terms should vanish on `H`. +pub(crate) fn eval_vanishing_poly, const D: usize>( + common_data: &CommonCircuitData, + x: F::Extension, + vars: EvaluationVars, + local_plonk_zs: &[F::Extension], + next_plonk_zs: &[F::Extension], + s_sigmas: &[F::Extension], + betas: &[F], + gammas: &[F], + alphas: &[F], +) -> Vec { + let constraint_terms = + evaluate_gate_constraints(&common_data.gates, common_data.num_gate_constraints, vars); + + // The L_1(x) (Z(x) - 1) vanishing terms. + let mut vanishing_z_1_terms = Vec::new(); + // The Z(x) f'(x) - g'(x) Z(g x) terms. + let mut vanishing_v_shift_terms = Vec::new(); + + for i in 0..common_data.config.num_challenges { + let z_x = local_plonk_zs[i]; + let z_gz = next_plonk_zs[i]; + vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::Extension::ONE)); + + let mut f_prime = F::Extension::ONE; + let mut g_prime = F::Extension::ONE; + for j in 0..common_data.config.num_routed_wires { + let wire_value = vars.local_wires[j]; + let k_i = common_data.k_is[j]; + let s_id = x * k_i.into(); + let s_sigma = s_sigmas[j]; + f_prime *= wire_value + s_id * betas[i].into() + gammas[i].into(); + g_prime *= wire_value + s_sigma * betas[i].into() + gammas[i].into(); + } + vanishing_v_shift_terms.push(f_prime * z_x - g_prime * z_gz); + } + + let vanishing_terms = [ + vanishing_z_1_terms, + vanishing_v_shift_terms, + constraint_terms, + ] + .concat(); + + let alphas = &alphas.iter().map(|&a| a.into()).collect::>(); + reduce_with_powers_multi(&vanishing_terms, alphas) +} + +/// Like `eval_vanishing_poly`, but specialized for base field points. +pub(crate) fn eval_vanishing_poly_base, const D: usize>( + common_data: &CommonCircuitData, + x: F, + vars: EvaluationVarsBase, + local_plonk_zs: &[F], + next_plonk_zs: &[F], + s_sigmas: &[F], + betas: &[F], + gammas: &[F], + alphas: &[F], +) -> Vec { + let constraint_terms = + evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars); + + // The L_1(x) (Z(x) - 1) vanishing terms. + let mut vanishing_z_1_terms = Vec::new(); + // The Z(x) f'(x) - g'(x) Z(g x) terms. + let mut vanishing_v_shift_terms = Vec::new(); + + for i in 0..common_data.config.num_challenges { + let z_x = local_plonk_zs[i]; + let z_gz = next_plonk_zs[i]; + vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::ONE)); + + let mut f_prime = F::ONE; + let mut g_prime = F::ONE; + for j in 0..common_data.config.num_routed_wires { + let wire_value = vars.local_wires[j]; + let k_i = common_data.k_is[j]; + let s_id = k_i * x; + let s_sigma = s_sigmas[j]; + f_prime *= wire_value + betas[i] * s_id + gammas[i]; + g_prime *= wire_value + betas[i] * s_sigma + gammas[i]; + } + vanishing_v_shift_terms.push(f_prime * z_x - g_prime * z_gz); + } + + let vanishing_terms = [ + vanishing_z_1_terms, + vanishing_v_shift_terms, + constraint_terms, + ] + .concat(); + + reduce_with_powers_multi(&vanishing_terms, alphas) +} + /// Evaluates all gate constraints. /// /// `num_gate_constraints` is the largest number of constraints imposed by any gate. It is not diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 06194ad9..e8cb2542 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -126,7 +126,7 @@ impl ListPolynomialCommitment { poly_count += 1; &(&acc * alpha) + &p.to_extension() }); - let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys] + let composition_eval = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys] .iter() .flat_map(|v| v.iter()) .rev() diff --git a/src/proof.rs b/src/proof.rs index 46288808..12735b73 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -140,7 +140,7 @@ pub struct FriProofTarget { /// The purported values of each polynomial at a single point. pub struct OpeningSet, const D: usize> { pub constants: Vec, - pub plonk_sigmas: Vec, + pub plonk_s_sigmas: Vec, pub wires: Vec, pub plonk_zs: Vec, pub plonk_zs_right: Vec, @@ -165,7 +165,7 @@ impl, const D: usize> OpeningSet { }; Self { constants: eval_commitment(z, constant_commitment), - plonk_sigmas: eval_commitment(z, plonk_sigmas_commitment), + plonk_s_sigmas: eval_commitment(z, plonk_sigmas_commitment), wires: eval_commitment(z, wires_commitment), plonk_zs: eval_commitment(z, plonk_zs_commitment), plonk_zs_right: eval_commitment(g * z, plonk_zs_commitment), diff --git a/src/prover.rs b/src/prover.rs index d7dc0df8..7a492eaa 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -9,7 +9,7 @@ use crate::field::fft::ifft; use crate::field::field::Field; use crate::generator::generate_partial_witness; use crate::plonk_challenger::Challenger; -use crate::plonk_common::{eval_l_1, evaluate_gate_constraints_base, reduce_with_powers_multi}; +use crate::plonk_common::eval_vanishing_poly_base; use crate::polynomial::commitment::ListPolynomialCommitment; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::Proof; @@ -115,7 +115,7 @@ pub(crate) fn prove, const D: usize>( let zeta = challenger.get_extension_challenge(); - let (opening_proof, openings) = timed!( + let (opening_proof, mut openings) = timed!( ListPolynomialCommitment::open_plonk( &[ &prover_data.constants_commitment, @@ -192,7 +192,7 @@ fn compute_vanishing_polys, const D: usize>( local_constants, local_wires, }; - compute_vanishing_poly_entry( + eval_vanishing_poly_base( common_data, x, vars, @@ -212,56 +212,6 @@ fn compute_vanishing_polys, const D: usize>( .collect() } -/// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random -/// linear combination of gate constraints, plus some other terms relating to the permutation -/// argument. All such terms should vanish on `H`. -fn compute_vanishing_poly_entry, const D: usize>( - common_data: &CommonCircuitData, - x: F, - vars: EvaluationVarsBase, - local_plonk_zs: &[F], - next_plonk_zs: &[F], - s_sigmas: &[F], - betas: &[F], - gammas: &[F], - alphas: &[F], -) -> Vec { - let constraint_terms = - evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars); - - // The L_1(x) (Z(x) - 1) vanishing terms. - let mut vanishing_z_1_terms = Vec::new(); - // The Z(x) f'(x) - g'(x) Z(g x) terms. - let mut vanishing_v_shift_terms = Vec::new(); - - for i in 0..common_data.config.num_challenges { - let z_x = local_plonk_zs[i]; - let z_gz = next_plonk_zs[i]; - vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::ONE)); - - let mut f_prime = F::ONE; - let mut g_prime = F::ONE; - for j in 0..common_data.config.num_routed_wires { - let wire_value = vars.local_wires[j]; - let k_i = common_data.k_is[j]; - let s_id = k_i * x; - let s_sigma = s_sigmas[j]; - f_prime *= wire_value + betas[i] * s_id + gammas[i]; - g_prime *= wire_value + betas[i] * s_sigma + gammas[i]; - } - vanishing_v_shift_terms.push(f_prime * z_x - g_prime * z_gz); - } - - let vanishing_terms = [ - vanishing_z_1_terms, - vanishing_v_shift_terms, - constraint_terms, - ] - .concat(); - - reduce_with_powers_multi(&vanishing_terms, alphas) -} - fn compute_wire_polynomial( input: usize, witness: &PartialWitness, diff --git a/src/verifier.rs b/src/verifier.rs index 0ad7a1a0..396f23c0 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -1,9 +1,11 @@ -use anyhow::Result; +use anyhow::{ensure, Result}; use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; use crate::field::extension_field::Extendable; use crate::plonk_challenger::Challenger; +use crate::plonk_common::{eval_vanishing_poly, eval_zero_poly}; use crate::proof::Proof; +use crate::vars::EvaluationVars; pub(crate) fn verify, const D: usize>( proof: Proof, @@ -29,7 +31,35 @@ pub(crate) fn verify, const D: usize>( challenger.observe_hash(&proof.quotient_polys_root); let zeta = challenger.get_extension_challenge(); - // TODO: Compute PI(zeta), Z_H(zeta), etc. and check the identity at zeta. + let local_constants = &proof.openings.constants; + let local_wires = &proof.openings.wires; + let vars = EvaluationVars { + local_constants, + local_wires, + }; + let local_plonk_zs = &proof.openings.plonk_zs; + let next_plonk_zs = &proof.openings.plonk_zs_right; + let s_sigmas = &proof.openings.plonk_s_sigmas; + + // Evaluate the vanishing polynomial at our challenge point, zeta. + let vanishing_polys_zeta = eval_vanishing_poly( + common_data, + zeta, + vars, + local_plonk_zs, + next_plonk_zs, + s_sigmas, + &betas, + &gammas, + &alphas, + ); + + // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta. + let quotient_polys_zeta = proof.openings.quotient_polys; + let z_h_zeta = eval_zero_poly(common_data.degree(), zeta); + for i in 0..num_challenges { + ensure!(vanishing_polys_zeta[i] == z_h_zeta * quotient_polys_zeta[i]); + } let evaluations = todo!();