use crate::field::fft::{fft, ifft}; use crate::field::field::Field; use crate::util::log2_strict; /// A polynomial in point-value form. /// /// The points are implicitly `g^i`, where `g` generates the subgroup whose size equals the number /// of points. #[derive(Clone, Debug, Eq, PartialEq)] pub struct PolynomialValues { pub values: Vec, } impl PolynomialValues { pub fn new(values: Vec) -> Self { PolynomialValues { values } } pub(crate) fn zero(len: usize) -> Self { Self::new(vec![F::ZERO; len]) } /// The number of values stored. pub(crate) fn len(&self) -> usize { self.values.len() } pub fn lde_multiple(polys: Vec, rate_bits: usize) -> Vec { polys.into_iter().map(|p| p.lde(rate_bits)).collect() } pub fn lde(self, rate_bits: usize) -> Self { let coeffs = ifft(self).lde(rate_bits); fft(coeffs) } } /// A polynomial in coefficient form. #[derive(Clone, Debug, Eq, PartialEq)] pub struct PolynomialCoeffs { pub(crate) coeffs: Vec, } impl PolynomialCoeffs { pub fn new(coeffs: Vec) -> Self { PolynomialCoeffs { coeffs } } /// Create a new polynomial with its coefficient list padded to the next power of two. pub(crate) fn new_padded(mut coeffs: Vec) -> Self { while !coeffs.len().is_power_of_two() { coeffs.push(F::ZERO); } PolynomialCoeffs { coeffs } } pub(crate) fn zero(len: usize) -> Self { Self::new(vec![F::ZERO; len]) } /// 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 { self.coeffs.len() } pub(crate) fn log_len(&self) -> usize { log2_strict(self.len()) } pub(crate) fn chunks(&self, chunk_size: usize) -> Vec { self.coeffs .chunks(chunk_size) .map(|chunk| PolynomialCoeffs::new(chunk.to_vec())) .collect() } pub fn eval(&self, x: F) -> F { self.coeffs .iter() .rev() .fold(F::ZERO, |acc, &c| acc * x + c) } pub fn lde_multiple(polys: Vec, rate_bits: usize) -> Vec { 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); } Self { coeffs } } /// Removes leading zero coefficients. pub fn trim(&mut self) { self.coeffs.drain(self.degree_plus_one()..); } /// Degree of the polynomial + 1. fn degree_plus_one(&self) -> usize { (0usize..self.len()) .rev() .find(|&i| self.coeffs[i].is_nonzero()) .map_or(0, |i| i + 1) } }