shockwave-plus/shockwave_plus/src/polynomial/ml_poly.rs
shockwave_plus/src/polynomial/ml_poly.rsRaw
1use tensor_pcs::EqPoly;
2
3use crate::FieldExt;
4
5#[derive(Clone, Debug)]
6pub struct MlPoly<F> {
7 pub evals: Vec<F>,
8 pub num_vars: usize,
9}
10
11impl<F: FieldExt> MlPoly<F> {
12 pub fn new(evals: Vec<F>) -> Self {
13 assert!(evals.len().is_power_of_two());
14 let num_vars = (evals.len() as f64).log2() as usize;
15 Self { evals, num_vars }
16 }
17
18 fn dot_prod(x: &[F], y: &[F]) -> F {
19 assert_eq!(x.len(), y.len());
20 let mut result = F::ZERO;
21 for i in 0..x.len() {
22 result += x[i] * y[i];
23 }
24 result
25 }
26
27 // Evaluate the multilinear extension of the polynomial `a`, at point `t`.
28 // `a` is in evaluation form.
29 // `t` should be in big-endian form.
30 pub fn eval(&self, t: &[F]) -> F {
31 let n = self.evals.len();
32 debug_assert_eq!((n as f64).log2() as usize, t.len());
33
34 let eq_evals = EqPoly::new(t.to_vec()).evals();
35
36 Self::dot_prod(&self.evals, &eq_evals)
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 type F = halo2curves::secp256k1::Fp;
44 use halo2curves::ff::Field;
45
46 #[test]
47 fn test_ml_poly_eval() {
48 let num_vars = 4;
49 let num_evals = 2usize.pow(num_vars as u32);
50 let evals = (0..num_evals)
51 .map(|x| F::from(x as u64))
52 .collect::<Vec<F>>();
53
54 let ml_poly = MlPoly::new(evals.clone());
55 let eval_last = ml_poly.eval(&[F::ONE, F::ONE, F::ONE, F::ONE]);
56 assert_eq!(
57 eval_last,
58 evals[evals.len() - 1],
59 "The last evaluation is not correct"
60 );
61
62 let eval_first = ml_poly.eval(&[F::ZERO, F::ZERO, F::ZERO, F::ZERO]);
63 assert_eq!(eval_first, evals[0], "The first evaluation is not correct");
64
65 let eval_second = ml_poly.eval(&[F::ZERO, F::ZERO, F::ZERO, F::ONE]);
66 assert_eq!(
67 eval_second, evals[1],
68 "The second evaluation is not correct"
69 );
70 }
71}