1use std::{io::Cursor, sync::Arc};
2
3use derive_more::derive::From;
4use eyre::Result;
5use openvm::platform::memory::MEM_SIZE;
6use openvm_circuit::arch::instructions::exe::VmExe;
7use openvm_continuations::{verifier::internal::types::VmStarkProof, SC};
8use openvm_stark_backend::proof::Proof;
9use openvm_transpiler::elf::Elf;
10use serde::{Deserialize, Serialize};
11use serde_with::serde_as;
12#[cfg(feature = "evm-prove")]
13use {
14 crate::commit::{AppExecutionCommit, CommitBytes},
15 itertools::Itertools,
16 openvm_native_recursion::halo2::{wrapper::EvmVerifierByteCode, Fr, RawEvmProof},
17 std::iter::{once, repeat_n},
18 thiserror::Error,
19};
20
21use crate::{
22 codec::{decode_vec, encode_slice, Decode, Encode},
23 OPENVM_VERSION,
24};
25
26pub(crate) const BN254_BYTES: usize = 32;
28pub const NUM_BN254_ACCUMULATOR: usize = 12;
30#[cfg(feature = "evm-prove")]
32const NUM_BN254_PROOF: usize = 43;
33
34#[derive(From)]
35pub enum ExecutableFormat {
36 Elf(Elf),
37 VmExe(VmExe<crate::F>),
38 SharedVmExe(Arc<VmExe<crate::F>>),
39}
40
41impl<'a> From<&'a [u8]> for ExecutableFormat {
42 fn from(bytes: &'a [u8]) -> Self {
43 let elf = Elf::decode(bytes, MEM_SIZE.try_into().unwrap()).expect("Invalid ELF bytes");
44 ExecutableFormat::Elf(elf)
45 }
46}
47impl From<Vec<u8>> for ExecutableFormat {
48 fn from(bytes: Vec<u8>) -> Self {
49 ExecutableFormat::from(&bytes[..])
50 }
51}
52
53#[cfg(feature = "evm-prove")]
54#[derive(Clone, Debug, Serialize, Deserialize)]
55pub struct EvmHalo2Verifier {
56 pub halo2_verifier_code: String,
57 pub openvm_verifier_code: String,
58 pub openvm_verifier_interface: String,
59 pub artifact: EvmVerifierByteCode,
60}
61
62#[serde_as]
63#[derive(Clone, Debug, Deserialize, Serialize)]
64pub struct ProofData {
65 #[serde_as(as = "serde_with::hex::Hex")]
66 pub accumulator: Vec<u8>,
68 #[serde_as(as = "serde_with::hex::Hex")]
69 pub proof: Vec<u8>,
72}
73
74#[cfg(feature = "evm-prove")]
75#[serde_as]
76#[derive(Clone, Debug, Deserialize, Serialize)]
77pub struct EvmProof {
78 pub version: String,
81 #[serde(flatten)]
82 pub app_commit: AppExecutionCommit,
84 #[serde_as(as = "serde_with::hex::Hex")]
85 pub user_public_values: Vec<u8>,
87 pub proof_data: ProofData,
89}
90
91#[cfg(feature = "evm-prove")]
92#[derive(Debug, Error)]
93pub enum EvmProofConversionError {
94 #[error("Invalid length of proof")]
95 InvalidLengthProof,
96 #[error("Invalid length of instances")]
97 InvalidLengthInstances,
98 #[error("Invalid length of user public values")]
99 InvalidUserPublicValuesLength,
100 #[error("Invalid length of accumulator")]
101 InvalidLengthAccumulator,
102}
103
104#[cfg(feature = "evm-prove")]
105impl EvmProof {
106 #[cfg(feature = "evm-verify")]
107 pub fn verifier_calldata(self) -> Vec<u8> {
109 use alloy_sol_types::SolCall;
110
111 use crate::IOpenVmHalo2Verifier;
112
113 let EvmProof {
114 user_public_values,
115 app_commit,
116 proof_data,
117 version: _,
118 } = self;
119
120 let ProofData { accumulator, proof } = proof_data;
121
122 let mut proof_data = accumulator;
123 proof_data.extend(proof);
124
125 IOpenVmHalo2Verifier::verifyCall {
126 publicValues: user_public_values.into(),
127 proofData: proof_data.into(),
128 appExeCommit: app_commit.app_exe_commit.as_slice().into(),
129 appVmCommit: app_commit.app_vm_commit.as_slice().into(),
130 }
131 .abi_encode()
132 }
133
134 #[cfg(feature = "evm-verify")]
135 pub fn fallback_calldata(&self) -> Vec<u8> {
136 let evm_proof: RawEvmProof = self.clone().try_into().unwrap();
137 evm_proof.verifier_calldata()
138 }
139}
140
141#[cfg(feature = "evm-prove")]
142impl TryFrom<RawEvmProof> for EvmProof {
143 type Error = EvmProofConversionError;
144
145 fn try_from(evm_proof: RawEvmProof) -> Result<Self, Self::Error> {
146 let RawEvmProof { instances, proof } = evm_proof;
147 if NUM_BN254_ACCUMULATOR + 2 >= instances.len() {
148 return Err(EvmProofConversionError::InvalidLengthInstances);
149 }
150 if proof.len() != NUM_BN254_PROOF * BN254_BYTES {
151 return Err(EvmProofConversionError::InvalidLengthProof);
152 }
153 let accumulator = instances[0..NUM_BN254_ACCUMULATOR]
154 .iter()
155 .flat_map(|f| f.to_bytes())
156 .collect::<Vec<_>>();
157 let mut app_exe_commit = instances[NUM_BN254_ACCUMULATOR].to_bytes();
158 let mut app_vm_commit = instances[NUM_BN254_ACCUMULATOR + 1].to_bytes();
159 app_exe_commit.reverse();
160 app_vm_commit.reverse();
161
162 let mut evm_accumulator: Vec<u8> = Vec::with_capacity(accumulator.len());
163 accumulator
164 .chunks(32)
165 .for_each(|chunk| evm_accumulator.extend(chunk.iter().rev().cloned()));
166
167 let user_public_values = instances[NUM_BN254_ACCUMULATOR + 2..].iter().fold(
168 Vec::<u8>::new(),
169 |mut acc: Vec<u8>, chunk| {
170 acc.push(*chunk.to_bytes().first().unwrap());
172 acc
173 },
174 );
175 let app_commit = AppExecutionCommit {
176 app_exe_commit: CommitBytes::new(app_exe_commit),
177 app_vm_commit: CommitBytes::new(app_vm_commit),
178 };
179
180 Ok(Self {
181 version: format!("v{}", OPENVM_VERSION),
182 app_commit,
183 user_public_values,
184 proof_data: ProofData {
185 accumulator: evm_accumulator,
186 proof,
187 },
188 })
189 }
190}
191
192#[cfg(feature = "evm-prove")]
193impl TryFrom<EvmProof> for RawEvmProof {
194 type Error = EvmProofConversionError;
195 fn try_from(evm_openvm_proof: EvmProof) -> Result<Self, Self::Error> {
196 let EvmProof {
197 mut app_commit,
198 user_public_values,
199 proof_data,
200 version: _,
201 } = evm_openvm_proof;
202
203 app_commit.app_exe_commit.reverse();
204 app_commit.app_vm_commit.reverse();
205
206 let ProofData { accumulator, proof } = proof_data;
207
208 if proof.len() != NUM_BN254_PROOF * BN254_BYTES {
209 return Err(EvmProofConversionError::InvalidLengthProof);
210 }
211 let instances = {
212 if accumulator.len() != NUM_BN254_ACCUMULATOR * BN254_BYTES {
213 return Err(EvmProofConversionError::InvalidLengthAccumulator);
214 }
215
216 let mut reversed_accumulator: Vec<u8> = Vec::with_capacity(accumulator.len());
217 accumulator
218 .chunks(32)
219 .for_each(|chunk| reversed_accumulator.extend(chunk.iter().rev().cloned()));
220
221 if user_public_values.is_empty() {
222 return Err(EvmProofConversionError::InvalidUserPublicValuesLength);
223 }
224
225 let user_public_values = user_public_values
226 .into_iter()
227 .flat_map(|byte| once(byte).chain(repeat_n(0, 31)))
228 .collect::<Vec<_>>();
229
230 let mut ret = Vec::new();
231 for chunk in &reversed_accumulator
232 .iter()
233 .chain(app_commit.app_exe_commit.as_slice())
234 .chain(app_commit.app_vm_commit.as_slice())
235 .chain(&user_public_values)
236 .chunks(BN254_BYTES)
237 {
238 let c = chunk.copied().collect::<Vec<_>>().try_into().unwrap();
239 ret.push(Fr::from_bytes(&c).unwrap());
240 }
241 ret
242 };
243 Ok(RawEvmProof { instances, proof })
244 }
245}
246
247#[serde_as]
249#[derive(Clone, Debug, Deserialize, Serialize)]
250pub struct VersionedVmStarkProof {
251 pub version: String,
254 #[serde_as(as = "serde_with::hex::Hex")]
255 pub user_public_values: Vec<u8>,
256 #[serde_as(as = "serde_with::hex::Hex")]
257 pub proof: Vec<u8>,
258}
259
260impl VersionedVmStarkProof {
261 pub fn new(proof: VmStarkProof<SC>) -> Result<Self> {
262 let mut user_public_values = Vec::new();
263 encode_slice(&proof.user_public_values, &mut user_public_values)?;
264 Ok(Self {
265 version: format!("v{}", OPENVM_VERSION),
266 user_public_values,
267 proof: proof.inner.encode_to_vec()?,
268 })
269 }
270}
271
272impl TryFrom<VersionedVmStarkProof> for VmStarkProof<SC> {
273 type Error = std::io::Error;
274 fn try_from(proof: VersionedVmStarkProof) -> Result<Self, std::io::Error> {
275 let VersionedVmStarkProof {
276 proof,
277 user_public_values,
278 ..
279 } = proof;
280 let mut reader = Cursor::new(user_public_values);
281 let user_public_values = decode_vec(&mut reader)?;
282 Ok(Self {
283 user_public_values,
284 inner: Proof::decode_from_bytes(&proof)?,
285 })
286 }
287}