arnaucube
arnaucube/hash-chain-sonobePublic Self-hosted repository
hash-chain-sonobe/src/lib.rs
src/lib.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///
 12
 13#[cfg(test)]
 14mod tests {
 15    use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1};
 16    use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
 17
 18    use ark_crypto_primitives::snark::SNARK;
 19    use ark_groth16::{Groth16, ProvingKey, VerifyingKey as G16VerifierKey};
 20    use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
 21
 22    use ark_std::Zero;
 23
 24    use std::path::PathBuf;
 25    use std::time::Instant;
 26
 27    use folding_schemes::{
 28        commitment::{
 29            kzg::{ProverKey as KZGProverKey, KZG},
 30            pedersen::Pedersen,
 31            CommitmentScheme,
 32        },
 33        folding::nova::{
 34            decider_eth::{prepare_calldata, Decider as DeciderEth},
 35            decider_eth_circuit::DeciderEthCircuit,
 36            get_r1cs, Nova, ProverParams, VerifierParams,
 37        },
 38        frontend::{circom::CircomFCircuit, FCircuit},
 39        transcript::poseidon::poseidon_test_config,
 40        Decider, FoldingScheme,
 41    };
 42    use solidity_verifiers::{
 43        evm::{compile_solidity, Evm},
 44        utils::get_function_selector_for_nova_cyclefold_verifier,
 45        verifiers::nova_cyclefold::get_decider_template_for_cyclefold_decider,
 46        NovaCycleFoldVerifierKey,
 47    };
 48
 49    // This method computes the Nova's Prover & Verifier parameters for the example.
 50    // Warning: this method is only for testing purposes. For a real world use case those parameters
 51    // should be generated carefully (both the PoseidonConfig and the PedersenParams).
 52    #[allow(clippy::type_complexity)]
 53    fn init_nova_ivc_params<FC: FCircuit<Fr>>(
 54        F_circuit: FC,
 55    ) -> (
 56        ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
 57        VerifierParams<G1, G2>,
 58        KZGVerifierKey<Bn254>,
 59    ) {
 60        let mut rng = ark_std::test_rng();
 61        let poseidon_config = poseidon_test_config::<Fr>();
 62
 63        // get the CM & CF_CM len
 64        let (r1cs, cf_r1cs) =
 65            get_r1cs::<G1, GVar, G2, GVar2, FC>(&poseidon_config, F_circuit).unwrap();
 66        let cs_len = r1cs.A.n_rows;
 67        let cf_cs_len = cf_r1cs.A.n_rows;
 68
 69        // let (pedersen_params, _) = Pedersen::<G1>::setup(&mut rng, cf_len).unwrap();
 70        let (kzg_pk, kzg_vk): (KZGProverKey<G1>, KZGVerifierKey<Bn254>) =
 71            KZG::<Bn254>::setup(&mut rng, cs_len).unwrap();
 72        let (cf_pedersen_params, _) = Pedersen::<G2>::setup(&mut rng, cf_cs_len).unwrap();
 73
 74        let fs_prover_params = ProverParams::<G1, G2, KZG<Bn254>, Pedersen<G2>> {
 75            poseidon_config: poseidon_config.clone(),
 76            cs_params: kzg_pk.clone(),
 77            cf_cs_params: cf_pedersen_params,
 78        };
 79        let fs_verifier_params = VerifierParams::<G1, G2> {
 80            poseidon_config: poseidon_config.clone(),
 81            r1cs,
 82            cf_r1cs,
 83        };
 84        (fs_prover_params, fs_verifier_params, kzg_vk)
 85    }
 86
 87    /// Initializes Nova parameters and DeciderEth parameters. Only for test purposes.
 88    #[allow(clippy::type_complexity)]
 89    fn init_ivc_and_decider_params<FC: FCircuit<Fr>>(
 90        f_circuit: FC,
 91    ) -> (
 92        ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
 93        KZGVerifierKey<Bn254>,
 94        ProvingKey<Bn254>,
 95        G16VerifierKey<Bn254>,
 96    ) {
 97        let mut rng = rand::rngs::OsRng;
 98        let start = Instant::now();
 99        let (fs_prover_params, _, kzg_vk) = init_nova_ivc_params::<FC>(f_circuit.clone());
100        println!("generated Nova folding params: {:?}", start.elapsed());
101
102        pub type NOVA<FC> = Nova<G1, GVar, G2, GVar2, FC, KZG<'static, Bn254>, Pedersen<G2>>;
103        let z_0 = vec![Fr::zero(); f_circuit.state_len()];
104        let nova = NOVA::init(&fs_prover_params, f_circuit, z_0.clone()).unwrap();
105
106        let decider_circuit =
107            DeciderEthCircuit::<G1, GVar, G2, GVar2, KZG<Bn254>, Pedersen<G2>>::from_nova::<FC>(
108                nova.clone(),
109            )
110            .unwrap();
111        let start = Instant::now();
112        let (g16_pk, g16_vk) =
113            Groth16::<Bn254>::circuit_specific_setup(decider_circuit.clone(), &mut rng).unwrap();
114        println!(
115            "generated G16 (Decider circuit) params: {:?}",
116            start.elapsed()
117        );
118        (fs_prover_params, kzg_vk, g16_pk, g16_vk)
119    }
120
121    #[test]
122    fn full_flow() {
123        // set the initial state
124        let z_0_aux: Vec<u32> = vec![0_u32; 32 * 8];
125        let z_0: Vec<Fr> = z_0_aux.iter().map(|v| Fr::from(*v)).collect::<Vec<Fr>>();
126
127        // initialize the Circom circuit
128        let r1cs_path = PathBuf::from("./circuit/keccak-chain.r1cs");
129        let wasm_path = PathBuf::from("./circuit/keccak-chain_js/keccak-chain.wasm");
130
131        let f_circuit_params = (r1cs_path, wasm_path, 32 * 8, 0);
132        let f_circuit = CircomFCircuit::<Fr>::new(f_circuit_params).unwrap();
133
134        let (fs_prover_params, kzg_vk, g16_pk, g16_vk) =
135            init_ivc_and_decider_params::<CircomFCircuit<Fr>>(f_circuit.clone());
136
137        pub type NOVA =
138            Nova<G1, GVar, G2, GVar2, CircomFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>>;
139        pub type DECIDERETH_FCircuit = DeciderEth<
140            G1,
141            GVar,
142            G2,
143            GVar2,
144            CircomFCircuit<Fr>,
145            KZG<'static, Bn254>,
146            Pedersen<G2>,
147            Groth16<Bn254>,
148            NOVA,
149        >;
150
151        // initialize the folding scheme engine, in our case we use Nova
152        let mut nova = NOVA::init(&fs_prover_params, f_circuit.clone(), z_0).unwrap();
153        // run n steps of the folding iteration
154        for i in 0..10 {
155            let start = Instant::now();
156            nova.prove_step(vec![]).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 =
200            NovaCycleFoldVerifierKey::from((g16_vk, kzg_vk, f_circuit.state_len()));
201
202        // generate the solidity code
203        let decider_solidity_code = get_decider_template_for_cyclefold_decider(nova_cyclefold_vk);
204
205        // verify the proof against the solidity code in the EVM
206        let nova_cyclefold_verifier_bytecode =
207            compile_solidity(&decider_solidity_code, "NovaDecider");
208        let mut evm = Evm::default();
209        let verifier_address = evm.create(nova_cyclefold_verifier_bytecode);
210        let (_, output) = evm.call(verifier_address, calldata.clone());
211        assert_eq!(*output.last().unwrap(), 1);
212
213        // save smart contract and the calldata
214        println!("storing nova-verifier.sol and the calldata into files");
215        use std::fs;
216        fs::write(
217            "./examples/nova-verifier.sol",
218            decider_solidity_code.clone(),
219        )
220        .unwrap();
221        fs::write("./examples/solidity-calldata.calldata", calldata.clone()).unwrap();
222        let s = solidity_verifiers::utils::get_formatted_calldata(calldata.clone());
223        fs::write("./examples/solidity-calldata.inputs", s.join(",\n")).expect("");
224    }
225}