diff --git a/crypto/math/src/polynomial.rs b/crypto/math/src/polynomial.rs index b7aeba734..e3eaf66d4 100644 --- a/crypto/math/src/polynomial.rs +++ b/crypto/math/src/polynomial.rs @@ -6,7 +6,7 @@ use crate::fft::bowers_fft::{bowers_fft_opt_fused_parallel, bowers_ifft_opt_para use crate::fft::errors::FFTError; use crate::field::traits::{IsFFTField, IsField, IsSubFieldOf}; use alloc::{borrow::ToOwned, vec, vec::Vec}; -use core::{fmt::Display, ops}; + /// Represents the polynomial c_0 + c_1 * X + c_2 * X^2 + ... + c_n * X^n /// as a vector of coefficients `[c_0, c_1, ... , c_n]` #[derive(Debug, Clone, PartialEq, Eq)] @@ -173,482 +173,6 @@ pub fn pad_with_zero_coefficients>( } (pa, pb) } - -// impl Add -impl ops::Add<&Polynomial>> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, a_polynomial: &Polynomial>) -> Self::Output { - let (pa, pb) = pad_with_zero_coefficients(self, a_polynomial); - let iter_coeff_pa = pa.coefficients.iter(); - let iter_coeff_pb = pb.coefficients.iter(); - let new_coefficients = iter_coeff_pa.zip(iter_coeff_pb).map(|(x, y)| x + y); - let new_coefficients_vec = new_coefficients.collect::>>(); - Polynomial::new(&new_coefficients_vec) - } -} - -impl ops::Add>> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, a_polynomial: Polynomial>) -> Polynomial> { - &self + &a_polynomial - } -} - -impl ops::Add<&Polynomial>> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, a_polynomial: &Polynomial>) -> Polynomial> { - &self + a_polynomial - } -} - -impl ops::Add>> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, a_polynomial: Polynomial>) -> Polynomial> { - self + &a_polynomial - } -} - -// impl neg, that is, additive inverse for polynomials P(t) + Q(t) = 0 -impl ops::Neg for &Polynomial> { - type Output = Polynomial>; - - fn neg(self) -> Polynomial> { - let neg = self - .coefficients - .iter() - .map(|x| -x) - .collect::>>(); - Polynomial::new(&neg) - } -} - -impl ops::Neg for Polynomial> { - type Output = Polynomial>; - - fn neg(self) -> Polynomial> { - -&self - } -} - -// impl Sub -impl ops::Sub<&Polynomial>> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, substrahend: &Polynomial>) -> Polynomial> { - self + (-substrahend) - } -} - -impl ops::Sub>> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, substrahend: Polynomial>) -> Polynomial> { - &self - &substrahend - } -} - -impl ops::Sub<&Polynomial>> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, substrahend: &Polynomial>) -> Polynomial> { - &self - substrahend - } -} - -impl ops::Sub>> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, substrahend: Polynomial>) -> Polynomial> { - self - &substrahend - } -} - -impl ops::Mul<&Polynomial>> for &Polynomial> { - type Output = Polynomial>; - fn mul(self, factor: &Polynomial>) -> Polynomial> { - self.mul_with_ref(factor) - } -} - -impl ops::Mul>> for Polynomial> { - type Output = Polynomial>; - fn mul(self, factor: Polynomial>) -> Polynomial> { - &self * &factor - } -} - -impl ops::Mul>> for &Polynomial> { - type Output = Polynomial>; - fn mul(self, factor: Polynomial>) -> Polynomial> { - self * &factor - } -} - -impl ops::Mul<&Polynomial>> for Polynomial> { - type Output = Polynomial>; - fn mul(self, factor: &Polynomial>) -> Polynomial> { - &self * factor - } -} - -/* Operations between Polynomials and field elements */ -/* Multiplication field element at left */ -impl ops::Mul> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn mul(self, multiplicand: FieldElement) -> Polynomial> { - let new_coefficients = self - .coefficients - .iter() - .map(|value| &multiplicand * value) - .collect(); - Polynomial { - coefficients: new_coefficients, - } - } -} - -impl ops::Mul<&FieldElement> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn mul(self, multiplicand: &FieldElement) -> Polynomial> { - self.clone() * multiplicand.clone() - } -} - -impl ops::Mul> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn mul(self, multiplicand: FieldElement) -> Polynomial> { - self * &multiplicand - } -} - -impl ops::Mul<&FieldElement> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn mul(self, multiplicand: &FieldElement) -> Polynomial> { - &self * multiplicand - } -} - -/* Multiplication field element at right */ -impl ops::Mul<&Polynomial>> for &FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn mul(self, multiplicand: &Polynomial>) -> Polynomial> { - multiplicand * self - } -} - -impl ops::Mul>> for &FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn mul(self, multiplicand: Polynomial>) -> Polynomial> { - &multiplicand * self - } -} - -impl ops::Mul<&Polynomial>> for FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn mul(self, multiplicand: &Polynomial>) -> Polynomial> { - multiplicand * self - } -} - -impl ops::Mul>> for FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn mul(self, multiplicand: Polynomial>) -> Polynomial> { - &multiplicand * &self - } -} - -/* Addition field element at left */ -impl ops::Add<&FieldElement> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, other: &FieldElement) -> Polynomial> { - Polynomial::new_monomial(other.clone(), 0) + self - } -} - -impl ops::Add> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, other: FieldElement) -> Polynomial> { - &self + &other - } -} - -impl ops::Add> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, other: FieldElement) -> Polynomial> { - self + &other - } -} - -impl ops::Add<&FieldElement> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, other: &FieldElement) -> Polynomial> { - &self + other - } -} - -/* Addition field element at right */ -impl ops::Add<&Polynomial>> for &FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, other: &Polynomial>) -> Polynomial> { - Polynomial::new_monomial(self.clone(), 0) + other - } -} - -impl ops::Add>> for FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, other: Polynomial>) -> Polynomial> { - &self + &other - } -} - -impl ops::Add>> for &FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, other: Polynomial>) -> Polynomial> { - self + &other - } -} - -impl ops::Add<&Polynomial>> for FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn add(self, other: &Polynomial>) -> Polynomial> { - &self + other - } -} - -/* Substraction field element at left */ -impl ops::Sub<&FieldElement> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, other: &FieldElement) -> Polynomial> { - -Polynomial::new_monomial(other.clone(), 0) + self - } -} - -impl ops::Sub> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, other: FieldElement) -> Polynomial> { - &self - &other - } -} - -impl ops::Sub> for &Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, other: FieldElement) -> Polynomial> { - self - &other - } -} - -impl ops::Sub<&FieldElement> for Polynomial> -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, other: &FieldElement) -> Polynomial> { - &self - other - } -} - -/* Substraction field element at right */ -impl ops::Sub<&Polynomial>> for &FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, other: &Polynomial>) -> Polynomial> { - Polynomial::new_monomial(self.clone(), 0) - other - } -} - -impl ops::Sub>> for FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, other: Polynomial>) -> Polynomial> { - &self - &other - } -} - -impl ops::Sub>> for &FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, other: Polynomial>) -> Polynomial> { - self - &other - } -} - -impl ops::Sub<&Polynomial>> for FieldElement -where - L: IsField, - F: IsSubFieldOf, -{ - type Output = Polynomial>; - - fn sub(self, other: &Polynomial>) -> Polynomial> { - &self - other - } -} - -#[derive(Debug)] -pub enum InterpolateError { - UnequalLengths(usize, usize), - NonUniqueXs, -} - -impl Display for InterpolateError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - InterpolateError::UnequalLengths(x, y) => { - write!(f, "xs and ys must be the same length. Got: {x} != {y}") - } - InterpolateError::NonUniqueXs => write!(f, "xs values should be unique."), - } - } -} - -#[cfg(feature = "std")] -impl std::error::Error for InterpolateError {} - // ── Barycentric coset interpolation ────────────────────────────────────── // Four evaluation variants along two axes: // - eval field: base field (F) or extension field (E) @@ -714,64 +238,6 @@ where &scalar * &(vanishing * &sum) // F × E → E } -#[cfg(test)] -impl Polynomial> { - /// Returns a polynomial that interpolates the points with x coordinates and y coordinates given by - /// `xs` and `ys`. - pub fn interpolate( - xs: &[FieldElement], - ys: &[FieldElement], - ) -> Result { - use core::slice; - - if xs.len() != ys.len() { - return Err(InterpolateError::UnequalLengths(xs.len(), ys.len())); - } - if xs.is_empty() { - return Ok(Polynomial::new(&[])); - } - - let mut denominators = Vec::with_capacity(xs.len() * (xs.len() - 1) / 2); - let mut indexes = Vec::with_capacity(xs.len()); - - let mut idx = 0; - - for (i, xi) in xs.iter().enumerate().skip(1) { - indexes.push(idx); - for xj in xs.iter().take(i) { - if xi == xj { - return Err(InterpolateError::NonUniqueXs); - } - denominators.push(xi - xj); - idx += 1; - } - } - - FieldElement::inplace_batch_inverse(&mut denominators).unwrap(); - - let mut result = Polynomial::zero(); - - for (i, y) in ys.iter().enumerate() { - let mut y_term = Polynomial::new(slice::from_ref(y)); - for (j, x) in xs.iter().enumerate() { - if i == j { - continue; - } - let denominator = if i > j { - denominators[indexes[i - 1] + j].clone() - } else { - -&denominators[indexes[j - 1] + i] - }; - let denominator_poly = Polynomial::new(&[denominator]); - let numerator = Polynomial::new(&[-x, FieldElement::one()]); - y_term = y_term.mul_with_ref(&(numerator * denominator_poly)); - } - result = result + y_term; - } - Ok(result) - } -} - // ============================================================================= // FFT-based polynomial methods (merged from the former fft/polynomial.rs) // ============================================================================= diff --git a/crypto/math/src/tests/fft_friendly_u64_goldilocks_tests.rs b/crypto/math/src/tests/fft_friendly_u64_goldilocks_tests.rs index 01bd0a176..759c928e5 100644 --- a/crypto/math/src/tests/fft_friendly_u64_goldilocks_tests.rs +++ b/crypto/math/src/tests/fft_friendly_u64_goldilocks_tests.rs @@ -319,30 +319,36 @@ mod fft_tests { (fft_eval, naive_eval) } - fn gen_fft_and_naive_interpolate( + /// FFT interpolation round-trip: interpolate the evals back into a + /// coefficient-form polynomial via FFT, then re-evaluate that polynomial + /// at every twiddle via Horner (`Polynomial::evaluate`). The two + /// representations agree iff `interpolate_fft` produced the right + /// polynomial — an independent check using a different algorithm, with + /// no naive Lagrange `interpolate` needed. + fn gen_fft_interpolate_round_trip( fft_evals: &[FieldElement], - ) -> (Polynomial>, Polynomial>) { + ) -> (Vec>, Vec>) { let order = fft_evals.len().trailing_zeros() as u64; let twiddles = get_powers_of_primitive_root(order, 1 << order, RootsConfig::Natural).unwrap(); - let naive_poly = Polynomial::interpolate(&twiddles, fft_evals).unwrap(); let fft_poly = Polynomial::interpolate_fft::(fft_evals).unwrap(); + let recovered = evaluate_slice(&fft_poly, &twiddles); - (fft_poly, naive_poly) + (recovered, fft_evals.to_vec()) } - fn gen_fft_and_naive_coset_interpolate( + fn gen_fft_coset_interpolate_round_trip( fft_evals: &[FieldElement], offset: &FieldElement, - ) -> (Polynomial>, Polynomial>) { + ) -> (Vec>, Vec>) { let order = fft_evals.len().trailing_zeros() as u64; let twiddles = get_powers_of_primitive_root_coset(order, 1 << order, offset).unwrap(); - let naive_poly = Polynomial::interpolate(&twiddles, fft_evals).unwrap(); let fft_poly = Polynomial::interpolate_offset_fft(fft_evals, offset).unwrap(); + let recovered = evaluate_slice(&fft_poly, &twiddles); - (fft_poly, naive_poly) + (recovered, fft_evals.to_vec()) } fn gen_fft_interpolate_and_evaluate( @@ -403,16 +409,16 @@ mod fft_tests { fn test_fft_interpolate_matches_naive(fft_evals in field_vec(4) .prop_filter("Avoid polynomials of size not power of two", |evals| evals.len().is_power_of_two())) { - let (fft_poly, naive_poly) = gen_fft_and_naive_interpolate(&fft_evals); - prop_assert_eq!(fft_poly, naive_poly); + let (recovered, original) = gen_fft_interpolate_round_trip(&fft_evals); + prop_assert_eq!(recovered, original); } #[test] fn test_fft_interpolate_coset_matches_naive(offset in offset(), fft_evals in field_vec(4) .prop_filter("Avoid polynomials of size not power of two", |evals| evals.len().is_power_of_two())) { - let (fft_poly, naive_poly) = gen_fft_and_naive_coset_interpolate(&fft_evals, &offset); - prop_assert_eq!(fft_poly, naive_poly); + let (recovered, original) = gen_fft_coset_interpolate_round_trip(&fft_evals, &offset); + prop_assert_eq!(recovered, original); } #[test] diff --git a/crypto/math/src/tests/fft_tests.rs b/crypto/math/src/tests/fft_tests.rs index 50b618545..50d1bcc13 100644 --- a/crypto/math/src/tests/fft_tests.rs +++ b/crypto/math/src/tests/fft_tests.rs @@ -97,30 +97,34 @@ mod fft_polynomial_tests { (fft_eval, naive_eval) } - fn gen_fft_and_naive_interpolate( + /// FFT interpolation round-trip: interpolate `fft_evals` back to a + /// polynomial via FFT, then re-evaluate at every twiddle via Horner. + /// `(recovered, original)` agree iff `interpolate_fft` is correct — an + /// independent check using a different algorithm. + fn gen_fft_interpolate_round_trip( fft_evals: &[FieldElement], - ) -> (Polynomial>, Polynomial>) { + ) -> (Vec>, Vec>) { let order = fft_evals.len().trailing_zeros() as u64; let twiddles = get_powers_of_primitive_root(order, 1 << order, RootsConfig::Natural).unwrap(); - let naive_poly = Polynomial::interpolate(&twiddles, fft_evals).unwrap(); let fft_poly = Polynomial::interpolate_fft::(fft_evals).unwrap(); + let recovered = evaluate_slice(&fft_poly, &twiddles); - (fft_poly, naive_poly) + (recovered, fft_evals.to_vec()) } - fn gen_fft_and_naive_coset_interpolate( + fn gen_fft_coset_interpolate_round_trip( fft_evals: &[FieldElement], offset: &FieldElement, - ) -> (Polynomial>, Polynomial>) { + ) -> (Vec>, Vec>) { let order = fft_evals.len().trailing_zeros() as u64; let twiddles = get_powers_of_primitive_root_coset(order, 1 << order, offset).unwrap(); - let naive_poly = Polynomial::interpolate(&twiddles, fft_evals).unwrap(); let fft_poly = Polynomial::interpolate_offset_fft(fft_evals, offset).unwrap(); + let recovered = evaluate_slice(&fft_poly, &twiddles); - (fft_poly, naive_poly) + (recovered, fft_evals.to_vec()) } fn gen_fft_interpolate_and_evaluate( @@ -204,8 +208,8 @@ mod fft_polynomial_tests { fn test_fft_interpolate_matches_naive(fft_evals in field_vec(4) .prop_filter("Avoid polynomials of size not power of two", |evals| evals.len().is_power_of_two())) { - let (fft_poly, naive_poly) = gen_fft_and_naive_interpolate(&fft_evals); - prop_assert_eq!(fft_poly, naive_poly); + let (recovered, original) = gen_fft_interpolate_round_trip(&fft_evals); + prop_assert_eq!(recovered, original); } // Property-based test that ensures FFT interpolation with an offset is the same as naive. @@ -213,8 +217,8 @@ mod fft_polynomial_tests { fn test_fft_interpolate_coset_matches_naive(offset in offset(), fft_evals in field_vec(4) .prop_filter("Avoid polynomials of size not power of two", |evals| evals.len().is_power_of_two())) { - let (fft_poly, naive_poly) = gen_fft_and_naive_coset_interpolate(&fft_evals, &offset); - prop_assert_eq!(fft_poly, naive_poly); + let (recovered, original) = gen_fft_coset_interpolate_round_trip(&fft_evals, &offset); + prop_assert_eq!(recovered, original); } // Property-based test that ensures interpolation is the inverse operation of evaluation. diff --git a/crypto/math/src/tests/polynomial_tests.rs b/crypto/math/src/tests/polynomial_tests.rs index ca1bfde22..94623585d 100644 --- a/crypto/math/src/tests/polynomial_tests.rs +++ b/crypto/math/src/tests/polynomial_tests.rs @@ -5,7 +5,7 @@ mod tests { use crate::field::traits::{IsField, IsPrimeField}; use crate::polynomial::{Polynomial, pad_with_zero_coefficients}; use alloc::string::{String, ToString}; - use alloc::{format, vec, vec::Vec}; + use alloc::{format, vec::Vec}; type F = GoldilocksField; type FE = FieldElement; @@ -74,105 +74,8 @@ mod tests { string } - /// Computes the composition of polynomials P1(t) and P2(t), that is P1(P2(t)) - fn compose( - poly_1: &Polynomial>, - poly_2: &Polynomial>, - ) -> Polynomial> { - let max_degree: u64 = (poly_1.degree() * poly_2.degree()) as u64; - - let mut interpolation_points = vec![]; - for i in 0_u64..max_degree + 1 { - interpolation_points.push(FieldElement::::from(i)); - } - - let values: Vec<_> = interpolation_points - .iter() - .map(|value| { - let intermediate_value = poly_2.evaluate(value); - poly_1.evaluate(&intermediate_value) - }) - .collect(); - - Polynomial::interpolate(interpolation_points.as_slice(), values.as_slice()) - .expect("xs and ys have equal length and xs are unique") - } - // ==================== End of test helper functions ==================== - fn polynomial_a() -> Polynomial { - Polynomial::new(&[FE::new(1), FE::new(2), FE::new(3)]) - } - - fn polynomial_minus_a() -> Polynomial { - Polynomial::new(&[-FE::new(1), -FE::new(2), -FE::new(3)]) - } - - fn polynomial_b() -> Polynomial { - Polynomial::new(&[FE::new(3), FE::new(4), FE::new(5)]) - } - - fn polynomial_a_plus_b() -> Polynomial { - Polynomial::new(&[FE::new(4), FE::new(6), FE::new(8)]) - } - - fn polynomial_b_minus_a() -> Polynomial { - Polynomial::new(&[FE::new(2), FE::new(2), FE::new(2)]) - } - - #[test] - fn adding_a_and_b_equals_a_plus_b() { - assert_eq!(polynomial_a() + polynomial_b(), polynomial_a_plus_b()); - } - - #[test] - fn adding_a_and_a_plus_b_does_not_equal_b() { - assert_ne!(polynomial_a() + polynomial_a_plus_b(), polynomial_b()); - } - - #[test] - fn add_5_to_0_is_5() { - let p1 = Polynomial::new(&[FE::new(5)]); - let p2 = Polynomial::new(&[FE::new(0)]); - assert_eq!(p1 + p2, Polynomial::new(&[FE::new(5)])); - } - - #[test] - fn add_0_to_5_is_5() { - let p1 = Polynomial::new(&[FE::new(5)]); - let p2 = Polynomial::new(&[FE::new(0)]); - assert_eq!(p2 + p1, Polynomial::new(&[FE::new(5)])); - } - - #[test] - fn negating_0_returns_0() { - let p1 = Polynomial::new(&[FE::new(0)]); - assert_eq!(-p1, Polynomial::new(&[FE::new(0)])); - } - - #[test] - fn negating_a_is_equal_to_minus_a() { - assert_eq!(-polynomial_a(), polynomial_minus_a()); - } - - #[test] - fn negating_a_is_not_equal_to_a() { - assert_ne!(-polynomial_a(), polynomial_a()); - } - - #[test] - fn substracting_5_5_gives_0() { - let p1 = Polynomial::new(&[FE::new(5)]); - let p2 = Polynomial::new(&[FE::new(5)]); - let p3 = Polynomial::new(&[FE::new(0)]); - assert_eq!(p1 - p2, p3); - } - - #[test] - fn substracting_b_and_a_equals_b_minus_a() { - assert_eq!(polynomial_b() - polynomial_a(), polynomial_b_minus_a()); - } - #[test] fn constructor_removes_zeros_at_the_end_of_polynomial() { let p1 = Polynomial::new(&[FE::new(3), FE::new(4), FE::new(0)]); @@ -190,47 +93,6 @@ mod tests { assert_eq!(pp2.coefficients, &[FE::new(3), FE::new(0)]); } - #[test] - fn multiply_5_and_0_is_0() { - let p1 = Polynomial::new(&[FE::new(5)]); - let p2 = Polynomial::new(&[FE::new(0)]); - assert_eq!(p1 * p2, Polynomial::new(&[FE::new(0)])); - } - - #[test] - fn multiply_0_and_x_is_0() { - let p1 = Polynomial::new(&[FE::new(0)]); - let p2 = Polynomial::new(&[FE::new(0), FE::new(1)]); - assert_eq!(p1 * p2, Polynomial::new(&[FE::new(0)])); - } - - #[test] - fn multiply_2_by_3_is_6() { - let p1 = Polynomial::new(&[FE::new(2)]); - let p2 = Polynomial::new(&[FE::new(3)]); - assert_eq!(p1 * p2, Polynomial::new(&[FE::new(6)])); - } - - #[test] - fn multiply_2xx_3x_3_times_x_4() { - let p1 = Polynomial::new(&[FE::new(3), FE::new(3), FE::new(2)]); - let p2 = Polynomial::new(&[FE::new(4), FE::new(1)]); - assert_eq!( - p1 * p2, - Polynomial::new(&[FE::new(12), FE::new(15), FE::new(11), FE::new(2)]) - ); - } - - #[test] - fn multiply_x_4_times_2xx_3x_3() { - let p1 = Polynomial::new(&[FE::new(3), FE::new(3), FE::new(2)]); - let p2 = Polynomial::new(&[FE::new(4), FE::new(1)]); - assert_eq!( - p2 * p1, - Polynomial::new(&[FE::new(12), FE::new(15), FE::new(11), FE::new(2)]) - ); - } - #[test] fn evaluate_constant_polynomial_returns_constant() { let three = FE::new(3); @@ -288,7 +150,7 @@ mod tests { fn simple_interpolating_polynomial_by_hand_works() { let denominator = Polynomial::new(&[FE::new(1) * (FE::new(2) - FE::new(4)).inv().unwrap()]); let numerator = Polynomial::new(&[-FE::new(4), FE::new(1)]); - let interpolating = numerator * denominator; + let interpolating = numerator.mul_with_ref(&denominator); assert_eq!( (FE::new(2) - FE::new(4)) * (FE::new(1) * (FE::new(2) - FE::new(4)).inv().unwrap()), FE::new(1) @@ -297,58 +159,6 @@ mod tests { assert_eq!(interpolating.evaluate(&FE::new(4)), FE::new(0)); } - #[test] - fn interpolate_x_2_y_3() { - let p = Polynomial::interpolate(&[FE::new(2)], &[FE::new(3)]).unwrap(); - assert_eq!(FE::new(3), p.evaluate(&FE::new(2))); - } - - #[test] - fn interpolate_x_0_2_y_3_4() { - let p = - Polynomial::interpolate(&[FE::new(0), FE::new(2)], &[FE::new(3), FE::new(4)]).unwrap(); - assert_eq!(FE::new(3), p.evaluate(&FE::new(0))); - assert_eq!(FE::new(4), p.evaluate(&FE::new(2))); - } - - #[test] - fn interpolate_x_2_5_7_y_10_19_43() { - let p = Polynomial::interpolate( - &[FE::new(2), FE::new(5), FE::new(7)], - &[FE::new(10), FE::new(19), FE::new(43)], - ) - .unwrap(); - - assert_eq!(FE::new(10), p.evaluate(&FE::new(2))); - assert_eq!(FE::new(19), p.evaluate(&FE::new(5))); - assert_eq!(FE::new(43), p.evaluate(&FE::new(7))); - } - - #[test] - fn interpolate_x_0_0_y_1_1() { - let p = - Polynomial::interpolate(&[FE::new(0), FE::new(1)], &[FE::new(0), FE::new(1)]).unwrap(); - - assert_eq!(FE::new(0), p.evaluate(&FE::new(0))); - assert_eq!(FE::new(1), p.evaluate(&FE::new(1))); - } - - #[test] - fn interpolate_x_0_y_0() { - let p = Polynomial::interpolate(&[FE::new(0)], &[FE::new(0)]).unwrap(); - assert_eq!(FE::new(0), p.evaluate(&FE::new(0))); - } - - #[test] - fn composition_works() { - let p = Polynomial::new(&[FE::new(0), FE::new(2)]); - let q = Polynomial::new(&[FE::new(0), FE::new(0), FE::new(1)]); - assert_eq!( - compose(&p, &q), - Polynomial::new(&[FE::new(0), FE::new(0), FE::new(2)]) - ); - } - #[test] fn break_in_parts() { // p = 3 X^3 + X^2 + 2X + 1