Skip to content

Commit 2b70673

Browse files
committed
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 6803f32 commit 2b70673

File tree

21 files changed

+343
-56
lines changed

21 files changed

+343
-56
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
@@ -25,6 +25,7 @@ use openvm_native_circuit::{
2525
CastFExtension, CastFExtensionExecutor, CastFExtensionPeriphery, Native, NativeExecutor,
2626
NativePeriphery,
2727
};
28+
use openvm_native_transpiler::LongFormTranspilerExtension;
2829
use openvm_pairing_circuit::{
2930
PairingExtension, PairingExtensionExecutor, PairingExtensionPeriphery,
3031
};
@@ -139,6 +140,9 @@ impl SdkVmConfig {
139140
if self.sha256.is_some() {
140141
transpiler = transpiler.with_extension(Sha256TranspilerExtension);
141142
}
143+
if self.native.is_some() {
144+
transpiler = transpiler.with_extension(LongFormTranspilerExtension);
145+
}
142146
if self.rv32m.is_some() {
143147
transpiler = transpiler.with_extension(Rv32MTranspilerExtension);
144148
}

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: 123 additions & 8 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 {
@@ -469,7 +474,7 @@ fn test_sdk_guest_build_and_transpile() {
469474
// .with_options(vec!["--release"]);
470475
;
471476
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
472-
pkg_dir.push("guest");
477+
pkg_dir.push("guest/fib");
473478

474479
let vm_config = SdkVmConfig::builder()
475480
.system(SdkSystemConfig {
@@ -516,7 +521,7 @@ fn test_inner_proof_codec_roundtrip() -> eyre::Result<()> {
516521
// generate a proof
517522
let sdk = Sdk::new();
518523
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
519-
pkg_dir.push("guest");
524+
pkg_dir.push("guest/fib");
520525

521526
let vm_config = SdkVmConfig::builder()
522527
.system(SdkSystemConfig {
@@ -614,9 +619,119 @@ fn test_segmentation_retry() {
614619
}
615620

616621
#[test]
617-
fn test_root_verifier_asm_generate() {
618-
let agg_stark_config = agg_stark_config_for_test();
619-
let agg_pk = AggStarkProvingKey::keygen(agg_stark_config);
622+
fn test_verify_openvm_stark_e2e() -> Result<()> {
623+
const ASM_FILENAME: &str = "root_verifier.asm";
620624
let sdk = Sdk::new();
621-
sdk.generate_root_verifier_asm(&agg_pk);
625+
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
626+
pkg_dir.push("guest/fib");
627+
628+
let vm_config = SdkVmConfig::builder()
629+
.system(SdkSystemConfig {
630+
config: SystemConfig::default().with_continuations(),
631+
})
632+
.rv32i(Default::default())
633+
.rv32m(Default::default())
634+
.io(Default::default())
635+
.native(Default::default())
636+
.build();
637+
assert!(vm_config.system.config.continuation_enabled);
638+
let elf = sdk.build(
639+
Default::default(),
640+
&vm_config,
641+
pkg_dir,
642+
&Default::default(),
643+
None,
644+
)?;
645+
646+
let app_exe = sdk.transpile(elf, vm_config.transpiler())?;
647+
let fri_params = FriParameters::new_for_testing(LEAF_LOG_BLOWUP);
648+
let app_config = AppConfig::new_with_leaf_fri_params(fri_params, vm_config.clone(), fri_params);
649+
650+
let app_pk = sdk.app_keygen(app_config.clone())?;
651+
let committed_app_exe = sdk.commit_app_exe(fri_params, app_exe.clone())?;
652+
653+
let commits =
654+
AppExecutionCommit::compute(&vm_config, &committed_app_exe, &app_pk.leaf_committed_exe);
655+
656+
let agg_pk = AggStarkProvingKey::keygen(AggStarkConfig {
657+
max_num_user_public_values: DEFAULT_MAX_NUM_PUBLIC_VALUES,
658+
leaf_fri_params: FriParameters::new_for_testing(LEAF_LOG_BLOWUP),
659+
internal_fri_params: FriParameters::new_for_testing(INTERNAL_LOG_BLOWUP),
660+
root_fri_params: FriParameters::new_for_testing(ROOT_LOG_BLOWUP),
661+
profiling: false,
662+
compiler_options: CompilerOptions {
663+
enable_cycle_tracker: true,
664+
..Default::default()
665+
},
666+
root_max_constraint_degree: (1 << ROOT_LOG_BLOWUP) + 1,
667+
});
668+
let asm = sdk.generate_root_verifier_asm(&agg_pk);
669+
let asm_path = format!(
670+
"{}/guest/verify_openvm_stark/{}",
671+
env!("CARGO_MANIFEST_DIR"),
672+
ASM_FILENAME
673+
);
674+
std::fs::write(asm_path, asm)?;
675+
676+
let e2e_stark_proof = sdk.generate_e2e_stark_proof(
677+
Arc::new(app_pk),
678+
committed_app_exe,
679+
agg_pk,
680+
StdIn::default(),
681+
)?;
682+
683+
let verify_exe = {
684+
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
685+
pkg_dir.push("guest/verify_openvm_stark");
686+
let elf = sdk.build(
687+
Default::default(),
688+
&vm_config,
689+
pkg_dir,
690+
&Default::default(),
691+
None,
692+
)?;
693+
sdk.transpile(elf, vm_config.transpiler())?
694+
};
695+
696+
let pvs = [13u32, 21, 0, 0, 0, 0, 0, 0];
697+
698+
let exe_commit_u32: Vec<_> = commits
699+
.exe_commit
700+
.iter()
701+
.map(|x| x.as_canonical_u32())
702+
.collect();
703+
let vm_commit_u32: Vec<_> = commits
704+
.leaf_vm_verifier_commit
705+
.iter()
706+
.map(|x| x.as_canonical_u32())
707+
.collect();
708+
let pvs_u32: Vec<_> = pvs
709+
.iter()
710+
.flat_map(|x| x.to_le_bytes())
711+
.map(|x| x as u32)
712+
.collect();
713+
714+
let key = ASM_FILENAME
715+
.as_bytes()
716+
.iter()
717+
.cloned()
718+
.chain(exe_commit_u32.iter().flat_map(|x| x.to_le_bytes()))
719+
.chain(vm_commit_u32.iter().flat_map(|x| x.to_le_bytes()))
720+
.chain(pvs_u32.iter().flat_map(|x| x.to_le_bytes()))
721+
.collect();
722+
let mut stdin = StdIn::default();
723+
let to_encode: Vec<Vec<F>> = e2e_stark_proof.proof.write();
724+
let value = hint_load_by_key_encode(&to_encode);
725+
stdin.add_key_value(key, value);
726+
727+
let exe_commit_u32_8: [u32; 8] = exe_commit_u32.try_into().unwrap();
728+
let vm_commit_u32_8: [u32; 8] = vm_commit_u32.try_into().unwrap();
729+
730+
stdin.write(&exe_commit_u32_8);
731+
stdin.write(&vm_commit_u32_8);
732+
stdin.write(&pvs_u32);
733+
734+
sdk.execute(verify_exe, vm_config, stdin)?;
735+
736+
Ok(())
622737
}

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
@@ -31,6 +31,8 @@ pub mod utils;
3131

3232
#[cfg(not(target_os = "zkvm"))]
3333
pub mod host;
34+
#[cfg(target_os = "zkvm")]
35+
pub mod verify_stark;
3436

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

0 commit comments

Comments
 (0)