diff --git a/Cargo.lock b/Cargo.lock index de4823caf3..fb6a9eff60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4335,6 +4335,7 @@ dependencies = [ "openvm-native-circuit", "openvm-native-compiler", "openvm-native-recursion", + "openvm-native-transpiler", "openvm-pairing-circuit", "openvm-pairing-transpiler", "openvm-rv32im-circuit", diff --git a/crates/cli/src/commands/prove.rs b/crates/cli/src/commands/prove.rs index bf263d2c1a..2ecc219d59 100644 --- a/crates/cli/src/commands/prove.rs +++ b/crates/cli/src/commands/prove.rs @@ -7,8 +7,8 @@ use openvm_sdk::{ commit::AppExecutionCommit, config::SdkVmConfig, fs::{ - read_agg_pk_from_file, read_app_pk_from_file, read_exe_from_file, write_app_proof_to_file, - write_evm_proof_to_file, + read_agg_pk_from_file, read_app_pk_from_file, read_exe_from_file, read_root_pk_from_file, + write_app_proof_to_file, write_evm_proof_to_file, write_root_proof_to_file, }, keygen::AppProvingKey, NonRootCommittedExe, Sdk, StdIn, @@ -17,7 +17,7 @@ use openvm_sdk::{ use crate::{ default::{ DEFAULT_AGG_PK_PATH, DEFAULT_APP_EXE_PATH, DEFAULT_APP_PK_PATH, DEFAULT_APP_PROOF_PATH, - DEFAULT_EVM_PROOF_PATH, DEFAULT_PARAMS_DIR, + DEFAULT_EVM_PROOF_PATH, DEFAULT_PARAMS_DIR, DEFAULT_ROOT_PK_PATH, DEFAULT_ROOT_PROOF_PATH, }, util::{read_to_stdin, Input}, }; @@ -44,6 +44,19 @@ enum ProveSubCommand { #[clap(long, action, help = "Path to output proof", default_value = DEFAULT_APP_PROOF_PATH)] output: PathBuf, }, + Root { + #[clap(long, action, help = "Path to app proving key", default_value = DEFAULT_APP_PK_PATH)] + app_pk: PathBuf, + + #[clap(long, action, help = "Path to OpenVM executable", default_value = DEFAULT_APP_EXE_PATH)] + exe: PathBuf, + + #[clap(long, value_parser, help = "Input to OpenVM program")] + input: Option, + + #[clap(long, action, help = "Path to output proof", default_value = DEFAULT_ROOT_PROOF_PATH)] + output: PathBuf, + }, Evm { #[clap(long, action, help = "Path to app proving key", default_value = DEFAULT_APP_PK_PATH)] app_pk: PathBuf, @@ -72,6 +85,19 @@ impl ProveCmd { let app_proof = Sdk.generate_app_proof(app_pk, committed_exe, input)?; write_app_proof_to_file(app_proof, output)?; } + ProveSubCommand::Root { + app_pk, + exe, + input, + output, + } => { + let (app_pk, committed_exe, input) = Self::prepare_execution(app_pk, exe, input)?; + let root_pk = read_root_pk_from_file(DEFAULT_ROOT_PK_PATH).map_err(|e| { + eyre::eyre!("Failed to read root aggregation proving key: {}\nPlease run 'cargo openvm setup' first", e) + })?; + let root_proof = Sdk.generate_root_proof(app_pk, committed_exe, root_pk, input)?; + write_root_proof_to_file(root_proof, output)?; + } ProveSubCommand::Evm { app_pk, exe, diff --git a/crates/cli/src/commands/setup.rs b/crates/cli/src/commands/setup.rs index d5fd7fd2b2..a7b1219f2f 100644 --- a/crates/cli/src/commands/setup.rs +++ b/crates/cli/src/commands/setup.rs @@ -6,25 +6,39 @@ use std::{ use aws_config::{defaults, BehaviorVersion, Region}; use aws_sdk_s3::Client; use clap::Parser; -use eyre::{eyre, Result}; +use eyre::{eyre, Ok, Result}; use openvm_native_recursion::halo2::utils::CacheHalo2ParamsReader; use openvm_sdk::{ config::AggConfig, - fs::{write_agg_pk_to_file, write_evm_verifier_to_file}, + fs::{write_agg_pk_to_file, write_evm_verifier_to_file, write_root_pk_to_file}, + keygen::AggStarkProvingKey, Sdk, }; -use crate::default::{DEFAULT_AGG_PK_PATH, DEFAULT_PARAMS_DIR, DEFAULT_VERIFIER_PATH}; +use crate::default::{ + DEFAULT_AGG_PK_PATH, DEFAULT_PARAMS_DIR, DEFAULT_ROOT_PK_PATH, DEFAULT_VERIFIER_PATH, +}; #[derive(Parser)] #[command( name = "evm-proving-setup", about = "Set up for generating EVM proofs. ATTENTION: this requires large amounts of computation and memory. " )] -pub struct EvmProvingSetupCmd {} +pub struct EvmProvingSetupCmd { + #[arg(long, default_value = "false", help = "Only generate root proving key")] + pub stark_only: bool, +} impl EvmProvingSetupCmd { pub async fn run(&self) -> Result<()> { + if self.stark_only { + let agg_config = AggConfig::default(); + let (agg_stark_pk, _) = + AggStarkProvingKey::dummy_proof_and_keygen(agg_config.agg_stark_config); + println!("Writing stark proving key to file..."); + write_root_pk_to_file(agg_stark_pk, DEFAULT_ROOT_PK_PATH)?; + return Ok(()); + } if PathBuf::from(DEFAULT_AGG_PK_PATH).exists() && PathBuf::from(DEFAULT_VERIFIER_PATH).exists() { @@ -46,6 +60,9 @@ impl EvmProvingSetupCmd { println!("Generating verifier contract..."); let verifier = Sdk.generate_snark_verifier_contract(¶ms_reader, &agg_pk)?; + println!("Writing stark proving key to file..."); + write_root_pk_to_file(agg_pk.agg_stark_pk.clone(), DEFAULT_ROOT_PK_PATH)?; + println!("Writing proving key to file..."); write_agg_pk_to_file(agg_pk, DEFAULT_AGG_PK_PATH)?; diff --git a/crates/cli/src/commands/verify.rs b/crates/cli/src/commands/verify.rs index ef02f34510..46f48e567b 100644 --- a/crates/cli/src/commands/verify.rs +++ b/crates/cli/src/commands/verify.rs @@ -2,16 +2,19 @@ use std::path::PathBuf; use clap::Parser; use eyre::{eyre, Result}; +use openvm_circuit::{arch::SingleSegmentVmExecutor, system::program::trace::VmCommittedExe}; +use openvm_native_recursion::hints::Hintable; use openvm_sdk::{ fs::{ read_app_proof_from_file, read_app_vk_from_file, read_evm_proof_from_file, - read_evm_verifier_from_file, + read_evm_verifier_from_file, read_root_pk_from_file, read_root_proof_from_file, }, Sdk, }; use crate::default::{ - DEFAULT_APP_PROOF_PATH, DEFAULT_APP_VK_PATH, DEFAULT_EVM_PROOF_PATH, DEFAULT_VERIFIER_PATH, + DEFAULT_APP_PROOF_PATH, DEFAULT_APP_VK_PATH, DEFAULT_EVM_PROOF_PATH, DEFAULT_ROOT_PK_PATH, + DEFAULT_ROOT_PROOF_PATH, DEFAULT_VERIFIER_PATH, }; #[derive(Parser)] @@ -30,6 +33,10 @@ enum VerifySubCommand { #[clap(long, action, help = "Path to app proof", default_value = DEFAULT_APP_PROOF_PATH)] proof: PathBuf, }, + Root { + #[clap(long, action, help = "Path to root proof", default_value = DEFAULT_ROOT_PROOF_PATH)] + proof: PathBuf, + }, Evm { #[clap(long, action, help = "Path to EVM proof", default_value = DEFAULT_EVM_PROOF_PATH)] proof: PathBuf, @@ -44,6 +51,19 @@ impl VerifyCmd { let app_proof = read_app_proof_from_file(proof)?; Sdk.verify_app_proof(&app_vk, &app_proof)?; } + VerifySubCommand::Root { proof } => { + let root_proof = read_root_proof_from_file(proof)?; + let input = root_proof.write(); + let agg_stark_pk = read_root_pk_from_file(DEFAULT_ROOT_PK_PATH).map_err(|e| { + eyre::eyre!("Failed to read root aggregation proving key: {}\nPlease run 'cargo openvm setup' first", e) + })?; + let root_verifier_pk = agg_stark_pk.root_verifier_pk; + //let config: openvm_native_circuit::NativeConfig = root_verifier_pk.vm_pk.vm_config.clone(); + let vm = SingleSegmentVmExecutor::new(root_verifier_pk.vm_pk.vm_config.clone()); + let exe: &VmCommittedExe<_> = &root_verifier_pk.root_committed_exe; + let result = vm.execute_and_compute_heights(exe.exe.clone(), input)?; + println!("root program execution result: {:?}", result); + } VerifySubCommand::Evm { proof } => { let evm_verifier = read_evm_verifier_from_file(DEFAULT_VERIFIER_PATH).map_err(|e| { eyre::eyre!("Failed to read EVM verifier: {}\nPlease run 'cargo openvm evm-proving-setup' first", e) diff --git a/crates/cli/src/default.rs b/crates/cli/src/default.rs index d24bd0d043..ba8f729e52 100644 --- a/crates/cli/src/default.rs +++ b/crates/cli/src/default.rs @@ -3,6 +3,7 @@ use openvm_stark_sdk::config::FriParameters; pub const DEFAULT_MANIFEST_DIR: &str = "."; +pub const DEFAULT_ROOT_PK_PATH: &str = concat!(env!("HOME"), "/.openvm/root.pk"); pub const DEFAULT_AGG_PK_PATH: &str = concat!(env!("HOME"), "/.openvm/agg.pk"); pub const DEFAULT_VERIFIER_PATH: &str = concat!(env!("HOME"), "/.openvm/verifier.sol"); pub const DEFAULT_PARAMS_DIR: &str = concat!(env!("HOME"), "/.openvm/params/"); @@ -12,6 +13,7 @@ pub const DEFAULT_APP_EXE_PATH: &str = "./openvm/app.vmexe"; pub const DEFAULT_APP_PK_PATH: &str = "./openvm/app.pk"; pub const DEFAULT_APP_VK_PATH: &str = "./openvm/app.vk"; pub const DEFAULT_APP_PROOF_PATH: &str = "./openvm/app.proof"; +pub const DEFAULT_ROOT_PROOF_PATH: &str = "./openvm/root.proof"; pub const DEFAULT_EVM_PROOF_PATH: &str = "./openvm/evm.proof"; pub fn default_app_config() -> AppConfig { diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index 3cd82adaf9..751edfde7d 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -23,6 +23,7 @@ openvm-pairing-circuit = { workspace = true } openvm-pairing-transpiler = { workspace = true } openvm-native-circuit = { workspace = true } openvm-native-compiler = { workspace = true } +openvm-native-transpiler = { workspace = true } openvm-native-recursion = { workspace = true, features = ["static-verifier"] } openvm-rv32im-circuit = { workspace = true } openvm-rv32im-transpiler = { workspace = true } diff --git a/crates/sdk/src/config/global.rs b/crates/sdk/src/config/global.rs index a062269b53..80fe2e31b7 100644 --- a/crates/sdk/src/config/global.rs +++ b/crates/sdk/src/config/global.rs @@ -24,6 +24,7 @@ use openvm_native_circuit::{ CastFExtension, CastFExtensionExecutor, CastFExtensionPeriphery, Native, NativeExecutor, NativePeriphery, }; +use openvm_native_transpiler::LongFormTranspilerExtension; use openvm_pairing_circuit::{ PairingExtension, PairingExtensionExecutor, PairingExtensionPeriphery, }; @@ -53,6 +54,7 @@ pub struct SdkVmConfig { pub keccak: Option, pub sha256: Option, pub native: Option, + pub castf: Option, pub rv32m: Option, pub bigint: Option, @@ -60,7 +62,6 @@ pub struct SdkVmConfig { pub fp2: Option, pub pairing: Option, pub ecc: Option, - pub castf: Option, } #[derive(ChipUsageGetter, Chip, InstructionExecutor, From, AnyEnum, BytesStateful)] @@ -156,7 +157,7 @@ impl SdkVmConfig { if self.ecc.is_some() { transpiler = transpiler.with_extension(EccTranspilerExtension); } - transpiler + transpiler.with_extension(LongFormTranspilerExtension) } } @@ -192,6 +193,9 @@ impl VmConfig for SdkVmConfig { if self.native.is_some() { complex = complex.extend(&Native)?; } + if self.castf.is_some() { + complex = complex.extend(&CastFExtension)?; + } if let Some(rv32m) = self.rv32m { let mut rv32m = rv32m; @@ -225,9 +229,6 @@ impl VmConfig for SdkVmConfig { if let Some(ref ecc) = self.ecc { complex = complex.extend(ecc)?; } - if let Some(ref castf) = self.castf { - complex = complex.extend(castf)?; - } Ok(complex) } @@ -286,3 +287,9 @@ impl From for UnitStruct { UnitStruct {} } } + +impl From for UnitStruct { + fn from(_: CastFExtension) -> Self { + UnitStruct {} + } +} diff --git a/crates/sdk/src/fs.rs b/crates/sdk/src/fs.rs index 1359adb13c..abf47075b6 100644 --- a/crates/sdk/src/fs.rs +++ b/crates/sdk/src/fs.rs @@ -9,8 +9,9 @@ use openvm_native_recursion::halo2::{wrapper::EvmVerifier, EvmProof}; use serde::{de::DeserializeOwned, Serialize}; use crate::{ - keygen::{AggProvingKey, AppProvingKey, AppVerifyingKey}, + keygen::{AggProvingKey, AggStarkProvingKey, AppProvingKey, AppVerifyingKey}, prover::vm::ContinuationVmProof, + verifier::root::types::RootVmVerifierInput, F, SC, }; @@ -54,14 +55,33 @@ pub fn write_app_proof_to_file>( write_to_file_bitcode(path, proof) } +pub fn write_root_proof_to_file>( + proof: RootVmVerifierInput, + path: P, +) -> Result<()> { + write_to_file_bitcode(path, proof) +} + pub fn read_agg_pk_from_file>(path: P) -> Result { read_from_file_bitcode(path) } +pub fn read_root_pk_from_file>(path: P) -> Result { + read_from_file_bitcode(path) +} + +pub fn write_root_pk_to_file>(agg_pk: AggStarkProvingKey, path: P) -> Result<()> { + write_to_file_bitcode(path, agg_pk) +} + pub fn write_agg_pk_to_file>(agg_pk: AggProvingKey, path: P) -> Result<()> { write_to_file_bitcode(path, agg_pk) } +pub fn read_root_proof_from_file>(path: P) -> Result> { + read_from_file_bitcode(path) +} + pub fn read_evm_proof_from_file>(path: P) -> Result { read_from_file_bitcode(path) } diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index a4038e194a..e07b25cd1e 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -5,7 +5,7 @@ use std::{fs::read, panic::catch_unwind, path::Path, sync::Arc}; use commit::commit_app_exe; use config::AppConfig; use eyre::Result; -use keygen::{AppProvingKey, AppVerifyingKey}; +use keygen::{AggStarkProvingKey, AppProvingKey, AppVerifyingKey}; use openvm_build::{ build_guest_package, find_unique_executable, get_package, GuestOptions, TargetFilter, }; @@ -50,12 +50,13 @@ pub mod verifier; mod stdin; pub use stdin::*; +use verifier::root::types::RootVmVerifierInput; pub mod fs; use crate::{ config::AggConfig, keygen::AggProvingKey, - prover::{AppProver, ContinuationProver}, + prover::{AppProver, ContinuationProver, StarkProver}, }; pub(crate) type SC = BabyBearPoseidon2Config; @@ -183,6 +184,22 @@ impl Sdk { Ok(agg_pk) } + pub fn generate_root_proof>( + &self, + app_pk: Arc>, + app_exe: Arc, + agg_stark_pk: AggStarkProvingKey, + inputs: StdIn, + ) -> Result> + where + VC::Executor: Chip, + VC::Periphery: Chip, + { + let stark_prover = StarkProver::new(app_pk, app_exe, agg_stark_pk); + let proof = stark_prover.generate_proof_for_root_program(inputs); + Ok(proof) + } + pub fn generate_evm_proof>( &self, reader: &impl Halo2ParamsReader, diff --git a/crates/sdk/src/prover/agg.rs b/crates/sdk/src/prover/agg.rs index d5e9f13957..46417d09f2 100644 --- a/crates/sdk/src/prover/agg.rs +++ b/crates/sdk/src/prover/agg.rs @@ -87,6 +87,20 @@ impl AggStarkProver { }) } + /// Generate a root stark proof to aggregate app proofs. + pub fn generate_root_proof( + &self, + app_proofs: ContinuationVmProof, + ) -> RootVmVerifierInput { + let leaf_proofs = self.leaf_prover.generate_proof(&app_proofs); + let public_values = app_proofs.user_public_values.public_values; + let internal_proof = self.generate_internal_proof_impl(leaf_proofs, &public_values); + RootVmVerifierInput { + proofs: vec![internal_proof], + public_values, + } + } + fn generate_internal_proof_impl( &self, leaf_proofs: Vec>, diff --git a/crates/sdk/src/prover/mod.rs b/crates/sdk/src/prover/mod.rs index 08c602f032..b14cb9dfe6 100644 --- a/crates/sdk/src/prover/mod.rs +++ b/crates/sdk/src/prover/mod.rs @@ -23,10 +23,7 @@ pub mod vm; #[allow(unused_imports)] pub use stark::*; -use crate::{ - keygen::AggProvingKey, - prover::{halo2::Halo2Prover, stark::StarkProver}, -}; +use crate::{keygen::AggProvingKey, prover::halo2::Halo2Prover}; pub struct ContinuationProver { stark_prover: StarkProver, diff --git a/crates/sdk/src/prover/stark.rs b/crates/sdk/src/prover/stark.rs index 87f5aa2cd8..c47814caa5 100644 --- a/crates/sdk/src/prover/stark.rs +++ b/crates/sdk/src/prover/stark.rs @@ -6,6 +6,7 @@ use openvm_stark_backend::{prover::types::Proof, Chip}; use crate::{ keygen::{AggStarkProvingKey, AppProvingKey}, prover::{agg::AggStarkProver, app::AppProver}, + verifier::root::types::RootVmVerifierInput, NonRootCommittedExe, RootSC, StdIn, F, SC, }; @@ -50,4 +51,13 @@ impl StarkProver { let app_proof = self.app_prover.generate_app_proof(input); self.agg_prover.generate_agg_proof(app_proof) } + pub fn generate_proof_for_root_program(&self, input: StdIn) -> RootVmVerifierInput + where + VC: VmConfig, + VC::Executor: Chip, + VC::Periphery: Chip, + { + let app_proof = self.app_prover.generate_app_proof(input); + self.agg_prover.generate_root_proof(app_proof) + } } diff --git a/crates/vm/src/arch/vm.rs b/crates/vm/src/arch/vm.rs index da4c8fc093..acf47f92f1 100644 --- a/crates/vm/src/arch/vm.rs +++ b/crates/vm/src/arch/vm.rs @@ -255,6 +255,7 @@ pub struct SingleSegmentVmExecutor { } /// Execution result of a single segment VM execution. +#[derive(Debug)] pub struct SingleSegmentVmExecutionResult { /// All user public values pub public_values: Vec>,