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 S::prove(pp, circuit.clone(), &mut rng).map_err(|e| Error::Other(e.to_string()))
72 }
73
74 fn verify(
75 vp: &Self::VerifierParam,
76 i: C1::ScalarField,
77 z_0: Vec<C1::ScalarField>,
78 z_i: Vec<C1::ScalarField>,
79 running_instance: &Self::CommittedInstance,
80 proof: Self::Proof,
81 ) -> Result<bool, Error> {
82 let (cmE_x, cmE_y) = point_to_nonnative_limbs_custom_opt::<C1>(
83 running_instance.cmE,
84 OptimizationType::Constraints,
85 )?;
86 let (cmW_x, cmW_y) = point_to_nonnative_limbs_custom_opt::<C1>(
87 running_instance.cmW,
88 OptimizationType::Constraints,
89 )?;
90 let public_input: Vec<C1::ScalarField> = vec![
91 vec![i],
92 z_0,
93 z_i,
94 vec![running_instance.u],
95 running_instance.x.clone(),
96 cmE_x,
97 cmE_y,
98 cmW_x,
99 cmW_y,
100 ]
101 .concat();
102 S::verify(vp, &public_input, &proof).map_err(|e| Error::Other(e.to_string()))
103 }
104}
105
106#[cfg(test)]
107pub mod tests {
108 use super::*;
109 use ark_groth16::Groth16;
110 use ark_mnt4_298::{constraints::G1Var as GVar, Fr, G1Projective as Projective, MNT4_298};
111 use ark_mnt6_298::{constraints::G1Var as GVar2, G1Projective as Projective2};
112 use std::time::Instant;
113
114 use crate::commitment::pedersen::Pedersen;
115 use crate::folding::nova::{get_pedersen_params_len, ProverParams};
116 use crate::frontend::tests::CubicFCircuit;
117 use crate::transcript::poseidon::poseidon_test_config;
118
119 // Note: since we're testing a big circuit, this test takes a bit more of computation and time,
120 // do not run in the normal CI.
121 // To run the test use `--ignored` flag, eg. `cargo test -- --ignored`
122 #[test]
123 #[ignore]
124 fn test_decider() {
125 type NOVA = Nova<
126 Projective,
127 GVar,
128 Projective2,
129 GVar2,
130 CubicFCircuit<Fr>,
131 Pedersen<Projective>,
132 Pedersen<Projective2>,
133 >;
134 type DECIDER = Decider<
135 Projective,
136 GVar,
137 Projective2,
138 GVar2,
139 CubicFCircuit<Fr>,
140 Pedersen<Projective>,
141 Pedersen<Projective2>,
142 Groth16<MNT4_298>, // here we define the Snark to use in the decider
143 NOVA, // here we define the FoldingScheme to use
144 >;
145
146 let mut rng = ark_std::test_rng();
147 let poseidon_config = poseidon_test_config::<Fr>();
148
149 let F_circuit = CubicFCircuit::<Fr>::new(());
150 let z_0 = vec![Fr::from(3_u32)];
151
152 let (cm_len, cf_cm_len) =
153 get_pedersen_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
154 &poseidon_config,
155 F_circuit,
156 )
157 .unwrap();
158 let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, cm_len);
159 let cf_pedersen_params = Pedersen::<Projective2>::new_params(&mut rng, cf_cm_len);
160
161 let start = Instant::now();
162 let prover_params =
163 ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> {
164 poseidon_config: poseidon_config.clone(),
165 cm_params: pedersen_params,
166 cf_cm_params: cf_pedersen_params,
167 };
168 println!("generating pedersen params, {:?}", start.elapsed());
169
170 // use Nova as FoldingScheme
171 let start = Instant::now();
172 let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
173 println!("Nova initialized, {:?}", start.elapsed());
174 let start = Instant::now();
175 nova.prove_step().unwrap();
176 println!("prove_step, {:?}", start.elapsed());
177
178 // generate Groth16 setup
179 let circuit = DeciderEthCircuit::<
180 Projective,
181 GVar,
182 Projective2,
183 GVar2,
184 Pedersen<Projective>,
185 Pedersen<Projective2>,
186 >::from_nova::<CubicFCircuit<Fr>>(nova.clone());
187 let mut rng = rand::rngs::OsRng;
188
189 let start = Instant::now();
190 let (pk, vk) =
191 Groth16::<MNT4_298>::circuit_specific_setup(circuit.clone(), &mut rng).unwrap();
192 println!("Groth16 setup, {:?}", start.elapsed());
193
194 // decider proof generation
195 let start = Instant::now();
196 let proof = DECIDER::prove(&pk, rng, nova.clone()).unwrap();
197 println!("Decider Groth16 prove, {:?}", start.elapsed());
198
199 // decider proof verification
200 let verified = DECIDER::verify(&vk, nova.i, nova.z_0, nova.z_i, &nova.U_i, proof).unwrap();
201 assert!(verified);
202 }
203}