openvm_sdk/
types.rs

1use itertools::Itertools;
2use openvm_native_recursion::halo2::{Fr, RawEvmProof};
3use serde::{Deserialize, Serialize};
4use serde_with::serde_as;
5use thiserror::Error;
6
7/// Number of bytes in a Bn254Fr.
8const BN254_BYTES: usize = 32;
9/// Number of Bn254Fr in `accumulators` field.
10const NUM_BN254_ACCUMULATORS: usize = 12;
11/// Number of Bn254Fr in `proof` field for a circuit with only 1 advice column.
12const NUM_BN254_PROOF: usize = 43;
13
14#[serde_as]
15#[derive(Clone, Deserialize, Serialize)]
16pub struct EvmProof {
17    #[serde_as(as = "serde_with::hex::Hex")]
18    /// Bn254Fr public values for accumulators in flatten little-endian bytes. Length is `NUM_BN254_ACCUMULATORS * BN254_BYTES`.
19    pub accumulators: Vec<u8>,
20    #[serde_as(as = "serde_with::hex::Hex")]
21    /// 1 Bn254Fr public value for exe commit in little-endian bytes.
22    pub exe_commit: [u8; BN254_BYTES],
23    #[serde_as(as = "serde_with::hex::Hex")]
24    /// 1 Bn254Fr public value for leaf commit in little-endian bytes.
25    pub leaf_commit: [u8; BN254_BYTES],
26    #[serde_as(as = "serde_with::hex::Hex")]
27    /// Bn254Fr user public values in little-endian bytes.
28    pub user_public_values: Vec<u8>,
29    #[serde_as(as = "serde_with::hex::Hex")]
30    /// Bn254Fr proof in little-endian bytes. The circuit only has 1 advice column, so the proof is of length `NUM_BN254_PROOF * BN254_BYTES`.
31    pub proof: Vec<u8>,
32}
33
34#[derive(Debug, Error)]
35pub enum EvmProofConversionError {
36    #[error("Invalid length of proof")]
37    InvalidLengthProof,
38    #[error("Invalid length of instances")]
39    InvalidLengthInstances,
40    #[error("Invalid length of user public values")]
41    InvalidUserPublicValuesLength,
42    #[error("Invalid length of accumulators")]
43    InvalidLengthAccumulators,
44}
45
46impl EvmProof {
47    /// Return bytes calldata to be passed to the verifier contract.
48    pub fn verifier_calldata(&self) -> Vec<u8> {
49        let evm_proof: RawEvmProof = self.clone().try_into().unwrap();
50        evm_proof.verifier_calldata()
51    }
52}
53
54impl TryFrom<RawEvmProof> for EvmProof {
55    type Error = EvmProofConversionError;
56
57    fn try_from(evm_proof: RawEvmProof) -> Result<Self, Self::Error> {
58        let RawEvmProof { instances, proof } = evm_proof;
59        if NUM_BN254_ACCUMULATORS + 2 >= instances.len() {
60            return Err(EvmProofConversionError::InvalidLengthInstances);
61        }
62        if proof.len() != NUM_BN254_PROOF * BN254_BYTES {
63            return Err(EvmProofConversionError::InvalidLengthProof);
64        }
65        let accumulators = instances[0..NUM_BN254_ACCUMULATORS]
66            .iter()
67            .flat_map(|f| f.to_bytes())
68            .collect::<Vec<_>>();
69        let exe_commit = instances[NUM_BN254_ACCUMULATORS].to_bytes();
70        let leaf_commit = instances[NUM_BN254_ACCUMULATORS + 1].to_bytes();
71        let user_public_values = instances[NUM_BN254_ACCUMULATORS + 2..]
72            .iter()
73            .flat_map(|f| f.to_bytes())
74            .collect::<Vec<_>>();
75        Ok(Self {
76            accumulators,
77            exe_commit,
78            leaf_commit,
79            user_public_values,
80            proof,
81        })
82    }
83}
84
85impl TryFrom<EvmProof> for RawEvmProof {
86    type Error = EvmProofConversionError;
87    fn try_from(evm_openvm_proof: EvmProof) -> Result<Self, Self::Error> {
88        let EvmProof {
89            accumulators,
90            exe_commit,
91            leaf_commit,
92            user_public_values,
93            proof,
94        } = evm_openvm_proof;
95        if proof.len() != NUM_BN254_PROOF * BN254_BYTES {
96            return Err(EvmProofConversionError::InvalidLengthProof);
97        }
98        let instances = {
99            if accumulators.len() != NUM_BN254_ACCUMULATORS * BN254_BYTES {
100                return Err(EvmProofConversionError::InvalidLengthAccumulators);
101            }
102            if user_public_values.is_empty() || user_public_values.len() % BN254_BYTES != 0 {
103                return Err(EvmProofConversionError::InvalidUserPublicValuesLength);
104            }
105            let mut ret = Vec::new();
106            for chunk in &accumulators
107                .iter()
108                .chain(&exe_commit)
109                .chain(&leaf_commit)
110                .chain(&user_public_values)
111                .chunks(BN254_BYTES)
112            {
113                let c = chunk.copied().collect::<Vec<_>>().try_into().unwrap();
114                ret.push(Fr::from_bytes(&c).unwrap());
115            }
116            ret
117        };
118        Ok(RawEvmProof { instances, proof })
119    }
120}