arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/frontends/src/noname/mod.rs
frontends/src/noname/mod.rsRaw
  1use ark_noname::sonobe::NonameSonobeCircuit;
  2use ark_r1cs_std::alloc::AllocVar;
  3use ark_r1cs_std::fields::fp::FpVar;
  4use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
  5use num_bigint::BigUint;
  6use std::marker::PhantomData;
  7
  8use self::utils::NonameInputs;
  9
 10use ark_ff::PrimeField;
 11use ark_noname::utils::compile_source_code;
 12use folding_schemes::{frontend::FCircuit, Error};
 13use noname::backends::{r1cs::R1CS as R1CSNoname, BackendField};
 14use noname::witness::CompiledCircuit;
 15pub mod utils;
 16#[derive(Debug, Clone)]
 17pub struct NonameFCircuit<F: PrimeField, BF: BackendField> {
 18    pub state_len: usize,
 19    pub external_inputs_len: usize,
 20    pub circuit: CompiledCircuit<R1CSNoname<BF>>,
 21    _f: PhantomData<F>,
 22}
 23
 24impl<F: PrimeField, BF: BackendField> FCircuit<F> for NonameFCircuit<F, BF> {
 25    type Params = (String, usize, usize);
 26
 27    fn new(params: Self::Params) -> Result<Self, Error> {
 28        let (code, state_len, external_inputs_len) = params;
 29        let compiled_circuit = compile_source_code::<BF>(&code).map_err(|_| {
 30            Error::Other("Encountered an error while compiling a noname circuit".to_owned())
 31        })?;
 32        Ok(NonameFCircuit {
 33            state_len,
 34            external_inputs_len,
 35            circuit: compiled_circuit,
 36            _f: PhantomData,
 37        })
 38    }
 39
 40    fn state_len(&self) -> usize {
 41        self.state_len
 42    }
 43
 44    fn external_inputs_len(&self) -> usize {
 45        self.external_inputs_len
 46    }
 47
 48    fn step_native(
 49        &self,
 50        _i: usize,
 51        z_i: Vec<F>,
 52        external_inputs: Vec<F>,
 53    ) -> Result<Vec<F>, Error> {
 54        let wtns_external_inputs =
 55            NonameInputs::from((&external_inputs, "external_inputs".to_string()));
 56        let wtns_ivc_inputs = NonameInputs::from((&z_i, "ivc_inputs".to_string()));
 57
 58        let noname_witness = self
 59            .circuit
 60            .generate_witness(wtns_ivc_inputs.0, wtns_external_inputs.0)
 61            .map_err(|e| Error::WitnessCalculationError(e.to_string()))?;
 62
 63        let z_i1_end_index = z_i.len() + 1;
 64        let assigned_z_i1 = (1..z_i1_end_index)
 65            .map(|idx| {
 66                let value: BigUint = Into::into(noname_witness.witness[idx]);
 67                F::from(value)
 68            })
 69            .collect();
 70
 71        Ok(assigned_z_i1)
 72    }
 73
 74    fn generate_step_constraints(
 75        &self,
 76        cs: ConstraintSystemRef<F>,
 77        _i: usize,
 78        z_i: Vec<FpVar<F>>,
 79        external_inputs: Vec<FpVar<F>>,
 80    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 81        let wtns_external_inputs =
 82            NonameInputs::from_fpvars((&external_inputs, "external_inputs".to_string()))?;
 83        let wtns_ivc_inputs = NonameInputs::from_fpvars((&z_i, "ivc_inputs".to_string()))?;
 84        let noname_witness = self
 85            .circuit
 86            .generate_witness(wtns_ivc_inputs.0, wtns_external_inputs.0)
 87            .map_err(|_| SynthesisError::Unsatisfiable)?;
 88        let z_i1_end_index = z_i.len() + 1;
 89        let assigned_z_i1: Vec<FpVar<F>> = (1..z_i1_end_index)
 90            .map(|idx| -> Result<FpVar<F>, SynthesisError> {
 91                // the assigned zi1 is of the same size than the initial zi and is located in the
 92                // output of the witness vector
 93                // we prefer to assign z_i1 here since (1) we have to return it, (2) we cant return
 94                // anything with the `generate_constraints` method used below
 95                let value: BigUint = Into::into(noname_witness.witness[idx]);
 96                let field_element = F::from(value);
 97                FpVar::<F>::new_witness(cs.clone(), || Ok(field_element))
 98            })
 99            .collect::<Result<Vec<FpVar<F>>, SynthesisError>>()?;
100
101        let noname_circuit = NonameSonobeCircuit {
102            compiled_circuit: self.circuit.clone(),
103            witness: noname_witness,
104            assigned_z_i: &z_i,
105            assigned_external_inputs: &external_inputs,
106            assigned_z_i1: &assigned_z_i1,
107        };
108        noname_circuit.generate_constraints(cs.clone())?;
109
110        Ok(assigned_z_i1)
111    }
112}
113
114#[cfg(test)]
115mod tests {
116
117    use ark_bn254::Fr;
118    use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
119    use noname::backends::r1cs::R1csBn254Field;
120
121    use folding_schemes::frontend::FCircuit;
122
123    use super::NonameFCircuit;
124    use ark_relations::r1cs::ConstraintSystem;
125
126    const NONAME_CIRCUIT_EXTERNAL_INPUTS: &str =
127        "fn main(pub ivc_inputs: [Field; 2], external_inputs: [Field; 2]) -> [Field; 2] {
128    let xx = external_inputs[0] + ivc_inputs[0];
129    let yy = external_inputs[1] * ivc_inputs[1];
130    assert_eq(yy, xx);
131    return [xx, yy];
132}";
133
134    const NONAME_CIRCUIT_NO_EXTERNAL_INPUTS: &str =
135        "fn main(pub ivc_inputs: [Field; 2]) -> [Field; 2] {
136    let out = ivc_inputs[0] * ivc_inputs[1];
137    return [out, ivc_inputs[1]];
138}";
139
140    #[test]
141    fn test_step_native() {
142        let cs = ConstraintSystem::<Fr>::new_ref();
143        let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2);
144        let circuit = NonameFCircuit::<Fr, R1csBn254Field>::new(params).unwrap();
145        let inputs_public = vec![Fr::from(2), Fr::from(5)];
146        let inputs_private = vec![Fr::from(8), Fr::from(2)];
147
148        let ivc_inputs_var =
149            Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(inputs_public.clone())).unwrap();
150        let external_inputs_var =
151            Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(inputs_private.clone())).unwrap();
152
153        let z_i1 = circuit
154            .generate_step_constraints(cs.clone(), 0, ivc_inputs_var, external_inputs_var)
155            .unwrap();
156        let z_i1_native = circuit
157            .step_native(0, inputs_public, inputs_private)
158            .unwrap();
159
160        assert_eq!(z_i1[0].value().unwrap(), z_i1_native[0]);
161        assert_eq!(z_i1[1].value().unwrap(), z_i1_native[1]);
162    }
163
164    #[test]
165    fn test_step_constraints() {
166        let cs = ConstraintSystem::<Fr>::new_ref();
167        let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2);
168        let circuit = NonameFCircuit::<Fr, R1csBn254Field>::new(params).unwrap();
169        let inputs_public = vec![Fr::from(2), Fr::from(5)];
170        let inputs_private = vec![Fr::from(8), Fr::from(2)];
171
172        let ivc_inputs_var =
173            Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(inputs_public)).unwrap();
174        let external_inputs_var =
175            Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(inputs_private)).unwrap();
176
177        let z_i1 = circuit
178            .generate_step_constraints(cs.clone(), 0, ivc_inputs_var, external_inputs_var)
179            .unwrap();
180        assert!(cs.is_satisfied().unwrap());
181        assert_eq!(z_i1[0].value().unwrap(), Fr::from(10_u8));
182        assert_eq!(z_i1[1].value().unwrap(), Fr::from(10_u8));
183    }
184
185    #[test]
186    fn test_generate_constraints_no_external_inputs() {
187        let cs = ConstraintSystem::<Fr>::new_ref();
188        let params = (NONAME_CIRCUIT_NO_EXTERNAL_INPUTS.to_owned(), 2, 0);
189        let inputs_public = vec![Fr::from(2), Fr::from(5)];
190
191        let ivc_inputs_var =
192            Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(inputs_public)).unwrap();
193
194        let f_circuit = NonameFCircuit::<Fr, R1csBn254Field>::new(params).unwrap();
195        f_circuit
196            .generate_step_constraints(cs.clone(), 0, ivc_inputs_var, vec![])
197            .unwrap();
198        assert!(cs.is_satisfied().unwrap());
199    }
200}