Skip to content

Commit 95eda25

Browse files
HrikByi-sun
andauthored
chore: alter json format of proof to align with verifier contract (#1578)
This PR alters the JSON proof outputted by `cargo openvm prove` to conform to the format of the verifier contract. --------- Co-authored-by: Yi Sun <[email protected]>
1 parent 3f42814 commit 95eda25

File tree

13 files changed

+156
-132
lines changed

13 files changed

+156
-132
lines changed

Cargo.lock

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ snark-verifier = { version = "0.2.0", default-features = false }
188188
halo2curves-axiom = "0.7.0"
189189

190190
cargo_metadata = "0.18"
191-
alloy-primitives = "0.8.25"
192191
alloy-sol-types = "0.8.25"
193192
tracing = "0.1.40"
194193
bon = "3.2.0"

book/src/writing-apps/verify.md

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,24 @@ This command can take ~20mins on a `m6a.16xlarge` instance due to the keygen tim
4848
Upon a successful run, the command will write the files
4949

5050
- `agg.pk`
51-
- `verifier.sol`
52-
- `verifier.bytecode.json`
51+
- `halo2/Halo2Verifier.sol`
52+
- `halo2/OpenVmHalo2Verifier.sol`
53+
- `halo2/interfaces/IOpenVmHalo2Verifier.sol`
54+
- `halo2/verifier.bytecode.json`
5355

5456
to `~/.openvm/`, where `~` is the directory specified by environment variable `$HOME`. Every command that requires these files will look for them in this directory.
5557

5658
The `agg.pk` contains all aggregation proving keys necessary for aggregating to a final EVM proof.
57-
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.
59+
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.
60+
61+
```solidity
62+
interface IOpenVmHalo2Verifier {
63+
function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit)
64+
external
65+
view;
66+
}
67+
```
68+
5869
In addition, the command outputs a JSON file `verifier.bytecode.json` of the form
5970

6071
```json
@@ -92,30 +103,26 @@ The EVM proof is written to `evm.proof` as a JSON of the following format:
92103

93104
```json
94105
{
95-
"accumulators": "0x..",
96-
"exe_commit": "0x..",
97-
"leaf_commit": "0x..",
106+
"app_exe_commit": "0x..",
107+
"app_vm_commit": "0x..",
98108
"user_public_values": "0x..",
99-
"proof": "0x.."
109+
"proof_data": {
110+
"accumulator": "0x..",
111+
"proof": "0x.."
112+
},
100113
}
101114
```
102115

103116
where each field is a hex string. We explain what each field represents:
104117

105-
- `accumulators`: `12 * 32` bytes representing the KZG accumulator of the proof, where the proof is from a SNARK using the KZG commitment scheme.
106-
- `exe_commit`: `32` bytes for the commitment of the app executable.
107-
- `leaf_commit`: `32` bytes for the commitment of the executable verifying app VM proofs.
118+
- `app_exe_commit`: `32` bytes for the commitment of the app executable.
119+
- `app_vm_commit`: `32` bytes for the commitment of the app VM configuration.
108120
- `user_public_values`: concatenation of 32 byte chunks for user public values. The number of user public values is a configuration parameter.
121+
- `accumulator`: `12 * 32` bytes representing the KZG accumulator of the proof, where the proof is from a SNARK using the KZG commitment scheme.
109122
- `proof`: The rest of the proof required by the SNARK as a hex string of `43 * 32` bytes.
110123

111124
### EVM Proof: Calldata Format
112125

113126
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.
114127

115-
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:
116-
117-
1. `accumulators`: every `32` bytes are _reversed_ from little endian to big endian and concatenated.
118-
2. `exe_commit`: the `32` bytes are _reversed_ from little endian to big endian.
119-
3. `leaf_commit`: the `32` bytes are _reversed_ from little endian to big endian.
120-
4. `user_public_values`: every `32` bytes are _reversed_ from little endian to big endian and concatenated.
121-
5. `proof`: The rest of the proof is treated as raw bytes and concatenated.
128+
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)`.

crates/cli/src/commands/verify.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl VerifyCmd {
5151
eyre::eyre!("Failed to read EVM verifier: {}\nPlease run 'cargo openvm evm-proving-setup' first", e)
5252
})?;
5353
let evm_proof = read_evm_proof_from_file(proof)?;
54-
sdk.verify_evm_halo2_proof(&evm_verifier, &evm_proof)?;
54+
sdk.verify_evm_halo2_proof(&evm_verifier, evm_proof)?;
5555
}
5656
}
5757
Ok(())

crates/sdk/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ openvm-circuit = { workspace = true }
3434
openvm-continuations = { workspace = true }
3535
openvm = { workspace = true }
3636

37-
alloy-primitives = { workspace = true, optional = true }
3837
alloy-sol-types = { workspace = true, optional = true, features = ["json"] }
3938
bitcode = { workspace = true }
4039
bon = { workspace = true }
@@ -62,7 +61,6 @@ evm-prove = ["openvm-native-recursion/evm-prove"]
6261
evm-verify = [
6362
"evm-prove",
6463
"openvm-native-recursion/evm-verify",
65-
"dep:alloy-primitives",
6664
"dep:alloy-sol-types",
6765
]
6866
bench-metrics = [

crates/sdk/contracts/template/OpenVmHalo2Verifier.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
3535
/// use with the `snark-verifier` verification.
3636
///
3737
/// @dev The verifier expected proof format is:
38-
/// proof[..12 * 32]: KZG accumulators
38+
/// proof[..12 * 32]: KZG accumulator
3939
/// proof[12 * 32..13 * 32]: app exe commit
4040
/// proof[13 * 32..14 * 32]: app vm commit
4141
/// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValues[0..PUBLIC_VALUES_LENGTH]
@@ -44,7 +44,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
4444
/// @param publicValues The PVs revealed by the OpenVM guest program.
4545
/// @param proofData All components of the proof except the public values and
4646
/// app exe and vm commits. The expected format is:
47-
/// `abi.encodePacked(kzgAccumulators, proofSuffix)`
47+
/// `abi.encodePacked(kzgAccumulator, proofSuffix)`
4848
/// @param appExeCommit The commitment to the OpenVM application executable whose execution
4949
/// is being verified.
5050
/// @param appVmCommit The commitment to the VM configuration.
@@ -95,7 +95,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
9595

9696
// The expected proof format using hex offsets:
9797
//
98-
// proof[..0x180]: KZG accumulators
98+
// proof[..0x180]: KZG accumulator
9999
// proof[0x180..0x1a0]: app exe commit
100100
// proof[0x1a0..0x1c0]: app vm commit
101101
// proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValues[0..PUBLIC_VALUES_LENGTH]
@@ -107,7 +107,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
107107
// Allocate the memory as a safety measure.
108108
mstore(0x40, add(proofPtr, fullProofLength))
109109

110-
// Copy the KZG accumulators (length 0x180) into the beginning of
110+
// Copy the KZG accumulator (length 0x180) into the beginning of
111111
// the memory buffer
112112
calldatacopy(proofPtr, proofData.offset, 0x180)
113113

@@ -119,7 +119,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {
119119
// end of the memory buffer, leaving PUBLIC_VALUES_LENGTH words in
120120
// between for the publicValuesPayload.
121121
//
122-
// Begin copying from the end of the KZG accumulators in the
122+
// Begin copying from the end of the KZG accumulator in the
123123
// calldata buffer (0x180)
124124
let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH))
125125
calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560)

crates/sdk/contracts/test/OpenVmHalo2Verifier.t.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ contract TemplateTest is Test {
5252

5353
uint256 proofSuffixOffset = 0x1c0 + (32 * publicValuesLength);
5454

55-
bytes memory kzgAccumulators = proof[0:0x180];
55+
bytes memory kzgAccumulator = proof[0:0x180];
5656
bytes memory proofSuffix = proof[proofSuffixOffset:];
57-
bytes memory _proofData = abi.encodePacked(kzgAccumulators, proofSuffix);
57+
bytes memory _proofData = abi.encodePacked(kzgAccumulator, proofSuffix);
5858

5959
require(keccak256(_proofData) == keccak256(proofDataExpected), "Partial proof mismatch");
6060

crates/sdk/examples/sdk_evm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
108108
)?;
109109

110110
// 11. Verify the EVM proof
111-
sdk.verify_evm_halo2_proof(&verifier, &proof)?;
111+
sdk.verify_evm_halo2_proof(&verifier, proof)?;
112112
// ANCHOR_END: evm_verification
113113

114114
Ok(())

crates/sdk/src/lib.rs

Lines changed: 9 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use std::{fs::read, marker::PhantomData, path::Path, sync::Arc};
22

33
#[cfg(feature = "evm-verify")]
4-
use alloy_primitives::{Bytes, FixedBytes};
5-
#[cfg(feature = "evm-verify")]
6-
use alloy_sol_types::{sol, SolCall, SolValue};
4+
use alloy_sol_types::sol;
5+
use commit::commit_app_exe;
6+
use config::{AggregationTreeConfig, AppConfig};
77
use eyre::Result;
8+
use keygen::{AppProvingKey, AppVerifyingKey};
89
use openvm_build::{
910
build_guest_package, find_unique_executable, get_package, GuestOptions, TargetFilter,
1011
};
@@ -41,9 +42,8 @@ use openvm_transpiler::{
4142
use snark_verifier_sdk::{evm::gen_evm_verifier_sol_code, halo2::aggregation::AggregationCircuit};
4243

4344
use crate::{
44-
commit::commit_app_exe,
45-
config::{AggConfig, AggregationTreeConfig, AppConfig},
46-
keygen::{AggProvingKey, AggStarkProvingKey, AppProvingKey, AppVerifyingKey},
45+
config::AggConfig,
46+
keygen::{AggProvingKey, AggStarkProvingKey},
4747
prover::{AppProver, StarkProver},
4848
};
4949
#[cfg(feature = "evm-prove")]
@@ -327,7 +327,7 @@ impl<E: StarkFriEngine<SC>> GenericSdk<E> {
327327

328328
let wrapper_pvs = agg_pk.halo2_pk.wrapper.pinning.metadata.num_pvs.clone();
329329
let pvs_length = match wrapper_pvs.first() {
330-
// We subtract 14 to exclude the KZG accumulators and the app exe
330+
// We subtract 14 to exclude the KZG accumulator and the app exe
331331
// and vm commits.
332332
Some(v) => v
333333
.checked_sub(14)
@@ -411,55 +411,9 @@ impl<E: StarkFriEngine<SC>> GenericSdk<E> {
411411
pub fn verify_evm_halo2_proof(
412412
&self,
413413
openvm_verifier: &types::EvmHalo2Verifier,
414-
evm_proof: &EvmProof,
414+
evm_proof: EvmProof,
415415
) -> Result<u64> {
416-
use crate::types::NUM_BN254_ACCUMULATORS;
417-
418-
let EvmProof {
419-
accumulators,
420-
proof,
421-
user_public_values,
422-
exe_commit,
423-
leaf_commit,
424-
} = evm_proof;
425-
let mut exe_commit = *exe_commit;
426-
let mut leaf_commit = *leaf_commit;
427-
exe_commit.reverse();
428-
leaf_commit.reverse();
429-
430-
assert_eq!(accumulators.len(), NUM_BN254_ACCUMULATORS * 32);
431-
let mut evm_accumulators: Vec<u8> = Vec::with_capacity(accumulators.len());
432-
accumulators
433-
.chunks(32)
434-
.for_each(|chunk| evm_accumulators.extend(chunk.iter().rev().cloned()));
435-
436-
let mut proof_data = evm_accumulators;
437-
proof_data.extend(proof);
438-
439-
assert!(
440-
user_public_values.len() % 32 == 0,
441-
"User public values length must be a multiple of 32"
442-
);
443-
444-
// Take the first byte of each 32 byte chunk, and pack them together
445-
// into one payload.
446-
let user_public_values: Bytes =
447-
user_public_values
448-
.chunks(32)
449-
.fold(Vec::<u8>::new().into(), |acc: Bytes, chunk| {
450-
// We only care about the first byte, everything else should be 0-bytes
451-
(acc, FixedBytes::<1>::from(*chunk.first().unwrap()))
452-
.abi_encode_packed()
453-
.into()
454-
});
455-
456-
let calldata = IOpenVmHalo2Verifier::verifyCall {
457-
publicValues: user_public_values.clone(),
458-
proofData: proof_data.into(),
459-
appExeCommit: exe_commit.into(),
460-
appVmCommit: leaf_commit.into(),
461-
}
462-
.abi_encode();
416+
let calldata = evm_proof.verifier_calldata();
463417
let deployment_code = openvm_verifier.artifact.bytecode.clone();
464418

465419
let gas_cost = snark_verifier::loader::evm::deploy_and_call(deployment_code, calldata)

0 commit comments

Comments
 (0)