sonobe-docs/src/usage/frontend-circom.md
src/usage/frontend-circom.mdRaw
1# Circom frontend
2 > **Note**: Circom frontend will be significantly slower than the Arkworks frontend.
3
4Experimental frontend using [arkworks/circom-compat](https://github.com/arkworks-rs/circom-compat).
5
6We can define the circuit to be folded in Circom. The only interface that we need to fit in is:
7
8```c
9template FCircuit() {
10 signal input ivc_input[1]; // IVC state
11 signal input external_inputs[2]; // not state
12
13 signal output ivc_output[1]; // next IVC state
14
15 // [...]
16}
17component main {public [ivc_input]} = Example();
18```
19
20The `ivc_input` is the array that defines the initial state, and the `ivc_output` is the array that defines the output state after the step.
21
22So for example, the following circuit does the traditional example at each step, which proves knowledge of $x$ such that $y==x^3 + x + e_0 + e_1$ for a known $y$ ($e_i$ are the `external_inputs[i]`):
23
24```c
25pragma circom 2.0.3;
26
27template Example () {
28 signal input ivc_input[1]; // IVC state
29 signal input external_inputs[2]; // not state
30
31 signal output ivc_output[1]; // next IVC state
32
33 signal temp1;
34 signal temp2;
35
36 temp1 <== ivc_input[0] * ivc_input[0];
37 temp2 <== ivc_input[0] * external_inputs[0];
38 ivc_output[0] <== temp1 * ivc_input[0] + temp2 + external_inputs[1];
39}
40
41component main {public [ivc_input]} = CubicCircuit();
42```
43
44Once your `circom` circuit is ready, you can instantiate it with Sonobe. To do this, you will need the `struct CircomFCircuit`.
45
46```rust
47// we load our circom compiled R1CS, along with the witness wasm calculator
48let r1cs_path = PathBuf::from("./src/frontend/circom/test_folder/cubic_circuit.r1cs");
49 let wasm_path =
50 PathBuf::from("./src/frontend/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm");
51let mut circom_fcircuit = CircomFCircuit::<Fr>::new((r1cs_path, wasm_path, 1, 2)).unwrap(); // state_len:1, external_inputs_len:2
52
53// to speed things up, you can define a custom step function to avoid defaulting to the snarkjs witness calculator
54circom_fcircuit.set_custom_step_native(Rc::new(|_i, z_i, _external| {
55 let z = z_i[0];
56 Ok(vec![z * z * z + z + Fr::from(5)])
57 }));
58
59// we initialize the required folding schemes parameters, the folding scheme and the final decider that we want to use
60let (fs_prover_params, kzg_vk, g16_pk, g16_vk) =
61 init_ivc_and_decider_params::<CircomFCircuit<Fr>>(f_circuit.clone());
62
63pub type NOVA = Nova<G1, GVar, G2, GVar2, CircomFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>>;
64pub type DECIDERETH_FCircuit = DeciderEth<
65 G1,
66 GVar,
67 G2,
68 GVar2,
69 CircomFCircuit<Fr>,
70 KZG<'static, Bn254>,
71 Pedersen<G2>,
72 Groth16<Bn254>,
73 NOVA,
74>;
75
76// initialize the folding scheme engine, in our case we use Nova
77let mut nova = NOVA::init(&fs_prover_params, f_circuit.clone(), z_0).unwrap();
78
79// run n steps of the folding iteration
80for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
81 let start = Instant::now();
82 nova.prove_step(external_inputs_at_step.clone()).unwrap();
83 println!("Nova::prove_step {}: {:?}", i, start.elapsed());
84}
85
86```
87You can find an example for using Nova over a circom circuit [here](https://github.com/privacy-scaling-explorations/sonobe/blob/main/examples/circom_full_flow.rs).