arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/src/folding/circuits/utils.rs
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}