Some cleanup related to the two polynomial APIs

Porting over some code from `old_polynomial`, and changing `ListPolynomialCommitment` to use the newer API.

There's one remaining use of `old_polynomial` for long division; I think that can eventually go away when we switch to doing values-only FRI (unless another use comes up).
This commit is contained in:
Daniel Lubarov 2021-05-10 12:58:58 -07:00
parent e44fbb86d0
commit 44a5e0be1b
2 changed files with 101 additions and 24 deletions

View File

@ -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<F: Field> ListPolynomialCommitment<F> {
.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<F: Field> ListPolynomialCommitment<F> {
/// 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<F>) -> Polynomial<F> {
fn compute_quotient(
points: &[F],
evals: &[F],
poly: &PolynomialCoeffs<F>,
) -> PolynomialCoeffs<F> {
let pairs = points
.iter()
.zip(evals)
@ -126,18 +130,15 @@ impl<F: Field> ListPolynomialCommitment<F> {
.collect::<Vec<_>>();
debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e));
let interpolant: Polynomial<F> = interpolant(&pairs).into();
let denominator = points
.iter()
.fold(Polynomial::from(vec![F::ONE]), |acc, &x| {
acc.mul(&vec![-x, F::ONE].into())
let interpolant = interpolant(&pairs);
let denominator = points.iter().fold(PolynomialCoeffs::one(), |acc, &x| {
&acc * &PolynomialCoeffs::new(vec![-x, F::ONE])
});
let numerator = poly.add(&interpolant.neg());
let (mut quotient, rem) = numerator.polynomial_division(&denominator);
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())
}
}

View File

@ -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<F: Field> PolynomialCoeffs<F> {
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<F: Field> PolynomialCoeffs<F> {
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<F: Field> PolynomialCoeffs<F> {
}
/// 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<F> {
fft(self)
}
@ -137,11 +155,69 @@ impl<F: Field> From<Vec<F>> for PolynomialCoeffs<F> {
}
}
impl<F: Field> Add for &PolynomialCoeffs<F> {
type Output = PolynomialCoeffs<F>;
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<F: Field> Sub for &PolynomialCoeffs<F> {
type Output = PolynomialCoeffs<F>;
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<F: Field> Mul<F> for &PolynomialCoeffs<F> {
type Output = PolynomialCoeffs<F>;
fn mul(self, rhs: F) -> Self::Output {
let coeffs = self.coeffs.iter().map(|&x| rhs * x).collect();
PolynomialCoeffs::new(coeffs)
}
}
impl<F: Field> Mul for &PolynomialCoeffs<F> {
type Output = PolynomialCoeffs<F>;
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<F> = 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;