openvm_sdk/
types.rs

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
26/// Number of bytes in a Bn254Fr.
27pub(crate) const BN254_BYTES: usize = 32;
28/// Number of Bn254Fr in `accumulator` field.
29pub const NUM_BN254_ACCUMULATOR: usize = 12;
30/// Number of Bn254Fr in `proof` field for a circuit with only 1 advice column.
31#[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    /// KZG accumulator.
67    pub accumulator: Vec<u8>,
68    #[serde_as(as = "serde_with::hex::Hex")]
69    /// Bn254Fr proof in little-endian bytes. The circuit only has 1 advice column, so the proof is
70    /// of length `NUM_BN254_PROOF * BN254_BYTES`.
71    pub proof: Vec<u8>,
72}
73
74#[cfg(feature = "evm-prove")]
75#[serde_as]
76#[derive(Clone, Debug, Deserialize, Serialize)]
77pub struct EvmProof {
78    /// The openvm major and minor version v{}.{}. The proof format will not change on patch
79    /// versions.
80    pub version: String,
81    #[serde(flatten)]
82    /// Bn254Fr public value app commits.
83    pub app_commit: AppExecutionCommit,
84    #[serde_as(as = "serde_with::hex::Hex")]
85    /// User public values packed into bytes.
86    pub user_public_values: Vec<u8>,
87    /// The concatenation of `accumulator` and `proof`.
88    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    /// Return bytes calldata to be passed to the verifier contract.
108    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                // We only care about the first byte, everything else should be 0-bytes
171                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/// Struct purely for encoding and decoding of [VmStarkProof].
248#[serde_as]
249#[derive(Clone, Debug, Deserialize, Serialize)]
250pub struct VersionedVmStarkProof {
251    /// The openvm major and minor version v{}.{}. The proof format will not change on patch
252    /// versions.
253    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}