diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 19b3f4b9..e403cd36 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -13,7 +13,7 @@ use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::{FriProof, FriProofTarget, Hash, OpeningSet}; use crate::timed; use crate::util::scaling::ReducingFactor; -use crate::util::{log2_strict, reverse_index_bits_in_place, transpose}; +use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place, transpose}; pub const SALT_SIZE: usize = 2; @@ -111,6 +111,11 @@ impl ListPolynomialCommitment { pub fn original_values(&self, index: usize) -> Vec { self.values.iter().map(|v| v.values[index]).collect() } + pub fn get_lde_values(&self, mut index: usize) -> &[F] { + reverse_bits(index, self.degree_log + self.rate_bits); + let slice = &self.merkle_tree.leaves[index]; + &slice[..slice.len() - if self.blinding { SALT_SIZE } else { 0 }] + } /// Takes the commitments to the constants - sigmas - wires - zs - quotient — polynomials, /// and an opening point `zeta` and produces a batched opening proof + opening set. diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index 54c96c7e..e176aaf8 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -34,6 +34,18 @@ impl PolynomialValues { ifft(self) } + pub fn coset_ifft(self, shift: F) -> PolynomialCoeffs { + let mut shifted_coeffs = self.ifft(); + shifted_coeffs + .coeffs + .iter_mut() + .zip(shift.inverse().powers()) + .for_each(|(c, r)| { + *c *= r; + }); + shifted_coeffs + } + pub fn lde_multiple(polys: Vec, rate_bits: usize) -> Vec { polys.into_iter().map(|p| p.lde(rate_bits)).collect() } @@ -127,16 +139,20 @@ impl PolynomialCoeffs { self.padded(self.len() << rate_bits) } - pub(crate) fn padded(&self, new_len: usize) -> Self { + pub(crate) fn pad(&mut self, new_len: usize) { assert!( new_len >= self.len(), "Trying to pad a polynomial of length {} to a length of {}.", self.len(), new_len ); - let mut coeffs = self.coeffs.clone(); - coeffs.resize(new_len, F::ZERO); - Self { coeffs } + self.coeffs.resize(new_len, F::ZERO); + } + + pub(crate) fn padded(&self, new_len: usize) -> Self { + let mut poly = self.clone(); + poly.pad(new_len); + poly } /// Removes leading zero coefficients. diff --git a/src/prover.rs b/src/prover.rs index 16f63fdb..cd03f6e7 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -10,7 +10,7 @@ use crate::generator::generate_partial_witness; use crate::plonk_challenger::Challenger; use crate::plonk_common::eval_vanishing_poly_base; use crate::polynomial::commitment::ListPolynomialCommitment; -use crate::polynomial::polynomial::PolynomialValues; +use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::Proof; use crate::timed; use crate::util::transpose; @@ -89,8 +89,8 @@ pub(crate) fn prove, const D: usize>( let alphas = challenger.get_n_challenges(num_challenges); - let vanishing_polys = timed!( - compute_vanishing_polys( + let quotient_polys = timed!( + compute_quotient_polys( common_data, prover_data, &wires_commitment, @@ -104,21 +104,13 @@ pub(crate) fn prove, const D: usize>( // Compute the quotient polynomials, aka `t` in the Plonk paper. let all_quotient_poly_chunks = timed!( - vanishing_polys + quotient_polys .into_par_iter() - .flat_map(|vanishing_poly| { - let vanishing_poly_coeff = ifft(vanishing_poly); - // TODO: run `padded` when the division works. - let quotient_poly_coeff = vanishing_poly_coeff.divide_by_z_h(degree); - let x = F::rand(); - assert!( - quotient_poly_coeff.eval(x) * (x.exp(degree as u64) - F::ONE) - != vanishing_poly_coeff.eval(x), - "That's good news, this should fail! The division by z_h doesn't work yet,\ - most likely because compute_vanishing_polys isn't complete (doesn't use filters for example)." - ); + .flat_map(|mut quotient_poly| { + quotient_poly.trim(); + quotient_poly.pad(quotient_degree); // Split t into degree-n chunks. - quotient_poly_coeff.chunks(degree) + quotient_poly.chunks(degree) }) .collect(), "to compute quotient polys" @@ -208,49 +200,50 @@ fn compute_z, const D: usize>( plonk_z_points.into() } -fn compute_vanishing_polys, const D: usize>( +fn compute_quotient_polys<'a, F: Extendable, const D: usize>( common_data: &CommonCircuitData, - prover_data: &ProverOnlyCircuitData, - wires_commitment: &ListPolynomialCommitment, - plonk_zs_commitment: &ListPolynomialCommitment, + prover_data: &'a ProverOnlyCircuitData, + wires_commitment: &'a ListPolynomialCommitment, + plonk_zs_commitment: &'a ListPolynomialCommitment, betas: &[F], gammas: &[F], alphas: &[F], -) -> Vec> { +) -> Vec> { let num_challenges = common_data.config.num_challenges; + assert!( + common_data.max_filtered_constraint_degree_bits <= common_data.config.rate_bits, + "Having constraints of degree higher than the rate is not supported yet. \ + If we need this in the future, we can precompute the larger LDE before computing the `ListPolynomialCommitment`s." + ); + + // We reuse the LDE computed in `ListPolynomialCommitment` and extract every `step` points to get + // an LDE matching `max_filtered_constraint_degree`. + let step = + 1 << (common_data.config.rate_bits - common_data.max_filtered_constraint_degree_bits); + // When opening the `Z`s polys at the "next" point in Plonk, need to look at the point `next_step` + // steps away since we work on an LDE of degree `max_filtered_constraint_degree`. + let next_step = 1 << common_data.max_filtered_constraint_degree_bits; + let points = F::two_adic_subgroup( common_data.degree_bits + common_data.max_filtered_constraint_degree_bits, ); let lde_size = points.len(); - // Low-degree extend the polynomials commited in `comm` to the subgroup of size `lde_size`. - let commitment_to_lde = |comm: &ListPolynomialCommitment| -> Vec> { - comm.polynomials - .iter() - .map(|p| p.lde(common_data.max_filtered_constraint_degree_bits).fft()) - .collect() + // Retrieve the LDE values at index `i`. + let get_at_index = |comm: &'a ListPolynomialCommitment, i: usize| -> &'a [F] { + comm.get_lde_values(i * step) }; - let constants_lde = commitment_to_lde(&prover_data.constants_commitment); - let sigmas_lde = commitment_to_lde(&prover_data.sigmas_commitment); - let wires_lde = commitment_to_lde(wires_commitment); - let zs_lde = commitment_to_lde(plonk_zs_commitment); - - // Retrieve the polynomial values at index `i`. - let get_at_index = |ldes: &[PolynomialValues], i: usize| { - ldes.iter().map(|l| l.values[i]).collect::>() - }; - - let values: Vec> = points + let quotient_values: Vec> = points .into_par_iter() .enumerate() .map(|(i, x)| { - let i_next = (i + 1) % lde_size; - let local_constants = &get_at_index(&constants_lde, i); - let s_sigmas = &get_at_index(&sigmas_lde, i); - let local_wires = &get_at_index(&wires_lde, i); - let local_plonk_zs = &get_at_index(&zs_lde, i); - let next_plonk_zs = &get_at_index(&zs_lde, i_next); + let i_next = (i + next_step) % lde_size; + let local_constants = get_at_index(&prover_data.constants_commitment, i); + let s_sigmas = get_at_index(&prover_data.sigmas_commitment, i); + let local_wires = get_at_index(&wires_commitment, i); + let local_plonk_zs = get_at_index(&plonk_zs_commitment, i); + let next_plonk_zs = get_at_index(&plonk_zs_commitment, i_next); debug_assert_eq!(local_wires.len(), common_data.config.num_wires); debug_assert_eq!(local_plonk_zs.len(), num_challenges); @@ -259,7 +252,7 @@ fn compute_vanishing_polys, const D: usize>( local_constants, local_wires, }; - eval_vanishing_poly_base( + let mut quotient_values = eval_vanishing_poly_base( common_data, x, vars, @@ -269,12 +262,19 @@ fn compute_vanishing_polys, const D: usize>( betas, gammas, alphas, - ) + ); + // TODO: We can avoid computing the exp. + let denominator_inv = x.exp(common_data.degree() as u64).inverse(); + quotient_values + .iter_mut() + .for_each(|v| *v *= denominator_inv); + quotient_values }) .collect(); - transpose(&values) + transpose("ient_values) .into_iter() .map(PolynomialValues::new) + .map(|values| values.coset_ifft(F::MULTIPLICATIVE_GROUP_GENERATOR)) .collect() }