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: Vec<FpVar<F>>, y: Vec<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
34 use crate::utils::virtual_polynomial::eq_eval;
35
36 use super::EqEvalGadget;
37 use ark_ff::Field;
38 use ark_pallas::Fr;
39 use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
40 use ark_relations::r1cs::ConstraintSystem;
41 use ark_std::{test_rng, UniformRand};
42
43 #[test]
44 pub fn test_eq_eval_gadget() {
45 let mut rng = test_rng();
46 let cs = ConstraintSystem::<Fr>::new_ref();
47
48 for i in 1..20 {
49 let x_vec: Vec<Fr> = (0..i).map(|_| Fr::rand(&mut rng)).collect();
50 let y_vec: Vec<Fr> = (0..i).map(|_| Fr::rand(&mut rng)).collect();
51 let x: Vec<FpVar<Fr>> = x_vec
52 .iter()
53 .map(|x| FpVar::<Fr>::new_witness(cs.clone(), || Ok(x)).unwrap())
54 .collect();
55 let y: Vec<FpVar<Fr>> = y_vec
56 .iter()
57 .map(|y| FpVar::<Fr>::new_witness(cs.clone(), || Ok(y)).unwrap())
58 .collect();
59 let expected_eq_eval = eq_eval::<Fr>(&x_vec, &y_vec).unwrap();
60 let gadget_eq_eval: FpVar<Fr> = EqEvalGadget::<Fr>::eq_eval(x, y).unwrap();
61 assert_eq!(expected_eq_eval, gadget_eq_eval.value().unwrap());
62 }
63
64 let x: Vec<FpVar<Fr>> = vec![];
65 let y: Vec<FpVar<Fr>> = vec![];
66 let gadget_eq_eval = EqEvalGadget::<Fr>::eq_eval(x, y);
67 assert!(gadget_eq_eval.is_err());
68
69 let x: Vec<FpVar<Fr>> = vec![];
70 let y: Vec<FpVar<Fr>> =
71 vec![FpVar::<Fr>::new_witness(cs.clone(), || Ok(&Fr::ONE)).unwrap()];
72 let gadget_eq_eval = EqEvalGadget::<Fr>::eq_eval(x, y);
73 assert!(gadget_eq_eval.is_err());
74 }
75}