Skip to content

Commit c942537

Browse files
authored
feat: Macro define_verify_openvm_stark (#1620)
- Add a RISC-V custom instruction `nativestorew` into `Rv32IoTranspilerExtension`. - Add macro `define_verify_openvm_stark`, which can define a function for guest program to verify a stark proof. closes INT-3896
1 parent d7a1322 commit c942537

File tree

21 files changed

+332
-57
lines changed

21 files changed

+332
-57
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ openvm-native-circuit = { path = "extensions/native/circuit", default-features =
140140
openvm-native-compiler = { path = "extensions/native/compiler", default-features = false }
141141
openvm-native-compiler-derive = { path = "extensions/native/compiler/derive", default-features = false }
142142
openvm-native-recursion = { path = "extensions/native/recursion", default-features = false }
143+
openvm-native-transpiler = { path = "extensions/native/transpiler", default-features = false }
143144
openvm-keccak256-circuit = { path = "extensions/keccak256/circuit", default-features = false }
144145
openvm-keccak256-transpiler = { path = "extensions/keccak256/transpiler", default-features = false }
145146
openvm-keccak256-guest = { path = "extensions/keccak256/guest", default-features = false }

crates/sdk/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ openvm-pairing-transpiler = { workspace = true }
2525
openvm-native-circuit = { workspace = true }
2626
openvm-native-compiler = { workspace = true }
2727
openvm-native-recursion = { workspace = true, features = ["static-verifier"] }
28+
openvm-native-transpiler = { workspace = true }
2829
openvm-rv32im-circuit = { workspace = true }
2930
openvm-rv32im-transpiler = { workspace = true }
3031
openvm-transpiler = { workspace = true }
@@ -57,6 +58,10 @@ hex.workspace = true
5758
forge-fmt = { workspace = true, optional = true }
5859
rrs-lib = { workspace = true }
5960

61+
[dev-dependencies]
62+
openvm-rv32im-guest.workspace = true
63+
64+
6065
[features]
6166
default = ["parallel", "jemalloc", "evm-verify"]
6267
evm-prove = ["openvm-native-recursion/evm-prove"]

crates/sdk/examples/sdk_app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
4646
/// use std::path::PathBuf;
4747
///
4848
/// let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
49-
/// path.push("guest");
49+
/// path.push("guest/fib");
5050
/// let target_path = path.to_str().unwrap();
5151
/// ```
5252
// ANCHOR: build

crates/sdk/examples/sdk_evm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
4646
/// use std::path::PathBuf;
4747
///
4848
/// let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
49-
/// path.push("guest");
49+
/// path.push("guest/fib");
5050
/// let target_path = path.to_str().unwrap();
5151
/// ```
5252
// ANCHOR: build

crates/sdk/guest/Cargo.toml renamed to crates/sdk/guest/fib/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ version = "0.0.0"
55
edition = "2021"
66

77
[dependencies]
8-
openvm = { path = "../../toolchain/openvm" }
8+
openvm = { path = "../../../toolchain/openvm" }
File renamed without changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.asm
2+
Cargo.lock
3+
target/
4+
openvm/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[workspace]
2+
[package]
3+
name = "openvm-verify-stark-program"
4+
version = "0.0.0"
5+
edition = "2021"
6+
7+
[dependencies]
8+
openvm = { path = "../../../toolchain/openvm", features = ["std"] }
9+
hex-literal = { version = "0.4.1", default-features = false }
10+
bytemuck = { version = "1.20.0", features = ["extern_crate_alloc"] }
11+
12+
[features]
13+
default = []
14+
15+
[profile.profiling]
16+
inherits = "release"
17+
debug = 2
18+
strip = false
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
extern crate alloc;
2+
use alloc::vec::Vec;
3+
4+
use openvm::{define_verify_openvm_stark, io::read};
5+
6+
define_verify_openvm_stark!(
7+
verify_openvm_stark,
8+
env!("CARGO_MANIFEST_DIR"),
9+
"root_verifier.asm"
10+
);
11+
12+
// const APP_EXE_COMMIT: [u32; 8] = [
13+
// 343014587, 230645511, 1447462186, 773379336, 1182270030, 1497892484, 461820702, 353704350,
14+
// ];
15+
// const APP_VM_COMMIT: [u32; 8] = [
16+
// 445134834, 1133596793, 530952192, 425228715, 1806903712, 1362083369, 295028151, 482389308,
17+
// ];
18+
19+
pub fn main() {
20+
let app_exe_commit: [u32; 8] = read();
21+
let app_vm_commit: [u32; 8] = read();
22+
let pvs: Vec<u32> = read();
23+
verify_openvm_stark(&app_exe_commit, &app_vm_commit, &pvs);
24+
}

crates/sdk/src/config/global.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use openvm_native_circuit::{
2424
CastFExtension, CastFExtensionExecutor, CastFExtensionPeriphery, Native, NativeExecutor,
2525
NativePeriphery,
2626
};
27+
use openvm_native_transpiler::LongFormTranspilerExtension;
2728
use openvm_pairing_circuit::{
2829
PairingExtension, PairingExtensionExecutor, PairingExtensionPeriphery,
2930
};
@@ -138,6 +139,9 @@ impl SdkVmConfig {
138139
if self.sha256.is_some() {
139140
transpiler = transpiler.with_extension(Sha256TranspilerExtension);
140141
}
142+
if self.native.is_some() {
143+
transpiler = transpiler.with_extension(LongFormTranspilerExtension);
144+
}
141145
if self.rv32m.is_some() {
142146
transpiler = transpiler.with_extension(Rv32MTranspilerExtension);
143147
}

crates/sdk/src/stdin.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::collections::VecDeque;
1+
use std::{
2+
collections::{HashMap, VecDeque},
3+
sync::Arc,
4+
};
25

36
use openvm_circuit::arch::Streams;
47
use openvm_stark_backend::p3_field::FieldAlgebra;
@@ -9,6 +12,7 @@ use crate::F;
912
#[derive(Clone, Default, Serialize, Deserialize)]
1013
pub struct StdIn {
1114
pub buffer: VecDeque<Vec<F>>,
15+
pub kv_store: HashMap<Vec<u8>, Vec<u8>>,
1216
}
1317

1418
impl StdIn {
@@ -36,6 +40,9 @@ impl StdIn {
3640
pub fn write_field(&mut self, data: &[F]) {
3741
self.buffer.push_back(data.to_vec());
3842
}
43+
pub fn add_key_value(&mut self, key: Vec<u8>, value: Vec<u8>) {
44+
self.kv_store.insert(key, value);
45+
}
3946
}
4047

4148
impl From<StdIn> for Streams<F> {
@@ -44,7 +51,9 @@ impl From<StdIn> for Streams<F> {
4451
while let Some(input) = std_in.read() {
4552
data.push(input);
4653
}
47-
Streams::new(data)
54+
let mut ret = Streams::new(data);
55+
ret.kv_store = Arc::new(std_in.kv_store);
56+
ret
4857
}
4958
}
5059

crates/sdk/tests/integration_test.rs

Lines changed: 112 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use openvm_circuit::{
66
arch::{
77
hasher::poseidon2::vm_poseidon2_hasher, ContinuationVmProof, ExecutionError,
88
GenerationError, SingleSegmentVmExecutor, SystemConfig, VmConfig, VmExecutor,
9+
DEFAULT_MAX_NUM_PUBLIC_VALUES,
910
},
1011
system::{memory::tree::public_values::UserPublicValuesProof, program::trace::VmCommittedExe},
1112
};
@@ -27,9 +28,11 @@ use openvm_native_recursion::{
2728
wrapper::Halo2WrapperProvingKey,
2829
RawEvmProof,
2930
},
31+
hints::Hintable,
3032
types::InnerConfig,
3133
vars::StarkProofVariable,
3234
};
35+
use openvm_rv32im_guest::hint_load_by_key_encode;
3336
use openvm_rv32im_transpiler::{
3437
Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension,
3538
};
@@ -41,7 +44,9 @@ use openvm_sdk::{
4144
types::{EvmHalo2Verifier, EvmProof},
4245
DefaultStaticVerifierPvHandler, Sdk, StdIn,
4346
};
44-
use openvm_stark_backend::{keygen::types::LinearConstraint, p3_matrix::Matrix};
47+
use openvm_stark_backend::{
48+
keygen::types::LinearConstraint, p3_field::PrimeField32, p3_matrix::Matrix,
49+
};
4550
use openvm_stark_sdk::{
4651
config::{
4752
baby_bear_poseidon2::{BabyBearPoseidon2Config, BabyBearPoseidon2Engine},
@@ -393,7 +398,7 @@ fn test_static_verifier_custom_pv_handler() {
393398
#[test]
394399
fn test_e2e_proof_generation_and_verification_with_pvs() {
395400
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
396-
pkg_dir.push("guest");
401+
pkg_dir.push("guest/fib");
397402

398403
let vm_config = SdkVmConfig::builder()
399404
.system(SdkSystemConfig {
@@ -463,7 +468,7 @@ fn test_sdk_guest_build_and_transpile() {
463468
// .with_options(vec!["--release"]);
464469
;
465470
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
466-
pkg_dir.push("guest");
471+
pkg_dir.push("guest/fib");
467472
let one = sdk
468473
.build(guest_opts.clone(), &pkg_dir, &Default::default())
469474
.unwrap();
@@ -484,7 +489,7 @@ fn test_inner_proof_codec_roundtrip() -> eyre::Result<()> {
484489
// generate a proof
485490
let sdk = Sdk::new();
486491
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
487-
pkg_dir.push("guest");
492+
pkg_dir.push("guest/fib");
488493
let elf = sdk.build(Default::default(), pkg_dir, &Default::default())?;
489494

490495
let vm_config = SdkVmConfig::builder()
@@ -574,11 +579,109 @@ fn test_segmentation_retry() {
574579
.sum();
575580
assert!(new_total_height < total_height);
576581
}
577-
578582
#[test]
579-
fn test_root_verifier_asm_generate() {
580-
let agg_stark_config = agg_stark_config_for_test();
581-
let agg_pk = AggStarkProvingKey::keygen(agg_stark_config);
583+
fn test_verify_openvm_stark_e2e() -> Result<()> {
584+
const ASM_FILENAME: &str = "root_verifier.asm";
582585
let sdk = Sdk::new();
583-
sdk.generate_root_verifier_asm(&agg_pk);
586+
let guest_opts = GuestOptions::default();
587+
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
588+
pkg_dir.push("guest/fib");
589+
let elf = sdk.build(guest_opts.clone(), &pkg_dir, &Default::default())?;
590+
591+
let vm_config = SdkVmConfig::builder()
592+
.system(SdkSystemConfig {
593+
config: SystemConfig::default().with_continuations(),
594+
})
595+
.rv32i(Default::default())
596+
.rv32m(Default::default())
597+
.io(Default::default())
598+
.native(Default::default())
599+
.build();
600+
assert!(vm_config.system.config.continuation_enabled);
601+
602+
let app_exe = sdk.transpile(elf, vm_config.transpiler())?;
603+
let fri_params = FriParameters::new_for_testing(LEAF_LOG_BLOWUP);
604+
let app_config = AppConfig::new_with_leaf_fri_params(fri_params, vm_config.clone(), fri_params);
605+
606+
let app_pk = sdk.app_keygen(app_config.clone())?;
607+
let committed_app_exe = sdk.commit_app_exe(fri_params, app_exe.clone())?;
608+
609+
let commits =
610+
AppExecutionCommit::compute(&vm_config, &committed_app_exe, &app_pk.leaf_committed_exe);
611+
612+
let agg_pk = AggStarkProvingKey::keygen(AggStarkConfig {
613+
max_num_user_public_values: DEFAULT_MAX_NUM_PUBLIC_VALUES,
614+
leaf_fri_params: FriParameters::new_for_testing(LEAF_LOG_BLOWUP),
615+
internal_fri_params: FriParameters::new_for_testing(INTERNAL_LOG_BLOWUP),
616+
root_fri_params: FriParameters::new_for_testing(ROOT_LOG_BLOWUP),
617+
profiling: false,
618+
compiler_options: CompilerOptions {
619+
enable_cycle_tracker: true,
620+
..Default::default()
621+
},
622+
root_max_constraint_degree: (1 << ROOT_LOG_BLOWUP) + 1,
623+
});
624+
let asm = sdk.generate_root_verifier_asm(&agg_pk);
625+
let asm_path = format!(
626+
"{}/guest/verify_openvm_stark/{}",
627+
env!("CARGO_MANIFEST_DIR"),
628+
ASM_FILENAME
629+
);
630+
std::fs::write(asm_path, asm)?;
631+
632+
let e2e_stark_proof = sdk.generate_e2e_stark_proof(
633+
Arc::new(app_pk),
634+
committed_app_exe,
635+
agg_pk,
636+
StdIn::default(),
637+
)?;
638+
639+
let verify_exe = {
640+
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
641+
pkg_dir.push("guest/verify_openvm_stark");
642+
let elf = sdk.build(guest_opts.clone(), &pkg_dir, &Default::default())?;
643+
sdk.transpile(elf, vm_config.transpiler())?
644+
};
645+
646+
let pvs = [13u32, 21, 0, 0, 0, 0, 0, 0];
647+
648+
let exe_commit_u32: Vec<_> = commits
649+
.exe_commit
650+
.iter()
651+
.map(|x| x.as_canonical_u32())
652+
.collect();
653+
let vm_commit_u32: Vec<_> = commits
654+
.leaf_vm_verifier_commit
655+
.iter()
656+
.map(|x| x.as_canonical_u32())
657+
.collect();
658+
let pvs_u32: Vec<_> = pvs
659+
.iter()
660+
.flat_map(|x| x.to_le_bytes())
661+
.map(|x| x as u32)
662+
.collect();
663+
664+
let key = ASM_FILENAME
665+
.as_bytes()
666+
.iter()
667+
.cloned()
668+
.chain(exe_commit_u32.iter().flat_map(|x| x.to_le_bytes()))
669+
.chain(vm_commit_u32.iter().flat_map(|x| x.to_le_bytes()))
670+
.chain(pvs_u32.iter().flat_map(|x| x.to_le_bytes()))
671+
.collect();
672+
let mut stdin = StdIn::default();
673+
let to_encode: Vec<Vec<F>> = e2e_stark_proof.proof.write();
674+
let value = hint_load_by_key_encode(&to_encode);
675+
stdin.add_key_value(key, value);
676+
677+
let exe_commit_u32_8: [u32; 8] = exe_commit_u32.try_into().unwrap();
678+
let vm_commit_u32_8: [u32; 8] = vm_commit_u32.try_into().unwrap();
679+
680+
stdin.write(&exe_commit_u32_8);
681+
stdin.write(&vm_commit_u32_8);
682+
stdin.write(&pvs_u32);
683+
684+
sdk.execute(verify_exe, vm_config, stdin)?;
685+
686+
Ok(())
584687
}

crates/toolchain/openvm/src/io/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ pub fn reveal_u32(x: u32, index: usize) {
126126
println!("reveal {} at byte location {}", x, index * 4);
127127
}
128128

129+
/// Store u32 `x` to the native address `native_addr` as 4 field element in byte.
130+
#[allow(unused_variables)]
131+
#[inline(always)]
132+
pub fn store_u32_to_native(native_addr: u32, x: u32) {
133+
#[cfg(target_os = "zkvm")]
134+
openvm_rv32im_guest::store_to_native!(native_addr, x);
135+
#[cfg(not(target_os = "zkvm"))]
136+
panic!("store_to_native_u32 cannot run on non-zkVM platforms");
137+
}
138+
129139
/// A no-alloc writer to print to stdout on host machine for debugging purposes.
130140
pub struct Writer;
131141

crates/toolchain/openvm/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub mod utils;
2929

3030
#[cfg(not(target_os = "zkvm"))]
3131
pub mod host;
32+
#[cfg(target_os = "zkvm")]
33+
pub mod verify_stark;
3234

3335
#[cfg(target_os = "zkvm")]
3436
core::arch::global_asm!(include_str!("memset.s"));

0 commit comments

Comments
 (0)