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.

177 lines
5.6 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_ff::PrimeField;
  14. use ark_groth16::Groth16;
  15. use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
  16. use ark_r1cs_std::alloc::AllocVar;
  17. use ark_r1cs_std::fields::fp::FpVar;
  18. use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
  19. use std::marker::PhantomData;
  20. use std::time::Instant;
  21. use folding_schemes::{
  22. commitment::{kzg::KZG, pedersen::Pedersen},
  23. folding::{
  24. nova::{
  25. decider_eth::{prepare_calldata, Decider as DeciderEth},
  26. Nova, PreprocessorParam,
  27. },
  28. traits::CommittedInstanceOps,
  29. },
  30. frontend::FCircuit,
  31. transcript::poseidon::poseidon_canonical_config,
  32. Decider, Error, FoldingScheme,
  33. };
  34. use solidity_verifiers::{
  35. evm::{compile_solidity, Evm},
  36. utils::get_function_selector_for_nova_cyclefold_verifier,
  37. verifiers::nova_cyclefold::get_decider_template_for_cyclefold_decider,
  38. NovaCycleFoldVerifierKey,
  39. };
  40. /// Test circuit to be folded
  41. #[derive(Clone, Copy, Debug)]
  42. pub struct CubicFCircuit<F: PrimeField> {
  43. _f: PhantomData<F>,
  44. }
  45. impl<F: PrimeField> FCircuit<F> for CubicFCircuit<F> {
  46. type Params = ();
  47. fn new(_params: Self::Params) -> Result<Self, Error> {
  48. Ok(Self { _f: PhantomData })
  49. }
  50. fn state_len(&self) -> usize {
  51. 1
  52. }
  53. fn external_inputs_len(&self) -> usize {
  54. 0
  55. }
  56. fn step_native(
  57. &self,
  58. _i: usize,
  59. z_i: Vec<F>,
  60. _external_inputs: Vec<F>,
  61. ) -> 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. _external_inputs: Vec<FpVar<F>>,
  70. ) -> Result<Vec<FpVar<F>>, SynthesisError> {
  71. let five = FpVar::<F>::new_constant(cs.clone(), F::from(5u32))?;
  72. let z_i = z_i[0].clone();
  73. Ok(vec![&z_i * &z_i * &z_i + &z_i + &five])
  74. }
  75. }
  76. fn main() {
  77. let n_steps = 5;
  78. // set the initial state
  79. let z_0 = vec![Fr::from(3_u32)];
  80. let f_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
  81. pub type N =
  82. Nova<G1, GVar, G2, GVar2, CubicFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>, false>;
  83. pub type D = DeciderEth<
  84. G1,
  85. GVar,
  86. G2,
  87. GVar2,
  88. CubicFCircuit<Fr>,
  89. KZG<'static, Bn254>,
  90. Pedersen<G2>,
  91. Groth16<Bn254>,
  92. N,
  93. >;
  94. let poseidon_config = poseidon_canonical_config::<Fr>();
  95. let mut rng = rand::rngs::OsRng;
  96. // prepare the Nova prover & verifier params
  97. let nova_preprocess_params = PreprocessorParam::new(poseidon_config.clone(), f_circuit);
  98. let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
  99. // initialize the folding scheme engine, in our case we use Nova
  100. let mut nova = N::init(&nova_params, f_circuit, z_0).unwrap();
  101. // prepare the Decider prover & verifier params
  102. let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone()).unwrap();
  103. // run n steps of the folding iteration
  104. for i in 0..n_steps {
  105. let start = Instant::now();
  106. nova.prove_step(rng, vec![], None).unwrap();
  107. println!("Nova::prove_step {}: {:?}", i, start.elapsed());
  108. }
  109. let start = Instant::now();
  110. let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
  111. println!("generated Decider proof: {:?}", start.elapsed());
  112. let verified = D::verify(
  113. decider_vp.clone(),
  114. nova.i,
  115. nova.z_0.clone(),
  116. nova.z_i.clone(),
  117. &nova.U_i.get_commitments(),
  118. &nova.u_i.get_commitments(),
  119. &proof,
  120. )
  121. .unwrap();
  122. assert!(verified);
  123. println!("Decider proof verification: {}", verified);
  124. // Now, let's generate the Solidity code that verifies this Decider final proof
  125. let function_selector =
  126. get_function_selector_for_nova_cyclefold_verifier(nova.z_0.len() * 2 + 1);
  127. let calldata: Vec<u8> = prepare_calldata(
  128. function_selector,
  129. nova.i,
  130. nova.z_0,
  131. nova.z_i,
  132. &nova.U_i,
  133. &nova.u_i,
  134. proof,
  135. )
  136. .unwrap();
  137. // prepare the setup params for the solidity verifier
  138. let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((decider_vp, f_circuit.state_len()));
  139. // generate the solidity code
  140. let decider_solidity_code = get_decider_template_for_cyclefold_decider(nova_cyclefold_vk);
  141. // verify the proof against the solidity code in the EVM
  142. let nova_cyclefold_verifier_bytecode = compile_solidity(&decider_solidity_code, "NovaDecider");
  143. let mut evm = Evm::default();
  144. let verifier_address = evm.create(nova_cyclefold_verifier_bytecode);
  145. let (_, output) = evm.call(verifier_address, calldata.clone());
  146. assert_eq!(*output.last().unwrap(), 1);
  147. // save smart contract and the calldata
  148. println!("storing nova-verifier.sol and the calldata into files");
  149. use std::fs;
  150. fs::write(
  151. "./examples/nova-verifier.sol",
  152. decider_solidity_code.clone(),
  153. )
  154. .unwrap();
  155. fs::write("./examples/solidity-calldata.calldata", calldata.clone()).unwrap();
  156. let s = solidity_verifiers::utils::get_formatted_calldata(calldata.clone());
  157. fs::write("./examples/solidity-calldata.inputs", s.join(",\n")).expect("");
  158. }