arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/examples/full_flow.rs
examples/full_flow.rsRaw
  1#![allow(non_snake_case)]
  2#![allow(non_camel_case_types)]
  3#![allow(clippy::upper_case_acronyms)]
  4///
  5/// This example performs the full flow:
  6/// - define the circuit to be folded
  7/// - fold the circuit with Nova+CycleFold's IVC
  8/// - generate a DeciderEthCircuit final proof
  9/// - generate the Solidity contract that verifies the proof
 10/// - verify the proof in the EVM
 11///
 12use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1};
 13use ark_crypto_primitives::snark::SNARK;
 14use ark_ff::PrimeField;
 15use ark_groth16::VerifyingKey as G16VerifierKey;
 16use ark_groth16::{Groth16, ProvingKey};
 17use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
 18use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
 19use ark_r1cs_std::alloc::AllocVar;
 20use ark_r1cs_std::fields::fp::FpVar;
 21use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
 22use ark_std::Zero;
 23use std::marker::PhantomData;
 24use std::time::Instant;
 25
 26use folding_schemes::{
 27    commitment::{
 28        kzg::{ProverKey as KZGProverKey, KZG},
 29        pedersen::Pedersen,
 30        CommitmentScheme,
 31    },
 32    folding::nova::{
 33        decider_eth::{prepare_calldata, Decider as DeciderEth},
 34        decider_eth_circuit::DeciderEthCircuit,
 35        get_cs_params_len, Nova, ProverParams,
 36    },
 37    frontend::FCircuit,
 38    transcript::poseidon::poseidon_test_config,
 39    Decider, Error, FoldingScheme,
 40};
 41use solidity_verifiers::{
 42    evm::{compile_solidity, Evm},
 43    utils::get_function_selector_for_nova_cyclefold_verifier,
 44    verifiers::nova_cyclefold::get_decider_template_for_cyclefold_decider,
 45    NovaCycleFoldVerifierKey,
 46};
 47
 48/// Test circuit to be folded
 49#[derive(Clone, Copy, Debug)]
 50pub struct CubicFCircuit<F: PrimeField> {
 51    _f: PhantomData<F>,
 52}
 53impl<F: PrimeField> FCircuit<F> for CubicFCircuit<F> {
 54    type Params = ();
 55    fn new(_params: Self::Params) -> Self {
 56        Self { _f: PhantomData }
 57    }
 58    fn state_len(&self) -> usize {
 59        1
 60    }
 61    fn step_native(&self, _i: usize, z_i: Vec<F>) -> Result<Vec<F>, Error> {
 62        Ok(vec![z_i[0] * z_i[0] * z_i[0] + z_i[0] + F::from(5_u32)])
 63    }
 64    fn generate_step_constraints(
 65        &self,
 66        cs: ConstraintSystemRef<F>,
 67        _i: usize,
 68        z_i: Vec<FpVar<F>>,
 69    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 70        let five = FpVar::<F>::new_constant(cs.clone(), F::from(5u32))?;
 71        let z_i = z_i[0].clone();
 72
 73        Ok(vec![&z_i * &z_i * &z_i + &z_i + &five])
 74    }
 75}
 76
 77#[allow(clippy::type_complexity)]
 78fn init_test_prover_params<FC: FCircuit<Fr, Params = ()>>() -> (
 79    ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
 80    KZGVerifierKey<Bn254>,
 81) {
 82    let mut rng = ark_std::test_rng();
 83    let poseidon_config = poseidon_test_config::<Fr>();
 84    let f_circuit = FC::new(());
 85    let (cs_len, cf_cs_len) =
 86        get_cs_params_len::<G1, GVar, G2, GVar2, FC>(&poseidon_config, f_circuit).unwrap();
 87    let (kzg_pk, kzg_vk): (KZGProverKey<G1>, KZGVerifierKey<Bn254>) =
 88        KZG::<Bn254>::setup(&mut rng, cs_len).unwrap();
 89    let (cf_pedersen_params, _) = Pedersen::<G2>::setup(&mut rng, cf_cs_len).unwrap();
 90    let fs_prover_params = ProverParams::<G1, G2, KZG<Bn254>, Pedersen<G2>> {
 91        poseidon_config: poseidon_config.clone(),
 92        cs_params: kzg_pk.clone(),
 93        cf_cs_params: cf_pedersen_params,
 94    };
 95    (fs_prover_params, kzg_vk)
 96}
 97/// Initializes Nova parameters and DeciderEth parameters. Only for test purposes.
 98#[allow(clippy::type_complexity)]
 99fn init_params<FC: FCircuit<Fr, Params = ()>>() -> (
100    ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
101    KZGVerifierKey<Bn254>,
102    ProvingKey<Bn254>,
103    G16VerifierKey<Bn254>,
104) {
105    let mut rng = rand::rngs::OsRng;
106    let start = Instant::now();
107    let (fs_prover_params, kzg_vk) = init_test_prover_params::<FC>();
108    println!("generated Nova folding params: {:?}", start.elapsed());
109    let f_circuit = FC::new(());
110
111    pub type NOVA<FC> = Nova<G1, GVar, G2, GVar2, FC, KZG<'static, Bn254>, Pedersen<G2>>;
112    let z_0 = vec![Fr::zero(); f_circuit.state_len()];
113    let nova = NOVA::init(&fs_prover_params, f_circuit, z_0.clone()).unwrap();
114
115    let decider_circuit =
116        DeciderEthCircuit::<G1, GVar, G2, GVar2, KZG<Bn254>, Pedersen<G2>>::from_nova::<FC>(
117            nova.clone(),
118        )
119        .unwrap();
120    let start = Instant::now();
121    let (g16_pk, g16_vk) =
122        Groth16::<Bn254>::circuit_specific_setup(decider_circuit.clone(), &mut rng).unwrap();
123    println!(
124        "generated G16 (Decider circuit) params: {:?}",
125        start.elapsed()
126    );
127    (fs_prover_params, kzg_vk, g16_pk, g16_vk)
128}
129
130fn main() {
131    let n_steps = 10;
132    // set the initial state
133    let z_0 = vec![Fr::from(3_u32)];
134
135    let (fs_prover_params, kzg_vk, g16_pk, g16_vk) = init_params::<CubicFCircuit<Fr>>();
136
137    pub type NOVA = Nova<G1, GVar, G2, GVar2, CubicFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>>;
138    pub type DECIDERETH_FCircuit = DeciderEth<
139        G1,
140        GVar,
141        G2,
142        GVar2,
143        CubicFCircuit<Fr>,
144        KZG<'static, Bn254>,
145        Pedersen<G2>,
146        Groth16<Bn254>,
147        NOVA,
148    >;
149    let f_circuit = CubicFCircuit::<Fr>::new(());
150
151    // initialize the folding scheme engine, in our case we use Nova
152    let mut nova = NOVA::init(&fs_prover_params, f_circuit, z_0).unwrap();
153    // run n steps of the folding iteration
154    for i in 0..n_steps {
155        let start = Instant::now();
156        nova.prove_step().unwrap();
157        println!("Nova::prove_step {}: {:?}", i, start.elapsed());
158    }
159
160    let rng = rand::rngs::OsRng;
161    let start = Instant::now();
162    let proof = DECIDERETH_FCircuit::prove(
163        (g16_pk, fs_prover_params.cs_params.clone()),
164        rng,
165        nova.clone(),
166    )
167    .unwrap();
168    println!("generated Decider proof: {:?}", start.elapsed());
169
170    let verified = DECIDERETH_FCircuit::verify(
171        (g16_vk.clone(), kzg_vk.clone()),
172        nova.i,
173        nova.z_0.clone(),
174        nova.z_i.clone(),
175        &nova.U_i,
176        &nova.u_i,
177        &proof,
178    )
179    .unwrap();
180    assert!(verified);
181    println!("Decider proof verification: {}", verified);
182
183    // Now, let's generate the Solidity code that verifies this Decider final proof
184    let function_selector =
185        get_function_selector_for_nova_cyclefold_verifier(nova.z_0.len() * 2 + 1);
186
187    let calldata: Vec<u8> = prepare_calldata(
188        function_selector,
189        nova.i,
190        nova.z_0,
191        nova.z_i,
192        &nova.U_i,
193        &nova.u_i,
194        proof,
195    )
196    .unwrap();
197
198    // prepare the setup params for the solidity verifier
199    let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((g16_vk, kzg_vk, f_circuit.state_len()));
200
201    // generate the solidity code
202    let decider_solidity_code = get_decider_template_for_cyclefold_decider(nova_cyclefold_vk);
203
204    // verify the proof against the solidity code in the EVM
205    let nova_cyclefold_verifier_bytecode = compile_solidity(&decider_solidity_code, "NovaDecider");
206    let mut evm = Evm::default();
207    let verifier_address = evm.create(nova_cyclefold_verifier_bytecode);
208    let (_, output) = evm.call(verifier_address, calldata.clone());
209    assert_eq!(*output.last().unwrap(), 1);
210
211    // save smart contract and the calldata
212    println!("storing nova-verifier.sol and the calldata into files");
213    use std::fs;
214    fs::write(
215        "./examples/nova-verifier.sol",
216        decider_solidity_code.clone(),
217    )
218    .unwrap();
219    fs::write("./examples/solidity-calldata.calldata", calldata.clone()).unwrap();
220    let s = solidity_verifiers::utils::get_formatted_calldata(calldata.clone());
221    fs::write("./examples/solidity-calldata.inputs", s.join(",\n")).expect("");
222}