snark_verifier_sdk/
evm.rs

1use crate::{GWC, SHPLONK};
2
3use super::{CircuitExt, PlonkVerifier};
4#[cfg(feature = "display")]
5use ark_std::{end_timer, start_timer};
6use halo2_base::halo2_proofs::{
7    halo2curves::bn256::{Bn256, Fq, Fr, G1Affine},
8    plonk::{create_proof, verify_proof, Circuit, ProvingKey, VerifyingKey},
9    poly::{
10        commitment::{ParamsProver, Prover, Verifier},
11        kzg::{
12            commitment::{KZGCommitmentScheme, ParamsKZG},
13            msm::DualMSM,
14            multiopen::{ProverGWC, ProverSHPLONK, VerifierGWC, VerifierSHPLONK},
15            strategy::{AccumulatorStrategy, GuardKZG},
16        },
17        VerificationStrategy,
18    },
19    transcript::{TranscriptReadBuffer, TranscriptWriterBuffer},
20};
21use itertools::Itertools;
22use rand::{rngs::StdRng, SeedableRng};
23pub use snark_verifier::loader::evm::encode_calldata;
24use snark_verifier::{
25    loader::evm::{compile_solidity, EvmLoader},
26    pcs::{
27        kzg::{KzgAccumulator, KzgAsVerifyingKey, KzgDecidingKey, KzgSuccinctVerifyingKey},
28        AccumulationDecider, AccumulationScheme, PolynomialCommitmentScheme,
29    },
30    system::halo2::{compile, transcript::evm::EvmTranscript, Config},
31    verifier::SnarkVerifier,
32};
33use std::{fs, io, path::Path, rc::Rc};
34
35/// Generates a proof for evm verification using either SHPLONK or GWC proving method. Uses Keccak for Fiat-Shamir.
36pub fn gen_evm_proof<'params, C, P, V>(
37    params: &'params ParamsKZG<Bn256>,
38    pk: &'params ProvingKey<G1Affine>,
39    circuit: C,
40    instances: Vec<Vec<Fr>>,
41) -> Vec<u8>
42where
43    C: Circuit<Fr>,
44    P: Prover<'params, KZGCommitmentScheme<Bn256>>,
45    V: Verifier<
46        'params,
47        KZGCommitmentScheme<Bn256>,
48        Guard = GuardKZG<'params, Bn256>,
49        MSMAccumulator = DualMSM<'params, Bn256>,
50    >,
51{
52    let instances = instances.iter().map(|instances| instances.as_slice()).collect_vec();
53
54    #[cfg(feature = "display")]
55    let proof_time = start_timer!(|| "Create EVM proof");
56    let rng = StdRng::from_entropy();
57    let proof = {
58        let mut transcript = TranscriptWriterBuffer::<_, G1Affine, _>::init(Vec::new());
59        create_proof::<KZGCommitmentScheme<Bn256>, P, _, _, EvmTranscript<_, _, _, _>, _>(
60            params,
61            pk,
62            &[circuit],
63            &[instances.as_slice()],
64            rng,
65            &mut transcript,
66        )
67        .unwrap();
68        transcript.finalize()
69    };
70    #[cfg(feature = "display")]
71    end_timer!(proof_time);
72
73    let accept = {
74        let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.as_slice());
75        VerificationStrategy::<_, V>::finalize(
76            verify_proof::<_, V, _, EvmTranscript<_, _, _, _>, _>(
77                params.verifier_params(),
78                pk.get_vk(),
79                AccumulatorStrategy::new(params.verifier_params()),
80                &[instances.as_slice()],
81                &mut transcript,
82            )
83            .unwrap(),
84        )
85    };
86    assert!(accept);
87
88    proof
89}
90
91pub fn gen_evm_proof_gwc<'params, C: Circuit<Fr>>(
92    params: &'params ParamsKZG<Bn256>,
93    pk: &'params ProvingKey<G1Affine>,
94    circuit: C,
95    instances: Vec<Vec<Fr>>,
96) -> Vec<u8> {
97    gen_evm_proof::<C, ProverGWC<_>, VerifierGWC<_>>(params, pk, circuit, instances)
98}
99
100pub fn gen_evm_proof_shplonk<'params, C: Circuit<Fr>>(
101    params: &'params ParamsKZG<Bn256>,
102    pk: &'params ProvingKey<G1Affine>,
103    circuit: C,
104    instances: Vec<Vec<Fr>>,
105) -> Vec<u8> {
106    gen_evm_proof::<C, ProverSHPLONK<_>, VerifierSHPLONK<_>>(params, pk, circuit, instances)
107}
108
109pub trait EvmKzgAccumulationScheme:
110    PolynomialCommitmentScheme<
111        G1Affine,
112        Rc<EvmLoader>,
113        VerifyingKey = KzgSuccinctVerifyingKey<G1Affine>,
114        Output = KzgAccumulator<G1Affine, Rc<EvmLoader>>,
115    > + AccumulationScheme<
116        G1Affine,
117        Rc<EvmLoader>,
118        VerifyingKey = KzgAsVerifyingKey,
119        Accumulator = KzgAccumulator<G1Affine, Rc<EvmLoader>>,
120    > + AccumulationDecider<G1Affine, Rc<EvmLoader>, DecidingKey = KzgDecidingKey<Bn256>>
121{
122}
123
124impl EvmKzgAccumulationScheme for crate::GWC {}
125impl EvmKzgAccumulationScheme for crate::SHPLONK {}
126
127pub fn gen_evm_verifier_sol_code<C, AS>(
128    params: &ParamsKZG<Bn256>,
129    vk: &VerifyingKey<G1Affine>,
130    num_instance: Vec<usize>,
131) -> String
132where
133    C: CircuitExt<Fr>,
134    AS: EvmKzgAccumulationScheme,
135{
136    let protocol = compile(
137        params,
138        vk,
139        Config::kzg()
140            .with_num_instance(num_instance.clone())
141            .with_accumulator_indices(C::accumulator_indices()),
142    );
143    // deciding key
144    let dk = (params.get_g()[0], params.g2(), params.s_g2()).into();
145
146    let loader = EvmLoader::new::<Fq, Fr>();
147    let protocol = protocol.loaded(&loader);
148    let mut transcript = EvmTranscript::<_, Rc<EvmLoader>, _, _>::new(&loader);
149
150    let instances = transcript.load_instances(num_instance);
151    let proof =
152        PlonkVerifier::<AS>::read_proof(&dk, &protocol, &instances, &mut transcript).unwrap();
153    PlonkVerifier::<AS>::verify(&dk, &protocol, &instances, &proof).unwrap();
154    loader.solidity_code()
155}
156
157pub fn gen_evm_verifier<C, AS>(
158    params: &ParamsKZG<Bn256>,
159    vk: &VerifyingKey<G1Affine>,
160    num_instance: Vec<usize>,
161    path: Option<&Path>,
162) -> Vec<u8>
163where
164    C: CircuitExt<Fr>,
165    AS: EvmKzgAccumulationScheme,
166{
167    let sol_code = gen_evm_verifier_sol_code::<C, AS>(params, vk, num_instance);
168    let byte_code = compile_solidity(&sol_code);
169    if let Some(path) = path {
170        path.parent().and_then(|dir| fs::create_dir_all(dir).ok()).unwrap();
171        fs::write(path, sol_code).unwrap();
172    }
173    byte_code
174}
175
176pub fn gen_evm_verifier_gwc<C: CircuitExt<Fr>>(
177    params: &ParamsKZG<Bn256>,
178    vk: &VerifyingKey<G1Affine>,
179    num_instance: Vec<usize>,
180    path: Option<&Path>,
181) -> Vec<u8> {
182    gen_evm_verifier::<C, GWC>(params, vk, num_instance, path)
183}
184
185pub fn gen_evm_verifier_shplonk<C: CircuitExt<Fr>>(
186    params: &ParamsKZG<Bn256>,
187    vk: &VerifyingKey<G1Affine>,
188    num_instance: Vec<usize>,
189    path: Option<&Path>,
190) -> Vec<u8> {
191    gen_evm_verifier::<C, SHPLONK>(params, vk, num_instance, path)
192}
193
194#[cfg(feature = "revm")]
195pub fn evm_verify(
196    deployment_code: Vec<u8>,
197    instances: Vec<Vec<Fr>>,
198    proof: Vec<u8>,
199) -> Result<u64, String> {
200    let calldata = encode_calldata(&instances, &proof);
201    let gas_cost = snark_verifier::loader::evm::deploy_and_call(deployment_code, calldata)?;
202    dbg!(gas_cost);
203    Ok(gas_cost)
204}
205
206pub fn write_calldata(instances: &[Vec<Fr>], proof: &[u8], path: &Path) -> io::Result<String> {
207    let calldata = encode_calldata(instances, proof);
208    let calldata = hex::encode(calldata);
209    fs::write(path, &calldata)?;
210    Ok(calldata)
211}