1use halo2_base::{
2 gates::circuit::CircuitBuilderStage,
3 halo2_proofs::plonk::{keygen_pk, keygen_vk},
4};
5use openvm_stark_sdk::{
6 config::baby_bear_bn254_poseidon2::BabyBearBn254Poseidon2Config as RootConfig,
7 openvm_stark_backend::proof::Proof,
8};
9#[cfg(feature = "evm-prove")]
10use serde::{Deserialize, Serialize};
11
12use crate::{
13 circuit::StaticVerifierCircuit,
14 config::StaticVerifierShape,
15 prover::{Halo2Params, Halo2ProvingMetadata, Halo2ProvingPinning, StaticVerifierProof},
16};
17
18impl StaticVerifierCircuit {
19 pub fn keygen(
24 &self,
25 params: &Halo2Params,
26 shape: &StaticVerifierShape,
27 representative_proof: &Proof<RootConfig>,
28 ) -> Halo2ProvingPinning {
29 let mut builder = Self::builder(CircuitBuilderStage::Keygen, shape);
30 self.populate(&mut builder, representative_proof);
31
32 let config_params = builder.calculate_params(Some(shape.minimum_rows));
33
34 let vk = keygen_vk(params, &builder).expect("keygen_vk should succeed");
35 let pk = keygen_pk(params, vk, &builder).expect("keygen_pk should succeed");
36 let break_points = builder.break_points();
37
38 Halo2ProvingPinning {
39 pk,
40 metadata: Halo2ProvingMetadata {
41 config_params,
42 break_points,
43 num_pvs: builder
44 .assigned_instances
45 .iter()
46 .map(|instances| instances.len())
47 .collect(),
48 },
49 }
50 }
51}
52
53#[derive(Clone)]
56pub struct StaticVerifierProvingKey {
57 pub circuit: StaticVerifierCircuit,
58 pub pinning: Halo2ProvingPinning,
59 pub shape: StaticVerifierShape,
60}
61
62impl StaticVerifierProvingKey {
63 pub fn keygen(
65 params: &Halo2Params,
66 shape: StaticVerifierShape,
67 circuit: StaticVerifierCircuit,
68 representative_proof: &Proof<RootConfig>,
69 ) -> Self {
70 let pinning = circuit.keygen(params, &shape, representative_proof);
71 Self {
72 circuit,
73 pinning,
74 shape,
75 }
76 }
77
78 pub fn prove(&self, params: &Halo2Params, proof: &Proof<RootConfig>) -> StaticVerifierProof {
80 self.circuit
81 .prove(params, &self.pinning, &self.shape, proof)
82 }
83
84 pub fn verify(&self, params: &Halo2Params, proof: &StaticVerifierProof) -> bool {
86 StaticVerifierCircuit::verify(params, self.pinning.pk.get_vk(), proof)
87 }
88}
89
90#[cfg(feature = "evm-prove")]
93use halo2_base::{
94 gates::circuit::builder::BaseCircuitBuilder, halo2_proofs::halo2curves::bn256::Fr,
95};
96#[cfg(feature = "evm-prove")]
97use snark_verifier_sdk::{
98 evm::{gen_evm_proof_shplonk, gen_evm_verifier_sol_code},
99 SHPLONK,
100};
101
102#[cfg(feature = "evm-prove")]
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct RawEvmProof {
106 pub instances: Vec<Fr>,
107 pub proof: Vec<u8>,
108}
109
110#[cfg(feature = "evm-prove")]
111impl StaticVerifierProvingKey {
112 pub fn generate_fallback_evm_verifier(&self, params: &Halo2Params) -> String {
114 gen_evm_verifier_sol_code::<BaseCircuitBuilder<Fr>, SHPLONK>(
115 params,
116 self.pinning.pk.get_vk(),
117 self.pinning.metadata.num_pvs.clone(),
118 )
119 }
120
121 pub fn prove_wrapped(
127 &self,
128 params: &Halo2Params,
129 proof: &Proof<RootConfig>,
130 ) -> snark_verifier_sdk::Snark {
131 let mut builder = BaseCircuitBuilder::prover(
132 self.pinning.metadata.config_params.clone(),
133 self.pinning.metadata.break_points.clone(),
134 )
135 .use_instance_columns(self.shape.instance_columns);
136
137 let _public_inputs = self.circuit.populate(&mut builder, proof);
138
139 snark_verifier_sdk::halo2::gen_snark_shplonk(
140 params,
141 &self.pinning.pk,
142 builder,
143 None::<&str>,
144 )
145 }
146
147 pub fn generate_dummy_snark(
149 &self,
150 reader: &impl crate::wrapper::Halo2ParamsReader,
151 ) -> snark_verifier_sdk::Snark {
152 let k = self.pinning.metadata.config_params.k;
153 let params = reader.read_params(k);
154 snark_verifier_sdk::halo2::gen_dummy_snark_from_vk::<SHPLONK>(
155 ¶ms,
156 self.pinning.pk.get_vk(),
157 self.pinning.metadata.num_pvs.clone(),
158 None,
159 )
160 }
161
162 pub fn prove_for_evm_unwrapped(
164 &self,
165 params: &Halo2Params,
166 proof: &Proof<RootConfig>,
167 ) -> RawEvmProof {
168 self.shape.assert_onchain_verifier_supported();
169
170 let mut builder = BaseCircuitBuilder::prover(
171 self.pinning.metadata.config_params.clone(),
172 self.pinning.metadata.break_points.clone(),
173 )
174 .use_instance_columns(self.shape.instance_columns);
175
176 let public_inputs = self.circuit.populate(&mut builder, proof);
177 let instances_vec = public_inputs.to_vec();
178
179 let snark = gen_evm_proof_shplonk(
180 params,
181 &self.pinning.pk,
182 builder,
183 vec![instances_vec.clone()],
184 );
185
186 RawEvmProof {
187 instances: instances_vec,
188 proof: snark,
189 }
190 }
191}
192
193#[cfg(feature = "evm-verify")]
197pub fn evm_verify(deployment_code: &[u8], proof: &RawEvmProof) -> Result<u64, String> {
198 snark_verifier_sdk::evm::evm_verify(
199 deployment_code.to_vec(),
200 vec![proof.instances.clone()],
201 proof.proof.clone(),
202 )
203 .map_err(|e| format!("EVM verification failed: {e}"))
204}