openvm_continuations/static_verifier/
mod.rs

1use openvm_circuit::arch::PROGRAM_CACHED_TRACE_INDEX;
2use openvm_native_compiler::prelude::*;
3use openvm_native_recursion::{
4    challenger::multi_field32::MultiField32ChallengerVariable,
5    config::outer::{new_from_outer_multi_vk, OuterConfig},
6    digest::DigestVariable,
7    fri::TwoAdicFriPcsVariable,
8    halo2::DslOperations,
9    stark::StarkVerifier,
10    utils::const_fri_config,
11    vars::StarkProofVariable,
12    witness::Witnessable,
13};
14use openvm_stark_backend::keygen::types::MultiStarkVerifyingKey;
15use openvm_stark_sdk::{config::FriParameters, openvm_stark_backend::proof::Proof};
16use p3_bn254::Bn254;
17
18use crate::{
19    verifier::{
20        common::{
21            assert_single_segment_vm_exit_successfully_with_connector_air_id, types::SpecialAirIds,
22        },
23        root::types::RootVmVerifierPvs,
24        utils::compress_babybear_var_to_bn254,
25    },
26    RootSC,
27};
28/// Custom public values handler for static verifier.
29/// This trait implementation defines what the public values of the
30/// final EVM proof will be.
31pub trait StaticVerifierPvHandler {
32    /// Returns the number of public values, as [Bn254] field elements.
33    fn handle_public_values(
34        &self,
35        builder: &mut Builder<OuterConfig>,
36        input: &StarkProofVariable<OuterConfig>,
37        special_air_ids: &SpecialAirIds,
38    ) -> usize;
39}
40
41pub struct DefaultStaticVerifierPvHandler;
42
43impl StaticVerifierPvHandler for DefaultStaticVerifierPvHandler {
44    fn handle_public_values(
45        &self,
46        builder: &mut Builder<OuterConfig>,
47        input: &StarkProofVariable<OuterConfig>,
48        special_air_ids: &SpecialAirIds,
49    ) -> usize {
50        let pv_air = builder.get(&input.per_air, special_air_ids.public_values_air_id);
51        let public_values: Vec<_> = pv_air
52            .public_values
53            .vec()
54            .into_iter()
55            .map(|x| builder.cast_felt_to_var(x))
56            .collect();
57        let pvs = RootVmVerifierPvs::from_flatten(public_values);
58        let exe_commit = compress_babybear_var_to_bn254(builder, pvs.exe_commit);
59        let leaf_commit = compress_babybear_var_to_bn254(builder, pvs.leaf_verifier_commit);
60        let num_public_values = 2 + pvs.public_values.len();
61        builder.static_commit_public_value(0, exe_commit);
62        builder.static_commit_public_value(1, leaf_commit);
63        for (i, x) in pvs.public_values.into_iter().enumerate() {
64            builder.static_commit_public_value(i + 2, x);
65        }
66        num_public_values
67    }
68}
69
70/// Config to generate static verifier DSL operations.
71pub struct StaticVerifierConfig {
72    pub root_verifier_fri_params: FriParameters,
73    pub special_air_ids: SpecialAirIds,
74    pub root_verifier_program_commit: [Bn254; 1],
75}
76
77impl StaticVerifierConfig {
78    pub fn build_static_verifier_operations(
79        &self,
80        root_verifier_vk: &MultiStarkVerifyingKey<RootSC>,
81        proof: &Proof<RootSC>,
82        pv_handler: &impl StaticVerifierPvHandler,
83    ) -> DslOperations<OuterConfig> {
84        let mut builder = Builder::<OuterConfig>::default();
85        builder.flags.static_only = true;
86        let num_public_values = {
87            builder.cycle_tracker_start("VerifierProgram");
88            let input = proof.read(&mut builder);
89            self.verify_root_proof(&mut builder, root_verifier_vk, &input);
90
91            let num_public_values =
92                pv_handler.handle_public_values(&mut builder, &input, &self.special_air_ids);
93            builder.cycle_tracker_end("VerifierProgram");
94            num_public_values
95        };
96        DslOperations {
97            operations: builder.operations,
98            num_public_values,
99        }
100    }
101
102    /// `root_verifier_vk` is the verifying key of the root verifier STARK circuit.
103    /// `root_verifier_fri_params` are the FRI parameters used to prove the root
104    /// verifier STARK circuit.
105    fn verify_root_proof(
106        &self,
107        builder: &mut Builder<OuterConfig>,
108        root_verifier_vk: &MultiStarkVerifyingKey<RootSC>,
109        input: &StarkProofVariable<OuterConfig>,
110    ) {
111        let advice = new_from_outer_multi_vk(root_verifier_vk);
112        let pcs = TwoAdicFriPcsVariable {
113            config: const_fri_config(builder, &self.root_verifier_fri_params),
114        };
115        StarkVerifier::verify::<MultiField32ChallengerVariable<_>>(builder, &pcs, &advice, input);
116        {
117            // Program AIR is the only AIR with a cached trace. The cached trace index doesn't
118            // change after reordering.
119            let t_id = RVar::from(PROGRAM_CACHED_TRACE_INDEX);
120            let commit = builder.get(&input.commitments.main_trace, t_id);
121            let commit = if let DigestVariable::Var(commit_arr) = commit {
122                builder.get(&commit_arr, 0)
123            } else {
124                unreachable!()
125            };
126            builder.assert_var_eq(commit, self.root_verifier_program_commit[0]);
127        }
128        assert_single_segment_vm_exit_successfully_with_connector_air_id(
129            builder,
130            input,
131            self.special_air_ids.connector_air_id,
132        );
133    }
134}