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