Repository: openvm-org/openvm
Pull request #1479: refactor: Add type `EvmProof` into openvm-sdk
Author: login: nyunyunyunyu
Labels: name: run-benchmark-e2e
Created: 2025-03-18T21:15:14Z | Merged: 2025-03-19T19:10:36Z

- Rename the existing `EvmProof` into `RawEvmProof`
- Add a more semantic type `EvmProof` into `openvm-sdk`. 
- [Breaking change] Replace all `RawEvmProof` usages in the SDK interface with `EvmProof`
- Serialize `EvmProof` in json instead of `bitcode`. All fields are represented as bytes.

closes INT-3596


Diff:
diff --git a/Cargo.lock b/Cargo.lock
index b85e0fcb1a..590d3fd8d9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4488,7 +4488,10 @@ dependencies = [
  "openvm-stark-sdk",
  "openvm-transpiler",
  "serde",
+ "serde_json",
+ "serde_with",
  "static_assertions",
+ "thiserror 1.0.69",
  "tracing",
 ]
 
diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml
index 9484f6d7dd..4d482658a2 100644
--- a/crates/sdk/Cargo.toml
+++ b/crates/sdk/Cargo.toml
@@ -46,6 +46,9 @@ tracing.workspace = true
 itertools.workspace = true
 getset.workspace = true
 clap = { workspace = true, features = ["derive"] }
+serde_with = { workspace = true, features = ["hex"] }
+serde_json.workspace = true
+thiserror.workspace = true
 
 [features]
 default = ["parallel"]
diff --git a/crates/sdk/src/fs.rs b/crates/sdk/src/fs.rs
index 9ce1640b37..830dc77d57 100644
--- a/crates/sdk/src/fs.rs
+++ b/crates/sdk/src/fs.rs
@@ -1,15 +1,16 @@
 use std::{
-    fs::{create_dir_all, read, write},
+    fs::{create_dir_all, read, write, File},
     path::Path,
 };
 
 use eyre::Result;
 use openvm_circuit::arch::{instructions::exe::VmExe, ContinuationVmProof, VmConfig};
-use openvm_native_recursion::halo2::{wrapper::EvmVerifier, EvmProof};
+use openvm_native_recursion::halo2::wrapper::EvmVerifier;
 use serde::{de::DeserializeOwned, Serialize};
 
 use crate::{
     keygen::{AggProvingKey, AppProvingKey, AppVerifyingKey},
+    types::EvmProof,
     F, SC,
 };
 
@@ -62,11 +63,13 @@ pub fn write_agg_pk_to_file<P: AsRef<Path>>(agg_pk: AggProvingKey, path: P) -> R
 }
 
 pub fn read_evm_proof_from_file<P: AsRef<Path>>(path: P) -> Result<EvmProof> {
-    read_from_file_bitcode(path)
+    let proof: EvmProof = serde_json::from_reader(File::open(path)?)?;
+    Ok(proof)
 }
 
 pub fn write_evm_proof_to_file<P: AsRef<Path>>(proof: EvmProof, path: P) -> Result<()> {
-    write_to_file_bitcode(path, proof)
+    serde_json::to_writer(File::create(path)?, &proof)?;
+    Ok(())
 }
 
 pub fn read_evm_verifier_from_file<P: AsRef<Path>>(path: P) -> Result<EvmVerifier> {
diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs
index f45b86e4c9..33900f7c6c 100644
--- a/crates/sdk/src/lib.rs
+++ b/crates/sdk/src/lib.rs
@@ -26,7 +26,7 @@ pub use openvm_continuations::{
 use openvm_native_recursion::halo2::{
     utils::Halo2ParamsReader,
     wrapper::{EvmVerifier, Halo2WrapperProvingKey},
-    EvmProof,
+    RawEvmProof,
 };
 use openvm_stark_backend::{engine::StarkEngine, proof::Proof};
 use openvm_stark_sdk::{
@@ -54,7 +54,11 @@ pub mod prover;
 
 mod stdin;
 pub use stdin::*;
+
+use crate::types::EvmProof;
+
 pub mod fs;
+pub mod types;
 
 pub type NonRootCommittedExe = VmCommittedExe<SC>;
 
@@ -257,7 +261,8 @@ impl Sdk {
         evm_verifier: &EvmVerifier,
         evm_proof: &EvmProof,
     ) -> Result<u64> {
-        let gas_cost = Halo2WrapperProvingKey::evm_verify(evm_verifier, evm_proof)
+        let evm_proof: RawEvmProof = evm_proof.clone().try_into()?;
+        let gas_cost = Halo2WrapperProvingKey::evm_verify(evm_verifier, &evm_proof)
             .map_err(|reason| eyre::eyre!("Sdk::verify_evm_proof: {reason:?}"))?;
         Ok(gas_cost)
     }
diff --git a/crates/sdk/src/prover/halo2.rs b/crates/sdk/src/prover/halo2.rs
index a5b2377dd3..5cf734d5f8 100644
--- a/crates/sdk/src/prover/halo2.rs
+++ b/crates/sdk/src/prover/halo2.rs
@@ -2,13 +2,14 @@ use std::sync::Arc;
 
 use openvm_native_compiler::prelude::Witness;
 use openvm_native_recursion::{
-    halo2::{utils::Halo2ParamsReader, EvmProof, Halo2Params},
+    halo2::{utils::Halo2ParamsReader, Halo2Params},
     witness::Witnessable,
 };
 use openvm_stark_sdk::openvm_stark_backend::proof::Proof;
 use tracing::info_span;
 
-use crate::{keygen::Halo2ProvingKey, RootSC};
+use crate::{keygen::Halo2ProvingKey, types::EvmProof, RootSC};
+
 pub struct Halo2Prover {
     halo2_pk: Halo2ProvingKey,
     verifier_srs: Arc<Halo2Params>,
@@ -39,6 +40,8 @@ impl Halo2Prover {
             self.halo2_pk
                 .wrapper
                 .prove_for_evm(&self.wrapper_srs, snark)
+                .try_into()
+                .unwrap()
         })
     }
 }
diff --git a/crates/sdk/src/prover/mod.rs b/crates/sdk/src/prover/mod.rs
index b14cb9dfe6..5e4fee43ad 100644
--- a/crates/sdk/src/prover/mod.rs
+++ b/crates/sdk/src/prover/mod.rs
@@ -1,7 +1,6 @@
 use std::sync::Arc;
 
 use openvm_circuit::arch::VmConfig;
-use openvm_native_recursion::halo2::EvmProof;
 use openvm_stark_sdk::openvm_stark_backend::Chip;
 
 use crate::{keygen::AppProvingKey, stdin::StdIn, NonRootCommittedExe, F, SC};
@@ -23,7 +22,7 @@ pub mod vm;
 #[allow(unused_imports)]
 pub use stark::*;
 
-use crate::{keygen::AggProvingKey, prover::halo2::Halo2Prover};
+use crate::{keygen::AggProvingKey, prover::halo2::Halo2Prover, types::EvmProof};
 
 pub struct ContinuationProver<VC> {
     stark_prover: StarkProver<VC>,
diff --git a/crates/sdk/src/types.rs b/crates/sdk/src/types.rs
new file mode 100644
index 0000000000..f46302d106
--- /dev/null
+++ b/crates/sdk/src/types.rs
@@ -0,0 +1,120 @@
+use itertools::Itertools;
+use openvm_native_recursion::halo2::{Fr, RawEvmProof};
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+use thiserror::Error;
+
+/// Number of bytes in a Bn254Fr.
+const BN254_BYTES: usize = 32;
+/// Number of Bn254Fr in `accumulators` field.
+const NUM_BN254_ACCUMULATORS: usize = 12;
+/// Number of Bn254Fr in `proof` field for a circuit with only 1 advice column.
+const NUM_BN254_PROOF: usize = 43;
+
+#[serde_as]
+#[derive(Clone, Deserialize, Serialize)]
+pub struct EvmProof {
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// Bn254Fr public values for accumulators in flatten little-endian bytes. Length is `NUM_BN254_ACCUMULATORS * BN254_BYTES`.
+    pub accumulators: Vec<u8>,
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// 1 Bn254Fr public value for exe commit in little-endian bytes.
+    pub exe_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// 1 Bn254Fr public value for leaf commit in little-endian bytes.
+    pub leaf_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// Bn254Fr user public values in little-endian bytes.
+    pub user_public_values: Vec<u8>,
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// Bn254Fr proof in little-endian bytes. The circuit only has 1 advice column, so the proof is of length `NUM_BN254_PROOF * BN254_BYTES`.
+    pub proof: Vec<u8>,
+}
+
+#[derive(Debug, Error)]
+pub enum EvmProofConversionError {
+    #[error("Invalid length of proof")]
+    InvalidLengthProof,
+    #[error("Invalid length of instances")]
+    InvalidLengthInstances,
+    #[error("Invalid length of user public values")]
+    InvalidUserPublicValuesLength,
+    #[error("Invalid length of accumulators")]
+    InvalidLengthAccumulators,
+}
+
+impl EvmProof {
+    /// Return bytes calldata to be passed to the verifier contract.
+    pub fn verifier_calldata(&self) -> Vec<u8> {
+        let evm_proof: RawEvmProof = self.clone().try_into().unwrap();
+        evm_proof.verifier_calldata()
+    }
+}
+
+impl TryFrom<RawEvmProof> for EvmProof {
+    type Error = EvmProofConversionError;
+
+    fn try_from(evm_proof: RawEvmProof) -> Result<Self, Self::Error> {
+        let RawEvmProof { instances, proof } = evm_proof;
+        if NUM_BN254_ACCUMULATORS + 2 >= instances.len() {
+            return Err(EvmProofConversionError::InvalidLengthInstances);
+        }
+        if proof.len() != NUM_BN254_PROOF * BN254_BYTES {
+            return Err(EvmProofConversionError::InvalidLengthProof);
+        }
+        let accumulators = instances[0..NUM_BN254_ACCUMULATORS]
+            .iter()
+            .flat_map(|f| f.to_bytes())
+            .collect::<Vec<_>>();
+        let exe_commit = instances[NUM_BN254_ACCUMULATORS].to_bytes();
+        let leaf_commit = instances[NUM_BN254_ACCUMULATORS + 1].to_bytes();
+        let user_public_values = instances[NUM_BN254_ACCUMULATORS + 2..]
+            .iter()
+            .flat_map(|f| f.to_bytes())
+            .collect::<Vec<_>>();
+        Ok(Self {
+            accumulators,
+            exe_commit,
+            leaf_commit,
+            user_public_values,
+            proof,
+        })
+    }
+}
+
+impl TryFrom<EvmProof> for RawEvmProof {
+    type Error = EvmProofConversionError;
+    fn try_from(evm_openvm_proof: EvmProof) -> Result<Self, Self::Error> {
+        let EvmProof {
+            accumulators,
+            exe_commit,
+            leaf_commit,
+            user_public_values,
+            proof,
+        } = evm_openvm_proof;
+        if proof.len() != NUM_BN254_PROOF * BN254_BYTES {
+            return Err(EvmProofConversionError::InvalidLengthProof);
+        }
+        let instances = {
+            if accumulators.len() != NUM_BN254_ACCUMULATORS * BN254_BYTES {
+                return Err(EvmProofConversionError::InvalidLengthAccumulators);
+            }
+            if user_public_values.is_empty() || user_public_values.len() % BN254_BYTES != 0 {
+                return Err(EvmProofConversionError::InvalidUserPublicValuesLength);
+            }
+            let mut ret = Vec::new();
+            for chunk in &accumulators
+                .iter()
+                .chain(&exe_commit)
+                .chain(&leaf_commit)
+                .chain(&user_public_values)
+                .chunks(BN254_BYTES)
+            {
+                let c = chunk.copied().collect::<Vec<_>>().try_into().unwrap();
+                ret.push(Fr::from_bytes(&c).unwrap());
+            }
+            ret
+        };
+        Ok(RawEvmProof { instances, proof })
+    }
+}
diff --git a/extensions/native/recursion/src/halo2/mod.rs b/extensions/native/recursion/src/halo2/mod.rs
index a3e402db7f..cca9000214 100644
--- a/extensions/native/recursion/src/halo2/mod.rs
+++ b/extensions/native/recursion/src/halo2/mod.rs
@@ -17,6 +17,7 @@ use openvm_stark_backend::p3_field::extension::BinomialExtensionField;
 use openvm_stark_sdk::{p3_baby_bear::BabyBear, p3_bn254_fr::Bn254Fr};
 use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
 use snark_verifier_sdk::{
+    evm::encode_calldata,
     halo2::{gen_dummy_snark_from_vk, gen_snark_shplonk},
     snark_verifier::halo2_base::{
         gates::{
@@ -25,7 +26,7 @@ use snark_verifier_sdk::{
         },
         halo2_proofs::{
             dev::MockProver,
-            halo2curves::bn256::{Bn256, Fr, G1Affine},
+            halo2curves::bn256::{Bn256, G1Affine},
             plonk::{keygen_pk2, ProvingKey},
             poly::{commitment::Params, kzg::commitment::ParamsKZG},
             SerdeFormat,
@@ -37,14 +38,15 @@ use snark_verifier_sdk::{
 use crate::halo2::utils::Halo2ParamsReader;
 
 pub type Halo2Params = ParamsKZG<Bn256>;
+pub use snark_verifier_sdk::snark_verifier::halo2_base::halo2_proofs::halo2curves::bn256::Fr;
 
 /// A prover that can generate proofs with the Halo2
 #[derive(Debug, Clone)]
 pub struct Halo2Prover;
 
 #[derive(Clone, Deserialize, Serialize)]
-pub struct EvmProof {
-    pub instances: Vec<Vec<Fr>>,
+pub struct RawEvmProof {
+    pub instances: Vec<Fr>,
     pub proof: Vec<u8>,
 }
 
@@ -70,6 +72,13 @@ pub struct Halo2ProvingMetadata {
     pub num_pvs: Vec<usize>,
 }
 
+impl RawEvmProof {
+    /// Return bytes calldata to be passed to the verifier contract.
+    pub fn verifier_calldata(&self) -> Vec<u8> {
+        encode_calldata(&[self.instances.clone()], &self.proof)
+    }
+}
+
 impl Halo2ProvingPinning {
     pub fn generate_dummy_snark(&self, reader: &impl Halo2ParamsReader) -> Snark {
         let k = self.metadata.config_params.k;
diff --git a/extensions/native/recursion/src/halo2/wrapper.rs b/extensions/native/recursion/src/halo2/wrapper.rs
index e8041e66a9..ae95fa5f4f 100644
--- a/extensions/native/recursion/src/halo2/wrapper.rs
+++ b/extensions/native/recursion/src/halo2/wrapper.rs
@@ -16,7 +16,7 @@ use snark_verifier_sdk::{
 
 use crate::halo2::{
     utils::{Halo2ParamsReader, KZG_PARAMS_FOR_SVK},
-    EvmProof, Halo2Params, Halo2ProvingMetadata, Halo2ProvingPinning,
+    Halo2Params, Halo2ProvingMetadata, Halo2ProvingPinning, RawEvmProof,
 };
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -78,10 +78,10 @@ impl Halo2WrapperProvingKey {
         }
     }
     /// A helper function for testing to verify the proof of this circuit with evm verifier.
-    pub fn evm_verify(evm_verifier: &EvmVerifier, evm_proof: &EvmProof) -> Result<u64, String> {
+    pub fn evm_verify(evm_verifier: &EvmVerifier, evm_proof: &RawEvmProof) -> Result<u64, String> {
         evm_verify(
             evm_verifier.0.clone(),
-            evm_proof.instances.clone(),
+            vec![evm_proof.instances.clone()],
             evm_proof.proof.clone(),
         )
     }
@@ -99,18 +99,19 @@ impl Halo2WrapperProvingKey {
             None,
         ))
     }
-    pub fn prove_for_evm(&self, params: &Halo2Params, snark_to_verify: Snark) -> EvmProof {
+    pub fn prove_for_evm(&self, params: &Halo2Params, snark_to_verify: Snark) -> RawEvmProof {
         #[cfg(feature = "bench-metrics")]
         let start = std::time::Instant::now();
         let k = self.pinning.metadata.config_params.k;
         let prover_circuit = self.generate_circuit_object_for_proving(k, snark_to_verify);
-        let pvs = prover_circuit.instances();
+        let mut pvs = prover_circuit.instances();
+        assert_eq!(pvs.len(), 1);
         let proof = gen_evm_proof_shplonk(params, &self.pinning.pk, prover_circuit, pvs.clone());
         #[cfg(feature = "bench-metrics")]
         metrics::gauge!("total_proof_time_ms").set(start.elapsed().as_millis() as f64);
 
-        EvmProof {
-            instances: pvs,
+        RawEvmProof {
+            instances: pvs.pop().unwrap(),
             proof,
         }
     }


Reviews:
user: login: nyunyunyunyu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T21:30:08Z
user: login: jonathanpwang
body: Is it possible to just delete the old `EvmProof` completely, and rename the new one to `EvmProof`?

The lowest level `prove_for_evm` should return the new `EvmProof` struct, doing the necessary parsing and conversions.

The struct can have functions `instances(&self) -> Vec<Fr>` and `partial_proof(&self) -> Vec<u8>` (check with @HrikB on naming of the latter). 
Then it should have a function `.encode_calldata(&self) -> Vec<u8>` to encode the whole thing.

I believe default serialization method for `EvmProof` should ban all usage of bitcode, and serialize the fields as hex string in JSON. There should also be some other option to just serialize the whole thing as one big hex string; again @HrikB may have thoughts here on which is preferrable.

You should also provide a function to clarify how to `decode` from `Vec<u8>` to `EvmProof` with `Result` handling.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T21:49:47Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T00:36:19Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T00:36:45Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T00:38:11Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T00:39:28Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T00:41:08Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T00:41:44Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T00:42:32Z
user: login: jonathanpwang
body: LGTM after comments, but @luffykai should also review
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T00:42:56Z
user: login: luffykai
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T04:52:47Z
user: login: luffykai
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T04:55:50Z

Review comments:
diff_hunk: @@ -61,11 +62,11 @@ pub fn write_agg_pk_to_file<P: AsRef<Path>>(agg_pk: AggProvingKey, path: P) -> R
     write_to_file_bitcode(path, agg_pk)
 }
 
-pub fn read_evm_proof_from_file<P: AsRef<Path>>(path: P) -> Result<EvmProof> {
+pub fn read_evm_proof_from_file<P: AsRef<Path>>(path: P) -> Result<EvmOpenvmProof> {
path: crates/sdk/src/fs.rs
user: login: nyunyunyunyu
body: @luffykai do you want this to be serialized as json with hex strings or keep it as it is?
created_at: 2025-03-18T21:30:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -255,9 +259,10 @@ impl Sdk {
     pub fn verify_evm_proof(
         &self,
         evm_verifier: &EvmVerifier,
-        evm_proof: &EvmProof,
+        evm_openvm_proof: &EvmProof,
path: crates/sdk/src/lib.rs
user: login: jonathanpwang
body: ```suggestion
        evm_proof: &EvmProof,
```
created_at: 2025-03-19T00:36:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -255,9 +259,10 @@ impl Sdk {
     pub fn verify_evm_proof(
         &self,
         evm_verifier: &EvmVerifier,
-        evm_proof: &EvmProof,
+        evm_openvm_proof: &EvmProof,
     ) -> Result<u64> {
-        let gas_cost = Halo2WrapperProvingKey::evm_verify(evm_verifier, evm_proof)
+        let evm_proof: RawEvmProof = evm_openvm_proof.clone().into();
path: crates/sdk/src/lib.rs
user: login: jonathanpwang
body: ```suggestion
        let evm_proof: RawEvmProof = evm_proof.clone().into();
```
created_at: 2025-03-19T00:36:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+use itertools::Itertools;
+use openvm_native_recursion::halo2::{Fr, RawEvmProof};
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+
+const BN254_BYTES: usize = 32;
+const NUM_BN254_ACCUMULATORS: usize = 12;
+const NUM_BN254_PROOF: usize = 43;
path: crates/sdk/src/types.rs
user: login: jonathanpwang
body: note this would change if we changed the wrapper circuit or halo2 in some way
created_at: 2025-03-19T00:38:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+use itertools::Itertools;
+use openvm_native_recursion::halo2::{Fr, RawEvmProof};
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+
+const BN254_BYTES: usize = 32;
+const NUM_BN254_ACCUMULATORS: usize = 12;
+const NUM_BN254_PROOF: usize = 43;
+
+#[serde_as]
+#[derive(Clone, Deserialize, Serialize)]
+pub struct EvmProof {
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub accumulators: Vec<u8>,
path: crates/sdk/src/types.rs
user: login: jonathanpwang
body: can you document the endian-ness of different fields? I remember there was something about instances being big but proof being little
created_at: 2025-03-19T00:39:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+use itertools::Itertools;
+use openvm_native_recursion::halo2::{Fr, RawEvmProof};
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+
+const BN254_BYTES: usize = 32;
+const NUM_BN254_ACCUMULATORS: usize = 12;
+const NUM_BN254_PROOF: usize = 43;
+
+#[serde_as]
+#[derive(Clone, Deserialize, Serialize)]
+pub struct EvmProof {
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub accumulators: Vec<u8>,
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub exe_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub leaf_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub user_public_values: Vec<u8>,
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub proof: Vec<u8>,
+}
+
+impl EvmProof {
+    /// Return bytes calldata to be passed to the verifier contract.
+    pub fn verifier_calldata(&self) -> Vec<u8> {
+        let evm_proof: RawEvmProof = self.clone().into();
+        evm_proof.verifier_calldata()
+    }
+}
+
+impl From<RawEvmProof> for EvmProof {
path: crates/sdk/src/types.rs
user: login: jonathanpwang
body: should we use TryFrom since there are many length asserts?
created_at: 2025-03-19T00:41:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+use itertools::Itertools;
+use openvm_native_recursion::halo2::{Fr, RawEvmProof};
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+
+const BN254_BYTES: usize = 32;
+const NUM_BN254_ACCUMULATORS: usize = 12;
+const NUM_BN254_PROOF: usize = 43;
+
+#[serde_as]
+#[derive(Clone, Deserialize, Serialize)]
+pub struct EvmProof {
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub accumulators: Vec<u8>,
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub exe_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub leaf_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub user_public_values: Vec<u8>,
+    #[serde_as(as = "serde_with::hex::Hex")]
+    pub proof: Vec<u8>,
+}
+
+impl EvmProof {
+    /// Return bytes calldata to be passed to the verifier contract.
+    pub fn verifier_calldata(&self) -> Vec<u8> {
+        let evm_proof: RawEvmProof = self.clone().into();
+        evm_proof.verifier_calldata()
+    }
+}
+
+impl From<RawEvmProof> for EvmProof {
+    fn from(evm_proof: RawEvmProof) -> Self {
+        let RawEvmProof { instances, proof } = evm_proof;
+        assert!(NUM_BN254_ACCUMULATORS + 2 < instances.len());
+        assert_eq!(proof.len(), NUM_BN254_PROOF * BN254_BYTES);
+        let accumulators = instances[0..NUM_BN254_ACCUMULATORS]
+            .iter()
+            .flat_map(|f| f.to_bytes())
+            .collect::<Vec<_>>();
+        let exe_commit = instances[NUM_BN254_ACCUMULATORS].to_bytes();
+        let leaf_commit = instances[NUM_BN254_ACCUMULATORS + 1].to_bytes();
+        let user_public_values = instances[NUM_BN254_ACCUMULATORS + 2..]
+            .iter()
+            .flat_map(|f| f.to_bytes())
+            .collect::<Vec<_>>();
+        Self {
+            accumulators,
+            exe_commit,
+            leaf_commit,
+            user_public_values,
+            proof,
+        }
+    }
+}
+
+impl From<EvmProof> for RawEvmProof {
path: crates/sdk/src/types.rs
user: login: jonathanpwang
body: it seems more ok to use `From` here, but perhaps also consider `TryFrom`
created_at: 2025-03-19T00:41:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -99,18 +99,18 @@ impl Halo2WrapperProvingKey {
             None,
         ))
     }
-    pub fn prove_for_evm(&self, params: &Halo2Params, snark_to_verify: Snark) -> EvmProof {
+    pub fn prove_for_evm(&self, params: &Halo2Params, snark_to_verify: Snark) -> RawEvmProof {
         #[cfg(feature = "bench-metrics")]
         let start = std::time::Instant::now();
         let k = self.pinning.metadata.config_params.k;
         let prover_circuit = self.generate_circuit_object_for_proving(k, snark_to_verify);
-        let pvs = prover_circuit.instances();
+        let mut pvs = prover_circuit.instances();
path: extensions/native/recursion/src/halo2/wrapper.rs
user: login: jonathanpwang
body: assert `pvs.len() == 1` for safety
created_at: 2025-03-19T00:42:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+use itertools::Itertools;
+use openvm_native_recursion::halo2::{Fr, RawEvmProof};
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+
+const BN254_BYTES: usize = 32;
+const NUM_BN254_ACCUMULATORS: usize = 12;
+const NUM_BN254_PROOF: usize = 43;
path: crates/sdk/src/types.rs
user: login: luffykai
body: what does this number mean? maybe add comments to explain
created_at: 2025-03-19T04:52:47Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-18T21:22:15Z
body: <!--Benchmark Results-->
| group | app.proof_time_ms | app.cycles | app.cells_used | leaf.proof_time_ms | leaf.cycles | leaf.cells_used |
| -- | -- | -- | -- | -- | -- | -- |
| [verify_fibair](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/verify_fibair-ee7c3cc045988f47aff29939ec46b9469b7ee4c6.md) |<span style='color: red'>(+4 [+0.3%])</span> 1,242 |  333,982 |  17,901,856 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/fibonacci-ee7c3cc045988f47aff29939ec46b9469b7ee4c6.md) |<span style='color: red'>(+13 [+0.5%])</span> 2,683 |  1,500,096 |  51,485,167 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/regex-ee7c3cc045988f47aff29939ec46b9469b7ee4c6.md) |<span style='color: red'>(+82 [+1.0%])</span> 8,022 |  4,140,164 |  167,389,450 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/ecrecover-ee7c3cc045988f47aff29939ec46b9469b7ee4c6.md) |<span style='color: red'>(+28 [+2.0%])</span> 1,434 |  295,291 |  15,598,160 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/pairing-ee7c3cc045988f47aff29939ec46b9469b7ee4c6.md) |<span style='color: green'>(-62 [-1.3%])</span> 4,721 |  1,711,640 |  92,620,923 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/ee7c3cc045988f47aff29939ec46b9469b7ee4c6

[Benchmark Workflow](https://github.com/openvm-org/openvm/actions/runs/13933634262)

author_association: NONE
user: login: nyunyunyunyu
created_at: 2025-03-18T23:07:36Z
body: > Is it possible to just delete the old `EvmProof` completely, and rename the new one to `EvmProof`?
> 
> The lowest level `prove_for_evm` should return the new `EvmProof` struct, doing the necessary parsing and conversions.
> 
> The struct can have functions `instances(&self) -> Vec<Fr>` and `partial_proof(&self) -> Vec<u8>` (check with @HrikB on naming of the latter). Then it should have a function `.encode_calldata(&self) -> Vec<u8>` to encode the whole thing.
> 
> I believe default serialization method for `EvmProof` should ban all usage of bitcode, and serialize the fields as hex string in JSON. There should also be some other option to just serialize the whole thing as one big hex string; again @HrikB may have thoughts here on which is preferrable.
> 
> You should also provide a function to clarify how to `decode` from `Vec<u8>` to `EvmProof` with `Result` handling.

Discussed offline. We will keep the old `EvmProof` but rename it to `RawEvmProof`.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-18T23:11:49Z
body: <!--Benchmark Results-->
| group | app.proof_time_ms | app.cycles | app.cells_used | leaf.proof_time_ms | leaf.cycles | leaf.cells_used |
| -- | -- | -- | -- | -- | -- | -- |
| [verify_fibair](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/verify_fibair-bde5889c1513b41c83de3cff624e8ca6a3e788c7.md) |<span style='color: red'>(+4 [+0.3%])</span> 1,240 |  334,010 |  17,902,192 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/fibonacci-bde5889c1513b41c83de3cff624e8ca6a3e788c7.md) |<span style='color: green'>(-10 [-0.4%])</span> 2,679 |  1,500,096 |  51,485,167 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/regex-bde5889c1513b41c83de3cff624e8ca6a3e788c7.md) |<span style='color: red'>(+63 [+0.8%])</span> 8,043 |  4,140,164 |  167,389,450 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/ecrecover-bde5889c1513b41c83de3cff624e8ca6a3e788c7.md) |<span style='color: green'>(-18 [-1.3%])</span> 1,416 |  295,291 |  15,598,160 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/pairing-bde5889c1513b41c83de3cff624e8ca6a3e788c7.md) | 4,721 |  1,711,640 |  92,620,923 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/bde5889c1513b41c83de3cff624e8ca6a3e788c7

[Benchmark Workflow](https://github.com/openvm-org/openvm/actions/runs/13935159724)

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-18T23:48:15Z
body: <!--Benchmark Results-->
| group | app.proof_time_ms | app.cycles | app.cells_used | leaf.proof_time_ms | leaf.cycles | leaf.cells_used |
| -- | -- | -- | -- | -- | -- | -- |
| [verify_fibair](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/verify_fibair-5f750e8bc90c97bff23274f4527d0b6dc6e54a39.md) |<span style='color: red'>(+2 [+0.2%])</span> 1,238 |  334,118 |  17,903,488 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/fibonacci-5f750e8bc90c97bff23274f4527d0b6dc6e54a39.md) |<span style='color: red'>(+10 [+0.4%])</span> 2,699 |  1,500,096 |  51,485,167 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/regex-5f750e8bc90c97bff23274f4527d0b6dc6e54a39.md) |<span style='color: red'>(+63 [+0.8%])</span> 8,043 |  4,140,164 |  167,389,450 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/ecrecover-5f750e8bc90c97bff23274f4527d0b6dc6e54a39.md) |<span style='color: red'>(+18 [+1.3%])</span> 1,452 |  295,291 |  15,598,160 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/pairing-5f750e8bc90c97bff23274f4527d0b6dc6e54a39.md) |<span style='color: green'>(-24 [-0.5%])</span> 4,697 |  1,711,640 |  92,620,923 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/5f750e8bc90c97bff23274f4527d0b6dc6e54a39

[Benchmark Workflow](https://github.com/openvm-org/openvm/actions/runs/13935409597)

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-19T00:48:57Z
body: <!--Benchmark Results-->
| group | app.proof_time_ms | app.cycles | app.cells_used | leaf.proof_time_ms | leaf.cycles | leaf.cells_used |
| -- | -- | -- | -- | -- | -- | -- |
| [verify_fibair](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/verify_fibair-e196c518938636aa35c90726766df29a37658761.md) |<span style='color: green'>(-4 [-0.3%])</span> 1,232 |  334,045 |  17,902,612 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/fibonacci-e196c518938636aa35c90726766df29a37658761.md) |<span style='color: green'>(-4 [-0.1%])</span> 2,685 |  1,500,096 |  51,485,167 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/regex-e196c518938636aa35c90726766df29a37658761.md) |<span style='color: green'>(-53 [-0.7%])</span> 7,927 |  4,140,164 |  167,389,450 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/ecrecover-e196c518938636aa35c90726766df29a37658761.md) |<span style='color: red'>(+6 [+0.4%])</span> 1,440 |  295,291 |  15,598,160 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/pairing-e196c518938636aa35c90726766df29a37658761.md) |<span style='color: green'>(-46 [-1.0%])</span> 4,675 |  1,711,640 |  92,620,923 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/e196c518938636aa35c90726766df29a37658761

[Benchmark Workflow](https://github.com/openvm-org/openvm/actions/runs/13936319093)

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-19T18:38:17Z
body: <!--Benchmark Results-->
| group | app.proof_time_ms | app.cycles | app.cells_used | leaf.proof_time_ms | leaf.cycles | leaf.cells_used |
| -- | -- | -- | -- | -- | -- | -- |
| [verify_fibair](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/verify_fibair-04ff60660bcdcb294d300bc053b22a70d8ef09d5.md) |<span style='color: red'>(+13 [+1.1%])</span> 1,240 |  334,086 |  17,903,104 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/fibonacci-04ff60660bcdcb294d300bc053b22a70d8ef09d5.md) |<span style='color: red'>(+7 [+0.3%])</span> 2,662 |  1,500,096 |  51,485,167 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/regex-04ff60660bcdcb294d300bc053b22a70d8ef09d5.md) |<span style='color: red'>(+430 [+5.6%])</span> 8,106 |  4,140,164 |  167,389,450 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/ecrecover-04ff60660bcdcb294d300bc053b22a70d8ef09d5.md) |<span style='color: green'>(-4 [-0.3%])</span> 1,407 |  295,291 |  15,598,160 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/pairing-04ff60660bcdcb294d300bc053b22a70d8ef09d5.md) |<span style='color: red'>(+81 [+1.7%])</span> 4,753 |  1,711,640 |  92,620,923 |- | - | - |
| [fib_e2e](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/fib_e2e-04ff60660bcdcb294d300bc053b22a70d8ef09d5.md) | 18,979 |  12,000,096 |  410,692,061 | 23,394 |  7,618,726 |  429,078,885 |
| [kitchen_sink](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/kitchen_sink-04ff60660bcdcb294d300bc053b22a70d8ef09d5.md) | 21,931 |  99,743 |  901,865,748 | 42,598 |  10,549,828 |  933,240,489 |


Commit: https://github.com/openvm-org/openvm/commit/04ff60660bcdcb294d300bc053b22a70d8ef09d5

[Benchmark Workflow](https://github.com/openvm-org/openvm/actions/runs/13953953223)

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-19T18:59:18Z
body: <!--Benchmark Results-->
| group | app.proof_time_ms | app.cycles | app.cells_used | leaf.proof_time_ms | leaf.cycles | leaf.cells_used |
| -- | -- | -- | -- | -- | -- | -- |
| [verify_fibair](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/verify_fibair-bef146f83782d1b3bf2398b7e84a2cf74c0c6e2f.md) | 1,227 |  334,048 |  17,902,648 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/fibonacci-bef146f83782d1b3bf2398b7e84a2cf74c0c6e2f.md) |<span style='color: red'>(+28 [+1.1%])</span> 2,683 |  1,500,096 |  51,485,167 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/regex-bef146f83782d1b3bf2398b7e84a2cf74c0c6e2f.md) |<span style='color: red'>(+298 [+3.9%])</span> 7,974 |  4,140,164 |  167,389,450 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/ecrecover-bef146f83782d1b3bf2398b7e84a2cf74c0c6e2f.md) |<span style='color: red'>(+19 [+1.3%])</span> 1,430 |  295,291 |  15,598,160 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/pairing-bef146f83782d1b3bf2398b7e84a2cf74c0c6e2f.md) |<span style='color: red'>(+7 [+0.1%])</span> 4,679 |  1,711,640 |  92,620,923 |- | - | - |
| [fib_e2e](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/fib_e2e-bef146f83782d1b3bf2398b7e84a2cf74c0c6e2f.md) | 19,120 |  12,000,096 |  410,692,061 | 23,580 |  7,618,851 |  429,080,385 |
| [kitchen_sink](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1479/kitchen_sink-bef146f83782d1b3bf2398b7e84a2cf74c0c6e2f.md) | 21,886 |  99,743 |  901,865,748 | 42,886 |  10,549,865 |  933,240,933 |


Commit: https://github.com/openvm-org/openvm/commit/bef146f83782d1b3bf2398b7e84a2cf74c0c6e2f

[Benchmark Workflow](https://github.com/openvm-org/openvm/actions/runs/13954348518)

author_association: NONE