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
35pub 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 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}