arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/frontend/utils.rs
folding-schemes/src/frontend/utils.rsRaw
  1use ark_ff::PrimeField;
  2use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar};
  3use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
  4#[cfg(test)]
  5use ark_std::marker::PhantomData;
  6use ark_std::{fmt::Debug, Zero};
  7
  8use super::FCircuit;
  9use crate::Error;
 10
 11/// DummyCircuit is a circuit that has dummy state and external inputs whose
 12/// lengths are specified in the `state_len` and `external_inputs_len`
 13/// parameters, without any constraints.
 14#[derive(Clone, Debug)]
 15pub struct DummyCircuit {
 16    state_len: usize,
 17    external_inputs_len: usize,
 18}
 19impl<F: PrimeField> FCircuit<F> for DummyCircuit {
 20    type Params = (usize, usize);
 21
 22    fn new((state_len, external_inputs_len): Self::Params) -> Result<Self, Error> {
 23        Ok(Self {
 24            state_len,
 25            external_inputs_len,
 26        })
 27    }
 28    fn state_len(&self) -> usize {
 29        self.state_len
 30    }
 31    fn external_inputs_len(&self) -> usize {
 32        self.external_inputs_len
 33    }
 34    fn step_native(
 35        &self,
 36        _i: usize,
 37        _z_i: Vec<F>,
 38        _external_inputs: Vec<F>,
 39    ) -> Result<Vec<F>, Error> {
 40        Ok(vec![F::zero(); self.state_len])
 41    }
 42    fn generate_step_constraints(
 43        &self,
 44        cs: ConstraintSystemRef<F>,
 45        _i: usize,
 46        _z_i: Vec<FpVar<F>>,
 47        _external_inputs: Vec<FpVar<F>>,
 48    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 49        Vec::new_witness(cs.clone(), || Ok(vec![Zero::zero(); self.state_len]))
 50    }
 51}
 52
 53/// CubicFCircuit is a struct that implements the FCircuit trait, for the R1CS example circuit
 54/// from https://www.vitalik.ca/general/2016/12/10/qap.html, which checks `x^3 + x + 5 = y`.
 55/// `z_i` is used as `x`, and `z_{i+1}` is used as `y`, and at the next step, `z_{i+1}` will be
 56/// assigned to `z_i`, and a new `z+{i+1}` will be computted.
 57#[cfg(test)]
 58#[derive(Clone, Copy, Debug)]
 59pub struct CubicFCircuit<F: PrimeField> {
 60    _f: PhantomData<F>,
 61}
 62
 63#[cfg(test)]
 64impl<F: PrimeField> FCircuit<F> for CubicFCircuit<F> {
 65    type Params = ();
 66    fn new(_params: Self::Params) -> Result<Self, Error> {
 67        Ok(Self { _f: PhantomData })
 68    }
 69    fn state_len(&self) -> usize {
 70        1
 71    }
 72    fn external_inputs_len(&self) -> usize {
 73        0
 74    }
 75    fn step_native(
 76        &self,
 77        _i: usize,
 78        z_i: Vec<F>,
 79        _external_inputs: Vec<F>,
 80    ) -> Result<Vec<F>, Error> {
 81        Ok(vec![z_i[0] * z_i[0] * z_i[0] + z_i[0] + F::from(5_u32)])
 82    }
 83    fn generate_step_constraints(
 84        &self,
 85        cs: ConstraintSystemRef<F>,
 86        _i: usize,
 87        z_i: Vec<FpVar<F>>,
 88        _external_inputs: Vec<FpVar<F>>,
 89    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 90        let five = FpVar::<F>::new_constant(cs.clone(), F::from(5u32))?;
 91        let z_i = z_i[0].clone();
 92
 93        Ok(vec![&z_i * &z_i * &z_i + &z_i + &five])
 94    }
 95}
 96
 97/// CustomFCircuit is a circuit that has the number of constraints specified in the
 98/// `n_constraints` parameter. Note that the generated circuit will have very sparse matrices.
 99#[cfg(test)]
100#[derive(Clone, Copy, Debug)]
101pub struct CustomFCircuit<F: PrimeField> {
102    _f: PhantomData<F>,
103    pub n_constraints: usize,
104}
105
106#[cfg(test)]
107impl<F: PrimeField> FCircuit<F> for CustomFCircuit<F> {
108    type Params = usize;
109
110    fn new(params: Self::Params) -> Result<Self, Error> {
111        Ok(Self {
112            _f: PhantomData,
113            n_constraints: params,
114        })
115    }
116    fn state_len(&self) -> usize {
117        1
118    }
119    fn external_inputs_len(&self) -> usize {
120        0
121    }
122    fn step_native(
123        &self,
124        _i: usize,
125        z_i: Vec<F>,
126        _external_inputs: Vec<F>,
127    ) -> Result<Vec<F>, Error> {
128        let mut z_i1 = F::one();
129        for _ in 0..self.n_constraints - 1 {
130            z_i1 *= z_i[0];
131        }
132        Ok(vec![z_i1])
133    }
134    fn generate_step_constraints(
135        &self,
136        cs: ConstraintSystemRef<F>,
137        _i: usize,
138        z_i: Vec<FpVar<F>>,
139        _external_inputs: Vec<FpVar<F>>,
140    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
141        let mut z_i1 = FpVar::<F>::new_witness(cs.clone(), || Ok(F::one()))?;
142        for _ in 0..self.n_constraints - 1 {
143            z_i1 *= z_i[0].clone();
144        }
145
146        Ok(vec![z_i1])
147    }
148}
149
150/// WrapperCircuit is a circuit that wraps any circuit that implements the FCircuit trait. This
151/// is used to test the `FCircuit.generate_step_constraints` method. This is a similar wrapping
152/// than the one done in the `AugmentedFCircuit`, but without adding all the extra constraints
153/// of the AugmentedF circuit logic, in order to run lighter tests when we're not interested in
154/// the the AugmentedF logic but in the wrapping of the circuits.
155#[cfg(test)]
156pub struct WrapperCircuit<F: PrimeField, FC: FCircuit<F>> {
157    pub FC: FC, // F circuit
158    pub z_i: Option<Vec<F>>,
159    pub z_i1: Option<Vec<F>>,
160}
161
162#[cfg(test)]
163impl<F, FC> ark_relations::r1cs::ConstraintSynthesizer<F> for WrapperCircuit<F, FC>
164where
165    F: PrimeField,
166    FC: FCircuit<F>,
167{
168    fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
169        let z_i =
170            Vec::<FpVar<F>>::new_witness(cs.clone(), || Ok(self.z_i.unwrap_or(vec![F::zero()])))?;
171        let z_i1 =
172            Vec::<FpVar<F>>::new_input(cs.clone(), || Ok(self.z_i1.unwrap_or(vec![F::zero()])))?;
173        let computed_z_i1 =
174            self.FC
175                .generate_step_constraints(cs.clone(), 0, z_i.clone(), vec![])?;
176
177        use ark_r1cs_std::eq::EqGadget;
178        computed_z_i1.enforce_equal(&z_i1)?;
179        Ok(())
180    }
181}