1use std::sync::Arc;
2
3use derive_more::derive::From;
4use eyre::Result;
5use openvm::platform::memory::MEM_SIZE;
6use openvm_circuit::{
7 arch::instructions::exe::VmExe,
8 system::memory::{dimensions::MemoryDimensions, merkle::public_values::UserPublicValuesProof},
9};
10use openvm_continuations::CommitBytes;
11use openvm_stark_backend::{
12 codec::{Decode, Encode},
13 proof::Proof,
14};
15use openvm_transpiler::elf::Elf;
16use openvm_verify_stark_host::{
17 deferral::DeferralMerkleProofs, pvs::VkCommit, vk::VerificationBaseline, VmStarkProof,
18};
19use serde::{Deserialize, Serialize};
20use serde_with::serde_as;
21
22use crate::OPENVM_VERSION;
23
24#[derive(From)]
25pub enum ExecutableFormat {
26 Elf(Elf),
27 VmExe(VmExe<crate::F>),
28 SharedVmExe(Arc<VmExe<crate::F>>),
29}
30
31impl<'a> From<&'a [u8]> for ExecutableFormat {
32 fn from(bytes: &'a [u8]) -> Self {
33 let elf = Elf::decode(bytes, MEM_SIZE.try_into().unwrap()).expect("Invalid ELF bytes");
34 ExecutableFormat::Elf(elf)
35 }
36}
37impl From<Vec<u8>> for ExecutableFormat {
38 fn from(bytes: Vec<u8>) -> Self {
39 ExecutableFormat::from(&bytes[..])
40 }
41}
42
43#[allow(dead_code)]
45pub(crate) const BN254_BYTES: usize = 32;
46pub const NUM_BN254_ACCUMULATOR: usize = 12;
48#[cfg(feature = "evm-prove")]
50#[allow(dead_code)]
51pub(crate) const NUM_BN254_PROOF: usize = 43;
52
53#[derive(Clone, Debug, Deserialize, Serialize)]
54pub struct ProofData {
55 #[serde(with = "prefixed_hex")]
56 pub accumulator: Vec<u8>,
58 #[serde(with = "prefixed_hex")]
59 pub proof: Vec<u8>,
62}
63
64mod prefixed_hex {
65 use serde::{Deserialize, Deserializer, Serializer};
66
67 pub fn serialize<S: Serializer>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error> {
68 serializer.serialize_str(&format!("0x{}", hex::encode(bytes)))
69 }
70
71 pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
72 let hex_str = String::deserialize(deserializer)?;
73 let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str);
74 hex::decode(hex_str).map_err(serde::de::Error::custom)
75 }
76}
77
78#[cfg(feature = "evm-prove")]
81pub use openvm_static_verifier::wrapper::EvmVerifierByteCode;
82
83#[cfg(feature = "evm-prove")]
84#[derive(Clone, Debug, Serialize, Deserialize)]
85pub struct EvmHalo2Verifier {
86 pub halo2_verifier_code: String,
87 pub openvm_verifier_code: String,
88 pub openvm_verifier_interface: String,
89 pub artifact: EvmVerifierByteCode,
90}
91
92#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
94pub struct AppExecutionCommit {
95 pub app_exe_commit: openvm_continuations::CommitBytes,
96 pub app_vm_commit: openvm_continuations::CommitBytes,
97}
98
99#[cfg(feature = "evm-prove")]
100#[derive(Clone, Debug, Deserialize, Serialize)]
101pub struct EvmProof {
102 pub version: String,
105 #[serde(flatten)]
106 pub app_commit: AppExecutionCommit,
108 #[serde(with = "prefixed_hex")]
109 pub user_public_values: Vec<u8>,
111 pub proof_data: ProofData,
113}
114
115#[cfg(feature = "evm-prove")]
116#[derive(Debug, thiserror::Error)]
117pub enum EvmProofConversionError {
118 #[error("Invalid length of instances: expected at least 3, got {0}")]
119 InvalidLengthInstances(usize),
120 #[error("Invalid length of user public values")]
121 InvalidUserPublicValuesLength,
122}
123
124#[cfg(feature = "evm-prove")]
125impl EvmProof {
126 #[cfg(feature = "evm-verify")]
127 pub fn verifier_calldata(self) -> Vec<u8> {
129 use alloy_sol_types::SolCall;
130
131 use crate::solidity::IOpenVmHalo2Verifier;
132
133 let EvmProof {
134 user_public_values,
135 app_commit,
136 proof_data,
137 version: _,
138 } = self;
139
140 let ProofData { accumulator, proof } = proof_data;
141
142 let mut proof_data_bytes = accumulator;
143 proof_data_bytes.extend(proof);
144
145 IOpenVmHalo2Verifier::verifyCall {
146 publicValues: user_public_values.into(),
147 proofData: proof_data_bytes.into(),
148 appExeCommit: (*app_commit.app_exe_commit.as_slice()).into(),
149 appVmCommit: (*app_commit.app_vm_commit.as_slice()).into(),
150 }
151 .abi_encode()
152 }
153
154 #[cfg(feature = "evm-verify")]
155 pub fn fallback_calldata(&self) -> Vec<u8> {
156 let raw: openvm_static_verifier::keygen::RawEvmProof = self.clone().into();
157 encode_raw_evm_proof_calldata(&raw)
158 }
159}
160
161#[cfg(feature = "evm-verify")]
166pub fn encode_raw_evm_proof_calldata(
167 proof: &openvm_static_verifier::keygen::RawEvmProof,
168) -> Vec<u8> {
169 let mut calldata = Vec::new();
170 for instance in &proof.instances {
171 let mut bytes = instance.to_bytes();
173 bytes.reverse();
174 calldata.extend_from_slice(&bytes);
175 }
176 calldata.extend_from_slice(&proof.proof);
177 calldata
178}
179
180#[cfg(feature = "evm-prove")]
188impl From<openvm_static_verifier::keygen::RawEvmProof> for EvmProof {
189 fn from(raw: openvm_static_verifier::keygen::RawEvmProof) -> Self {
190 use openvm_continuations::CommitBytes;
191
192 let openvm_static_verifier::keygen::RawEvmProof { instances, proof } = raw;
193 assert!(
194 instances.len() > NUM_BN254_ACCUMULATOR + 2,
195 "RawEvmProof instances must have at least {} elements (accumulator + exe commit + vk commit)",
196 NUM_BN254_ACCUMULATOR + 2
197 );
198
199 let accumulator = instances[0..NUM_BN254_ACCUMULATOR]
201 .iter()
202 .flat_map(|f| f.to_bytes())
203 .collect::<Vec<_>>();
204
205 let mut evm_accumulator = Vec::with_capacity(accumulator.len());
207 accumulator
208 .chunks(BN254_BYTES)
209 .for_each(|chunk| evm_accumulator.extend(chunk.iter().rev().copied()));
210
211 let mut app_exe_bytes = instances[NUM_BN254_ACCUMULATOR].to_bytes();
214 app_exe_bytes.reverse();
215 let mut app_vm_bytes = instances[NUM_BN254_ACCUMULATOR + 1].to_bytes();
216 app_vm_bytes.reverse();
217
218 let user_public_values = instances[NUM_BN254_ACCUMULATOR + 2..]
219 .iter()
220 .map(|f| {
221 f.to_bytes()[0]
223 })
224 .collect::<Vec<u8>>();
225
226 let app_commit = AppExecutionCommit {
227 app_exe_commit: CommitBytes::new(app_exe_bytes),
228 app_vm_commit: CommitBytes::new(app_vm_bytes),
229 };
230
231 Self {
232 version: format!("v{OPENVM_VERSION}"),
233 app_commit,
234 user_public_values,
235 proof_data: ProofData {
236 accumulator: evm_accumulator,
237 proof,
238 },
239 }
240 }
241}
242
243#[cfg(feature = "evm-prove")]
245impl From<EvmProof> for openvm_static_verifier::keygen::RawEvmProof {
246 fn from(evm_proof: EvmProof) -> Self {
247 use openvm_static_verifier::Fr;
248
249 let EvmProof {
250 app_commit,
251 user_public_values,
252 proof_data,
253 version: _,
254 } = evm_proof;
255
256 let ProofData { accumulator, proof } = proof_data;
257
258 let mut reversed_accumulator = Vec::with_capacity(accumulator.len());
260 accumulator
261 .chunks(BN254_BYTES)
262 .for_each(|chunk| reversed_accumulator.extend(chunk.iter().rev().copied()));
263
264 let mut app_exe_bytes = *app_commit.app_exe_commit.as_slice();
266 app_exe_bytes.reverse();
267 let app_exe_fr = Fr::from_bytes(&app_exe_bytes).unwrap();
268
269 let mut app_vm_bytes = *app_commit.app_vm_commit.as_slice();
270 app_vm_bytes.reverse();
271 let app_vm_fr = Fr::from_bytes(&app_vm_bytes).unwrap();
272
273 let user_pvs_frs: Vec<Fr> = user_public_values
274 .into_iter()
275 .map(|byte| {
276 let mut bytes = [0u8; 32];
277 bytes[0] = byte;
278 Fr::from_bytes(&bytes).unwrap()
279 })
280 .collect();
281
282 let mut instances = Vec::new();
284 for chunk in reversed_accumulator.chunks(BN254_BYTES) {
285 let c: [u8; 32] = chunk.try_into().unwrap();
286 instances.push(Fr::from_bytes(&c).unwrap());
287 }
288 instances.push(app_exe_fr);
289 instances.push(app_vm_fr);
290 instances.extend(user_pvs_frs);
291
292 openvm_static_verifier::keygen::RawEvmProof { instances, proof }
293 }
294}
295
296#[serde_as]
300#[derive(Clone, Debug, Deserialize, Serialize, Encode, Decode)]
301pub struct VersionedVmStarkProof {
302 pub version: String,
305 #[serde_as(as = "serde_with::hex::Hex")]
306 pub proof: Vec<u8>,
307 #[serde_as(as = "serde_with::hex::Hex")]
308 pub user_pvs_proof: Vec<u8>,
309 #[serde(default)]
310 #[serde_as(as = "Option<serde_with::hex::Hex>")]
311 pub deferral_merkle_proofs: Option<Vec<u8>>,
312}
313
314impl VersionedVmStarkProof {
315 pub fn new(proof: VmStarkProof) -> Result<Self> {
316 Ok(Self {
317 version: format!("v{}", OPENVM_VERSION),
318 proof: proof.inner.encode_to_vec()?,
319 user_pvs_proof: {
320 let mut buf = Vec::new();
321 proof.user_pvs_proof.encode::<crate::SC, _>(&mut buf)?;
322 buf
323 },
324 deferral_merkle_proofs: proof
325 .deferral_merkle_proofs
326 .map(|ref dmp| {
327 let mut buf = Vec::new();
328 dmp.encode(&mut buf)?;
329 Ok::<_, std::io::Error>(buf)
330 })
331 .transpose()?,
332 })
333 }
334}
335
336impl TryFrom<VersionedVmStarkProof> for VmStarkProof {
337 type Error = std::io::Error;
338 fn try_from(proof: VersionedVmStarkProof) -> Result<Self, std::io::Error> {
339 let VersionedVmStarkProof {
340 proof,
341 user_pvs_proof,
342 deferral_merkle_proofs,
343 ..
344 } = proof;
345 Ok(Self {
346 inner: Proof::<crate::SC>::decode_from_bytes(&proof)?,
347 user_pvs_proof: UserPublicValuesProof::decode::<crate::SC, _>(
348 &mut std::io::Cursor::new(&user_pvs_proof),
349 )?,
350 deferral_merkle_proofs: deferral_merkle_proofs
351 .map(|bytes| DeferralMerkleProofs::decode(&mut std::io::Cursor::new(&bytes)))
352 .transpose()?,
353 })
354 }
355}
356
357#[derive(Clone, Debug, Serialize, Deserialize)]
361pub struct VkCommitJson {
362 pub cached_commit: CommitBytes,
363 pub vk_pre_hash: CommitBytes,
364}
365
366#[derive(Clone, Debug, Serialize, Deserialize)]
371pub struct VerificationBaselineJson {
372 pub app_exe_commit: CommitBytes,
373 pub memory_dimensions: MemoryDimensions,
374 pub num_user_pvs: usize,
375 pub app_vk_commit: VkCommitJson,
376 pub leaf_vk_commit: VkCommitJson,
377 pub internal_for_leaf_vk_commit: VkCommitJson,
378 pub internal_recursive_vk_commit: VkCommitJson,
379 pub expected_def_hook_commit: Option<CommitBytes>,
380}
381
382impl From<VerificationBaseline> for VerificationBaselineJson {
383 fn from(b: VerificationBaseline) -> Self {
384 let vk = |d: VkCommit<crate::F>| VkCommitJson {
385 cached_commit: CommitBytes::from(d.cached_commit),
386 vk_pre_hash: CommitBytes::from(d.vk_pre_hash),
387 };
388 Self {
389 app_exe_commit: CommitBytes::from(b.app_exe_commit),
390 memory_dimensions: b.memory_dimensions,
391 num_user_pvs: b.num_user_pvs,
392 app_vk_commit: vk(b.app_vk_commit),
393 leaf_vk_commit: vk(b.leaf_vk_commit),
394 internal_for_leaf_vk_commit: vk(b.internal_for_leaf_vk_commit),
395 internal_recursive_vk_commit: vk(b.internal_recursive_vk_commit),
396 expected_def_hook_commit: b.expected_def_hook_commit.map(CommitBytes::from),
397 }
398 }
399}
400
401impl From<VerificationBaselineJson> for VerificationBaseline {
402 fn from(b: VerificationBaselineJson) -> Self {
403 use openvm_verify_stark_host::pvs::VkCommit;
404 let vk = |d: VkCommitJson| VkCommit {
405 cached_commit: d.cached_commit.into(),
406 vk_pre_hash: d.vk_pre_hash.into(),
407 };
408 Self {
409 app_exe_commit: b.app_exe_commit.into(),
410 memory_dimensions: b.memory_dimensions,
411 num_user_pvs: b.num_user_pvs,
412 app_vk_commit: vk(b.app_vk_commit),
413 leaf_vk_commit: vk(b.leaf_vk_commit),
414 internal_for_leaf_vk_commit: vk(b.internal_for_leaf_vk_commit),
415 internal_recursive_vk_commit: vk(b.internal_recursive_vk_commit),
416 expected_def_hook_commit: b.expected_def_hook_commit.map(|c| c.into()),
417 }
418 }
419}