use ff::PrimeField;
use rayon::prelude::*;
#[derive(Debug)]
pub struct EqPolynomial<Scalar: PrimeField> {
pub r: Vec<Scalar>,
}
impl<Scalar: PrimeField> EqPolynomial<Scalar> {
pub const fn new(r: Vec<Scalar>) -> Self {
EqPolynomial { r }
}
pub fn evaluate(&self, rx: &[Scalar]) -> Scalar {
assert_eq!(self.r.len(), rx.len());
(0..rx.len())
.map(|i| rx[i] * self.r[i] + (Scalar::ONE - rx[i]) * (Scalar::ONE - self.r[i]))
.fold(Scalar::ONE, |acc, item| acc * item)
}
pub fn evals(&self) -> Vec<Scalar> {
Self::evals_from_points(&self.r)
}
pub fn evals_from_points(r: &[Scalar]) -> Vec<Scalar> {
let ell = r.len();
let mut evals: Vec<Scalar> = vec![Scalar::ZERO; (2_usize).pow(ell as u32)];
let mut size = 1;
evals[0] = Scalar::ONE;
for r in r.iter().rev() {
let (evals_left, evals_right) = evals.split_at_mut(size);
let (evals_right, _) = evals_right.split_at_mut(size);
zip_with_for_each!(par_iter_mut, (evals_left, evals_right), |x, y| {
*y = *x * r;
*x -= &*y;
});
size *= 2;
}
evals
}
}
impl<Scalar: PrimeField> FromIterator<Scalar> for EqPolynomial<Scalar> {
fn from_iter<I: IntoIterator<Item = Scalar>>(iter: I) -> Self {
let r: Vec<_> = iter.into_iter().collect();
EqPolynomial { r }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::provider::{bn256_grumpkin::bn256, pasta::pallas, secp_secq::secp256k1};
fn test_eq_polynomial_with<F: PrimeField>() {
let eq_poly = EqPolynomial::<F>::new(vec![F::ONE, F::ZERO, F::ONE]);
let y = eq_poly.evaluate(vec![F::ONE, F::ONE, F::ONE].as_slice());
assert_eq!(y, F::ZERO);
let y = eq_poly.evaluate(vec![F::ONE, F::ZERO, F::ONE].as_slice());
assert_eq!(y, F::ONE);
let eval_list = eq_poly.evals();
for (i, &coeff) in eval_list.iter().enumerate().take((2_usize).pow(3)) {
if i == 5 {
assert_eq!(coeff, F::ONE);
} else {
assert_eq!(coeff, F::ZERO);
}
}
}
#[test]
fn test_eq_polynomial() {
test_eq_polynomial_with::<pallas::Scalar>();
test_eq_polynomial_with::<bn256::Scalar>();
test_eq_polynomial_with::<secp256k1::Scalar>();
}
}