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