arnaucube
arnaucube/sonobePublic Self-hosted repository
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}