diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 24e24f64..68f4ee15 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -1,5 +1,4 @@ use anyhow::{ensure, Result}; -use itertools::izip; use crate::field::extension_field::{flatten, Extendable, FieldExtension, OEF}; use crate::field::field::Field; @@ -156,31 +155,29 @@ fn fri_combine_initial, const D: usize>( let mut sum = F::Extension::ZERO; // We will add three terms to `sum`: - // - one for polynomials opened at `x` only - // - one for polynomials opened at `x` and `g x` - // - one for polynomials opened at `x` and its conjugate + // - one for various polynomials which are opened at a single point `x` + // - one for Zs, which are opened at `x` and `g x` + // - one for wire polynomials, which are opened at `x` and its conjugate - let evals = [0, 1, 4] + let single_evals = [0, 1, 4] .iter() .flat_map(|&i| proof.unsalted_evals(i, config)) .map(|&e| F::Extension::from_basefield(e)); - let openings = os + let single_openings = os .constants .iter() .chain(&os.plonk_s_sigmas) .chain(&os.quotient_polys); - let numerator = izip!(evals, openings, &mut alpha_powers) - .map(|(e, &o, a)| a * (e - o)) - .sum::(); - let denominator = subgroup_x - zeta; - sum += numerator / denominator; + let single_diffs = single_evals.zip(single_openings).map(|(e, &o)| e - o); + let single_numerator = reduce_with_iter(single_diffs, &mut alpha_powers); + let single_denominator = subgroup_x - zeta; + sum += single_numerator / single_denominator; - let ev: F::Extension = proof + let zs_evals = proof .unsalted_evals(3, config) .iter() - .zip(alpha_powers.clone()) - .map(|(&e, a)| a * e.into()) - .sum(); + .map(|&e| F::Extension::from_basefield(e)); + let zs_composition_eval = reduce_with_iter(zs_evals, alpha_powers.clone()); let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta; let zs_interpol = interpolant(&[ (zeta, reduce_with_iter(&os.plonk_zs, alpha_powers.clone())), @@ -189,25 +186,24 @@ fn fri_combine_initial, const D: usize>( reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), ), ]); - let numerator = ev - zs_interpol.eval(subgroup_x); - let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); - sum += numerator / denominator; + let zs_numerator = zs_composition_eval - zs_interpol.eval(subgroup_x); + let zs_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right); + sum += zs_numerator / zs_denominator; - let ev: F::Extension = proof + let wire_evals = proof .unsalted_evals(2, config) .iter() - .zip(alpha_powers.clone()) - .map(|(&e, a)| a * e.into()) - .sum(); + .map(|&e| F::Extension::from_basefield(e)); + let wire_composition_eval = reduce_with_iter(wire_evals, alpha_powers.clone()); let zeta_frob = zeta.frobenius(); - let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::>(); + let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()); let wires_interpol = interpolant(&[ (zeta, reduce_with_iter(&os.wires, alpha_powers.clone())), - (zeta_frob, reduce_with_iter(&wire_evals_frob, alpha_powers)), + (zeta_frob, reduce_with_iter(wire_evals_frob, alpha_powers)), ]); - let numerator = ev - wires_interpol.eval(subgroup_x); - let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); - sum += numerator / denominator; + let wires_numerator = wire_composition_eval - wires_interpol.eval(subgroup_x); + let wires_denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob); + sum += wires_numerator / wires_denominator; sum } diff --git a/src/plonk_common.rs b/src/plonk_common.rs index e84cb340..e8c3c995 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -1,9 +1,12 @@ +use std::borrow::Borrow; + 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; use crate::gates::gate::GateRef; +use crate::polynomial::polynomial::PolynomialCoeffs; use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; @@ -209,13 +212,26 @@ pub(crate) fn reduce_with_powers_recursive, const D: usize>( todo!() } -pub(crate) fn reduce_with_iter(terms: &[F], coeffs: I) -> F -where - I: IntoIterator, -{ - let mut sum = F::ZERO; - for (&term, coeff) in terms.iter().zip(coeffs) { - sum += coeff * term; - } - sum +/// Reduce a sequence of field elements by the given coefficients. +pub(crate) fn reduce_with_iter( + terms: impl IntoIterator>, + coeffs: impl IntoIterator>, +) -> F { + terms + .into_iter() + .zip(coeffs) + .map(|(t, c)| *t.borrow() * *c.borrow()) + .sum() +} + +/// Reduce a sequence of polynomials by the given coefficients. +pub(crate) fn reduce_polys_with_iter( + polys: impl IntoIterator>>, + coeffs: impl IntoIterator>, +) -> PolynomialCoeffs { + polys + .into_iter() + .zip(coeffs) + .map(|(p, c)| p.borrow() * *c.borrow()) + .sum() } diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index e8cb2542..5169748b 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -8,7 +8,7 @@ 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_with_powers; +use crate::plonk_common::{reduce_polys_with_iter, reduce_with_iter}; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriProof, Hash, OpeningSet}; use crate::timed; @@ -90,7 +90,7 @@ impl ListPolynomialCommitment { assert!(D > 1, "Not implemented for D=1."); let degree_log = log2_strict(commitments[0].degree); let g = F::Extension::primitive_root_of_unity(degree_log); - for &p in &[zeta, g * zeta] { + for p in &[zeta, g * zeta] { assert_ne!( p.exp(1 << degree_log as u64), F::Extension::ONE, @@ -110,45 +110,34 @@ impl ListPolynomialCommitment { challenger.observe_opening_set(&os); let alpha = challenger.get_extension_challenge(); - let mut cur_alpha = F::Extension::ONE; + let mut alpha_powers = alpha.powers(); // Final low-degree polynomial that goes into FRI. let mut final_poly = PolynomialCoeffs::empty(); - // Count the total number of polynomials accumulated into `final_poly`. - let mut poly_count = 0; // Polynomials opened at a single point. - let composition_poly = [0, 1, 4] + let single_polys = [0, 1, 4] .iter() .flat_map(|&i| &commitments[i].polynomials) - .rev() - .fold(PolynomialCoeffs::empty(), |acc, p| { - poly_count += 1; - &(&acc * alpha) + &p.to_extension() - }); - let composition_eval = [&os.constants, &os.plonk_s_sigmas, &os.quotient_polys] - .iter() - .flat_map(|v| v.iter()) - .rev() - .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e); + .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 quotient = Self::compute_quotient(&[zeta], &[composition_eval], &composition_poly); - final_poly = &final_poly + &("ient * cur_alpha); - cur_alpha = alpha.exp(poly_count); + let single_quotient = Self::compute_quotient( + &[zeta], + &[single_composition_eval], + &single_composition_poly, + ); + final_poly = &final_poly + &single_quotient; // Zs polynomials are opened at `zeta` and `g*zeta`. - let zs_composition_poly = - commitments[3] - .polynomials - .iter() - .rev() - .fold(PolynomialCoeffs::empty(), |acc, p| { - poly_count += 1; - &(&acc * alpha) + &p.to_extension() - }); + 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_composition_evals = [ - reduce_with_powers(&os.plonk_zs, alpha), - reduce_with_powers(&os.plonk_zs_right, alpha), + reduce_with_iter(&os.plonk_zs, alpha_powers.clone()), + reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers), ]; let zs_quotient = Self::compute_quotient( @@ -156,33 +145,25 @@ impl ListPolynomialCommitment { &zs_composition_evals, &zs_composition_poly, ); - final_poly = &final_poly + &(&zs_quotient * cur_alpha); - cur_alpha = alpha.exp(poly_count); + 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 wires_composition_poly = - commitments[2] - .polynomials - .iter() - .rev() - .fold(PolynomialCoeffs::empty(), |acc, p| { - poly_count += 1; - &(&acc * alpha) + &p.to_extension() - }); + 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 wires_composition_evals = [ - reduce_with_powers(&os.wires, alpha), - reduce_with_powers(&wire_evals_frob, alpha), + let wire_composition_evals = [ + reduce_with_iter(&os.wires, alpha_powers.clone()), + reduce_with_iter(&wire_evals_frob, alpha_powers), ]; let wires_quotient = Self::compute_quotient( &[zeta, zeta.frobenius()], - &wires_composition_evals, - &wires_composition_poly, + &wire_composition_evals, + &wire_composition_poly, ); - final_poly = &final_poly + &(&wires_quotient * cur_alpha); + final_poly = &final_poly + &wires_quotient; let lde_final_poly = final_poly.lde(config.rate_bits); let lde_final_values = lde_final_poly @@ -275,9 +256,9 @@ impl, const D: usize> OpeningProof { #[cfg(test)] mod tests { use anyhow::Result; + use rand::Rng; use super::*; - use rand::Rng; fn gen_random_test_case, const D: usize>( k: usize, @@ -359,8 +340,10 @@ mod tests { } mod quadratic { - use super::*; use crate::field::crandall_field::CrandallField; + + use super::*; + #[test] fn test_batch_polynomial_commitment() -> Result<()> { check_batch_polynomial_commitment::() @@ -368,8 +351,10 @@ mod tests { } mod quartic { - use super::*; use crate::field::crandall_field::CrandallField; + + use super::*; + #[test] fn test_batch_polynomial_commitment() -> Result<()> { check_batch_polynomial_commitment::() diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index 5e3dd9f0..7c30ec02 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -5,6 +5,7 @@ use crate::field::extension_field::Extendable; use crate::field::fft::{fft, ifft}; use crate::field::field::Field; use crate::util::log2_strict; +use std::iter::Sum; /// A polynomial in point-value form. /// @@ -222,6 +223,12 @@ impl Add for &PolynomialCoeffs { } } +impl Sum for PolynomialCoeffs { + fn sum>(iter: I) -> Self { + iter.fold(Self::empty(), |acc, p| &acc + &p) + } +} + impl Sub for &PolynomialCoeffs { type Output = PolynomialCoeffs;