Repository: openvm-org/openvm
Pull request #1578: chore: alter json format of proof to align with verifier contract
Author: login: HrikB
Created: 2025-04-15T01:17:42Z | Merged: 2025-04-15T17:29:31Z

This PR alters the JSON proof outputted by `cargo openvm prove` to conform to the format of the verifier contract.




Diff:
diff --git a/Cargo.lock b/Cargo.lock
index eaa9e308bb..8f25ddd70d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4200,7 +4200,6 @@ dependencies = [
 name = "openvm-sdk"
 version = "1.0.0"
 dependencies = [
- "alloy-primitives",
  "alloy-sol-types",
  "async-trait",
  "bitcode",
@@ -6278,9 +6277,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.43.1"
+version = "1.44.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "492a604e2fd7f814268a378409e6c92b5525d747d10db9a229723f55a417958c"
+checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
 dependencies = [
  "backtrace",
  "bytes",
diff --git a/Cargo.toml b/Cargo.toml
index 46af9b21c7..374f84b299 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -188,7 +188,6 @@ snark-verifier = { version = "0.2.0", default-features = false }
 halo2curves-axiom = "0.7.0"
 
 cargo_metadata = "0.18"
-alloy-primitives = "0.8.25"
 alloy-sol-types = "0.8.25"
 tracing = "0.1.40"
 bon = "3.2.0"
diff --git a/book/src/writing-apps/verify.md b/book/src/writing-apps/verify.md
index 4a4f4b0dc3..846a30b2fa 100644
--- a/book/src/writing-apps/verify.md
+++ b/book/src/writing-apps/verify.md
@@ -48,13 +48,24 @@ This command can take ~20mins on a `m6a.16xlarge` instance due to the keygen tim
 Upon a successful run, the command will write the files
 
 - `agg.pk`
-- `verifier.sol`
-- `verifier.bytecode.json`
+- `halo2/Halo2Verifier.sol`
+- `halo2/OpenVmHalo2Verifier.sol`
+- `halo2/interfaces/IOpenVmHalo2Verifier.sol`
+- `halo2/verifier.bytecode.json`
 
 to `~/.openvm/`, where `~` is the directory specified by environment variable `$HOME`. Every command that requires these files will look for them in this directory.
 
 The `agg.pk` contains all aggregation proving keys necessary for aggregating to a final EVM proof.
-The `verifier.sol` file contains a Solidity contract to verify the final EVM proof. The contract is named `Halo2Verifier` and proof verification is the fallback function of the contract.
+The `OpenVmHalo2Verifier.sol` file contains a Solidity contract to verify the final EVM proof. The contract is named `OpenVmHalo2Verifier` and it implements the `IOpenVmHalo2Verifier` interface.
+
+```solidity
+interface IOpenVmHalo2Verifier {
+    function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit)
+        external
+        view;
+}
+```
+
 In addition, the command outputs a JSON file `verifier.bytecode.json` of the form
 
 ```json
@@ -92,30 +103,26 @@ The EVM proof is written to `evm.proof` as a JSON of the following format:
 
 ```json
 {
-  "accumulators": "0x..",
-  "exe_commit": "0x..",
-  "leaf_commit": "0x..",
+  "app_exe_commit": "0x..",
+  "app_vm_commit": "0x..",
   "user_public_values": "0x..",
-  "proof": "0x.."
+  "proof_data": {
+    "accumulator": "0x..",
+    "proof": "0x.."
+  },
 }
 ```
 
 where each field is a hex string. We explain what each field represents:
 
-- `accumulators`: `12 * 32` bytes representing the KZG accumulator of the proof, where the proof is from a SNARK using the KZG commitment scheme.
-- `exe_commit`: `32` bytes for the commitment of the app executable.
-- `leaf_commit`: `32` bytes for the commitment of the executable verifying app VM proofs.
+- `app_exe_commit`: `32` bytes for the commitment of the app executable.
+- `app_vm_commit`: `32` bytes for the commitment of the app VM configuration.
 - `user_public_values`: concatenation of 32 byte chunks for user public values. The number of user public values is a configuration parameter.
+- `accumulator`: `12 * 32` bytes representing the KZG accumulator of the proof, where the proof is from a SNARK using the KZG commitment scheme.
 - `proof`: The rest of the proof required by the SNARK as a hex string of `43 * 32` bytes.
 
 ### EVM Proof: Calldata Format
 
 The `cargo openvm verify evm` command reads the EVM proof from JSON file and then simulates the call to the verifier contract using [Revm](https://github.com/bluealloy/revm/tree/main). This function should only be used for testing and development purposes but not for production.
 
-To verify the EVM proof in an EVM execution environment, the EVM proof must be formatted into calldata bytes and sent to the fallback function of the verifier smart contract. The calldata bytes are formed by concatenating the fields of the EVM proof described above in the following order and format:
-
-1. `accumulators`: every `32` bytes are _reversed_ from little endian to big endian and concatenated.
-2. `exe_commit`: the `32` bytes are _reversed_ from little endian to big endian.
-3. `leaf_commit`: the `32` bytes are _reversed_ from little endian to big endian.
-4. `user_public_values`: every `32` bytes are _reversed_ from little endian to big endian and concatenated.
-5. `proof`: The rest of the proof is treated as raw bytes and concatenated.
+To verify the EVM proof in an EVM execution environment, the entries of the JSON can be passed as function arguments for the `verify` function, where the `proofData` argument is constructed by `proofData = abi.encodePacked(accumulator, proof)`.
diff --git a/crates/cli/src/commands/verify.rs b/crates/cli/src/commands/verify.rs
index 6651f3a7f4..41a1f397cc 100644
--- a/crates/cli/src/commands/verify.rs
+++ b/crates/cli/src/commands/verify.rs
@@ -51,7 +51,7 @@ impl VerifyCmd {
                     eyre::eyre!("Failed to read EVM verifier: {}\nPlease run 'cargo openvm evm-proving-setup' first", e)
                 })?;
                 let evm_proof = read_evm_proof_from_file(proof)?;
-                sdk.verify_evm_halo2_proof(&evm_verifier, &evm_proof)?;
+                sdk.verify_evm_halo2_proof(&evm_verifier, evm_proof)?;
             }
         }
         Ok(())
diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml
index ea687ca7c7..5a8e3b0060 100644
--- a/crates/sdk/Cargo.toml
+++ b/crates/sdk/Cargo.toml
@@ -34,7 +34,6 @@ openvm-circuit = { workspace = true }
 openvm-continuations = { workspace = true }
 openvm = { workspace = true }
 
-alloy-primitives = { workspace = true, optional = true }
 alloy-sol-types = { workspace = true, optional = true, features = ["json"] }
 bitcode = { workspace = true }
 bon = { workspace = true }
@@ -62,7 +61,6 @@ evm-prove = ["openvm-native-recursion/evm-prove"]
 evm-verify = [
     "evm-prove",
     "openvm-native-recursion/evm-verify",
-    "dep:alloy-primitives",
     "dep:alloy-sol-types",
 ]
 bench-metrics = [
diff --git a/crates/sdk/contracts/template/OpenVmHalo2Verifier.sol b/crates/sdk/contracts/template/OpenVmHalo2Verifier.sol
index f82d641fc5..581683af82 100644
--- a/crates/sdk/contracts/template/OpenVmHalo2Verifier.sol
+++ b/crates/sdk/contracts/template/OpenVmHalo2Verifier.sol
@@ -35,7 +35,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
     /// use with the `snark-verifier` verification.
     ///
     /// @dev The verifier expected proof format is:
-    /// proof[..12 * 32]: KZG accumulators
+    /// proof[..12 * 32]: KZG accumulator
     /// proof[12 * 32..13 * 32]: app exe commit
     /// proof[13 * 32..14 * 32]: app vm commit
     /// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValues[0..PUBLIC_VALUES_LENGTH]
@@ -44,7 +44,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
     /// @param publicValues The PVs revealed by the OpenVM guest program.
     /// @param proofData All components of the proof except the public values and
     /// app exe and vm commits. The expected format is:
-    /// `abi.encodePacked(kzgAccumulators, proofSuffix)`
+    /// `abi.encodePacked(kzgAccumulator, proofSuffix)`
     /// @param appExeCommit The commitment to the OpenVM application executable whose execution
     /// is being verified.
     /// @param appVmCommit The commitment to the VM configuration.
@@ -95,7 +95,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
 
         // The expected proof format using hex offsets:
         //
-        // proof[..0x180]: KZG accumulators
+        // proof[..0x180]: KZG accumulator
         // proof[0x180..0x1a0]: app exe commit
         // proof[0x1a0..0x1c0]: app vm commit
         // proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValues[0..PUBLIC_VALUES_LENGTH]
@@ -107,7 +107,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
             // Allocate the memory as a safety measure.
             mstore(0x40, add(proofPtr, fullProofLength))
 
-            // Copy the KZG accumulators (length 0x180) into the beginning of
+            // Copy the KZG accumulator (length 0x180) into the beginning of
             // the memory buffer
             calldatacopy(proofPtr, proofData.offset, 0x180)
 
@@ -119,7 +119,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
             // end of the memory buffer, leaving PUBLIC_VALUES_LENGTH words in
             // between for the publicValuesPayload.
             //
-            // Begin copying from the end of the KZG accumulators in the
+            // Begin copying from the end of the KZG accumulator in the
             // calldata buffer (0x180)
             let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH))
             calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560)
diff --git a/crates/sdk/contracts/test/OpenVmHalo2Verifier.t.sol b/crates/sdk/contracts/test/OpenVmHalo2Verifier.t.sol
index 3b57df9829..2547ba181c 100644
--- a/crates/sdk/contracts/test/OpenVmHalo2Verifier.t.sol
+++ b/crates/sdk/contracts/test/OpenVmHalo2Verifier.t.sol
@@ -52,9 +52,9 @@ contract TemplateTest is Test {
 
         uint256 proofSuffixOffset = 0x1c0 + (32 * publicValuesLength);
 
-        bytes memory kzgAccumulators = proof[0:0x180];
+        bytes memory kzgAccumulator = proof[0:0x180];
         bytes memory proofSuffix = proof[proofSuffixOffset:];
-        bytes memory _proofData = abi.encodePacked(kzgAccumulators, proofSuffix);
+        bytes memory _proofData = abi.encodePacked(kzgAccumulator, proofSuffix);
 
         require(keccak256(_proofData) == keccak256(proofDataExpected), "Partial proof mismatch");
 
diff --git a/crates/sdk/examples/sdk_evm.rs b/crates/sdk/examples/sdk_evm.rs
index 5df7af44db..7126870550 100644
--- a/crates/sdk/examples/sdk_evm.rs
+++ b/crates/sdk/examples/sdk_evm.rs
@@ -108,7 +108,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
     )?;
 
     // 11. Verify the EVM proof
-    sdk.verify_evm_halo2_proof(&verifier, &proof)?;
+    sdk.verify_evm_halo2_proof(&verifier, proof)?;
     // ANCHOR_END: evm_verification
 
     Ok(())
diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs
index 1af33d86fc..a942a0f243 100644
--- a/crates/sdk/src/lib.rs
+++ b/crates/sdk/src/lib.rs
@@ -1,10 +1,11 @@
 use std::{fs::read, marker::PhantomData, path::Path, sync::Arc};
 
 #[cfg(feature = "evm-verify")]
-use alloy_primitives::{Bytes, FixedBytes};
-#[cfg(feature = "evm-verify")]
-use alloy_sol_types::{sol, SolCall, SolValue};
+use alloy_sol_types::sol;
+use commit::commit_app_exe;
+use config::{AggregationTreeConfig, AppConfig};
 use eyre::Result;
+use keygen::{AppProvingKey, AppVerifyingKey};
 use openvm_build::{
     build_guest_package, find_unique_executable, get_package, GuestOptions, TargetFilter,
 };
@@ -41,9 +42,8 @@ use openvm_transpiler::{
 use snark_verifier_sdk::{evm::gen_evm_verifier_sol_code, halo2::aggregation::AggregationCircuit};
 
 use crate::{
-    commit::commit_app_exe,
-    config::{AggConfig, AggregationTreeConfig, AppConfig},
-    keygen::{AggProvingKey, AggStarkProvingKey, AppProvingKey, AppVerifyingKey},
+    config::AggConfig,
+    keygen::{AggProvingKey, AggStarkProvingKey},
     prover::{AppProver, StarkProver},
 };
 #[cfg(feature = "evm-prove")]
@@ -327,7 +327,7 @@ impl<E: StarkFriEngine<SC>> GenericSdk<E> {
 
         let wrapper_pvs = agg_pk.halo2_pk.wrapper.pinning.metadata.num_pvs.clone();
         let pvs_length = match wrapper_pvs.first() {
-            // We subtract 14 to exclude the KZG accumulators and the app exe
+            // We subtract 14 to exclude the KZG accumulator and the app exe
             // and vm commits.
             Some(v) => v
                 .checked_sub(14)
@@ -411,55 +411,9 @@ impl<E: StarkFriEngine<SC>> GenericSdk<E> {
     pub fn verify_evm_halo2_proof(
         &self,
         openvm_verifier: &types::EvmHalo2Verifier,
-        evm_proof: &EvmProof,
+        evm_proof: EvmProof,
     ) -> Result<u64> {
-        use crate::types::NUM_BN254_ACCUMULATORS;
-
-        let EvmProof {
-            accumulators,
-            proof,
-            user_public_values,
-            exe_commit,
-            leaf_commit,
-        } = evm_proof;
-        let mut exe_commit = *exe_commit;
-        let mut leaf_commit = *leaf_commit;
-        exe_commit.reverse();
-        leaf_commit.reverse();
-
-        assert_eq!(accumulators.len(), NUM_BN254_ACCUMULATORS * 32);
-        let mut evm_accumulators: Vec<u8> = Vec::with_capacity(accumulators.len());
-        accumulators
-            .chunks(32)
-            .for_each(|chunk| evm_accumulators.extend(chunk.iter().rev().cloned()));
-
-        let mut proof_data = evm_accumulators;
-        proof_data.extend(proof);
-
-        assert!(
-            user_public_values.len() % 32 == 0,
-            "User public values length must be a multiple of 32"
-        );
-
-        // Take the first byte of each 32 byte chunk, and pack them together
-        // into one payload.
-        let user_public_values: Bytes =
-            user_public_values
-                .chunks(32)
-                .fold(Vec::<u8>::new().into(), |acc: Bytes, chunk| {
-                    // We only care about the first byte, everything else should be 0-bytes
-                    (acc, FixedBytes::<1>::from(*chunk.first().unwrap()))
-                        .abi_encode_packed()
-                        .into()
-                });
-
-        let calldata = IOpenVmHalo2Verifier::verifyCall {
-            publicValues: user_public_values.clone(),
-            proofData: proof_data.into(),
-            appExeCommit: exe_commit.into(),
-            appVmCommit: leaf_commit.into(),
-        }
-        .abi_encode();
+        let calldata = evm_proof.verifier_calldata();
         let deployment_code = openvm_verifier.artifact.bytecode.clone();
 
         let gas_cost = snark_verifier::loader::evm::deploy_and_call(deployment_code, calldata)
diff --git a/crates/sdk/src/types.rs b/crates/sdk/src/types.rs
index c4c6abcfbe..f305505bef 100644
--- a/crates/sdk/src/types.rs
+++ b/crates/sdk/src/types.rs
@@ -1,3 +1,5 @@
+use std::iter::{once, repeat};
+
 use itertools::Itertools;
 use openvm_native_recursion::halo2::{wrapper::EvmVerifierByteCode, Fr, RawEvmProof};
 use serde::{Deserialize, Serialize};
@@ -6,8 +8,8 @@ use thiserror::Error;
 
 /// Number of bytes in a Bn254Fr.
 const BN254_BYTES: usize = 32;
-/// Number of Bn254Fr in `accumulators` field.
-pub const NUM_BN254_ACCUMULATORS: usize = 12;
+/// Number of Bn254Fr in `accumulator` field.
+pub const NUM_BN254_ACCUMULATOR: usize = 12;
 /// Number of Bn254Fr in `proof` field for a circuit with only 1 advice column.
 const NUM_BN254_PROOF: usize = 43;
 
@@ -21,26 +23,32 @@ pub struct EvmHalo2Verifier {
 
 #[serde_as]
 #[derive(Clone, Debug, 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],
+pub struct ProofData {
     #[serde_as(as = "serde_with::hex::Hex")]
-    /// Bn254Fr user public values in little-endian bytes.
-    pub user_public_values: Vec<u8>,
+    /// KZG accumulator.
+    pub accumulator: 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>,
 }
 
+#[serde_as]
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct EvmProof {
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// 1 Bn254Fr public value for app exe commit in big-endian bytes.
+    pub app_exe_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// 1 Bn254Fr public value for app vm commit in big-endian bytes.
+    pub app_vm_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// User public values packed into bytes.
+    pub user_public_values: Vec<u8>,
+    /// The concatenation of `accumulator` and `proof`.
+    pub proof_data: ProofData,
+}
+
 #[derive(Debug, Error)]
 pub enum EvmProofConversionError {
     #[error("Invalid length of proof")]
@@ -49,14 +57,41 @@ pub enum EvmProofConversionError {
     InvalidLengthInstances,
     #[error("Invalid length of user public values")]
     InvalidUserPublicValuesLength,
-    #[error("Invalid length of accumulators")]
-    InvalidLengthAccumulators,
+    #[error("Invalid length of accumulator")]
+    InvalidLengthAccumulator,
 }
 
 impl EvmProof {
-    #[cfg(feature = "evm-prove")]
+    #[cfg(feature = "evm-verify")]
     /// Return bytes calldata to be passed to the verifier contract.
-    pub fn verifier_calldata(&self) -> Vec<u8> {
+    pub fn verifier_calldata(self) -> Vec<u8> {
+        use alloy_sol_types::SolCall;
+
+        use crate::IOpenVmHalo2Verifier;
+
+        let EvmProof {
+            user_public_values,
+            app_exe_commit,
+            app_vm_commit,
+            proof_data,
+        } = self;
+
+        let ProofData { accumulator, proof } = proof_data;
+
+        let mut proof_data = accumulator;
+        proof_data.extend(proof);
+
+        IOpenVmHalo2Verifier::verifyCall {
+            publicValues: user_public_values.into(),
+            proofData: proof_data.into(),
+            appExeCommit: app_exe_commit.into(),
+            appVmCommit: app_vm_commit.into(),
+        }
+        .abi_encode()
+    }
+
+    #[cfg(feature = "evm-verify")]
+    pub fn fallback_calldata(&self) -> Vec<u8> {
         let evm_proof: RawEvmProof = self.clone().try_into().unwrap();
         evm_proof.verifier_calldata()
     }
@@ -67,28 +102,43 @@ impl TryFrom<RawEvmProof> for EvmProof {
 
     fn try_from(evm_proof: RawEvmProof) -> Result<Self, Self::Error> {
         let RawEvmProof { instances, proof } = evm_proof;
-        if NUM_BN254_ACCUMULATORS + 2 >= instances.len() {
+        if NUM_BN254_ACCUMULATOR + 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..]
+        let accumulator = instances[0..NUM_BN254_ACCUMULATOR]
             .iter()
             .flat_map(|f| f.to_bytes())
             .collect::<Vec<_>>();
+        let mut app_exe_commit = instances[NUM_BN254_ACCUMULATOR].to_bytes();
+        let mut app_vm_commit = instances[NUM_BN254_ACCUMULATOR + 1].to_bytes();
+        app_exe_commit.reverse();
+        app_vm_commit.reverse();
+
+        let mut evm_accumulator: Vec<u8> = Vec::with_capacity(accumulator.len());
+        accumulator
+            .chunks(32)
+            .for_each(|chunk| evm_accumulator.extend(chunk.iter().rev().cloned()));
+
+        let user_public_values = instances[NUM_BN254_ACCUMULATOR + 2..].iter().fold(
+            Vec::<u8>::new(),
+            |mut acc: Vec<u8>, chunk| {
+                // We only care about the first byte, everything else should be 0-bytes
+                acc.push(*chunk.to_bytes().first().unwrap());
+                acc
+            },
+        );
+
         Ok(Self {
-            accumulators,
-            exe_commit,
-            leaf_commit,
+            app_exe_commit,
+            app_vm_commit,
             user_public_values,
-            proof,
+            proof_data: ProofData {
+                accumulator: evm_accumulator,
+                proof,
+            },
         })
     }
 }
@@ -97,27 +147,44 @@ 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,
+            mut app_exe_commit,
+            mut app_vm_commit,
             user_public_values,
-            proof,
+            proof_data,
         } = evm_openvm_proof;
+
+        app_exe_commit.reverse();
+        app_vm_commit.reverse();
+
+        let ProofData { accumulator, proof } = proof_data;
+
         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 accumulator.len() != NUM_BN254_ACCUMULATOR * BN254_BYTES {
+                return Err(EvmProofConversionError::InvalidLengthAccumulator);
             }
-            if user_public_values.is_empty() || user_public_values.len() % BN254_BYTES != 0 {
+
+            let mut reversed_accumulator: Vec<u8> = Vec::with_capacity(accumulator.len());
+            accumulator
+                .chunks(32)
+                .for_each(|chunk| reversed_accumulator.extend(chunk.iter().rev().cloned()));
+
+            if user_public_values.is_empty() {
                 return Err(EvmProofConversionError::InvalidUserPublicValuesLength);
             }
+
+            let user_public_values = user_public_values
+                .into_iter()
+                .flat_map(|byte| once(byte).chain(repeat(0).take(31)))
+                .collect::<Vec<_>>();
+
             let mut ret = Vec::new();
-            for chunk in &accumulators
+            for chunk in &reversed_accumulator
                 .iter()
-                .chain(&exe_commit)
-                .chain(&leaf_commit)
+                .chain(&app_exe_commit)
+                .chain(&app_vm_commit)
                 .chain(&user_public_values)
                 .chunks(BN254_BYTES)
             {
diff --git a/crates/sdk/tests/integration_test.rs b/crates/sdk/tests/integration_test.rs
index 708ba43bac..1968f1c1da 100644
--- a/crates/sdk/tests/integration_test.rs
+++ b/crates/sdk/tests/integration_test.rs
@@ -457,7 +457,7 @@ fn test_e2e_proof_generation_and_verification_with_pvs() {
         .unwrap();
 
     verify_evm_halo2_proof_with_fallback(&evm_verifier, &evm_proof).unwrap();
-    sdk.verify_evm_halo2_proof(&evm_verifier, &evm_proof)
+    sdk.verify_evm_halo2_proof(&evm_verifier, evm_proof)
         .unwrap();
 }
 
diff --git a/docs/specs/continuations.md b/docs/specs/continuations.md
index 7d61380093..b37c300986 100644
--- a/docs/specs/continuations.md
+++ b/docs/specs/continuations.md
@@ -30,7 +30,7 @@ wrapper is determined by the following parameters:
 - The Aggregation VM chip constraints (but **not** the App VM chips)
 
 Public values:
-- `accumulators`: `12 * 32` bytes representing the KZG accumulator of the SNARK proof.
+- `accumulator`: `12 * 32` bytes representing the KZG accumulator of the SNARK proof.
 - `exe_commit`: one `Bn254Fr` element (as `32` bytes) for the commitment of the app executable.
 - `leaf_commit`: one `Bn254Fr` element (as `32` bytes) for the commitment of the executable verifying app VM proofs.
 - `user_public_values`: sequence of `num_public_values` user-defined public values, each as a `Bn254Fr` element (`32` bytes). The number of user public values is a VM configuration parameter.
diff --git a/extensions/native/recursion/src/fri/two_adic_pcs.rs b/extensions/native/recursion/src/fri/two_adic_pcs.rs
index a6527482f1..0814603fba 100644
--- a/extensions/native/recursion/src/fri/two_adic_pcs.rs
+++ b/extensions/native/recursion/src/fri/two_adic_pcs.rs
@@ -150,7 +150,7 @@ pub fn verify_two_adic_pcs<C: Config>(
     };
     builder.cycle_tracker_end("pre-compute-rounds-context");
 
-    // Accumulators of the reduced opening sums, reset per query. The array `ro` is indexed by
+    // Accumulator of the reduced opening sums, reset per query. The array `ro` is indexed by
     // log_height.
     let ro: Array<C, Ext<C::F, C::EF>> = builder.array(MAX_TWO_ADICITY + 1);
     let alpha_pow: Array<C, Ext<C::F, C::EF>> = builder.array(MAX_TWO_ADICITY + 1);
@@ -159,7 +159,7 @@ pub fn verify_two_adic_pcs<C: Config>(
         let query_proof = builder.iter_ptr_get(&proof.query_proofs, ptr_vec[0]);
         let index_bits = challenger.sample_bits(builder, log_max_lde_height);
 
-        // We reset the reduced opening accumulators at the start of each query.
+        // We reset the reduced opening accumulator at the start of each query.
         // We describe what `ro[log_height]` computes per query in pseduo-code, where `log_height`
         // is log2 of the size of the LDE domain: ro[log_height] = 0
         // alpha_pow[log_height] = 1


Reviews:
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:13:15Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:14:27Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:14:33Z
user: login: jonathanpwang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:15:08Z
user: login: jonathanpwang
body: lgtm but check the endian-ness, both in documentation and implementation
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:15:28Z
user: login: HrikB
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:49:29Z

Review comments:
diff_hunk: @@ -92,30 +103,26 @@ The EVM proof is written to `evm.proof` as a JSON of the following format:
 
 ```json
 {
-  "accumulators": "0x..",
-  "exe_commit": "0x..",
-  "leaf_commit": "0x..",
+  "app_exe_commit": "0x..",
+  "app_vm_commit": "0x..",
   "user_public_values": "0x..",
-  "proof": "0x.."
+  "proof_data": {
+    "accumulators": "0x..",
path: book/src/writing-apps/verify.md
user: login: jonathanpwang
body: I realized it's just one KZG accumulator, so it's `accumulator` not `accumulators`
created_at: 2025-04-15T16:13:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -21,26 +23,32 @@ pub struct EvmHalo2Verifier {
 
 #[serde_as]
 #[derive(Clone, Debug, Deserialize, Serialize)]
-pub struct EvmProof {
+pub struct ProofData {
     #[serde_as(as = "serde_with::hex::Hex")]
-    /// Bn254Fr public values for accumulators in flatten little-endian bytes. Length is
-    /// `NUM_BN254_ACCUMULATORS * BN254_BYTES`.
+    /// KZG accumulators.
     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>,
 }
 
+#[serde_as]
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct EvmProof {
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// 1 Bn254Fr public value for app exe commit in little-endian bytes.
path: crates/sdk/src/types.rs
user: login: jonathanpwang
body: I think you switched it to big endian?
created_at: 2025-04-15T16:14:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -21,26 +23,32 @@ pub struct EvmHalo2Verifier {
 
 #[serde_as]
 #[derive(Clone, Debug, Deserialize, Serialize)]
-pub struct EvmProof {
+pub struct ProofData {
     #[serde_as(as = "serde_with::hex::Hex")]
-    /// Bn254Fr public values for accumulators in flatten little-endian bytes. Length is
-    /// `NUM_BN254_ACCUMULATORS * BN254_BYTES`.
+    /// KZG accumulators.
     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>,
 }
 
+#[serde_as]
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct EvmProof {
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// 1 Bn254Fr public value for app exe commit in little-endian bytes.
+    pub app_exe_commit: [u8; BN254_BYTES],
+    #[serde_as(as = "serde_with::hex::Hex")]
+    /// 1 Bn254Fr public value for app vm commit in little-endian bytes.
path: crates/sdk/src/types.rs
user: login: jonathanpwang
body: big endian?
created_at: 2025-04-15T16:14:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -97,27 +150,47 @@ 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,
+            mut app_exe_commit,
+            mut app_vm_commit,
             user_public_values,
-            proof,
+            proof_data,
         } = evm_openvm_proof;
+
+        app_exe_commit.reverse();
+        app_vm_commit.reverse();
+
+        let ProofData {
+            accumulators,
+            proof,
+        } = proof_data;
+
         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 {
+
+            let mut reversed_accumulators: Vec<u8> = Vec::with_capacity(accumulators.len());
path: crates/sdk/src/types.rs
user: login: jonathanpwang
body: what is this reverse business?
created_at: 2025-04-15T16:15:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -97,27 +150,47 @@ 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,
+            mut app_exe_commit,
+            mut app_vm_commit,
             user_public_values,
-            proof,
+            proof_data,
         } = evm_openvm_proof;
+
+        app_exe_commit.reverse();
+        app_vm_commit.reverse();
+
+        let ProofData {
+            accumulators,
+            proof,
+        } = proof_data;
+
         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 {
+
+            let mut reversed_accumulators: Vec<u8> = Vec::with_capacity(accumulators.len());
path: crates/sdk/src/types.rs
user: login: HrikB
body: `RawEvmProof` expects the accumulators in little-endian format. `EvmProof` stores them in big-endian
created_at: 2025-04-15T16:49:28Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-15T01:52: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/1578/verify_fibair-51037bdff17091ead2b2c7245fa45760eaee17f9.md) |<span style='color: green'>(-14 [-1.1%])</span> 1,274 |  334,086 |  17,676,626 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/fibonacci-51037bdff17091ead2b2c7245fa45760eaee17f9.md) |<span style='color: green'>(-37 [-1.4%])</span> 2,671 |  1,500,277 |  50,589,503 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/regex-51037bdff17091ead2b2c7245fa45760eaee17f9.md) |<span style='color: green'>(-73 [-0.9%])</span> 8,034 |  4,165,226 |  166,511,152 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/ecrecover-51037bdff17091ead2b2c7245fa45760eaee17f9.md) |<span style='color: green'>(-21 [-1.4%])</span> 1,429 |  289,447 |  14,470,186 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/pairing-51037bdff17091ead2b2c7245fa45760eaee17f9.md) |<span style='color: green'>(-87 [-1.8%])</span> 4,821 |  1,820,436 |  95,832,407 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/51037bdff17091ead2b2c7245fa45760eaee17f9

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

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T02:08:52Z
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/1578/verify_fibair-9ba77f329a1151858116027fb465c795eb6c7c9d.md) |<span style='color: green'>(-3 [-0.2%])</span> 1,285 |  334,019 |  17,675,822 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/fibonacci-9ba77f329a1151858116027fb465c795eb6c7c9d.md) |<span style='color: green'>(-46 [-1.7%])</span> 2,662 |  1,500,277 |  50,589,503 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/regex-9ba77f329a1151858116027fb465c795eb6c7c9d.md) |<span style='color: green'>(-74 [-0.9%])</span> 8,033 |  4,165,226 |  166,511,152 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/ecrecover-9ba77f329a1151858116027fb465c795eb6c7c9d.md) |<span style='color: green'>(-38 [-2.6%])</span> 1,412 |  289,447 |  14,470,186 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/pairing-9ba77f329a1151858116027fb465c795eb6c7c9d.md) |<span style='color: red'>(+8 [+0.2%])</span> 4,916 |  1,820,436 |  95,832,407 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/9ba77f329a1151858116027fb465c795eb6c7c9d

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

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T02:17:58Z
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/1578/verify_fibair-6eb2de07f2c9cd099e23ef0e07ace439c586bbe1.md) |<span style='color: green'>(-14 [-1.1%])</span> 1,274 |  334,008 |  17,675,690 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/fibonacci-6eb2de07f2c9cd099e23ef0e07ace439c586bbe1.md) |<span style='color: green'>(-46 [-1.7%])</span> 2,662 |  1,500,277 |  50,589,503 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/regex-6eb2de07f2c9cd099e23ef0e07ace439c586bbe1.md) |<span style='color: green'>(-29 [-0.4%])</span> 8,078 |  4,165,226 |  166,511,152 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/ecrecover-6eb2de07f2c9cd099e23ef0e07ace439c586bbe1.md) |<span style='color: green'>(-28 [-1.9%])</span> 1,422 |  289,447 |  14,470,186 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/pairing-6eb2de07f2c9cd099e23ef0e07ace439c586bbe1.md) |<span style='color: green'>(-28 [-0.6%])</span> 4,880 |  1,820,436 |  95,832,407 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/6eb2de07f2c9cd099e23ef0e07ace439c586bbe1

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

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T02:30:10Z
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/1578/verify_fibair-b2d20755e1641967c5d103be0c64f8e5a4026114.md) |<span style='color: red'>(+9 [+0.7%])</span> 1,297 |  334,019 |  17,675,822 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/fibonacci-b2d20755e1641967c5d103be0c64f8e5a4026114.md) |<span style='color: red'>(+9 [+0.3%])</span> 2,717 |  1,500,277 |  50,589,503 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/regex-b2d20755e1641967c5d103be0c64f8e5a4026114.md) |<span style='color: green'>(-75 [-0.9%])</span> 8,032 |  4,165,226 |  166,511,152 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/ecrecover-b2d20755e1641967c5d103be0c64f8e5a4026114.md) |<span style='color: red'>(+3 [+0.2%])</span> 1,453 |  289,447 |  14,470,186 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/pairing-b2d20755e1641967c5d103be0c64f8e5a4026114.md) |<span style='color: green'>(-12 [-0.2%])</span> 4,896 |  1,820,436 |  95,832,407 |- | - | - |


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

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

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T14:54:21Z
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/1578/verify_fibair-bd8242b8a4f5aeb3b6b32701c505c6e449eae2be.md) |<span style='color: green'>(-28 [-2.2%])</span> 1,260 |  334,047 |  17,676,158 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/fibonacci-bd8242b8a4f5aeb3b6b32701c505c6e449eae2be.md) |<span style='color: green'>(-9 [-0.3%])</span> 2,699 |  1,500,277 |  50,589,503 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/regex-bd8242b8a4f5aeb3b6b32701c505c6e449eae2be.md) |<span style='color: green'>(-29 [-0.4%])</span> 8,078 |  4,165,226 |  166,511,152 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/ecrecover-bd8242b8a4f5aeb3b6b32701c505c6e449eae2be.md) |<span style='color: green'>(-5 [-0.3%])</span> 1,445 |  289,447 |  14,470,186 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/pairing-bd8242b8a4f5aeb3b6b32701c505c6e449eae2be.md) |<span style='color: red'>(+58 [+1.2%])</span> 4,966 |  1,820,436 |  95,832,407 |- | - | - |


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

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

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T16:59:00Z
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/1578/verify_fibair-47d89f888e7df432d9f95b13059bf6ce7e51c365.md) |<span style='color: green'>(-13 [-1.0%])</span> 1,275 |  334,142 |  17,677,298 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/fibonacci-47d89f888e7df432d9f95b13059bf6ce7e51c365.md) |<span style='color: green'>(-18 [-0.7%])</span> 2,690 |  1,500,277 |  50,589,503 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/regex-47d89f888e7df432d9f95b13059bf6ce7e51c365.md) |<span style='color: green'>(-57 [-0.7%])</span> 8,050 |  4,165,226 |  166,511,152 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/ecrecover-47d89f888e7df432d9f95b13059bf6ce7e51c365.md) |<span style='color: red'>(+34 [+2.3%])</span> 1,484 |  289,447 |  14,470,186 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/pairing-47d89f888e7df432d9f95b13059bf6ce7e51c365.md) |<span style='color: red'>(+90 [+1.8%])</span> 4,998 |  1,820,436 |  95,832,407 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/47d89f888e7df432d9f95b13059bf6ce7e51c365

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

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T17:06:37Z
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/1578/verify_fibair-308ac4da17e4f7b611ea85ae745fed02a21d4852.md) |<span style='color: green'>(-21 [-1.6%])</span> 1,267 |  334,157 |  17,677,478 |- | - | - |
| [fibonacci_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/fibonacci-308ac4da17e4f7b611ea85ae745fed02a21d4852.md) |<span style='color: green'>(-28 [-1.0%])</span> 2,680 |  1,500,277 |  50,589,503 |- | - | - |
| [regex_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/regex-308ac4da17e4f7b611ea85ae745fed02a21d4852.md) |<span style='color: green'>(-32 [-0.4%])</span> 8,075 |  4,165,226 |  166,511,152 |- | - | - |
| [ecrecover_program](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/ecrecover-308ac4da17e4f7b611ea85ae745fed02a21d4852.md) |<span style='color: red'>(+7 [+0.5%])</span> 1,457 |  289,447 |  14,470,186 |- | - | - |
| [pairing](https://github.com/openvm-org/openvm/blob/benchmark-results/benchmarks-pr/1578/pairing-308ac4da17e4f7b611ea85ae745fed02a21d4852.md) |<span style='color: red'>(+6 [+0.1%])</span> 4,914 |  1,820,436 |  95,832,407 |- | - | - |


Commit: https://github.com/openvm-org/openvm/commit/308ac4da17e4f7b611ea85ae745fed02a21d4852

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

author_association: NONE