openvm_recursion_circuit/system/
frame.rs

1use itertools::Itertools;
2use openvm_stark_backend::{
3    keygen::types::{
4        MultiStarkVerifyingKey, StarkVerifyingKey, StarkVerifyingParams,
5        VerifierSinglePreprocessedData,
6    },
7    SystemParams,
8};
9use openvm_stark_sdk::config::baby_bear_poseidon2::{BabyBearPoseidon2Config, Digest, F};
10
11use crate::whir::whir_round_encoder;
12
13/*
14 * Modified versions of the STARK and multi-STARK verifying keys for AirModule
15 * implementations. AirModules should use MultiStarkVerifyingKeyFrame instead
16 * of MultiStarkVerifyingKey<BabyBearPoseidon2Config> in their AIRs, as use of
17 * some fields in the latter will compromise internal vk stability.
18 *
19 * We also define check_param_compatibility, which asserts compatibility (with
20 * regards to vk stability) between given app, leaf, and internal SystemParams.
21 *
22 * For more information on vk stability and what can be used in AIRs and how,
23 * see crates/recursion/README.md.
24 */
25
26#[derive(Clone)]
27pub struct StarkVkeyFrame {
28    pub preprocessed_data: Option<VerifierSinglePreprocessedData<Digest>>,
29    pub params: StarkVerifyingParams,
30    pub num_interactions: usize,
31    pub max_constraint_degree: u8,
32    pub is_required: bool,
33}
34
35#[derive(Clone)]
36pub struct MultiStarkVkeyFrame {
37    pub params: SystemParams,
38    pub per_air: Vec<StarkVkeyFrame>,
39    pub max_constraint_degree: usize,
40}
41
42impl From<&StarkVerifyingKey<F, Digest>> for StarkVkeyFrame {
43    fn from(vk: &StarkVerifyingKey<F, Digest>) -> Self {
44        Self {
45            preprocessed_data: vk.preprocessed_data.clone(),
46            params: vk.params.clone(),
47            num_interactions: vk.num_interactions(),
48            max_constraint_degree: vk.max_constraint_degree,
49            is_required: vk.is_required,
50        }
51    }
52}
53
54impl From<&MultiStarkVerifyingKey<BabyBearPoseidon2Config>> for MultiStarkVkeyFrame {
55    fn from(mvk: &MultiStarkVerifyingKey<BabyBearPoseidon2Config>) -> Self {
56        Self {
57            params: mvk.inner.params.clone(),
58            per_air: mvk.inner.per_air.iter().map(Into::into).collect_vec(),
59            max_constraint_degree: mvk.max_constraint_degree(),
60        }
61    }
62}
63
64pub fn check_param_compatibility(
65    app_params: &SystemParams,
66    leaf_params: &SystemParams,
67    internal_params: &SystemParams,
68) {
69    // num_whir_rounds affects the number of columns in WhirRoundAir.
70    assert_eq!(
71        whir_round_encoder(leaf_params.num_whir_rounds()).width(),
72        whir_round_encoder(internal_params.num_whir_rounds()).width()
73    );
74    // logup_pow_bits affects the number of interactions in GkrInputAir.
75    assert_eq!(
76        app_params.logup_pow_bits() > 0,
77        leaf_params.logup_pow_bits() > 0
78    );
79    assert_eq!(
80        leaf_params.logup_pow_bits() > 0,
81        internal_params.logup_pow_bits() > 0
82    );
83    // mu_pow_bits affects the number of interactions in StackingClaimsAir.
84    assert_eq!(
85        app_params.whir.mu_pow_bits > 0,
86        leaf_params.whir.mu_pow_bits > 0
87    );
88    assert_eq!(
89        leaf_params.whir.mu_pow_bits > 0,
90        internal_params.whir.mu_pow_bits > 0
91    );
92    // folding_pow_bits affects the number of interactions in SumcheckAir.
93    assert_eq!(
94        app_params.whir.folding_pow_bits > 0,
95        leaf_params.whir.folding_pow_bits > 0
96    );
97    assert_eq!(
98        leaf_params.whir.folding_pow_bits > 0,
99        internal_params.whir.folding_pow_bits > 0
100    );
101    // query_phase_pow_bits affects the number of interactions in WhirRoundAir.
102    assert_eq!(
103        app_params.whir.query_phase_pow_bits > 0,
104        leaf_params.whir.query_phase_pow_bits > 0
105    );
106    assert_eq!(
107        leaf_params.whir.query_phase_pow_bits > 0,
108        internal_params.whir.query_phase_pow_bits > 0
109    );
110}