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 more than {}, got {0}", NUM_BN254_ACCUMULATOR + 2)]
119 InvalidLengthInstances(usize),
120 #[error("Accumulator length {0} is not a multiple of {BN254_BYTES}")]
121 InvalidAccumulatorLength(usize),
122 #[error("Value is not a canonical Bn254 scalar")]
123 NonCanonicalScalar,
124 #[error(transparent)]
125 NonCanonicalCommit(#[from] openvm_continuations::CommitBytesError),
126}
127
128#[cfg(feature = "evm-prove")]
129impl EvmProof {
130 #[cfg(feature = "evm-verify")]
131 pub fn verifier_calldata(self) -> Vec<u8> {
133 use alloy_sol_types::SolCall;
134
135 use crate::solidity::IOpenVmHalo2Verifier;
136
137 let EvmProof {
138 user_public_values,
139 app_commit,
140 proof_data,
141 version: _,
142 } = self;
143
144 let ProofData { accumulator, proof } = proof_data;
145
146 let mut proof_data_bytes = accumulator;
147 proof_data_bytes.extend(proof);
148
149 IOpenVmHalo2Verifier::verifyCall {
150 publicValues: user_public_values.into(),
151 proofData: proof_data_bytes.into(),
152 appExeCommit: (*app_commit.app_exe_commit.as_slice()).into(),
153 appVmCommit: (*app_commit.app_vm_commit.as_slice()).into(),
154 }
155 .abi_encode()
156 }
157
158 #[cfg(feature = "evm-verify")]
159 pub fn fallback_calldata(&self) -> Result<Vec<u8>, EvmProofConversionError> {
160 let raw: openvm_static_verifier::keygen::RawEvmProof = self.clone().try_into()?;
161 Ok(encode_raw_evm_proof_calldata(&raw))
162 }
163}
164
165#[cfg(feature = "evm-verify")]
170pub fn encode_raw_evm_proof_calldata(
171 proof: &openvm_static_verifier::keygen::RawEvmProof,
172) -> Vec<u8> {
173 let mut calldata = Vec::new();
174 for instance in &proof.instances {
175 let mut bytes = instance.to_bytes();
177 bytes.reverse();
178 calldata.extend_from_slice(&bytes);
179 }
180 calldata.extend_from_slice(&proof.proof);
181 calldata
182}
183
184#[cfg(feature = "evm-prove")]
192impl TryFrom<openvm_static_verifier::keygen::RawEvmProof> for EvmProof {
193 type Error = EvmProofConversionError;
194
195 fn try_from(raw: openvm_static_verifier::keygen::RawEvmProof) -> Result<Self, Self::Error> {
196 use openvm_continuations::CommitBytes;
197
198 let openvm_static_verifier::keygen::RawEvmProof { instances, proof } = raw;
199 if instances.len() <= NUM_BN254_ACCUMULATOR + 2 {
200 return Err(EvmProofConversionError::InvalidLengthInstances(
201 instances.len(),
202 ));
203 }
204
205 let accumulator = instances[0..NUM_BN254_ACCUMULATOR]
207 .iter()
208 .flat_map(|f| f.to_bytes())
209 .collect::<Vec<_>>();
210
211 let mut evm_accumulator = Vec::with_capacity(accumulator.len());
213 accumulator
214 .chunks(BN254_BYTES)
215 .for_each(|chunk| evm_accumulator.extend(chunk.iter().rev().copied()));
216
217 let mut app_exe_bytes = instances[NUM_BN254_ACCUMULATOR].to_bytes();
220 app_exe_bytes.reverse();
221 let mut app_vm_bytes = instances[NUM_BN254_ACCUMULATOR + 1].to_bytes();
222 app_vm_bytes.reverse();
223
224 let user_public_values = instances[NUM_BN254_ACCUMULATOR + 2..]
225 .iter()
226 .map(|f| {
227 f.to_bytes()[0]
229 })
230 .collect::<Vec<u8>>();
231
232 let app_commit = AppExecutionCommit {
233 app_exe_commit: CommitBytes::try_new(app_exe_bytes)?,
234 app_vm_commit: CommitBytes::try_new(app_vm_bytes)?,
235 };
236
237 Ok(Self {
238 version: format!("v{OPENVM_VERSION}"),
239 app_commit,
240 user_public_values,
241 proof_data: ProofData {
242 accumulator: evm_accumulator,
243 proof,
244 },
245 })
246 }
247}
248
249#[cfg(feature = "evm-prove")]
251impl TryFrom<EvmProof> for openvm_static_verifier::keygen::RawEvmProof {
252 type Error = EvmProofConversionError;
253
254 fn try_from(evm_proof: EvmProof) -> Result<Self, Self::Error> {
255 use openvm_static_verifier::Fr;
256
257 fn to_fr(le_bytes: &[u8; 32]) -> Result<Fr, EvmProofConversionError> {
258 Option::from(Fr::from_bytes(le_bytes))
259 .ok_or(EvmProofConversionError::NonCanonicalScalar)
260 }
261
262 let EvmProof {
263 app_commit,
264 user_public_values,
265 proof_data,
266 version: _,
267 } = evm_proof;
268
269 let ProofData { accumulator, proof } = proof_data;
270
271 if !accumulator.len().is_multiple_of(BN254_BYTES) {
272 return Err(EvmProofConversionError::InvalidAccumulatorLength(
273 accumulator.len(),
274 ));
275 }
276
277 let mut reversed_accumulator = Vec::with_capacity(accumulator.len());
279 accumulator
280 .chunks(BN254_BYTES)
281 .for_each(|chunk| reversed_accumulator.extend(chunk.iter().rev().copied()));
282
283 let mut app_exe_bytes = *app_commit.app_exe_commit.as_slice();
285 app_exe_bytes.reverse();
286 let app_exe_fr = to_fr(&app_exe_bytes)?;
287
288 let mut app_vm_bytes = *app_commit.app_vm_commit.as_slice();
289 app_vm_bytes.reverse();
290 let app_vm_fr = to_fr(&app_vm_bytes)?;
291
292 let user_pvs_frs: Vec<Fr> = user_public_values
293 .into_iter()
294 .map(|byte| {
295 let mut bytes = [0u8; 32];
296 bytes[0] = byte;
297 to_fr(&bytes)
298 })
299 .collect::<Result<_, _>>()?;
300
301 let mut instances = Vec::new();
303 for chunk in reversed_accumulator.chunks(BN254_BYTES) {
304 let c: [u8; 32] = chunk.try_into().unwrap();
306 instances.push(to_fr(&c)?);
307 }
308 instances.push(app_exe_fr);
309 instances.push(app_vm_fr);
310 instances.extend(user_pvs_frs);
311
312 Ok(openvm_static_verifier::keygen::RawEvmProof { instances, proof })
313 }
314}
315
316#[serde_as]
320#[derive(Clone, Debug, Deserialize, Serialize, Encode, Decode)]
321pub struct VersionedVmStarkProof {
322 pub version: String,
325 #[serde_as(as = "serde_with::hex::Hex")]
326 pub proof: Vec<u8>,
327 #[serde_as(as = "serde_with::hex::Hex")]
328 pub user_pvs_proof: Vec<u8>,
329 #[serde(default)]
330 #[serde_as(as = "Option<serde_with::hex::Hex>")]
331 pub deferral_merkle_proofs: Option<Vec<u8>>,
332}
333
334impl VersionedVmStarkProof {
335 pub fn new(proof: VmStarkProof) -> Result<Self> {
336 Ok(Self {
337 version: format!("v{}", OPENVM_VERSION),
338 proof: proof.inner.encode_to_vec()?,
339 user_pvs_proof: {
340 let mut buf = Vec::new();
341 proof.user_pvs_proof.encode::<crate::SC, _>(&mut buf)?;
342 buf
343 },
344 deferral_merkle_proofs: proof
345 .deferral_merkle_proofs
346 .map(|ref dmp| {
347 let mut buf = Vec::new();
348 dmp.encode(&mut buf)?;
349 Ok::<_, std::io::Error>(buf)
350 })
351 .transpose()?,
352 })
353 }
354}
355
356impl TryFrom<VersionedVmStarkProof> for VmStarkProof {
357 type Error = std::io::Error;
358 fn try_from(proof: VersionedVmStarkProof) -> Result<Self, std::io::Error> {
359 let VersionedVmStarkProof {
360 proof,
361 user_pvs_proof,
362 deferral_merkle_proofs,
363 ..
364 } = proof;
365 Ok(Self {
366 inner: Proof::<crate::SC>::decode_from_bytes(&proof)?,
367 user_pvs_proof: UserPublicValuesProof::decode::<crate::SC, _>(
368 &mut std::io::Cursor::new(&user_pvs_proof),
369 )?,
370 deferral_merkle_proofs: deferral_merkle_proofs
371 .map(|bytes| DeferralMerkleProofs::decode(&mut std::io::Cursor::new(&bytes)))
372 .transpose()?,
373 })
374 }
375}
376
377#[derive(Clone, Debug, Serialize, Deserialize)]
381pub struct VkCommitJson {
382 pub cached_commit: CommitBytes,
383 pub vk_pre_hash: CommitBytes,
384}
385
386#[derive(Clone, Debug, Serialize, Deserialize)]
391pub struct VerificationBaselineJson {
392 pub app_exe_commit: CommitBytes,
393 pub memory_dimensions: MemoryDimensions,
394 pub num_user_pvs: usize,
395 pub app_vk_commit: VkCommitJson,
396 pub leaf_vk_commit: VkCommitJson,
397 pub internal_for_leaf_vk_commit: VkCommitJson,
398 pub internal_recursive_vk_commit: VkCommitJson,
399 pub expected_def_hook_commit: Option<CommitBytes>,
400}
401
402impl From<VerificationBaseline> for VerificationBaselineJson {
403 fn from(b: VerificationBaseline) -> Self {
404 let vk = |d: VkCommit<crate::F>| VkCommitJson {
405 cached_commit: CommitBytes::from(d.cached_commit),
406 vk_pre_hash: CommitBytes::from(d.vk_pre_hash),
407 };
408 Self {
409 app_exe_commit: CommitBytes::from(b.app_exe_commit),
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(CommitBytes::from),
417 }
418 }
419}
420
421impl From<VerificationBaselineJson> for VerificationBaseline {
422 fn from(b: VerificationBaselineJson) -> Self {
423 use openvm_verify_stark_host::pvs::VkCommit;
424 let vk = |d: VkCommitJson| VkCommit {
425 cached_commit: d.cached_commit.into(),
426 vk_pre_hash: d.vk_pre_hash.into(),
427 };
428 Self {
429 app_exe_commit: b.app_exe_commit.into(),
430 memory_dimensions: b.memory_dimensions,
431 num_user_pvs: b.num_user_pvs,
432 app_vk_commit: vk(b.app_vk_commit),
433 leaf_vk_commit: vk(b.leaf_vk_commit),
434 internal_for_leaf_vk_commit: vk(b.internal_for_leaf_vk_commit),
435 internal_recursive_vk_commit: vk(b.internal_recursive_vk_commit),
436 expected_def_hook_commit: b.expected_def_hook_commit.map(|c| c.into()),
437 }
438 }
439}