From fe9cd3f76b2da36fd4a8bfd84d830fe91f72d618 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 17 Jun 2021 21:34:04 +0200 Subject: [PATCH] Working commitments and verifier --- src/fri/verifier.rs | 26 +++++++++++-------- src/polynomial/commitment.rs | 48 +++++++++++++++++++++++------------- src/util/scaling.rs | 32 +++++++++++++++++++++--- 3 files changed, 76 insertions(+), 30 deletions(-) diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index f27070b2..50537a9e 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -168,17 +168,22 @@ fn fri_combine_initial, const D: usize>( ] .iter() .flat_map(|&p| proof.unsalted_evals(p)) - .map(|&e| F::Extension::from_basefield(e)); + .map(|&e| F::Extension::from_basefield(e)) + .collect::>(); let single_openings = os .constants .iter() .chain(&os.plonk_s_sigmas) - .chain(&os.quotient_polys); - let single_diffs = single_evals.zip(single_openings).map(|(e, &o)| e - o); - let single_numerator = reduce_with_iter(single_diffs, &mut alpha_powers); + .chain(&os.quotient_polys) + .collect::>(); + let single_diffs = single_evals + .into_iter() + .zip(single_openings) + .map(|(e, &o)| e - o); + let single_numerator = alpha.scale(single_diffs); let single_denominator = subgroup_x - zeta; sum += single_numerator / single_denominator; - alpha.shift(sum); + alpha.reset(); // Polynomials opened at `x` and `g x`, i.e., the Zs polynomials. let zs_evals = proof @@ -188,13 +193,13 @@ fn fri_combine_initial, const D: usize>( let zs_composition_eval = alpha.clone().scale(zs_evals); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; let zs_interpol = interpolant(&[ - (zeta, alpha.clone().scale(&os.plonk_zs)), - (zeta_right, alpha.scale(&os.plonk_zs_right)), + (zeta, alpha.clone().scale(os.plonk_zs.iter())), + (zeta_right, alpha.scale(os.plonk_zs_right.iter())), ]); let zs_numerator = zs_composition_eval - zs_interpol.eval(subgroup_x); let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); + sum = alpha.shift(sum); sum += zs_numerator / zs_denominator; - alpha.shift(sum); // Polynomials opened at `x` and `x.frobenius()`, i.e., the wires polynomials. let wire_evals = proof @@ -203,17 +208,18 @@ fn fri_combine_initial, const D: usize>( .map(|&e| F::Extension::from_basefield(e)); let wire_composition_eval = alpha.clone().scale(wire_evals); let zeta_frob = zeta.frobenius(); - let wire_eval = alpha.clone().scale(&os.wires); + let wire_eval = alpha.clone().scale(os.wires.iter()); // We want to compute `sum a^i*phi(w_i)`, where `phi` denotes the Frobenius automorphism. // Since `phi^D=id` and `phi` is a field automorphism, we have the following equalities: // `sum a^i*phi(w_i) = sum phi(phi^(D-1)(a^i)*w_i) = phi(sum phi^(D-1)(a)^i*w_i)` // So we can compute the original sum using only one call to the `D-1`-repeated Frobenius of alpha, // and one call at the end of the sum. let mut alpha_frob = alpha.repeated_frobenius(D - 1); - let wire_eval_frob = alpha_frob.scale(&os.wires).frobenius(); + let wire_eval_frob = alpha_frob.scale(os.wires.iter()).frobenius(); let wire_interpol = interpolant(&[(zeta, wire_eval), (zeta_frob, wire_eval_frob)]); let wire_numerator = wire_composition_eval - wire_interpol.eval(subgroup_x); let wire_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); + sum = alpha_frob.shift(sum); sum += wire_numerator / wire_denominator; sum diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index caa61553..9fa7bc01 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -8,10 +8,11 @@ use crate::field::lagrange::interpolant; use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig}; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; -use crate::plonk_common::{reduce_polys_with_iter, reduce_with_iter}; +use crate::plonk_common::{reduce_polys_with_iter, reduce_with_iter, PlonkPolynomials}; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriProof, FriProofTarget, Hash, OpeningSet}; use crate::timed; +use crate::util::scaling::ScalingFactor; use crate::util::{log2_strict, reverse_index_bits_in_place, transpose}; pub const SALT_SIZE: usize = 2; @@ -110,20 +111,24 @@ impl ListPolynomialCommitment { challenger.observe_opening_set(&os); let alpha = challenger.get_extension_challenge(); - let mut alpha_powers = alpha.powers(); + let mut alpha = ScalingFactor::new(alpha); // Final low-degree polynomial that goes into FRI. let mut final_poly = PolynomialCoeffs::empty(); // Polynomials opened at a single point. - let single_polys = [0, 1, 4] - .iter() - .flat_map(|&i| &commitments[i].polynomials) - .map(|p| p.to_extension()); + let single_polys = [ + PlonkPolynomials::CONSTANTS, + PlonkPolynomials::SIGMAS, + PlonkPolynomials::QUOTIENT, + ] + .iter() + .flat_map(|&p| &commitments[p.index].polynomials) + .map(|p| p.to_extension()); let single_os = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys]; let single_evals = single_os.iter().flat_map(|v| v.iter()); - let single_composition_poly = reduce_polys_with_iter(single_polys, alpha_powers.clone()); - let single_composition_eval = reduce_with_iter(single_evals, &mut alpha_powers); + let single_composition_poly = alpha.clone().scale_polys(single_polys); + let single_composition_eval = alpha.scale(single_evals); let single_quotient = Self::compute_quotient( &[zeta], @@ -131,13 +136,17 @@ impl ListPolynomialCommitment { &single_composition_poly, ); final_poly = &final_poly + &single_quotient; + alpha.reset(); // Zs polynomials are opened at `zeta` and `g*zeta`. - let zs_polys = commitments[3].polynomials.iter().map(|p| p.to_extension()); - let zs_composition_poly = reduce_polys_with_iter(zs_polys, alpha_powers.clone()); + let zs_polys = commitments[PlonkPolynomials::ZS.index] + .polynomials + .iter() + .map(|p| p.to_extension()); + let zs_composition_poly = alpha.clone().scale_polys(zs_polys); let zs_composition_evals = [ - reduce_with_iter(&os.plonk_zs, alpha_powers.clone()), - reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), + alpha.clone().scale(os.plonk_zs.iter()), + alpha.scale(os.plonk_zs_right.iter()), ]; let zs_quotient = Self::compute_quotient( @@ -145,17 +154,21 @@ impl ListPolynomialCommitment { &zs_composition_evals, &zs_composition_poly, ); + final_poly = alpha.shift_poly(final_poly); final_poly = &final_poly + &zs_quotient; // When working in an extension field, need to check that wires are in the base field. // Check this by opening the wires polynomials at `zeta` and `zeta.frobenius()` and using the fact that // a polynomial `f` is over the base field iff `f(z).frobenius()=f(z.frobenius())` with high probability. - let wire_polys = commitments[2].polynomials.iter().map(|p| p.to_extension()); - let wire_composition_poly = reduce_polys_with_iter(wire_polys, alpha_powers.clone()); - let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wire_polys = commitments[PlonkPolynomials::WIRES.index] + .polynomials + .iter() + .map(|p| p.to_extension()); + let wire_composition_poly = alpha.clone().scale_polys(wire_polys); + let mut alpha_frob = alpha.repeated_frobenius(D - 1); let wire_composition_evals = [ - reduce_with_iter(&os.wires, alpha_powers.clone()), - reduce_with_iter(&wire_evals_frob, alpha_powers), + alpha.clone().scale(os.wires.iter()), + alpha_frob.scale(os.wires.iter()).frobenius(), ]; let wires_quotient = Self::compute_quotient( @@ -163,6 +176,7 @@ impl ListPolynomialCommitment { &wire_composition_evals, &wire_composition_poly, ); + final_poly = alpha_frob.shift_poly(final_poly); final_poly = &final_poly + &wires_quotient; let lde_final_poly = final_poly.lde(config.rate_bits); diff --git a/src/util/scaling.rs b/src/util/scaling.rs index 36148d85..e29edf0e 100644 --- a/src/util/scaling.rs +++ b/src/util/scaling.rs @@ -2,8 +2,9 @@ use std::borrow::Borrow; use crate::field::extension_field::Frobenius; use crate::field::field::Field; +use crate::polynomial::polynomial::PolynomialCoeffs; -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct ScalingFactor { base: F, count: u64, @@ -14,13 +15,28 @@ impl ScalingFactor { Self { base, count: 0 } } - pub fn mul(&mut self, x: F) -> F { + fn mul(&mut self, x: F) -> F { self.count += 1; self.base * x } + fn mul_poly(&mut self, p: PolynomialCoeffs) -> PolynomialCoeffs { + self.count += 1; + &p * self.base + } + pub fn scale(&mut self, iter: impl DoubleEndedIterator>) -> F { - iter.rev().fold(F::ZERO, |acc, x| self.mul(acc) + x) + iter.rev() + .fold(F::ZERO, |acc, x| self.mul(acc) + *x.borrow()) + } + + pub fn scale_polys( + &mut self, + polys: impl DoubleEndedIterator>>, + ) -> PolynomialCoeffs { + polys.rev().fold(PolynomialCoeffs::empty(), |acc, x| { + &self.mul_poly(acc) + x.borrow() + }) } pub fn shift(&mut self, x: F) -> F { @@ -29,6 +45,16 @@ impl ScalingFactor { tmp } + pub fn shift_poly(&mut self, p: PolynomialCoeffs) -> PolynomialCoeffs { + let tmp = &p * self.base.exp(self.count); + self.count = 0; + tmp + } + + pub fn reset(&mut self) { + self.count = 0; + } + pub fn repeated_frobenius(&self, count: usize) -> Self where F: Frobenius,