arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/dense_mlpoly.rs
src/dense_mlpoly.rsRaw
  1#![allow(clippy::too_many_arguments)]
  2
  3use crate::poseidon_transcript::{AppendToPoseidon, PoseidonTranscript};
  4
  5use super::commitments::{Commitments, MultiCommitGens};
  6use super::errors::ProofVerifyError;
  7use super::group::{
  8  CompressGroupElement, CompressedGroup, DecompressGroupElement, GroupElement,
  9  VartimeMultiscalarMul,
 10};
 11use super::math::Math;
 12use super::nizk::{DotProductProofGens, DotProductProofLog};
 13use super::random::RandomTape;
 14use super::scalar::Scalar;
 15use super::transcript::{AppendToTranscript, ProofTranscript};
 16use ark_bls12_377::Bls12_377 as I;
 17use ark_ff::{One, UniformRand, Zero};
 18use ark_poly::MultilinearExtension;
 19use ark_poly_commit::multilinear_pc::data_structures::{CommitterKey, VerifierKey};
 20use ark_poly_commit::multilinear_pc::MultilinearPC;
 21use ark_serialize::*;
 22use core::ops::Index;
 23use merlin::Transcript;
 24use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
 25
 26#[cfg(feature = "multicore")]
 27use rayon::prelude::*;
 28
 29// TODO: integrate the DenseMultilinearExtension(and Sparse) https://github.com/arkworks-rs/algebra/tree/master/poly/src/evaluations/multivariate/multilinear from arkworks into Spartan. This requires moving the specific Spartan functionalities in separate traits.
 30#[derive(Debug, Clone, Eq, PartialEq, Hash, CanonicalDeserialize, CanonicalSerialize)]
 31pub struct DensePolynomial {
 32  num_vars: usize, // the number of variables in the multilinear polynomial
 33  len: usize,
 34  Z: Vec<Scalar>, // evaluations of the polynomial in all the 2^num_vars Boolean inputs
 35}
 36
 37impl MultilinearExtension<Scalar> for DensePolynomial {
 38  fn num_vars(&self) -> usize {
 39    self.get_num_vars()
 40  }
 41
 42  fn evaluate(&self, point: &[Scalar]) -> Option<Scalar> {
 43    if point.len() == self.num_vars {
 44      Some(self.evaluate(&point))
 45    } else {
 46      None
 47    }
 48  }
 49
 50  fn rand<R: rand::Rng>(num_vars: usize, rng: &mut R) -> Self {
 51    let evals = (0..(1 << num_vars)).map(|_| Scalar::rand(rng)).collect();
 52    Self {
 53      num_vars: num_vars,
 54      len: 1 << num_vars,
 55      Z: evals,
 56    }
 57  }
 58
 59  fn relabel(&self, _a: usize, _b: usize, _k: usize) -> Self {
 60    unimplemented!()
 61  }
 62
 63  fn fix_variables(&self, _partial_point: &[Scalar]) -> Self {
 64    unimplemented!()
 65  }
 66
 67  fn to_evaluations(&self) -> Vec<Scalar> {
 68    self.Z.to_vec()
 69  }
 70}
 71
 72impl Zero for DensePolynomial {
 73  fn zero() -> Self {
 74    Self {
 75      num_vars: 0,
 76      len: 1,
 77      Z: vec![Scalar::zero()],
 78    }
 79  }
 80
 81  fn is_zero(&self) -> bool {
 82    self.num_vars == 0 && self.len == 1 && self.Z[0].is_zero()
 83  }
 84}
 85
 86impl Add for DensePolynomial {
 87  type Output = DensePolynomial;
 88  fn add(self, other: Self) -> Self {
 89    &self + &other
 90  }
 91}
 92
 93// function needed because the result might have a different lifetime than the
 94// operands
 95impl<'a, 'b> Add<&'a DensePolynomial> for &'b DensePolynomial {
 96  type Output = DensePolynomial;
 97
 98  fn add(self, other: &'a DensePolynomial) -> Self::Output {
 99    if other.is_zero() {
100      return self.clone();
101    }
102    if self.is_zero() {
103      return other.clone();
104    }
105    assert_eq!(self.num_vars, other.num_vars);
106
107    let res: Vec<Scalar> = self
108      .Z
109      .iter()
110      .zip(other.Z.iter())
111      .map(|(a, b)| *a + *b)
112      .collect();
113    Self::Output {
114      num_vars: self.num_vars,
115      len: self.len,
116      Z: res,
117    }
118  }
119}
120
121impl AddAssign for DensePolynomial {
122  fn add_assign(&mut self, other: Self) {
123    *self = &*self + &other;
124  }
125}
126
127impl<'a, 'b> AddAssign<&'a DensePolynomial> for DensePolynomial {
128  fn add_assign(&mut self, other: &'a DensePolynomial) {
129    *self = &*self + other;
130  }
131}
132
133impl<'a, 'b> AddAssign<(Scalar, &'a DensePolynomial)> for DensePolynomial {
134  fn add_assign(&mut self, (scalar, other): (Scalar, &'a DensePolynomial)) {
135    let other = Self {
136      num_vars: other.num_vars,
137      len: 1 << other.num_vars,
138      Z: other.Z.iter().map(|x| scalar * x).collect(),
139    };
140    *self = &*self + &other;
141  }
142}
143
144impl Neg for DensePolynomial {
145  type Output = DensePolynomial;
146
147  fn neg(self) -> Self::Output {
148    Self::Output {
149      num_vars: self.num_vars,
150      len: self.len,
151      Z: self.Z.iter().map(|x| -*x).collect(),
152    }
153  }
154}
155
156impl Sub for DensePolynomial {
157  type Output = DensePolynomial;
158
159  fn sub(self, other: Self) -> Self::Output {
160    &self - &other
161  }
162}
163
164impl<'a, 'b> Sub<&'a DensePolynomial> for &'b DensePolynomial {
165  type Output = DensePolynomial;
166
167  fn sub(self, other: &'a DensePolynomial) -> Self::Output {
168    self + &other.clone().neg()
169  }
170}
171
172impl SubAssign for DensePolynomial {
173  fn sub_assign(&mut self, other: Self) {
174    *self = &*self - &other;
175  }
176}
177
178impl<'a, 'b> SubAssign<&'a DensePolynomial> for DensePolynomial {
179  fn sub_assign(&mut self, other: &'a DensePolynomial) {
180    *self = &*self - other;
181  }
182}
183
184#[derive(Clone)]
185pub struct PolyCommitmentGens {
186  pub gens: DotProductProofGens,
187  pub ck: CommitterKey<I>,
188  pub vk: VerifierKey<I>,
189}
190
191impl PolyCommitmentGens {
192  // num vars is the number of variables in the multilinear polynomial
193  // this gives the maximum degree bound
194  pub fn new(num_vars: usize, label: &'static [u8]) -> PolyCommitmentGens {
195    let (_left, right) = EqPolynomial::compute_factored_lens(num_vars);
196    let gens = DotProductProofGens::new(right.pow2(), label);
197
198    // Generates the SRS and trims it based on the number of variables in the
199    // multilinear polynomial.
200    let mut rng = ark_std::test_rng();
201    let pst_gens = MultilinearPC::<I>::setup(num_vars, &mut rng);
202    let (ck, vk) = MultilinearPC::<I>::trim(&pst_gens, num_vars);
203
204    PolyCommitmentGens { gens, ck, vk }
205  }
206}
207
208pub struct PolyCommitmentBlinds {
209  blinds: Vec<Scalar>,
210}
211
212#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
213pub struct PolyCommitment {
214  C: Vec<CompressedGroup>,
215}
216
217#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
218pub struct ConstPolyCommitment {
219  C: CompressedGroup,
220}
221
222pub struct EqPolynomial {
223  r: Vec<Scalar>,
224}
225
226impl EqPolynomial {
227  pub fn new(r: Vec<Scalar>) -> Self {
228    EqPolynomial { r }
229  }
230
231  pub fn evaluate(&self, rx: &[Scalar]) -> Scalar {
232    assert_eq!(self.r.len(), rx.len());
233    (0..rx.len())
234      .map(|i| self.r[i] * rx[i] + (Scalar::one() - self.r[i]) * (Scalar::one() - rx[i]))
235      .product()
236  }
237
238  pub fn evals(&self) -> Vec<Scalar> {
239    let ell = self.r.len();
240
241    let mut evals: Vec<Scalar> = vec![Scalar::one(); ell.pow2()];
242    let mut size = 1;
243    for j in 0..ell {
244      // in each iteration, we double the size of chis
245      size *= 2;
246      // TODO: this reverse causes inconsistent evaluation in comparison to the
247      //evaluation function in ark-poly-commit, we should look into this to
248      // avoid the extra constraints in the circuit
249      for i in (0..size).rev().step_by(2) {
250        // copy each element from the prior iteration twice
251        let scalar = evals[i / 2];
252        evals[i] = scalar * self.r[j];
253        evals[i - 1] = scalar - evals[i];
254      }
255    }
256    evals
257  }
258
259  pub fn compute_factored_lens(ell: usize) -> (usize, usize) {
260    (ell / 2, ell - ell / 2)
261  }
262
263  pub fn compute_factored_evals(&self) -> (Vec<Scalar>, Vec<Scalar>) {
264    let ell = self.r.len();
265    let (left_num_vars, _right_num_vars) = EqPolynomial::compute_factored_lens(ell);
266
267    let L = EqPolynomial::new(self.r[..left_num_vars].to_vec()).evals();
268    let R = EqPolynomial::new(self.r[left_num_vars..ell].to_vec()).evals();
269
270    (L, R)
271  }
272}
273
274pub struct IdentityPolynomial {
275  size_point: usize,
276}
277
278impl IdentityPolynomial {
279  pub fn new(size_point: usize) -> Self {
280    IdentityPolynomial { size_point }
281  }
282
283  pub fn evaluate(&self, r: &[Scalar]) -> Scalar {
284    let len = r.len();
285    assert_eq!(len, self.size_point);
286    (0..len)
287      .map(|i| Scalar::from((len - i - 1).pow2() as u64) * r[i])
288      .sum()
289  }
290}
291
292impl DensePolynomial {
293  pub fn new(Z: Vec<Scalar>) -> Self {
294    DensePolynomial {
295      num_vars: Z.len().log_2(),
296      len: Z.len(),
297      Z,
298    }
299  }
300
301  pub fn get_num_vars(&self) -> usize {
302    self.num_vars
303  }
304
305  pub fn len(&self) -> usize {
306    self.len
307  }
308
309  pub fn clone(&self) -> DensePolynomial {
310    DensePolynomial::new(self.Z[0..self.len].to_vec())
311  }
312
313  pub fn split(&self, idx: usize) -> (DensePolynomial, DensePolynomial) {
314    assert!(idx < self.len());
315    (
316      DensePolynomial::new(self.Z[..idx].to_vec()),
317      DensePolynomial::new(self.Z[idx..2 * idx].to_vec()),
318    )
319  }
320
321  #[cfg(feature = "multicore")]
322  fn commit_inner(&self, blinds: &[Scalar], gens: &MultiCommitGens) -> PolyCommitment {
323    let L_size = blinds.len();
324    let R_size = self.Z.len() / L_size;
325    assert_eq!(L_size * R_size, self.Z.len());
326    let C = (0..L_size)
327      .into_par_iter()
328      .map(|i| {
329        self.Z[R_size * i..R_size * (i + 1)]
330          .commit(&blinds[i], gens)
331          .compress()
332      })
333      .collect();
334    PolyCommitment { C }
335  }
336
337  #[cfg(not(feature = "multicore"))]
338  fn commit_inner(&self, blinds: &[Scalar], gens: &MultiCommitGens) -> PolyCommitment {
339    let L_size = blinds.len();
340    let R_size = self.Z.len() / L_size;
341    assert_eq!(L_size * R_size, self.Z.len());
342    let C = (0..L_size)
343      .map(|i| {
344        self.Z[R_size * i..R_size * (i + 1)]
345          .commit(&blinds[i], gens)
346          .compress()
347      })
348      .collect();
349    PolyCommitment { C }
350  }
351
352  pub fn commit(
353    &self,
354    gens: &PolyCommitmentGens,
355    random_tape: Option<&mut RandomTape>,
356  ) -> (PolyCommitment, PolyCommitmentBlinds) {
357    let n = self.Z.len();
358    let ell = self.get_num_vars();
359    assert_eq!(n, ell.pow2());
360
361    let (left_num_vars, right_num_vars) = EqPolynomial::compute_factored_lens(ell);
362    let L_size = left_num_vars.pow2();
363    let R_size = right_num_vars.pow2();
364    assert_eq!(L_size * R_size, n);
365
366    let blinds = if let Some(t) = random_tape {
367      PolyCommitmentBlinds {
368        blinds: t.random_vector(b"poly_blinds", L_size),
369      }
370    } else {
371      PolyCommitmentBlinds {
372        blinds: vec![Scalar::zero(); L_size],
373      }
374    };
375
376    (self.commit_inner(&blinds.blinds, &gens.gens.gens_n), blinds)
377  }
378
379  pub fn bound(&self, L: &[Scalar]) -> Vec<Scalar> {
380    let (left_num_vars, right_num_vars) = EqPolynomial::compute_factored_lens(self.get_num_vars());
381    let L_size = left_num_vars.pow2();
382    let R_size = right_num_vars.pow2();
383    (0..R_size)
384      .map(|i| (0..L_size).map(|j| L[j] * self.Z[j * R_size + i]).sum())
385      .collect()
386  }
387
388  pub fn bound_poly_var_top(&mut self, r: &Scalar) {
389    let n = self.len() / 2;
390    for i in 0..n {
391      self.Z[i] = self.Z[i] + (self.Z[i + n] - self.Z[i]) * r;
392    }
393    self.num_vars -= 1;
394    self.len = n;
395  }
396
397  pub fn bound_poly_var_bot(&mut self, r: &Scalar) {
398    let n = self.len() / 2;
399    for i in 0..n {
400      self.Z[i] = self.Z[2 * i] + (self.Z[2 * i + 1] - self.Z[2 * i]) * r;
401    }
402    self.num_vars -= 1;
403    self.len = n;
404  }
405
406  // returns Z(r) in O(n) time
407  pub fn evaluate(&self, r: &[Scalar]) -> Scalar {
408    // r must have a value for each variable
409    assert_eq!(r.len(), self.get_num_vars());
410    let chis = EqPolynomial::new(r.to_vec()).evals();
411    assert_eq!(chis.len(), self.Z.len());
412    DotProductProofLog::compute_dotproduct(&self.Z, &chis)
413  }
414
415  fn vec(&self) -> &Vec<Scalar> {
416    &self.Z
417  }
418
419  pub fn extend(&mut self, other: &DensePolynomial) {
420    // TODO: allow extension even when some vars are bound
421    assert_eq!(self.Z.len(), self.len);
422    let other_vec = other.vec();
423    assert_eq!(other_vec.len(), self.len);
424    self.Z.extend(other_vec);
425    self.num_vars += 1;
426    self.len *= 2;
427    assert_eq!(self.Z.len(), self.len);
428  }
429
430  pub fn merge<'a, I>(polys: I) -> DensePolynomial
431  where
432    I: IntoIterator<Item = &'a DensePolynomial>,
433  {
434    let mut Z: Vec<Scalar> = Vec::new();
435    for poly in polys.into_iter() {
436      Z.extend(poly.vec());
437    }
438
439    // pad the polynomial with zero polynomial at the end
440    Z.resize(Z.len().next_power_of_two(), Scalar::zero());
441
442    DensePolynomial::new(Z)
443  }
444
445  pub fn from_usize(Z: &[usize]) -> Self {
446    DensePolynomial::new(
447      (0..Z.len())
448        .map(|i| Scalar::from(Z[i] as u64))
449        .collect::<Vec<Scalar>>(),
450    )
451  }
452}
453
454impl Index<usize> for DensePolynomial {
455  type Output = Scalar;
456
457  #[inline(always)]
458  fn index(&self, _index: usize) -> &Scalar {
459    &(self.Z[_index])
460  }
461}
462
463impl AppendToTranscript for PolyCommitment {
464  fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
465    transcript.append_message(label, b"poly_commitment_begin");
466    for i in 0..self.C.len() {
467      transcript.append_point(b"poly_commitment_share", &self.C[i]);
468    }
469    transcript.append_message(label, b"poly_commitment_end");
470  }
471}
472
473impl AppendToPoseidon for PolyCommitment {
474  fn append_to_poseidon(&self, transcript: &mut PoseidonTranscript) {
475    for i in 0..self.C.len() {
476      transcript.append_point(&self.C[i]);
477    }
478  }
479}
480
481#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
482pub struct PolyEvalProof {
483  proof: DotProductProofLog,
484}
485
486impl PolyEvalProof {
487  fn protocol_name() -> &'static [u8] {
488    b"polynomial evaluation proof"
489  }
490
491  pub fn prove(
492    poly: &DensePolynomial,
493    blinds_opt: Option<&PolyCommitmentBlinds>,
494    r: &[Scalar],                  // point at which the polynomial is evaluated
495    Zr: &Scalar,                   // evaluation of \widetilde{Z}(r)
496    blind_Zr_opt: Option<&Scalar>, // specifies a blind for Zr
497    gens: &PolyCommitmentGens,
498    transcript: &mut PoseidonTranscript,
499    random_tape: &mut RandomTape,
500  ) -> (PolyEvalProof, CompressedGroup) {
501    // transcript.append_protocol_name(PolyEvalProof::protocol_name());
502
503    // assert vectors are of the right size
504    assert_eq!(poly.get_num_vars(), r.len());
505
506    let (left_num_vars, right_num_vars) = EqPolynomial::compute_factored_lens(r.len());
507    let L_size = left_num_vars.pow2();
508    let R_size = right_num_vars.pow2();
509
510    let default_blinds = PolyCommitmentBlinds {
511      blinds: vec![Scalar::zero(); L_size],
512    };
513    let blinds = blinds_opt.map_or(&default_blinds, |p| p);
514
515    assert_eq!(blinds.blinds.len(), L_size);
516
517    let zero = Scalar::zero();
518    let blind_Zr = blind_Zr_opt.map_or(&zero, |p| p);
519
520    // compute the L and R vectors
521    let eq = EqPolynomial::new(r.to_vec());
522    let (L, R) = eq.compute_factored_evals();
523    assert_eq!(L.len(), L_size);
524    assert_eq!(R.len(), R_size);
525
526    // compute the vector underneath L*Z and the L*blinds
527    // compute vector-matrix product between L and Z viewed as a matrix
528    let LZ = poly.bound(&L);
529    let LZ_blind: Scalar = (0..L.len()).map(|i| blinds.blinds[i] * L[i]).sum();
530
531    // a dot product proof of size R_size
532    let (proof, _C_LR, C_Zr_prime) = DotProductProofLog::prove(
533      &gens.gens,
534      transcript,
535      random_tape,
536      &LZ,
537      &LZ_blind,
538      &R,
539      Zr,
540      blind_Zr,
541    );
542
543    (PolyEvalProof { proof }, C_Zr_prime)
544  }
545
546  pub fn verify(
547    &self,
548    gens: &PolyCommitmentGens,
549    transcript: &mut PoseidonTranscript,
550    r: &[Scalar],           // point at which the polynomial is evaluated
551    C_Zr: &CompressedGroup, // commitment to \widetilde{Z}(r)
552    comm: &PolyCommitment,
553  ) -> Result<(), ProofVerifyError> {
554    // transcript.append_protocol_name(PolyEvalProof::protocol_name());
555
556    // compute L and R
557    let eq = EqPolynomial::new(r.to_vec());
558    let (L, R) = eq.compute_factored_evals();
559
560    // compute a weighted sum of commitments and L
561    let C_decompressed = comm
562      .C
563      .iter()
564      .map(|pt| GroupElement::decompress(pt).unwrap())
565      .collect::<Vec<GroupElement>>();
566
567    let C_LZ = GroupElement::vartime_multiscalar_mul(&L, C_decompressed.as_slice()).compress();
568
569    self
570      .proof
571      .verify(R.len(), &gens.gens, transcript, &R, &C_LZ, C_Zr)
572  }
573
574  pub fn verify_plain(
575    &self,
576    gens: &PolyCommitmentGens,
577    transcript: &mut PoseidonTranscript,
578    r: &[Scalar], // point at which the polynomial is evaluated
579    Zr: &Scalar,  // evaluation \widetilde{Z}(r)
580    comm: &PolyCommitment,
581  ) -> Result<(), ProofVerifyError> {
582    // compute a commitment to Zr with a blind of zero
583    let C_Zr = Zr.commit(&Scalar::zero(), &gens.gens.gens_1).compress();
584
585    self.verify(gens, transcript, r, &C_Zr, comm)
586  }
587}
588
589#[cfg(test)]
590mod tests {
591  use crate::parameters::poseidon_params;
592
593  use super::*;
594  use ark_std::UniformRand;
595
596  fn evaluate_with_LR(Z: &[Scalar], r: &[Scalar]) -> Scalar {
597    let eq = EqPolynomial::new(r.to_vec());
598    let (L, R) = eq.compute_factored_evals();
599
600    let ell = r.len();
601    // ensure ell is even
602    assert!(ell % 2 == 0);
603    // compute n = 2^\ell
604    let n = ell.pow2();
605    // compute m = sqrt(n) = 2^{\ell/2}
606    let m = n.square_root();
607
608    // compute vector-matrix product between L and Z viewed as a matrix
609    let LZ = (0..m)
610      .map(|i| (0..m).map(|j| L[j] * Z[j * m + i]).sum())
611      .collect::<Vec<Scalar>>();
612
613    // compute dot product between LZ and R
614    DotProductProofLog::compute_dotproduct(&LZ, &R)
615  }
616
617  #[test]
618  fn check_polynomial_evaluation() {
619    // Z = [1, 2, 1, 4]
620    let Z = vec![
621      Scalar::one(),
622      Scalar::from(2),
623      Scalar::from(1),
624      Scalar::from(4),
625    ];
626
627    // r = [4,3]
628    let r = vec![Scalar::from(4), Scalar::from(3)];
629
630    let eval_with_LR = evaluate_with_LR(&Z, &r);
631    let poly = DensePolynomial::new(Z);
632
633    let eval = poly.evaluate(&r);
634    assert_eq!(eval, Scalar::from(28));
635    assert_eq!(eval_with_LR, eval);
636  }
637
638  pub fn compute_factored_chis_at_r(r: &[Scalar]) -> (Vec<Scalar>, Vec<Scalar>) {
639    let mut L: Vec<Scalar> = Vec::new();
640    let mut R: Vec<Scalar> = Vec::new();
641
642    let ell = r.len();
643    assert!(ell % 2 == 0); // ensure ell is even
644    let n = ell.pow2();
645    let m = n.square_root();
646
647    // compute row vector L
648    for i in 0..m {
649      let mut chi_i = Scalar::one();
650      for j in 0..ell / 2 {
651        let bit_j = ((m * i) & (1 << (r.len() - j - 1))) > 0;
652        if bit_j {
653          chi_i *= r[j];
654        } else {
655          chi_i *= Scalar::one() - r[j];
656        }
657      }
658      L.push(chi_i);
659    }
660
661    // compute column vector R
662    for i in 0..m {
663      let mut chi_i = Scalar::one();
664      for j in ell / 2..ell {
665        let bit_j = (i & (1 << (r.len() - j - 1))) > 0;
666        if bit_j {
667          chi_i *= r[j];
668        } else {
669          chi_i *= Scalar::one() - r[j];
670        }
671      }
672      R.push(chi_i);
673    }
674    (L, R)
675  }
676
677  pub fn compute_chis_at_r(r: &[Scalar]) -> Vec<Scalar> {
678    let ell = r.len();
679    let n = ell.pow2();
680    let mut chis: Vec<Scalar> = Vec::new();
681    for i in 0..n {
682      let mut chi_i = Scalar::one();
683      for j in 0..r.len() {
684        let bit_j = (i & (1 << (r.len() - j - 1))) > 0;
685        if bit_j {
686          chi_i *= r[j];
687        } else {
688          chi_i *= Scalar::one() - r[j];
689        }
690      }
691      chis.push(chi_i);
692    }
693    chis
694  }
695
696  pub fn compute_outerproduct(L: Vec<Scalar>, R: Vec<Scalar>) -> Vec<Scalar> {
697    assert_eq!(L.len(), R.len());
698    (0..L.len())
699      .map(|i| (0..R.len()).map(|j| L[i] * R[j]).collect::<Vec<Scalar>>())
700      .collect::<Vec<Vec<Scalar>>>()
701      .into_iter()
702      .flatten()
703      .collect::<Vec<Scalar>>()
704  }
705
706  #[test]
707  fn check_memoized_chis() {
708    let mut rng = ark_std::rand::thread_rng();
709
710    let s = 10;
711    let mut r: Vec<Scalar> = Vec::new();
712    for _i in 0..s {
713      r.push(Scalar::rand(&mut rng));
714    }
715    let chis = tests::compute_chis_at_r(&r);
716    let chis_m = EqPolynomial::new(r).evals();
717    assert_eq!(chis, chis_m);
718  }
719
720  #[test]
721  fn check_factored_chis() {
722    let mut rng = ark_std::rand::thread_rng();
723
724    let s = 10;
725    let mut r: Vec<Scalar> = Vec::new();
726    for _i in 0..s {
727      r.push(Scalar::rand(&mut rng));
728    }
729    let chis = EqPolynomial::new(r.clone()).evals();
730    let (L, R) = EqPolynomial::new(r).compute_factored_evals();
731    let O = compute_outerproduct(L, R);
732    assert_eq!(chis, O);
733  }
734
735  #[test]
736  fn check_memoized_factored_chis() {
737    let mut rng = ark_std::rand::thread_rng();
738
739    let s = 10;
740    let mut r: Vec<Scalar> = Vec::new();
741    for _i in 0..s {
742      r.push(Scalar::rand(&mut rng));
743    }
744    let (L, R) = tests::compute_factored_chis_at_r(&r);
745    let eq = EqPolynomial::new(r);
746    let (L2, R2) = eq.compute_factored_evals();
747    assert_eq!(L, L2);
748    assert_eq!(R, R2);
749  }
750
751  #[test]
752  fn check_polynomial_commit() {
753    let Z = vec![
754      Scalar::from(1),
755      Scalar::from(2),
756      Scalar::from(1),
757      Scalar::from(4),
758    ];
759    let poly = DensePolynomial::new(Z);
760
761    // r = [4,3]
762    let r = vec![Scalar::from(4), Scalar::from(3)];
763    let eval = poly.evaluate(&r);
764    assert_eq!(eval, Scalar::from(28));
765
766    let gens = PolyCommitmentGens::new(poly.get_num_vars(), b"test-two");
767    let (poly_commitment, blinds) = poly.commit(&gens, None);
768
769    let mut random_tape = RandomTape::new(b"proof");
770    let params = poseidon_params();
771    let mut prover_transcript = PoseidonTranscript::new(&params);
772    let (proof, C_Zr) = PolyEvalProof::prove(
773      &poly,
774      Some(&blinds),
775      &r,
776      &eval,
777      None,
778      &gens,
779      &mut prover_transcript,
780      &mut random_tape,
781    );
782
783    let mut verifier_transcript = PoseidonTranscript::new(&params);
784    assert!(proof
785      .verify(&gens, &mut verifier_transcript, &r, &C_Zr, &poly_commitment)
786      .is_ok());
787  }
788}