#![allow(clippy::module_name_repetitions)]
#[cfg(feature = "std")]
use log::trace;
use std::prelude::v1::*;
use zkp_macros_decl::field_element;
use zkp_mmap_vec::MmapVec;
#[cfg(feature = "std")]
use zkp_primefield::{fft::permute_index, Fft, Pow, Root};
use zkp_primefield::{FieldElement, Zero};
use zkp_u256::U256;
#[derive(Clone)]
pub struct DensePolynomial(MmapVec<FieldElement>);
#[cfg(feature = "std")]
impl std::fmt::Debug for DensePolynomial {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(fmt, "DensePolynomial(degree = {:?})", self.degree())
}
}
impl PartialEq for DensePolynomial {
fn eq(&self, other: &Self) -> bool {
let x = field_element!("754ed488ec9208d1b552bb254c0890042078a9e1f7e36072ebff1bf4e193d11b");
self.evaluate(&x) == other.evaluate(&x)
}
}
impl Eq for DensePolynomial {}
impl DensePolynomial {
pub fn from_mmap_vec(coefficients: MmapVec<FieldElement>) -> Self {
assert!(coefficients.len().is_power_of_two());
Self(coefficients)
}
pub fn new(coefficients: &[FieldElement]) -> Self {
assert!(coefficients.len().is_power_of_two());
let mut vec = MmapVec::with_capacity(coefficients.len());
vec.extend_from_slice(coefficients);
Self(vec)
}
pub fn zeros(size: usize) -> Self {
assert!(size.is_power_of_two());
let mut vec = MmapVec::with_capacity(size);
vec.resize(size, FieldElement::zero());
Self(vec)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn coefficients(&self) -> &[FieldElement] {
&self.0
}
pub fn degree(&self) -> usize {
let mut degree = self.len() - 1;
while self.0[degree] == FieldElement::zero() && degree > 0 {
degree -= 1;
}
degree
}
pub fn evaluate(&self, x: &FieldElement) -> FieldElement {
let mut result = FieldElement::zero();
for coefficient in self.0.iter().rev() {
result *= x;
result += coefficient;
}
result
}
#[cfg(feature = "std")]
pub fn low_degree_extension(&self, blowup: usize) -> MmapVec<FieldElement> {
trace!("BEGIN Low degree extension");
let shift_factor: FieldElement = FieldElement::generator();
let length = self.len() * blowup;
let generator =
FieldElement::root(length).expect("No generator for extended_domain_length.");
#[allow(unsafe_code)]
let mut result: MmapVec<FieldElement> = unsafe { MmapVec::zero_initialized(length) };
result
.as_mut_slice()
.chunks_mut(self.len())
.enumerate()
.for_each(|(i, slice)| {
let cofactor = &shift_factor * generator.pow(permute_index(blowup, i));
slice.clone_shifted(&self.coefficients(), &cofactor);
slice.fft();
});
trace!("END Low degree extension");
result
}
pub fn divide_out_point_into(&self, z: &FieldElement, c: &FieldElement, target: &mut Self) {
let mut remainder = FieldElement::zero();
for (coefficient, target) in self.0.iter().rev().zip(target.0.iter_mut().rev()) {
*target += c * &remainder;
remainder *= z;
remainder += coefficient;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn dense_polynomial(coefficients: &[isize]) -> DensePolynomial {
DensePolynomial::new(
&coefficients
.iter()
.map(|c| FieldElement::from(*c))
.collect::<Vec<_>>(),
)
}
#[test]
fn example_evaluate() {
let p = dense_polynomial(&[1, 0, 0, 2]);
assert_eq!(p.evaluate(&FieldElement::from(2)), FieldElement::from(17));
}
}