diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 610fbc55..7f9b44bd 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -4,7 +4,6 @@ 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::polynomial::old_polynomial::Polynomial; use crate::polynomial::polynomial::PolynomialCoeffs; use crate::proof::{FriProof, Hash}; use crate::util::{log2_strict, reverse_index_bits_in_place, transpose}; @@ -84,8 +83,9 @@ impl ListPolynomialCommitment { .polynomials .iter() .rev() - .map(|p| p.clone().into()) - .fold(Polynomial::empty(), |acc, p| acc.scalar_mul(alpha).add(&p)); + .fold(PolynomialCoeffs::zero(self.degree), |acc, p| { + &(&acc * alpha) + &p + }); // Scale evaluations by `alpha`. let composition_evals = evaluations .iter() @@ -118,7 +118,11 @@ impl ListPolynomialCommitment { /// Given `points=(x_i)`, `evals=(y_i)` and `poly=P` with `P(x_i)=y_i`, computes the polynomial /// `Q=(P-I)/Z` where `I` interpolates `(x_i, y_i)` and `Z` is the vanishing polynomial on `(x_i)`. - fn compute_quotient(points: &[F], evals: &[F], poly: &Polynomial) -> Polynomial { + fn compute_quotient( + points: &[F], + evals: &[F], + poly: &PolynomialCoeffs, + ) -> PolynomialCoeffs { let pairs = points .iter() .zip(evals) @@ -126,18 +130,15 @@ impl ListPolynomialCommitment { .collect::>(); debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e)); - let interpolant: Polynomial = interpolant(&pairs).into(); - let denominator = points - .iter() - .fold(Polynomial::from(vec![F::ONE]), |acc, &x| { - acc.mul(&vec![-x, F::ONE].into()) - }); - let numerator = poly.add(&interpolant.neg()); - let (mut quotient, rem) = numerator.polynomial_division(&denominator); + let interpolant = interpolant(&pairs); + let denominator = points.iter().fold(PolynomialCoeffs::one(), |acc, &x| { + &acc * &PolynomialCoeffs::new(vec![-x, F::ONE]) + }); + let numerator = poly - &interpolant; + let (mut quotient, rem) = numerator.div_rem(&denominator); debug_assert!(rem.is_zero()); - quotient.pad((quotient.degree() + 1).next_power_of_two()); - quotient + quotient.padded(quotient.degree_plus_one().next_power_of_two()) } } diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index 113a6d2a..a0cdeb8b 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -1,7 +1,10 @@ +use std::cmp::max; +use std::ops::{Add, Mul, Sub}; + use crate::field::fft::{fft, ifft}; use crate::field::field::Field; +use crate::polynomial::old_polynomial::Polynomial; use crate::util::log2_strict; -use std::slice::Iter; /// A polynomial in point-value form. /// @@ -65,6 +68,14 @@ impl PolynomialCoeffs { Self::new(vec![F::ZERO; len]) } + pub(crate) fn one() -> Self { + Self::new(vec![F::ONE]) + } + + pub(crate) fn is_zero(&self) -> bool { + self.coeffs.iter().all(|x| x.is_zero()) + } + /// The number of coefficients. This does not filter out any zero coefficients, so it is not /// necessarily related to the degree. pub(crate) fn len(&self) -> usize { @@ -93,13 +104,13 @@ impl PolynomialCoeffs { polys.into_iter().map(|p| p.lde(rate_bits)).collect() } - pub(crate) fn lde(self, rate_bits: usize) -> Self { - let original_size = self.len(); - let lde_size = original_size << rate_bits; - let Self { mut coeffs } = self; - for _ in 0..(lde_size - original_size) { - coeffs.push(F::ZERO); - } + pub(crate) fn lde(&self, rate_bits: usize) -> Self { + self.padded(self.len() << rate_bits) + } + + pub(crate) fn padded(&self, new_len: usize) -> Self { + let mut coeffs = self.coeffs.clone(); + coeffs.resize(new_len, F::ZERO); Self { coeffs } } @@ -109,13 +120,20 @@ impl PolynomialCoeffs { } /// Degree of the polynomial + 1. - fn degree_plus_one(&self) -> usize { + pub(crate) fn degree_plus_one(&self) -> usize { (0usize..self.len()) .rev() .find(|&i| self.coeffs[i].is_nonzero()) .map_or(0, |i| i + 1) } + pub(crate) fn div_rem(&self, rhs: &Self) -> (Self, Self) { + let lhs = Polynomial::from(self.clone()); + let rhs = Polynomial::from(rhs.clone()); + let (q, r) = lhs.polynomial_long_division(&rhs); + (q.into(), r.into()) + } + pub fn fft(self) -> PolynomialValues { fft(self) } @@ -137,11 +155,69 @@ impl From> for PolynomialCoeffs { } } +impl Add for &PolynomialCoeffs { + type Output = PolynomialCoeffs; + + fn add(self, rhs: Self) -> Self::Output { + let len = max(self.len(), rhs.len()); + let mut coeffs = self.coeffs.clone(); + coeffs.resize(len, F::ZERO); + for (i, &c) in rhs.coeffs.iter().enumerate() { + coeffs[i] += c; + } + PolynomialCoeffs::new(coeffs) + } +} + +impl Sub for &PolynomialCoeffs { + type Output = PolynomialCoeffs; + + fn sub(self, rhs: Self) -> Self::Output { + let len = max(self.len(), rhs.len()); + let mut coeffs = self.coeffs.clone(); + coeffs.resize(len, F::ZERO); + for (i, &c) in rhs.coeffs.iter().enumerate() { + coeffs[i] -= c; + } + PolynomialCoeffs::new(coeffs) + } +} + +impl Mul for &PolynomialCoeffs { + type Output = PolynomialCoeffs; + + fn mul(self, rhs: F) -> Self::Output { + let coeffs = self.coeffs.iter().map(|&x| rhs * x).collect(); + PolynomialCoeffs::new(coeffs) + } +} + +impl Mul for &PolynomialCoeffs { + type Output = PolynomialCoeffs; + + fn mul(self, rhs: Self) -> Self::Output { + let new_len = (self.len() + rhs.len()).next_power_of_two(); + let a = self.padded(new_len); + let b = rhs.padded(new_len); + let a_evals = a.fft(); + let b_evals = b.fft(); + + let mul_evals: Vec = a_evals + .values + .into_iter() + .zip(b_evals.values) + .map(|(pa, pb)| pa * pb) + .collect(); + ifft(mul_evals.into()) + } +} + #[cfg(test)] mod tests { - use super::*; use crate::field::crandall_field::CrandallField; + use super::*; + #[test] fn test_coset_fft() { type F = CrandallField;