diff --git a/crates/proof-of-sql/src/base/polynomial/interpolate.rs b/crates/proof-of-sql/src/base/polynomial/interpolate.rs index 0c356a874..bfca71758 100644 --- a/crates/proof-of-sql/src/base/polynomial/interpolate.rs +++ b/crates/proof-of-sql/src/base/polynomial/interpolate.rs @@ -1,10 +1,10 @@ -use core::cmp::PartialEq; /** * Adapted from arkworks * * See third_party/license/arkworks.LICENSE */ -use core::ops::{AddAssign, Mul, MulAssign, SubAssign}; +use core::ops::{Add, AddAssign, Mul, MulAssign, SubAssign}; +use core::{cmp::PartialEq, iter::Product}; use num_traits::{Inv, One, Zero}; /// Interpolate a uni-variate degree-`polynomial.len()-1` polynomial and evaluate this @@ -67,3 +67,50 @@ where } sum * product } + +/// Let d be the evals.len() - 1 and let f be the polynomial such that f(i) = evals[i]. +/// The output of this function is the vector of coefficients of f, leading coefficient first. +/// That is, `f(x) = evals[j]*x^(d-j)``. +#[allow(dead_code)] +pub fn interpolate_evaluations_to_reverse_coefficients(evals: &[S]) -> Vec +where + S: Zero + + Copy + + From + + Mul + + Add + + Inv> + + Product, +{ + let n = evals.len().max(1) - 1; + evals + .iter() + .enumerate() + .map(|(idx, &eval_i)| { + let i = idx as i32; + let mut scaled_lagrange_basis = vec![S::zero(); n + 1]; + // First compute the constant factor of this lagrange basis polynomial: + scaled_lagrange_basis[0] = (i - n as i32..0) + .chain(1..=i) + .map(S::from) + .product::() + .inv() + .unwrap() + * eval_i; + // Then multiply by the appropriate linear terms: + // for j in 0..=n if j != i { + for neg_j in (-(n as i32)..-i).chain(1 - i..=0).map(S::from) { + for k in (0..n).rev() { + scaled_lagrange_basis[k + 1] = + scaled_lagrange_basis[k + 1] + neg_j * scaled_lagrange_basis[k]; + } + } + scaled_lagrange_basis + }) + // Finally, sum up all the resulting polynomials + .reduce(|mut acc, b| { + acc.iter_mut().zip(b).for_each(|(a, b)| *a = *a + b); + acc + }) + .unwrap_or(vec![]) +} diff --git a/crates/proof-of-sql/src/base/polynomial/interpolate_test.rs b/crates/proof-of-sql/src/base/polynomial/interpolate_test.rs index 910d49df9..99e3d2dc3 100644 --- a/crates/proof-of-sql/src/base/polynomial/interpolate_test.rs +++ b/crates/proof-of-sql/src/base/polynomial/interpolate_test.rs @@ -3,10 +3,10 @@ * * See third_party/license/arkworks.LICENSE */ -use crate::base::polynomial::interpolate::*; -use crate::base::scalar::Curve25519Scalar; +use super::interpolate::*; +use crate::base::scalar::{Curve25519Scalar, Curve25519Scalar as S}; use ark_std::UniformRand; -use num_traits::Zero; +use num_traits::{Inv, Zero}; #[test] fn test_interpolate_uni_poly_for_random_polynomials() { @@ -93,3 +93,70 @@ fn interpolate_uni_poly_gives_correct_value_for_known_evaluation() { ); } } + +#[test] +fn we_can_interpolate_evaluations_to_reverse_coefficients_with_empty_input() { + assert_eq!( + interpolate_evaluations_to_reverse_coefficients(&[] as &[S]), + vec![] + ); +} + +#[test] +fn we_can_interpolate_evaluations_to_reverse_coefficients_with_degree_0() { + assert_eq!( + interpolate_evaluations_to_reverse_coefficients(&[S::from(2)]), + vec![S::from(2)] + ); +} + +#[test] +fn we_can_interpolate_evaluations_to_reverse_coefficients_with_degree_1() { + assert_eq!( + interpolate_evaluations_to_reverse_coefficients(&[S::from(2), S::from(3)]), + vec![S::from(1), S::from(2)] + ); +} + +#[test] +fn we_can_interpolate_evaluations_to_reverse_coefficients_with_degree_2() { + assert_eq!( + interpolate_evaluations_to_reverse_coefficients(&[S::from(2), S::from(3), S::from(5)]), + vec![ + S::from(1) * S::from(2).inv().unwrap(), + S::from(1) * S::from(2).inv().unwrap(), + S::from(2) + ] + ); +} + +#[test] +fn we_can_interpolate_evaluations_to_reverse_coefficients_with_degree_3() { + assert_eq!( + interpolate_evaluations_to_reverse_coefficients(&[ + S::from(2), + S::from(3), + S::from(5), + S::from(7) + ]), + vec![ + S::from(-1) * S::from(6).inv().unwrap(), + S::from(1), + S::from(1) * S::from(6).inv().unwrap(), + S::from(2) + ] + ); +} + +#[test] +fn we_can_interpolate_evaluations_to_reverse_coefficients_with_degree_3_degenerate_evals() { + assert_eq!( + interpolate_evaluations_to_reverse_coefficients(&[ + S::from(1), + S::from(3), + S::from(5), + S::from(7) + ]), + vec![S::from(0), S::from(0), S::from(2), S::from(1)] + ); +} diff --git a/crates/proof-of-sql/src/base/polynomial/mod.rs b/crates/proof-of-sql/src/base/polynomial/mod.rs index ce7a848b2..3959b576d 100644 --- a/crates/proof-of-sql/src/base/polynomial/mod.rs +++ b/crates/proof-of-sql/src/base/polynomial/mod.rs @@ -6,7 +6,8 @@ mod composite_polynomial_test; mod interpolate; #[cfg(test)] mod interpolate_test; -pub use interpolate::interpolate_uni_poly; +#[allow(unused_imports)] +pub use interpolate::{interpolate_evaluations_to_reverse_coefficients, interpolate_uni_poly}; mod evaluation_vector; pub use evaluation_vector::compute_evaluation_vector;