diff --git a/src/spartan/polys/multilinear.rs b/src/spartan/polys/multilinear.rs index e21ec35e..385d8a34 100644 --- a/src/spartan/polys/multilinear.rs +++ b/src/spartan/polys/multilinear.rs @@ -183,7 +183,8 @@ mod tests { use crate::provider::{self, bn256_grumpkin::bn256, secp_secq::secp256k1}; use super::*; - use pasta_curves::Fp; + use rand_chacha::ChaCha20Rng; + use rand_core::{CryptoRng, RngCore, SeedableRng}; fn make_mlp(len: usize, value: F) -> MultilinearPolynomial { MultilinearPolynomial { @@ -235,12 +236,12 @@ mod tests { #[test] fn test_multilinear_polynomial() { - test_multilinear_polynomial_with::(); + test_multilinear_polynomial_with::(); } #[test] fn test_sparse_polynomial() { - test_sparse_polynomial_with::(); + test_sparse_polynomial_with::(); } fn test_mlp_add_with() { @@ -254,7 +255,7 @@ mod tests { #[test] fn test_mlp_add() { - test_mlp_add_with::(); + test_mlp_add_with::(); test_mlp_add_with::(); test_mlp_add_with::(); } @@ -283,8 +284,65 @@ mod tests { #[test] fn test_evaluation() { - test_evaluation_with::(); + test_evaluation_with::(); test_evaluation_with::(); test_evaluation_with::(); } + + /// Returns a random ML polynomial + fn random( + num_vars: usize, + mut rng: &mut R, + ) -> MultilinearPolynomial { + MultilinearPolynomial::new( + std::iter::from_fn(|| Some(Scalar::random(&mut rng))) + .take(1 << num_vars) + .collect(), + ) + } + + /// This binds the variables of a multilinear polynomial to a provided sequence + /// of values. + /// + /// Assuming `bind_poly_var_top` defines the "top" variable of the polynomial, + /// this aims to test whether variables should be provided to the + /// `evaluate` function in topmost-first (big endian) of topmost-last (lower endian) + /// order. + fn bind_sequence( + poly: &MultilinearPolynomial, + values: &[F], + ) -> MultilinearPolynomial { + // Assert that the size of the polynomial being evaluated is a power of 2 greater than (1 << values.len()) + assert!(poly.Z.len().is_power_of_two()); + assert!(poly.Z.len() >= 1 << values.len()); + + let mut tmp = poly.clone(); + for v in values.iter() { + tmp.bind_poly_var_top(v); + } + tmp + } + + fn bind_and_evaluate_with() { + for i in 0..50 { + // Initialize a random polynomial + let n = 7; + let mut rng = ChaCha20Rng::from_seed([i as u8; 32]); + let poly = random(n, &mut rng); + + // draw a random point + let pt: Vec<_> = std::iter::from_fn(|| Some(F::random(&mut rng))) + .take(n) + .collect(); + // this shows the order in which coordinates are evaluated + assert_eq!(poly.evaluate(&pt), bind_sequence(&poly, &pt).Z[0]) + } + } + + #[test] + fn test_bind_and_evaluate() { + bind_and_evaluate_with::(); + bind_and_evaluate_with::(); + bind_and_evaluate_with::(); + } }