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}