sonobe/folding-schemes/src/folding/nova/decider_eth.rs
folding-schemes/src/folding/nova/decider_eth.rsRaw
1/// This file implements the onchain (Ethereum's EVM) decider.
2use ark_crypto_primitives::sponge::Absorb;
3use ark_ec::{CurveGroup, Group};
4use ark_ff::PrimeField;
5use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar};
6use ark_snark::SNARK;
7use ark_std::rand::CryptoRng;
8use ark_std::rand::RngCore;
9use core::marker::PhantomData;
10
11pub use super::decider_eth_circuit::DeciderEthCircuit;
12use crate::commitment::{pedersen::Params as PedersenParams, CommitmentProver};
13use crate::folding::circuits::nonnative::point_to_nonnative_limbs_custom_opt;
14use crate::folding::nova::{circuits::CF2, CommittedInstance, Nova};
15use crate::frontend::FCircuit;
16use crate::Error;
17use crate::{Decider as DeciderTrait, FoldingScheme};
18use ark_r1cs_std::fields::nonnative::params::OptimizationType;
19
20/// Onchain Decider, for ethereum use cases
21#[derive(Clone, Debug)]
22pub struct Decider<C1, GC1, C2, GC2, FC, CP1, CP2, S, FS> {
23 _c1: PhantomData<C1>,
24 _gc1: PhantomData<GC1>,
25 _c2: PhantomData<C2>,
26 _gc2: PhantomData<GC2>,
27 _fc: PhantomData<FC>,
28 _cp1: PhantomData<CP1>,
29 _cp2: PhantomData<CP2>,
30 _s: PhantomData<S>,
31 _fs: PhantomData<FS>,
32}
33
34impl<C1, GC1, C2, GC2, FC, CP1, CP2, S, FS> DeciderTrait<C1, C2, FC, FS>
35 for Decider<C1, GC1, C2, GC2, FC, CP1, CP2, S, FS>
36where
37 C1: CurveGroup,
38 C2: CurveGroup,
39 GC1: CurveVar<C1, CF2<C1>>,
40 GC2: CurveVar<C2, CF2<C2>>,
41 FC: FCircuit<C1::ScalarField>,
42 CP1: CommitmentProver<C1>,
43 // enforce that the CP2 is Pedersen commitment, since we're at Ethereum's EVM decider
44 CP2: CommitmentProver<C2, Params = PedersenParams<C2>>,
45 S: SNARK<C1::ScalarField>,
46 FS: FoldingScheme<C1, C2, FC>,
47 <C1 as CurveGroup>::BaseField: PrimeField,
48 <C2 as CurveGroup>::BaseField: PrimeField,
49 <C1 as Group>::ScalarField: Absorb,
50 <C2 as Group>::ScalarField: Absorb,
51 C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
52 for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>,
53 // constrain FS into Nova, since this is a Decider specifically for Nova
54 Nova<C1, GC1, C2, GC2, FC, CP1, CP2>: From<FS>,
55{
56 type ProverParam = S::ProvingKey;
57 type Proof = S::Proof;
58 type VerifierParam = S::VerifyingKey;
59 type PublicInput = Vec<C1::ScalarField>;
60 type CommittedInstanceWithWitness = ();
61 type CommittedInstance = CommittedInstance<C1>;
62
63 fn prove(
64 pp: &Self::ProverParam,
65 mut rng: impl RngCore + CryptoRng,
66 folding_scheme: FS,
67 ) -> Result<Self::Proof, Error> {
68 let circuit =
69 DeciderEthCircuit::<C1, GC1, C2, GC2, CP1, CP2>::from_nova::<FC>(folding_scheme.into());
70
71 let proof = S::prove(pp, circuit.clone(), &mut rng).unwrap();
72
73 Ok(proof)
74 }
75
76 fn verify(
77 vp: &Self::VerifierParam,
78 i: C1::ScalarField,
79 z_0: Vec<C1::ScalarField>,
80 z_i: Vec<C1::ScalarField>,
81 running_instance: &Self::CommittedInstance,
82 proof: Self::Proof,
83 ) -> Result<bool, Error> {
84 let (cmE_x, cmE_y) = point_to_nonnative_limbs_custom_opt::<C1>(
85 running_instance.cmE,
86 OptimizationType::Constraints,
87 )?;
88 let (cmW_x, cmW_y) = point_to_nonnative_limbs_custom_opt::<C1>(
89 running_instance.cmW,
90 OptimizationType::Constraints,
91 )?;
92 let public_input: Vec<C1::ScalarField> = vec![
93 vec![i],
94 z_0,
95 z_i,
96 vec![running_instance.u],
97 running_instance.x.clone(),
98 cmE_x,
99 cmE_y,
100 cmW_x,
101 cmW_y,
102 ]
103 .concat();
104 S::verify(vp, &public_input, &proof).map_err(|e| Error::Other(e.to_string()))
105 }
106}
107
108#[cfg(test)]
109pub mod tests {
110 use super::*;
111 use ark_groth16::Groth16;
112 use ark_mnt4_298::{constraints::G1Var as GVar, Fr, G1Projective as Projective, MNT4_298};
113 use ark_mnt6_298::{constraints::G1Var as GVar2, G1Projective as Projective2};
114 use std::time::Instant;
115
116 use crate::commitment::pedersen::Pedersen;
117 use crate::folding::nova::{get_pedersen_params_len, ProverParams};
118 use crate::frontend::tests::CubicFCircuit;
119 use crate::transcript::poseidon::poseidon_test_config;
120
121 // Note: since we're testing a big circuit, this test takes a bit more of computation and time,
122 // do not run in the normal CI.
123 // To run the test use `--ignored` flag, eg. `cargo test -- --ignored`
124 #[test]
125 #[ignore]
126 fn test_decider() {
127 type NOVA = Nova<
128 Projective,
129 GVar,
130 Projective2,
131 GVar2,
132 CubicFCircuit<Fr>,
133 Pedersen<Projective>,
134 Pedersen<Projective2>,
135 >;
136 type DECIDER = Decider<
137 Projective,
138 GVar,
139 Projective2,
140 GVar2,
141 CubicFCircuit<Fr>,
142 Pedersen<Projective>,
143 Pedersen<Projective2>,
144 Groth16<MNT4_298>, // here we define the Snark to use in the decider
145 NOVA, // here we define the FoldingScheme to use
146 >;
147
148 let mut rng = ark_std::test_rng();
149 let poseidon_config = poseidon_test_config::<Fr>();
150
151 let F_circuit = CubicFCircuit::<Fr>::new(());
152 let z_0 = vec![Fr::from(3_u32)];
153
154 let (cm_len, cf_cm_len) =
155 get_pedersen_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
156 &poseidon_config,
157 F_circuit,
158 )
159 .unwrap();
160 let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, cm_len);
161 let cf_pedersen_params = Pedersen::<Projective2>::new_params(&mut rng, cf_cm_len);
162
163 let start = Instant::now();
164 let prover_params =
165 ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> {
166 poseidon_config: poseidon_config.clone(),
167 cm_params: pedersen_params,
168 cf_cm_params: cf_pedersen_params,
169 };
170 println!("generating pedersen params, {:?}", start.elapsed());
171
172 // use Nova as FoldingScheme
173 let start = Instant::now();
174 let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
175 println!("Nova initialized, {:?}", start.elapsed());
176 let start = Instant::now();
177 nova.prove_step().unwrap();
178 println!("prove_step, {:?}", start.elapsed());
179
180 // generate Groth16 setup
181 let circuit = DeciderEthCircuit::<
182 Projective,
183 GVar,
184 Projective2,
185 GVar2,
186 Pedersen<Projective>,
187 Pedersen<Projective2>,
188 >::from_nova::<CubicFCircuit<Fr>>(nova.clone());
189 let mut rng = rand::rngs::OsRng;
190
191 let start = Instant::now();
192 let (pk, vk) =
193 Groth16::<MNT4_298>::circuit_specific_setup(circuit.clone(), &mut rng).unwrap();
194 println!("Groth16 setup, {:?}", start.elapsed());
195
196 // decider proof generation
197 let start = Instant::now();
198 let proof = DECIDER::prove(&pk, rng, nova.clone()).unwrap();
199 println!("Decider Groth16 prove, {:?}", start.elapsed());
200
201 // decider proof verification
202 let verified = DECIDER::verify(&vk, nova.i, nova.z_0, nova.z_i, &nova.U_i, proof).unwrap();
203 assert!(verified);
204 }
205}