openvm_verify_stark_guest/
lib.rs

1#![cfg_attr(target_os = "zkvm", no_std)]
2
3extern crate alloc;
4
5use alloc::{vec, vec::Vec};
6
7use openvm_deferral_guest::{deferred_compute, get_deferred_output, Commit, COMMIT_NUM_BYTES};
8
9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct ProofOutput {
11    pub app_exe_commit: Commit,
12    pub app_vm_commit: Commit,
13    pub user_public_values: Vec<u8>,
14}
15
16pub fn verify_stark_unchecked<const DEF_IDX: u16>(input_commit: &Commit) -> ProofOutput {
17    let output_key = deferred_compute::<DEF_IDX>(input_commit);
18    let output_len = output_key.output_len as usize;
19    let mut output_bytes = vec![0u8; output_len];
20    get_deferred_output::<DEF_IDX>(&mut output_bytes, &output_key);
21
22    const MIN_OUTPUT_BYTES: usize = 2 * COMMIT_NUM_BYTES;
23    if output_len < MIN_OUTPUT_BYTES {
24        panic!("output_len too small for a ProofOutput");
25    }
26
27    let app_exe_commit = output_bytes[..COMMIT_NUM_BYTES].try_into().unwrap();
28    let app_vm_commit = output_bytes[COMMIT_NUM_BYTES..MIN_OUTPUT_BYTES]
29        .try_into()
30        .unwrap();
31    let user_public_values = collapse_user_public_values(&output_bytes[MIN_OUTPUT_BYTES..]);
32
33    ProofOutput {
34        app_exe_commit,
35        app_vm_commit,
36        user_public_values,
37    }
38}
39
40pub fn verify_stark<const DEF_IDX: u16>(input_commit: &Commit, expected: &ProofOutput) {
41    let actual = verify_stark_unchecked::<DEF_IDX>(input_commit);
42    if actual != *expected {
43        panic!("Proof verification failed for commit {:?}", input_commit);
44    }
45}
46
47fn collapse_user_public_values(expanded: &[u8]) -> Vec<u8> {
48    const F_NUM_BYTES: usize = 4;
49
50    if !expanded.len().is_multiple_of(F_NUM_BYTES) {
51        panic!("User public values output length is not a multiple of {F_NUM_BYTES}");
52    }
53
54    let mut user_public_values = Vec::with_capacity(expanded.len() / F_NUM_BYTES);
55    for bytes in expanded.chunks_exact(F_NUM_BYTES) {
56        if bytes[1..].iter().any(|&byte| byte != 0) {
57            panic!("User public value has non-zero high bytes");
58        }
59        user_public_values.push(bytes[0]);
60    }
61    user_public_values
62}