grapevine-sonobe/src/circom.rs
src/circom.rsRaw
1#[cfg(test)]
2mod test {
3 use super::*;
4 use crate::params::test_nova_setup;
5 use crate::utils::inputs::{
6 get_z0, prepare_external_inputs, random_f_bigint, CircomPrivateInput,
7 };
8 use ark_bn254::{constraints::GVar, Fr, G1Projective as Projective};
9 // use ark_circom::circom::CircomCircuit;
10 use ark_ff::{BigInteger, PrimeField};
11 use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
12 use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
13 use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
14 use lazy_static::lazy_static;
15 use num_bigint::{BigInt, Sign};
16 use sonobe::{
17 commitment::pedersen::Pedersen, folding::nova::Nova, frontend::circom::CircomFCircuit,
18 transcript::poseidon::poseidon_test_config, Error, FoldingScheme,
19 };
20 use sonobe::{frontend::FCircuit, Error as SonobeError};
21 use std::env::current_dir;
22 use std::path::PathBuf;
23 use std::time::Instant;
24
25 use crate::errors::GrapevineError;
26
27 lazy_static! {
28 pub static ref R1CS_PATH: PathBuf = PathBuf::from("./circom/artifacts/grapevine.r1cs");
29 pub static ref WASM_PATH: PathBuf = PathBuf::from("./circom/artifacts/grapevine.wasm");
30 pub static ref PHRASE: String = String::from("This is a secret");
31 pub static ref USERNAMES: [String; 5] = [
32 String::from("alice"),
33 String::from("bob"),
34 String::from("charlie"),
35 String::from("david"),
36 String::from("eve")
37 ];
38 pub static ref AUTH_SECRETS: [BigInt; 5] = (0..5)
39 .map(|_| random_f_bigint::<Fr>())
40 .collect::<Vec<BigInt>>()
41 .try_into()
42 .unwrap();
43 }
44
45 // Converts a PrimeField element to a num_bigint::BigInt representation.
46 pub fn ark_primefield_to_num_bigint<F: PrimeField>(value: F) -> BigInt {
47 let primefield_bigint: F::BigInt = value.into_bigint();
48 let bytes = primefield_bigint.to_bytes_be();
49 BigInt::from_bytes_be(Sign::Plus, &bytes)
50 }
51
52 /// This test tests the circom circuit without using anything from Sonobe, just using
53 /// arkworks/circom-compat to check the Grapevine circuit.
54 #[test]
55 fn test_circom_circuit() {
56 // define inputs
57 let step_0_inputs = CircomPrivateInput {
58 phrase: Some(String::from(&*PHRASE)),
59 usernames: [None, Some(String::from(&*USERNAMES[0]))],
60 auth_secrets: [None, Some(AUTH_SECRETS[0].clone())],
61 chaff: false,
62 };
63 let external_inputs = prepare_external_inputs::<Fr>(&step_0_inputs);
64 let z_0 = get_z0::<Fr>();
65 dbg!(&z_0);
66
67 let z_0_bi = z_0
68 .iter()
69 .map(|val| ark_primefield_to_num_bigint(*val))
70 .collect::<Vec<BigInt>>();
71 let external_inputs_bi = external_inputs
72 .iter()
73 .map(|val| ark_primefield_to_num_bigint(*val))
74 .collect::<Vec<BigInt>>();
75
76 use ark_circom::{CircomBuilder, CircomConfig};
77 let cfg = CircomConfig::<Fr>::new(
78 "./circom/artifacts/grapevine.wasm",
79 "./circom/artifacts/grapevine.r1cs",
80 )
81 .unwrap();
82
83 let mut builder = CircomBuilder::new(cfg);
84
85 // Insert our public inputs as key value pairs
86 use std::collections::HashMap;
87 builder.inputs = HashMap::from([
88 ("ivc_input".to_string(), z_0_bi),
89 ("external_ipnuts".to_string(), external_inputs_bi),
90 ]);
91 dbg!(&builder.inputs);
92
93 let circom = builder.build().unwrap();
94
95 // extract the public output (ivc_output) from the computed witness and print it
96 let z_1 = circom.witness.unwrap()[1..1 + 6 + 4].to_vec();
97 println!("z_1: {:?}", z_1);
98 }
99
100 #[test]
101 fn test_step_native() {
102 // define inputs
103 let step_0_inputs = CircomPrivateInput {
104 phrase: Some(String::from(&*PHRASE)),
105 usernames: [None, Some(String::from(&*USERNAMES[0]))],
106 auth_secrets: [None, Some(AUTH_SECRETS[0].clone())],
107 chaff: false,
108 };
109 let external_inputs = prepare_external_inputs::<Fr>(&step_0_inputs);
110
111 // initialize new Grapevine function circuit
112 let f_circuit =
113 CircomFCircuit::<Fr>::new((R1CS_PATH.clone(), WASM_PATH.clone(), 4, 6 + 4)).unwrap(); // 4=ivc_input.lenght, 6+4=external_inputs
114
115 let z_0 = get_z0();
116 let z_1 = f_circuit
117 .step_native(0, z_0.to_vec(), external_inputs)
118 .unwrap();
119 println!("z_1: {:?}", z_1);
120 }
121
122 #[test]
123 fn test_step_constraints() {
124 // define inputs
125 let step_0_inputs = CircomPrivateInput {
126 phrase: Some(String::from(&*PHRASE)),
127 usernames: [None, Some(String::from(&*USERNAMES[0]))],
128 auth_secrets: [None, Some(AUTH_SECRETS[0].clone())],
129 chaff: false,
130 };
131 let external_inputs = prepare_external_inputs::<Fr>(&step_0_inputs);
132
133 // initialize new Grapevine function circuit
134 let f_circuit =
135 CircomFCircuit::<Fr>::new((R1CS_PATH.clone(), WASM_PATH.clone(), 4, 6 + 4)).unwrap(); // 4=ivc_input.lenght, 6+4=external_inputs
136
137 let z_0 = get_z0();
138 let z_1 = f_circuit
139 .step_native(0, z_0.to_vec(), external_inputs.clone())
140 .unwrap();
141
142 // assign z0
143 let cs = ConstraintSystem::<Fr>::new_ref();
144 let z_0_var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_0)).unwrap();
145 let external_inputs_var =
146 Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(external_inputs)).unwrap();
147
148 // compute constraints for step 0
149 let z_1_var = f_circuit
150 .generate_step_constraints(cs.clone(), 1, z_0_var, external_inputs_var)
151 .unwrap();
152 println!("z_1: {:?}", z_1_var);
153
154 assert_eq!(z_1_var.value().unwrap(), z_1);
155 }
156
157 // WIP
158 /*
159 #[test]
160 fn test_multiple_steps_native() {
161 // initialize new Grapevine function circuit
162 let mut f_circuit = GrapevineFCircuit::<Fr>::new((R1CS_PATH.clone(), WASM_PATH.clone()));
163
164 /* DEGREE 1 */
165 // define degree 1 logic inputs
166 let inputs = CircomPrivateInput {
167 phrase: Some(String::from(&*PHRASE)),
168 usernames: [None, Some(String::from(&*USERNAMES[0]))],
169 auth_secrets: [None, Some(AUTH_SECRETS[0].clone())],
170 chaff: false,
171 };
172 f_circuit.set_private_input(inputs);
173
174 // compute step 0 (degree 1 logic step)
175 let z_i = f_circuit.step_native(0, get_z0().to_vec()).unwrap();
176
177 // define degree 1 chaff inputs
178 let inputs = CircomPrivateInput::empty(true);
179 f_circuit.set_private_input(inputs);
180
181 // compute step 1 (degree 1 chaff step)
182 let z_i = f_circuit.step_native(1, z_i.to_vec()).unwrap();
183 println!("z_i: {:?}", z_i);
184
185 /* DEGREE 2 */
186 // define degree 2 logic inputs
187 let inputs = CircomPrivateInput {
188 phrase: None,
189 usernames: [
190 Some(String::from(&*USERNAMES[0])),
191 Some(String::from(&*USERNAMES[1])),
192 ],
193 auth_secrets: [Some(AUTH_SECRETS[0].clone()), Some(AUTH_SECRETS[1].clone())],
194 chaff: false,
195 };
196 f_circuit.set_private_input(inputs);
197
198 // compute step 2 (degree 2 logic step)
199 let z_i = f_circuit.step_native(2, z_i.to_vec()).unwrap();
200
201 // define degree 2 chaff inputs
202 let inputs = CircomPrivateInput::empty(true);
203 f_circuit.set_private_input(inputs);
204
205 // compute step 3 (degree 2 chaff step)
206 let z_i = f_circuit.step_native(3, z_i.to_vec()).unwrap();
207
208 /* DEGREE 3 */
209 // define degree 3 logic inputs
210 let inputs = CircomPrivateInput {
211 phrase: None,
212 usernames: [
213 Some(String::from(&*USERNAMES[1])),
214 Some(String::from(&*USERNAMES[2])),
215 ],
216 auth_secrets: [Some(AUTH_SECRETS[1].clone()), Some(AUTH_SECRETS[2].clone())],
217 chaff: false,
218 };
219 f_circuit.set_private_input(inputs);
220
221 // compute step 4 (degree 3 logic step)
222 let z_i = f_circuit.step_native(4, z_i.to_vec()).unwrap();
223
224 // define degree 3 chaff inputs
225 let inputs = CircomPrivateInput::empty(true);
226 f_circuit.set_private_input(inputs);
227
228 // compute step 5 (degree 3 chaff step)
229 let z_i = f_circuit.step_native(5, z_i.to_vec()).unwrap();
230
231 /* RESULT */
232 // @todo: compute hashes natively
233 assert_eq!(z_i[0], Fr::from(3));
234 assert_eq!(z_i[3], Fr::from(0));
235 }
236 */
237
238 // #[test]
239 // fn test_multiple_steps_constraints() {
240 // // initialize new Grapevine function circuit
241 // let mut f_circuit = GrapevineFCircuit::<Fr>::new((R1CS_PATH.clone(), WASM_PATH.clone()));
242 //
243 // /* DEGREE 1 */
244 // // define degree 1 logic inputs
245 // let inputs = CircomPrivateInput {
246 // phrase: Some(String::from(&*PHRASE)),
247 // usernames: [None, Some(String::from(&*USERNAMES[0]))],
248 // auth_secrets: [None, Some(AUTH_SECRETS[0].clone())],
249 // chaff: false
250 // };
251 // f_circuit.set_private_input(inputs);
252 //
253 // // assign z0
254 // let cs = ConstraintSystem::<Fr>::new_ref();
255 // let z_0_var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(get_z0())).unwrap();
256 //
257 // // compute constraints for step 0 (degree 1 logic step)
258 // let cs = ConstraintSystem::<Fr>::new_ref();
259 // let z_1_var = f_circuit
260 // .generate_step_constraints(cs.clone(), 0, z_0_var)
261 // .unwrap();
262 // println!("z_1: {:?}", z_1_var);
263 //
264 // // define degree 1 chaff inputs
265 // let inputs = CircomPrivateInput::empty(true);
266 // f_circuit.set_private_input(inputs);
267 //
268 // // compute step 1 (degree 1 chaff step)
269 // let z_i = f_circuit.step_native(1, z_i.to_vec()).unwrap();
270 // println!("z_i: {:?}", z_i);
271 //
272 // // define inputs
273 // let step_0_inputs = CircomPrivateInput {
274 // phrase: Some(String::from(&*PHRASE)),
275 // usernames: [None, Some(String::from(&*USERNAMES[0]))],
276 // auth_secrets: [None, Some(AUTH_SECRETS[0].clone())],
277 // chaff: false
278 // };
279 //
280 // // initialize new Grapevine function circuit
281 // let mut f_circuit = GrapevineFCircuit::<Fr>::new((R1CS_PATH.clone(), WASM_PATH.clone()));
282 // f_circuit.set_private_input(step_0_inputs);
283 //
284 // }
285
286 /*
287 #[test]
288 fn test_full_one_step() {
289 // initialize new Grapevine function circuit
290 let mut f_circuit = GrapevineFCircuit::<Fr>::new((R1CS_PATH.clone(), WASM_PATH.clone()));
291
292 // Get test params
293 let (prover_params, verifier_params) =
294 test_nova_setup::<GrapevineFCircuit<Fr>>(f_circuit.clone());
295
296 // define inputs
297 // define inputs
298 let step_0_inputs = CircomPrivateInput {
299 phrase: Some(String::from(&*PHRASE)),
300 usernames: [None, Some(String::from(&*USERNAMES[0]))],
301 auth_secrets: [None, Some(AUTH_SECRETS[0].clone())],
302 chaff: false,
303 };
304 // let z_0 = get_z0();
305 }
306
307 #[test]
308 fn test_full() {
309 let num_steps = 10;
310 let initial_state = vec![Fr::from(19), Fr::from(0)];
311
312 let r1cs_path = PathBuf::from("./circom/artifacts/grapevine.r1cs");
313 let wasm_path = PathBuf::from("./circom/artifacts/grapevine.wasm");
314
315 let f_circuit = GrapevineFCircuit::<Fr>::new((r1cs_path, wasm_path));
316
317 let start = Instant::now();
318 println!("Generating params...");
319 let (prover_params, verifier_params) =
320 test_nova_setup::<GrapevineFCircuit<Fr>>(f_circuit.clone());
321 println!("Generated params: {:?}", start.elapsed());
322 type NOVA = Nova<
323 Projective,
324 GVar,
325 Projective2,
326 GVar2,
327 GrapevineFCircuit<Fr>,
328 Pedersen<Projective>,
329 Pedersen<Projective2>,
330 >;
331
332 let start = Instant::now();
333 println!("Initializing folding scheme...");
334 let mut folding_scheme =
335 NOVA::init(&prover_params, f_circuit, initial_state.clone()).unwrap();
336 println!("Initialized folding scheme: {:?}", start.elapsed());
337
338 for i in 0..num_steps {
339 let start = Instant::now();
340 folding_scheme.prove_step().unwrap();
341 println!("Proved step {}: {:?}", i, start.elapsed());
342 }
343
344 let (running_instance, incoming_instance, cyclefold_instance) = folding_scheme.instances();
345
346 println!("Running IVC Verifier...");
347 let start = Instant::now();
348 NOVA::verify(
349 verifier_params,
350 initial_state.clone(),
351 folding_scheme.state(),
352 Fr::from(num_steps as u32),
353 running_instance,
354 incoming_instance,
355 cyclefold_instance,
356 )
357 .unwrap();
358 println!("Verified: {:?}", start.elapsed());
359 }
360 */
361}