1use std::{fs::read, marker::PhantomData, path::Path, sync::Arc};
2
3use commit::commit_app_exe;
4use config::AppConfig;
5use eyre::Result;
6use keygen::{AppProvingKey, AppVerifyingKey};
7use openvm_build::{
8 build_guest_package, find_unique_executable, get_package, GuestOptions, TargetFilter,
9};
10use openvm_circuit::{
11 arch::{
12 hasher::poseidon2::vm_poseidon2_hasher, instructions::exe::VmExe, verify_segments,
13 ContinuationVmProof, ExecutionError, VerifiedExecutionPayload, VmConfig, VmExecutor,
14 VmVerificationError,
15 },
16 system::{
17 memory::{tree::public_values::extract_public_values, CHUNK},
18 program::trace::VmCommittedExe,
19 },
20};
21use openvm_continuations::verifier::root::types::RootVmVerifierInput;
22pub use openvm_continuations::{
23 static_verifier::{DefaultStaticVerifierPvHandler, StaticVerifierPvHandler},
24 RootSC, C, F, SC,
25};
26use openvm_native_recursion::halo2::{
27 utils::Halo2ParamsReader,
28 wrapper::{EvmVerifier, Halo2WrapperProvingKey},
29 RawEvmProof,
30};
31use openvm_stark_backend::proof::Proof;
32use openvm_stark_sdk::{
33 config::{baby_bear_poseidon2::BabyBearPoseidon2Engine, FriParameters},
34 engine::StarkFriEngine,
35 openvm_stark_backend::{verifier::VerificationError, Chip},
36};
37use openvm_transpiler::{
38 elf::Elf,
39 openvm_platform::memory::MEM_SIZE,
40 transpiler::{Transpiler, TranspilerError},
41 FromElf,
42};
43
44use crate::{
45 config::AggConfig,
46 keygen::{AggProvingKey, AggStarkProvingKey},
47 prover::{AppProver, ContinuationProver, StarkProver},
48};
49
50pub mod codec;
51pub mod commit;
52pub mod config;
53pub mod keygen;
54pub mod prover;
55
56mod stdin;
57pub use stdin::*;
58
59use crate::types::EvmProof;
60
61pub mod fs;
62pub mod types;
63
64pub type NonRootCommittedExe = VmCommittedExe<SC>;
65
66pub struct VerifiedContinuationVmPayload {
69 pub exe_commit: [F; CHUNK],
77 pub user_public_values: Vec<F>,
78}
79
80pub struct GenericSdk<E: StarkFriEngine<SC>> {
81 _phantom: PhantomData<E>,
82}
83
84impl<E: StarkFriEngine<SC>> Default for GenericSdk<E> {
85 fn default() -> Self {
86 Self {
87 _phantom: PhantomData,
88 }
89 }
90}
91
92pub type Sdk = GenericSdk<BabyBearPoseidon2Engine>;
93
94impl<E: StarkFriEngine<SC>> GenericSdk<E> {
95 pub fn new() -> Self {
96 Self::default()
97 }
98
99 pub fn build<P: AsRef<Path>>(
100 &self,
101 guest_opts: GuestOptions,
102 pkg_dir: P,
103 target_filter: &Option<TargetFilter>,
104 ) -> Result<Elf> {
105 let pkg = get_package(pkg_dir.as_ref());
106 let target_dir = match build_guest_package(&pkg, &guest_opts, None, target_filter) {
107 Ok(target_dir) => target_dir,
108 Err(Some(code)) => {
109 return Err(eyre::eyre!("Failed to build guest: code = {}", code));
110 }
111 Err(None) => {
112 return Err(eyre::eyre!(
113 "Failed to build guest (OPENVM_SKIP_BUILD is set)"
114 ));
115 }
116 };
117
118 let elf_path = find_unique_executable(pkg_dir, target_dir, target_filter)?;
119 let data = read(&elf_path)?;
120 Elf::decode(&data, MEM_SIZE as u32)
121 }
122
123 pub fn transpile(
124 &self,
125 elf: Elf,
126 transpiler: Transpiler<F>,
127 ) -> Result<VmExe<F>, TranspilerError> {
128 VmExe::from_elf(elf, transpiler)
129 }
130
131 pub fn execute<VC: VmConfig<F>>(
132 &self,
133 exe: VmExe<F>,
134 vm_config: VC,
135 inputs: StdIn,
136 ) -> Result<Vec<F>, ExecutionError>
137 where
138 VC::Executor: Chip<SC>,
139 VC::Periphery: Chip<SC>,
140 {
141 let vm = VmExecutor::new(vm_config);
142 let final_memory = vm.execute(exe, inputs)?;
143 let public_values = extract_public_values(
144 &vm.config.system().memory_config.memory_dimensions(),
145 vm.config.system().num_public_values,
146 final_memory.as_ref().unwrap(),
147 );
148 Ok(public_values)
149 }
150
151 pub fn commit_app_exe(
152 &self,
153 app_fri_params: FriParameters,
154 exe: VmExe<F>,
155 ) -> Result<Arc<NonRootCommittedExe>> {
156 let committed_exe = commit_app_exe(app_fri_params, exe);
157 Ok(committed_exe)
158 }
159
160 pub fn app_keygen<VC: VmConfig<F>>(&self, config: AppConfig<VC>) -> Result<AppProvingKey<VC>>
161 where
162 VC::Executor: Chip<SC>,
163 VC::Periphery: Chip<SC>,
164 {
165 let app_pk = AppProvingKey::keygen(config);
166 Ok(app_pk)
167 }
168
169 pub fn generate_app_proof<VC: VmConfig<F>>(
170 &self,
171 app_pk: Arc<AppProvingKey<VC>>,
172 app_committed_exe: Arc<NonRootCommittedExe>,
173 inputs: StdIn,
174 ) -> Result<ContinuationVmProof<SC>>
175 where
176 VC::Executor: Chip<SC>,
177 VC::Periphery: Chip<SC>,
178 {
179 let app_prover = AppProver::new(app_pk.app_vm_pk.clone(), app_committed_exe);
180 let proof = app_prover.generate_app_proof(inputs);
181 Ok(proof)
182 }
183
184 pub fn verify_app_proof(
193 &self,
194 app_vk: &AppVerifyingKey,
195 proof: &ContinuationVmProof<SC>,
196 ) -> Result<VerifiedContinuationVmPayload, VmVerificationError> {
197 let engine = E::new(app_vk.fri_params);
198 let VerifiedExecutionPayload {
199 exe_commit,
200 final_memory_root,
201 } = verify_segments(&engine, &app_vk.app_vm_vk, &proof.per_segment)?;
202
203 let hasher = vm_poseidon2_hasher();
204 proof
205 .user_public_values
206 .verify(&hasher, app_vk.memory_dimensions, final_memory_root)?;
207
208 Ok(VerifiedContinuationVmPayload {
209 exe_commit,
210 user_public_values: proof.user_public_values.public_values.clone(),
211 })
212 }
213
214 pub fn verify_app_proof_without_continuations(
215 &self,
216 app_vk: &AppVerifyingKey,
217 proof: &Proof<SC>,
218 ) -> Result<(), VerificationError> {
219 let e = E::new(app_vk.fri_params);
220 e.verify(&app_vk.app_vm_vk, proof)
221 }
222
223 pub fn agg_keygen(
224 &self,
225 config: AggConfig,
226 reader: &impl Halo2ParamsReader,
227 pv_handler: &impl StaticVerifierPvHandler,
228 ) -> Result<AggProvingKey> {
229 let agg_pk = AggProvingKey::keygen(config, reader, pv_handler);
230 Ok(agg_pk)
231 }
232
233 pub fn generate_root_verifier_input<VC: VmConfig<F>>(
234 &self,
235 app_pk: Arc<AppProvingKey<VC>>,
236 app_exe: Arc<NonRootCommittedExe>,
237 agg_stark_pk: AggStarkProvingKey,
238 inputs: StdIn,
239 ) -> Result<RootVmVerifierInput<SC>>
240 where
241 VC::Executor: Chip<SC>,
242 VC::Periphery: Chip<SC>,
243 {
244 let stark_prover = StarkProver::new(app_pk, app_exe, agg_stark_pk);
245 let proof = stark_prover.generate_root_verifier_input(inputs);
246 Ok(proof)
247 }
248
249 pub fn generate_evm_proof<VC: VmConfig<F>>(
250 &self,
251 reader: &impl Halo2ParamsReader,
252 app_pk: Arc<AppProvingKey<VC>>,
253 app_exe: Arc<NonRootCommittedExe>,
254 agg_pk: AggProvingKey,
255 inputs: StdIn,
256 ) -> Result<EvmProof>
257 where
258 VC::Executor: Chip<SC>,
259 VC::Periphery: Chip<SC>,
260 {
261 let e2e_prover = ContinuationProver::new(reader, app_pk, app_exe, agg_pk);
262 let proof = e2e_prover.generate_proof_for_evm(inputs);
263 Ok(proof)
264 }
265
266 pub fn generate_snark_verifier_contract(
267 &self,
268 reader: &impl Halo2ParamsReader,
269 agg_pk: &AggProvingKey,
270 ) -> Result<EvmVerifier> {
271 let params = reader.read_params(agg_pk.halo2_pk.wrapper.pinning.metadata.config_params.k);
272 let evm_verifier = agg_pk.halo2_pk.wrapper.generate_evm_verifier(¶ms);
273 Ok(evm_verifier)
274 }
275
276 pub fn verify_evm_proof(
277 &self,
278 evm_verifier: &EvmVerifier,
279 evm_proof: &EvmProof,
280 ) -> Result<u64> {
281 let evm_proof: RawEvmProof = evm_proof.clone().try_into()?;
282 let gas_cost = Halo2WrapperProvingKey::evm_verify(evm_verifier, &evm_proof)
283 .map_err(|reason| eyre::eyre!("Sdk::verify_evm_proof: {reason:?}"))?;
284 Ok(gas_cost)
285 }
286}