diff --git a/crates/core/executor/src/context.rs b/crates/core/executor/src/context.rs index 55304192..cd8a5bc8 100644 --- a/crates/core/executor/src/context.rs +++ b/crates/core/executor/src/context.rs @@ -21,6 +21,9 @@ pub struct ZKMContext<'a> { /// The maximum number of cpu cycles to use for execution. pub max_cycles: Option, + + /// Skip deferred proof verification. + pub skip_deferred_proof_verification: bool, } /// A builder for [`ZKMContext`]. @@ -30,6 +33,7 @@ pub struct ZKMContextBuilder<'a> { hook_registry_entries: Vec<(u32, BoxedHook<'a>)>, subproof_verifier: Option<&'a dyn SubproofVerifier>, max_cycles: Option, + skip_deferred_proof_verification: bool, } impl<'a> ZKMContext<'a> { @@ -68,7 +72,13 @@ impl<'a> ZKMContextBuilder<'a> { }); let subproof_verifier = take(&mut self.subproof_verifier); let cycle_limit = take(&mut self.max_cycles); - ZKMContext { hook_registry, subproof_verifier, max_cycles: cycle_limit } + let skip_deferred_proof_verification = take(&mut self.skip_deferred_proof_verification); + ZKMContext { + hook_registry, + subproof_verifier, + max_cycles: cycle_limit, + skip_deferred_proof_verification, + } } /// Add a runtime [Hook](super::Hook) into the context. @@ -107,6 +117,12 @@ impl<'a> ZKMContextBuilder<'a> { self.max_cycles = Some(max_cycles); self } + + /// Set the skip deferred proof verification flag. + pub fn set_skip_deferred_proof_verification(&mut self, skip: bool) -> &mut Self { + self.skip_deferred_proof_verification = skip; + self + } } #[cfg(test)] diff --git a/crates/core/executor/src/executor.rs b/crates/core/executor/src/executor.rs index 5e31e399..4a482d1a 100644 --- a/crates/core/executor/src/executor.rs +++ b/crates/core/executor/src/executor.rs @@ -46,6 +46,15 @@ pub const DEFAULT_PC_INC: u32 = 4; /// A valid pc should be divisible by 4, so we use 1 to indicate that the pc is not used. pub const UNUSED_PC: u32 = 1; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// Whether to verify deferred proofs during execution. +pub enum DeferredProofVerification { + /// Verify deferred proofs during execution. + Enabled, + /// Skip verification of deferred proofs. + Disabled, +} + /// An executor for the MIPS zkVM. /// /// The executor is responsible for executing a user program and tracing important events which @@ -100,6 +109,10 @@ pub struct Executor<'a> { /// The maximum number of cpu cycles to use for execution. pub max_cycles: Option, + /// Skip deferred proof verification. This check is informational only, not related to circuit + /// correctness. + pub deferred_proof_verification: DeferredProofVerification, + /// The state of the execution. pub state: ExecutionState, @@ -327,6 +340,11 @@ impl<'a> Executor<'a> { hook_registry, opts, max_cycles: context.max_cycles, + deferred_proof_verification: if context.skip_deferred_proof_verification { + DeferredProofVerification::Disabled + } else { + DeferredProofVerification::Enabled + }, memory_checkpoint: Memory::default(), uninitialized_memory_checkpoint: Memory::default(), local_memory_access: HashMap::new(), @@ -363,6 +381,9 @@ impl<'a> Executor<'a> { pub fn recover(program: Program, state: ExecutionState, opts: ZKMCoreOpts) -> Self { let mut runtime = Self::new(program, opts); runtime.state = state; + // Disable deferred proof verification since we're recovering from a checkpoint, and the + // checkpoint creator already had a chance to check the proofs. + runtime.deferred_proof_verification = DeferredProofVerification::Disabled; runtime } diff --git a/crates/core/executor/src/syscalls/verify.rs b/crates/core/executor/src/syscalls/verify.rs index f400e40c..a9d6e689 100644 --- a/crates/core/executor/src/syscalls/verify.rs +++ b/crates/core/executor/src/syscalls/verify.rs @@ -1,6 +1,6 @@ use crate::program::MAX_MEMORY; -use crate::ExecutionError; +use crate::{DeferredProofVerification, ExecutionError}; use super::{Syscall, SyscallCode, SyscallContext}; @@ -17,6 +17,10 @@ impl Syscall for VerifySyscall { ) -> Result, ExecutionError> { let rt = &mut ctx.rt; + if rt.deferred_proof_verification == DeferredProofVerification::Disabled { + return Ok(None); + } + // vkey_ptr is a pointer to [u32; 8] which contains the verification key. // pv_digest_ptr is a pointer to [u32; 8] which contains the public values digest. @@ -36,13 +40,13 @@ impl Syscall for VerifySyscall { if proof_index >= rt.state.proof_stream.len() { panic!("Not enough proofs were written to the runtime."); } + let (proof, proof_vk) = &rt.state.proof_stream[proof_index]; rt.state.proof_stream_ptr += 1; let vkey_bytes: [u32; 8] = vkey.try_into().unwrap(); let pv_digest_bytes: [u32; 8] = pv_digest.try_into().unwrap(); if let Some(verifier) = rt.subproof_verifier { - let (proof, proof_vk) = &rt.state.proof_stream[proof_index]; if let Err(e) = verifier.verify_deferred_proof(proof, proof_vk, vkey_bytes, pv_digest_bytes) { diff --git a/crates/sdk/src/action.rs b/crates/sdk/src/action.rs index 98b58e19..87a46bb2 100644 --- a/crates/sdk/src/action.rs +++ b/crates/sdk/src/action.rs @@ -69,6 +69,12 @@ impl<'a> Execute<'a> { self.context_builder.max_cycles(max_cycles); self } + + /// Skip deferred proof verification. + pub fn set_skip_deferred_proof_verification(mut self, value: bool) -> Self { + self.context_builder.set_skip_deferred_proof_verification(value); + self + } } /// Builder to prepare and configure proving execution of a program on an input. @@ -221,4 +227,10 @@ impl<'a> Prove<'a> { self.timeout = Some(timeout); self } + + /// Set the skip deferred proof verification flag. + pub fn set_skip_deferred_proof_verification(mut self, value: bool) -> Self { + self.context_builder.set_skip_deferred_proof_verification(value); + self + } }