Skip to content

Commit 4da0af9

Browse files
feat: ability to verify e2e STARK proof + CLI command
1 parent 18f14e9 commit 4da0af9

File tree

2 files changed

+97
-11
lines changed

2 files changed

+97
-11
lines changed

crates/cli/src/commands/verify.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@ use std::path::{Path, PathBuf};
33
use clap::Parser;
44
use eyre::Result;
55
use openvm_sdk::{
6-
fs::{read_app_proof_from_file, read_app_vk_from_file},
6+
fs::{
7+
decode_from_file, read_agg_stark_pk_from_file, read_app_proof_from_file,
8+
read_app_vk_from_file,
9+
},
710
Sdk,
811
};
912

1013
use super::KeygenCargoArgs;
1114
#[cfg(feature = "evm-verify")]
1215
use crate::default::default_evm_halo2_verifier_path;
13-
use crate::util::{get_app_vk_path, get_files_with_ext, get_manifest_path_and_dir, get_target_dir};
16+
use crate::{
17+
default::default_agg_stark_pk_path,
18+
util::{get_app_vk_path, get_files_with_ext, get_manifest_path_and_dir, get_target_dir},
19+
};
1420

1521
#[derive(Parser)]
1622
#[command(name = "verify", about = "Verify a proof")]
@@ -41,6 +47,15 @@ enum VerifySubCommand {
4147
#[command(flatten)]
4248
cargo_args: KeygenCargoArgs,
4349
},
50+
Stark {
51+
#[arg(
52+
long,
53+
action,
54+
help = "Path to STARK proof, by default will search the working directory for a file with extension .stark.proof",
55+
help_heading = "OpenVM Options"
56+
)]
57+
proof: Option<PathBuf>,
58+
},
4459
#[cfg(feature = "evm-verify")]
4560
Evm {
4661
#[arg(
@@ -85,6 +100,28 @@ impl VerifyCmd {
85100
let app_proof = read_app_proof_from_file(proof_path)?;
86101
sdk.verify_app_proof(&app_vk, &app_proof)?;
87102
}
103+
VerifySubCommand::Stark { proof } => {
104+
let agg_stark_pk = read_agg_stark_pk_from_file(default_agg_stark_pk_path())
105+
.map_err(|e| {
106+
eyre::eyre!(
107+
"Failed to read aggregation STARK proving key: {}\nPlease run 'cargo openvm setup' first",
108+
e
109+
)
110+
})?;
111+
let proof_path = if let Some(proof) = proof {
112+
proof.clone()
113+
} else {
114+
let files = get_files_with_ext(Path::new("."), "stark.proof")?;
115+
if files.len() > 1 {
116+
return Err(eyre::eyre!("multiple .stark.proof files found, please specify the path using option --proof"));
117+
} else if files.is_empty() {
118+
return Err(eyre::eyre!("no .stark.proof file found, please specify the path using option --proof"));
119+
}
120+
files[0].clone()
121+
};
122+
let stark_proof = decode_from_file(proof_path)?;
123+
sdk.verify_e2e_stark_proof(agg_stark_pk, &stark_proof)?;
124+
}
88125
#[cfg(feature = "evm-verify")]
89126
VerifySubCommand::Evm { proof } => {
90127
use openvm_sdk::fs::{

crates/sdk/src/lib.rs

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

33
#[cfg(feature = "evm-verify")]
44
use alloy_sol_types::sol;
@@ -11,16 +11,19 @@ use openvm_build::{
1111
};
1212
use openvm_circuit::{
1313
arch::{
14-
hasher::poseidon2::vm_poseidon2_hasher, instructions::exe::VmExe, verify_segments,
15-
ContinuationVmProof, ExecutionError, InitFileGenerator, VerifiedExecutionPayload, VmConfig,
16-
VmExecutor, VmVerificationError,
14+
hasher::{poseidon2::vm_poseidon2_hasher, Hasher},
15+
instructions::exe::VmExe,
16+
verify_segments, ContinuationVmProof, ExecutionError, InitFileGenerator,
17+
VerifiedExecutionPayload, VmConfig, VmExecutor, PROGRAM_CACHED_TRACE_INDEX,
18+
PUBLIC_VALUES_AIR_ID,
1719
},
1820
system::{
1921
memory::{tree::public_values::extract_public_values, CHUNK},
20-
program::trace::VmCommittedExe,
22+
program::trace::{compute_exe_commit, VmCommittedExe},
2123
},
2224
};
2325
use openvm_continuations::verifier::{
26+
common::types::VmVerifierPvs,
2427
internal::types::VmStarkProof,
2528
root::{types::RootVmVerifierInput, RootVmVerifierConfig},
2629
};
@@ -33,7 +36,7 @@ use openvm_stark_backend::proof::Proof;
3336
use openvm_stark_sdk::{
3437
config::{baby_bear_poseidon2::BabyBearPoseidon2Engine, FriParameters},
3538
engine::StarkFriEngine,
36-
openvm_stark_backend::{verifier::VerificationError, Chip},
39+
openvm_stark_backend::Chip,
3740
};
3841
use openvm_transpiler::{
3942
elf::Elf,
@@ -228,7 +231,7 @@ impl<E: StarkFriEngine<SC>> GenericSdk<E> {
228231
&self,
229232
app_vk: &AppVerifyingKey,
230233
proof: &ContinuationVmProof<SC>,
231-
) -> Result<VerifiedContinuationVmPayload, VmVerificationError> {
234+
) -> Result<VerifiedContinuationVmPayload> {
232235
let engine = E::new(app_vk.fri_params);
233236
let VerifiedExecutionPayload {
234237
exe_commit,
@@ -250,9 +253,10 @@ impl<E: StarkFriEngine<SC>> GenericSdk<E> {
250253
&self,
251254
app_vk: &AppVerifyingKey,
252255
proof: &Proof<SC>,
253-
) -> Result<(), VerificationError> {
256+
) -> Result<()> {
254257
let e = E::new(app_vk.fri_params);
255-
e.verify(&app_vk.app_vm_vk, proof)
258+
e.verify(&app_vk.app_vm_vk, proof)?;
259+
Ok(())
256260
}
257261

258262
pub fn agg_keygen(
@@ -322,6 +326,51 @@ impl<E: StarkFriEngine<SC>> GenericSdk<E> {
322326
Ok(proof)
323327
}
324328

329+
pub fn verify_e2e_stark_proof(
330+
&self,
331+
agg_stark_pk: AggStarkProvingKey,
332+
proof: &VmStarkProof<SC>,
333+
) -> Result<[F; CHUNK]> {
334+
let program_commit =
335+
proof.proof.commitments.main_trace[PROGRAM_CACHED_TRACE_INDEX].as_ref();
336+
let internal_commit: &[_; CHUNK] = &agg_stark_pk
337+
.internal_committed_exe
338+
.get_program_commit()
339+
.into();
340+
341+
let vm_pk = if program_commit == internal_commit {
342+
&agg_stark_pk.internal_vm_pk
343+
} else {
344+
&agg_stark_pk.leaf_vm_pk
345+
};
346+
let e = E::new(vm_pk.fri_params);
347+
e.verify(&vm_pk.vm_pk.get_vk(), &proof.proof)?;
348+
349+
let public_values_air_proof_data = proof
350+
.proof
351+
.per_air
352+
.iter()
353+
.find(|p| p.air_id == PUBLIC_VALUES_AIR_ID)
354+
.unwrap();
355+
let pvs: &VmVerifierPvs<_> =
356+
public_values_air_proof_data.public_values[..VmVerifierPvs::<u8>::width()].borrow();
357+
358+
let hasher = vm_poseidon2_hasher();
359+
let public_values_root = hasher.merkle_root(&proof.user_public_values);
360+
if public_values_root != pvs.public_values_commit {
361+
return Err(eyre::eyre!(
362+
"Invalid public values root: expected {:?}, got {:?}",
363+
pvs.public_values_commit,
364+
public_values_root
365+
));
366+
}
367+
368+
let start_pc = pvs.connector.initial_pc;
369+
let initial_memory_root = &pvs.memory.initial_root;
370+
let exe_commit = compute_exe_commit(&hasher, program_commit, initial_memory_root, start_pc);
371+
Ok(exe_commit)
372+
}
373+
325374
#[cfg(feature = "evm-prove")]
326375
pub fn generate_evm_proof<VC: VmConfig<F>>(
327376
&self,

0 commit comments

Comments
 (0)