openvm_continuations/circuit/root/verifier/
trace.rs

1use std::borrow::{Borrow, BorrowMut};
2
3use openvm_cpu_backend::CpuBackend;
4use openvm_poseidon2_air::Permutation;
5use openvm_stark_backend::{proof::Proof, prover::AirProvingContext, StarkProtocolConfig};
6use openvm_stark_sdk::config::baby_bear_poseidon2::{
7    poseidon2_compress_with_capacity, poseidon2_perm, BabyBearPoseidon2Config, DIGEST_SIZE, F,
8};
9use openvm_verify_stark_host::pvs::{
10    DeferralPvs, VerifierBasePvs, VerifierDefPvs, VmPvs, DEF_PVS_AIR_ID, VERIFIER_PVS_AIR_ID,
11    VM_PVS_AIR_ID,
12};
13use p3_field::{Field, PrimeCharacteristicRing, PrimeField32};
14use p3_matrix::dense::RowMajorMatrix;
15
16use crate::{
17    circuit::{
18        root::{
19            verifier::air::{RootDefVerifierCols, RootVerifierPvsCols},
20            RootVerifierPvs,
21        },
22        subair::hash_slice_trace,
23        SingleAirTraceData,
24    },
25    utils::pad_slice_to_poseidon2_input,
26};
27
28pub fn generate_proving_ctx<SC: StarkProtocolConfig<F = F>>(
29    proof: &Proof<BabyBearPoseidon2Config>,
30    deferral_enabled: bool,
31) -> SingleAirTraceData<CpuBackend<SC>> {
32    let base_width = RootVerifierPvsCols::<u8>::width();
33    let def_width = RootDefVerifierCols::<u8>::width();
34    let width = base_width + if deferral_enabled { def_width } else { 0 };
35    let mut trace = vec![F::ZERO; width];
36
37    let (base_cols_slice, def_cols_slice) = trace.as_mut_slice().split_at_mut(base_width);
38    let cols: &mut RootVerifierPvsCols<F> = base_cols_slice.borrow_mut();
39
40    let (base_pvs_slice, def_pvs_slice) = proof.public_values[VERIFIER_PVS_AIR_ID]
41        .as_slice()
42        .split_at(VerifierBasePvs::<u8>::width());
43    let child_verifier_pvs: &VerifierBasePvs<F> = base_pvs_slice.borrow();
44    let child_vm_pvs: &VmPvs<F> = proof.public_values[VM_PVS_AIR_ID].as_slice().borrow();
45
46    cols.child_verifier_pvs = *child_verifier_pvs;
47    cols.child_vm_pvs = *child_vm_pvs;
48    let depth_minus_one = child_verifier_pvs.recursion_depth - F::ONE;
49    cols.recursion_depth_minus_one_inv = if depth_minus_one == F::ZERO {
50        F::ZERO
51    } else {
52        depth_minus_one.inverse()
53    };
54    let range_check_inputs = vec![depth_minus_one.as_canonical_u32() as usize];
55
56    let padded_program_commit = pad_slice_to_poseidon2_input(&child_vm_pvs.program_commit, F::ZERO);
57    let padded_initial_root = pad_slice_to_poseidon2_input(&child_vm_pvs.initial_root, F::ZERO);
58    let padded_initial_pc = pad_slice_to_poseidon2_input(&[child_vm_pvs.initial_pc], F::ZERO);
59
60    let perm = poseidon2_perm();
61    cols.program_commit_hash = perm.permute(padded_program_commit)[..DIGEST_SIZE]
62        .try_into()
63        .unwrap();
64    cols.initial_root_hash = perm.permute(padded_initial_root)[..DIGEST_SIZE]
65        .try_into()
66        .unwrap();
67    cols.initial_pc_hash = perm.permute(padded_initial_pc)[..DIGEST_SIZE]
68        .try_into()
69        .unwrap();
70
71    let mut poseidon2_compress_inputs = Vec::with_capacity(5);
72    let mut poseidon2_permute_inputs = Vec::new();
73
74    poseidon2_compress_inputs.extend_from_slice(&[
75        padded_program_commit,
76        padded_initial_root,
77        padded_initial_pc,
78    ]);
79
80    cols.intermediate_exe_commit =
81        poseidon2_compress_with_capacity(cols.program_commit_hash, cols.initial_root_hash).0;
82    poseidon2_compress_inputs.push(crate::utils::digests_to_poseidon2_input(
83        cols.program_commit_hash,
84        cols.initial_root_hash,
85    ));
86
87    let vk_elements = [
88        child_verifier_pvs.app_vk_commit.cached_commit,
89        child_verifier_pvs.app_vk_commit.vk_pre_hash,
90        child_verifier_pvs.leaf_vk_commit.cached_commit,
91        child_verifier_pvs.leaf_vk_commit.vk_pre_hash,
92        child_verifier_pvs.internal_for_leaf_vk_commit.cached_commit,
93        child_verifier_pvs.internal_for_leaf_vk_commit.vk_pre_hash,
94    ];
95    let (intermediate_vk_states, app_vm_commit) = hash_slice_trace(
96        &vk_elements,
97        Some(&mut poseidon2_permute_inputs),
98        Some(&mut poseidon2_compress_inputs),
99    );
100    cols.intermediate_vk_states = intermediate_vk_states.try_into().unwrap();
101
102    let mut public_values = vec![F::ZERO; RootVerifierPvs::<u8>::width()];
103    let root_pvs: &mut RootVerifierPvs<F> = public_values.as_mut_slice().borrow_mut();
104
105    root_pvs.app_exe_commit =
106        poseidon2_compress_with_capacity(cols.intermediate_exe_commit, cols.initial_pc_hash).0;
107    poseidon2_compress_inputs.push(crate::utils::digests_to_poseidon2_input(
108        cols.intermediate_exe_commit,
109        cols.initial_pc_hash,
110    ));
111
112    root_pvs.app_vm_commit = app_vm_commit;
113
114    if deferral_enabled {
115        let def_verifier_pvs: &VerifierDefPvs<F> = def_pvs_slice.borrow();
116        let def_pvs: &DeferralPvs<F> = proof.public_values[DEF_PVS_AIR_ID].as_slice().borrow();
117        let def_cols: &mut RootDefVerifierCols<F> = def_cols_slice.borrow_mut();
118        def_cols.child_def_verifier_pvs = *def_verifier_pvs;
119        def_cols.child_def_pvs = *def_pvs;
120    }
121
122    SingleAirTraceData {
123        air_proving_ctx: AirProvingContext {
124            cached_mains: vec![],
125            common_main: RowMajorMatrix::new(trace, width),
126            public_values,
127        },
128        poseidon2_compress_inputs,
129        poseidon2_permute_inputs,
130        range_check_inputs,
131    }
132}