sonobe/folding-schemes/src/folding/circuits/utils.rs
folding-schemes/src/folding/circuits/utils.rsRaw
1use ark_ff::PrimeField;
2use ark_r1cs_std::fields::{fp::FpVar, FieldVar};
3use ark_relations::r1cs::SynthesisError;
4use std::marker::PhantomData;
5
6/// EqEval is a gadget for computing $\tilde{eq}(a, b) = \prod_{i=1}^{l}(a_i \cdot b_i + (1 - a_i)(1 - b_i))$
7/// :warning: This is not the ark_r1cs_std::eq::EqGadget
8pub struct EqEvalGadget<F: PrimeField> {
9 _f: PhantomData<F>,
10}
11
12impl<F: PrimeField> EqEvalGadget<F> {
13 /// Gadget to evaluate eq polynomial.
14 /// Follows the implementation of `eq_eval` found in this crate.
15 pub fn eq_eval(x: &[FpVar<F>], y: &[FpVar<F>]) -> Result<FpVar<F>, SynthesisError> {
16 if x.len() != y.len() {
17 return Err(SynthesisError::Unsatisfiable);
18 }
19 if x.is_empty() || y.is_empty() {
20 return Err(SynthesisError::AssignmentMissing);
21 }
22 let mut e = FpVar::<F>::one();
23 for (xi, yi) in x.iter().zip(y.iter()) {
24 let xi_yi = xi * yi;
25 e *= xi_yi.clone() + xi_yi - xi - yi + F::one();
26 }
27 Ok(e)
28 }
29}
30
31#[cfg(test)]
32mod tests {
33 use ark_ff::Field;
34 use ark_pallas::Fr;
35 use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
36 use ark_relations::r1cs::ConstraintSystem;
37 use ark_std::{test_rng, UniformRand};
38
39 use super::EqEvalGadget;
40 use crate::utils::virtual_polynomial::eq_eval;
41
42 #[test]
43 pub fn test_eq_eval_gadget() {
44 let mut rng = test_rng();
45 let cs = ConstraintSystem::<Fr>::new_ref();
46
47 for i in 1..20 {
48 let x_vec: Vec<Fr> = (0..i).map(|_| Fr::rand(&mut rng)).collect();
49 let y_vec: Vec<Fr> = (0..i).map(|_| Fr::rand(&mut rng)).collect();
50 let x: Vec<FpVar<Fr>> = x_vec
51 .iter()
52 .map(|x| FpVar::<Fr>::new_witness(cs.clone(), || Ok(x)).unwrap())
53 .collect();
54 let y: Vec<FpVar<Fr>> = y_vec
55 .iter()
56 .map(|y| FpVar::<Fr>::new_witness(cs.clone(), || Ok(y)).unwrap())
57 .collect();
58 let expected_eq_eval = eq_eval::<Fr>(&x_vec, &y_vec).unwrap();
59 let gadget_eq_eval: FpVar<Fr> = EqEvalGadget::<Fr>::eq_eval(&x, &y).unwrap();
60 assert_eq!(expected_eq_eval, gadget_eq_eval.value().unwrap());
61 }
62
63 let x: Vec<FpVar<Fr>> = vec![];
64 let y: Vec<FpVar<Fr>> = vec![];
65 let gadget_eq_eval = EqEvalGadget::<Fr>::eq_eval(&x, &y);
66 assert!(gadget_eq_eval.is_err());
67
68 let x: Vec<FpVar<Fr>> = vec![];
69 let y: Vec<FpVar<Fr>> =
70 vec![FpVar::<Fr>::new_witness(cs.clone(), || Ok(&Fr::ONE)).unwrap()];
71 let gadget_eq_eval = EqEvalGadget::<Fr>::eq_eval(&x, &y);
72 assert!(gadget_eq_eval.is_err());
73 }
74}