arnaucube
arnaucube/grapevine-sonobePublic Self-hosted repository
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}