You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
4.7 KiB

  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. use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1};
  13. use ark_groth16::Groth16;
  14. use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
  15. use folding_schemes::{
  16. commitment::{kzg::KZG, pedersen::Pedersen},
  17. folding::nova::{
  18. decider_eth::{prepare_calldata, Decider as DeciderEth},
  19. Nova, PreprocessorParam,
  20. },
  21. frontend::{
  22. noir::{load_noir_circuit, NoirFCircuit},
  23. FCircuit,
  24. },
  25. transcript::poseidon::poseidon_canonical_config,
  26. Decider, FoldingScheme,
  27. };
  28. use std::{env, time::Instant};
  29. use solidity_verifiers::{
  30. evm::{compile_solidity, Evm},
  31. utils::get_function_selector_for_nova_cyclefold_verifier,
  32. verifiers::nova_cyclefold::get_decider_template_for_cyclefold_decider,
  33. NovaCycleFoldVerifierKey,
  34. };
  35. fn main() {
  36. // set the initial state
  37. let z_0 = vec![Fr::from(1)];
  38. // initialize the noir fcircuit
  39. let cur_path = env::current_dir().unwrap();
  40. let circuit_path = format!(
  41. "{}/folding-schemes/src/frontend/noir/test_folder/test_mimc/target/test_mimc.json",
  42. cur_path.to_str().unwrap()
  43. );
  44. let circuit = load_noir_circuit(circuit_path);
  45. let f_circuit = NoirFCircuit {
  46. circuit,
  47. state_len: 1,
  48. external_inputs_len: 0,
  49. };
  50. pub type N = Nova<G1, GVar, G2, GVar2, NoirFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>>;
  51. pub type D = DeciderEth<
  52. G1,
  53. GVar,
  54. G2,
  55. GVar2,
  56. NoirFCircuit<Fr>,
  57. KZG<'static, Bn254>,
  58. Pedersen<G2>,
  59. Groth16<Bn254>,
  60. N,
  61. >;
  62. let poseidon_config = poseidon_canonical_config::<Fr>();
  63. let mut rng = rand::rngs::OsRng;
  64. // prepare the Nova prover & verifier params
  65. let nova_preprocess_params = PreprocessorParam::new(poseidon_config, f_circuit.clone());
  66. let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
  67. // initialize the folding scheme engine, in our case we use Nova
  68. let mut nova = N::init(&nova_params, f_circuit.clone(), z_0).unwrap();
  69. // prepare the Decider prover & verifier params
  70. let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone()).unwrap();
  71. // run n steps of the folding iteration
  72. for i in 0..5 {
  73. let start = Instant::now();
  74. nova.prove_step(rng, vec![], None).unwrap();
  75. println!("Nova::prove_step {}: {:?}", i, start.elapsed());
  76. }
  77. let start = Instant::now();
  78. let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
  79. println!("generated Decider proof: {:?}", start.elapsed());
  80. let verified = D::verify(
  81. decider_vp.clone(),
  82. nova.i,
  83. nova.z_0.clone(),
  84. nova.z_i.clone(),
  85. &nova.U_i,
  86. &nova.u_i,
  87. &proof,
  88. )
  89. .unwrap();
  90. assert!(verified);
  91. println!("Decider proof verification: {}", verified);
  92. // Now, let's generate the Solidity code that verifies this Decider final proof
  93. let function_selector =
  94. get_function_selector_for_nova_cyclefold_verifier(nova.z_0.len() * 2 + 1);
  95. let calldata: Vec<u8> = prepare_calldata(
  96. function_selector,
  97. nova.i,
  98. nova.z_0,
  99. nova.z_i,
  100. &nova.U_i,
  101. &nova.u_i,
  102. proof,
  103. )
  104. .unwrap();
  105. // prepare the setup params for the solidity verifier
  106. let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((decider_vp, f_circuit.state_len()));
  107. // generate the solidity code
  108. let decider_solidity_code = get_decider_template_for_cyclefold_decider(nova_cyclefold_vk);
  109. // verify the proof against the solidity code in the EVM
  110. let nova_cyclefold_verifier_bytecode = compile_solidity(&decider_solidity_code, "NovaDecider");
  111. let mut evm = Evm::default();
  112. let verifier_address = evm.create(nova_cyclefold_verifier_bytecode);
  113. let (_, output) = evm.call(verifier_address, calldata.clone());
  114. assert_eq!(*output.last().unwrap(), 1);
  115. // save smart contract and the calldata
  116. println!("storing nova-verifier.sol and the calldata into files");
  117. use std::fs;
  118. fs::write(
  119. "./examples/nova-verifier.sol",
  120. decider_solidity_code.clone(),
  121. )
  122. .unwrap();
  123. fs::write("./examples/solidity-calldata.calldata", calldata.clone()).unwrap();
  124. let s = solidity_verifiers::utils::get_formatted_calldata(calldata.clone());
  125. fs::write("./examples/solidity-calldata.inputs", s.join(",\n")).expect("");
  126. }