openvm_verify_stark_circuit/verifier/
trace.rs1use std::borrow::{Borrow, BorrowMut};
2
3use openvm_circuit::arch::POSEIDON2_WIDTH;
4use openvm_continuations::{
5 circuit::{
6 deferral::DeferralCircuitPvs, root::NUM_DIGESTS_IN_VM_COMMIT, subair::hash_slice_trace,
7 utils::vk_commit_components,
8 },
9 utils::{digests_to_poseidon2_input, pad_slice_to_poseidon2_input, poseidon2_input_to_digests},
10};
11use openvm_cpu_backend::CpuBackend;
12use openvm_poseidon2_air::Permutation;
13use openvm_stark_backend::{proof::Proof, prover::AirProvingContext};
14use openvm_stark_sdk::config::baby_bear_poseidon2::{
15 poseidon2_compress_with_capacity, poseidon2_perm, BabyBearPoseidon2Config, DIGEST_SIZE, F,
16};
17use openvm_verify_stark_host::pvs::{
18 DeferralPvs, VerifierBasePvs, VerifierDefPvs, VmPvs, DEF_PVS_AIR_ID, VERIFIER_PVS_AIR_ID,
19 VM_PVS_AIR_ID,
20};
21use p3_field::{Field, PrimeCharacteristicRing, PrimeField32};
22use p3_matrix::dense::RowMajorMatrix;
23
24use crate::verifier::{DeferredVerifyPvsCols, RecursiveDeferredVerifyCols};
25
26#[repr(C)]
27#[derive(Clone, Copy)]
28pub struct DeferredVerifyPvsRecord<F> {
29 pub program_commit_hash: [F; DIGEST_SIZE],
30 pub initial_root_hash: [F; DIGEST_SIZE],
31 pub initial_pc_hash: [F; DIGEST_SIZE],
32 pub intermediate_exe_commit: [F; DIGEST_SIZE],
33 pub intermediate_vk_states: [[F; POSEIDON2_WIDTH]; NUM_DIGESTS_IN_VM_COMMIT - 1],
34 pub app_exe_commit: [F; DIGEST_SIZE],
35 pub app_vm_commit: [F; DIGEST_SIZE],
36}
37
38#[allow(clippy::type_complexity)]
39pub fn generate_record(
40 proof: &Proof<BabyBearPoseidon2Config>,
41) -> (
42 DeferredVerifyPvsRecord<F>,
43 Vec<[F; POSEIDON2_WIDTH]>,
44 Vec<[F; POSEIDON2_WIDTH]>,
45 Vec<usize>,
46) {
47 let (base_pvs_slice, _) = proof.public_values[VERIFIER_PVS_AIR_ID]
48 .as_slice()
49 .split_at(VerifierBasePvs::<u8>::width());
50 let child_verifier_pvs: &VerifierBasePvs<F> = base_pvs_slice.borrow();
51 let child_vm_pvs: &VmPvs<F> = proof.public_values[VM_PVS_AIR_ID].as_slice().borrow();
52 let depth_minus_one = child_verifier_pvs.recursion_depth - F::ONE;
53 let range_check_inputs = vec![depth_minus_one.as_canonical_u32() as usize];
54
55 let padded_program_commit = pad_slice_to_poseidon2_input(&child_vm_pvs.program_commit, F::ZERO);
56 let padded_initial_root = pad_slice_to_poseidon2_input(&child_vm_pvs.initial_root, F::ZERO);
57 let padded_initial_pc = pad_slice_to_poseidon2_input(&[child_vm_pvs.initial_pc], F::ZERO);
58
59 let perm = poseidon2_perm();
60 let program_commit_hash = perm.permute(padded_program_commit)[..DIGEST_SIZE]
61 .try_into()
62 .unwrap();
63 let initial_root_hash = perm.permute(padded_initial_root)[..DIGEST_SIZE]
64 .try_into()
65 .unwrap();
66 let initial_pc_hash = perm.permute(padded_initial_pc)[..DIGEST_SIZE]
67 .try_into()
68 .unwrap();
69
70 let mut poseidon2_compress_inputs = Vec::with_capacity(5);
71 let mut poseidon2_permute_inputs = Vec::new();
72 poseidon2_compress_inputs.extend_from_slice(&[
73 padded_program_commit,
74 padded_initial_root,
75 padded_initial_pc,
76 ]);
77
78 let intermediate_exe_commit =
79 poseidon2_compress_with_capacity(program_commit_hash, initial_root_hash).0;
80 poseidon2_compress_inputs.push(digests_to_poseidon2_input(
81 program_commit_hash,
82 initial_root_hash,
83 ));
84
85 let (intermediate_vk_states_vec, app_vm_commit) = hash_slice_trace(
86 &vk_commit_components(child_verifier_pvs),
87 Some(&mut poseidon2_permute_inputs),
88 Some(&mut poseidon2_compress_inputs),
89 );
90 let intermediate_vk_states = intermediate_vk_states_vec.try_into().unwrap();
91
92 let app_exe_commit =
93 poseidon2_compress_with_capacity(intermediate_exe_commit, initial_pc_hash).0;
94 poseidon2_compress_inputs.push(digests_to_poseidon2_input(
95 intermediate_exe_commit,
96 initial_pc_hash,
97 ));
98
99 (
100 DeferredVerifyPvsRecord {
101 program_commit_hash,
102 initial_root_hash,
103 initial_pc_hash,
104 intermediate_exe_commit,
105 intermediate_vk_states,
106 app_exe_commit,
107 app_vm_commit,
108 },
109 poseidon2_compress_inputs,
110 poseidon2_permute_inputs,
111 range_check_inputs,
112 )
113}
114
115pub fn generate_proving_ctx(
116 proof: &Proof<BabyBearPoseidon2Config>,
117 record: DeferredVerifyPvsRecord<F>,
118 final_transcript_state: [F; POSEIDON2_WIDTH],
119 output_commit: [F; DIGEST_SIZE],
120 def_idx: usize,
121 deferral_enabled: bool,
122) -> AirProvingContext<CpuBackend<BabyBearPoseidon2Config>> {
123 let base_width = DeferredVerifyPvsCols::<u8>::width();
124 let rec_width = RecursiveDeferredVerifyCols::<u8>::width();
125 let width = base_width + if deferral_enabled { rec_width } else { 0 };
126
127 let mut trace = vec![F::ZERO; width];
128 let (base_cols_slice, def_cols_slice) = trace.as_mut_slice().split_at_mut(base_width);
129 let cols: &mut DeferredVerifyPvsCols<F> = base_cols_slice.borrow_mut();
130
131 let (base_pvs_slice, def_pvs_slice) = proof.public_values[VERIFIER_PVS_AIR_ID]
132 .as_slice()
133 .split_at(VerifierBasePvs::<u8>::width());
134 let child_verifier_pvs: &VerifierBasePvs<F> = base_pvs_slice.borrow();
135 let child_vm_pvs: &VmPvs<F> = proof.public_values[VM_PVS_AIR_ID].as_slice().borrow();
136
137 cols.child_verifier_pvs = *child_verifier_pvs;
138 cols.child_vm_pvs = *child_vm_pvs;
139 let depth_minus_one = child_verifier_pvs.recursion_depth - F::ONE;
140 cols.recursion_depth_minus_one_inv = if depth_minus_one == F::ZERO {
141 F::ZERO
142 } else {
143 depth_minus_one.inverse()
144 };
145 cols.program_commit_hash = record.program_commit_hash;
146 cols.initial_root_hash = record.initial_root_hash;
147 cols.initial_pc_hash = record.initial_pc_hash;
148 cols.intermediate_exe_commit = record.intermediate_exe_commit;
149 cols.intermediate_vk_states = record.intermediate_vk_states;
150 cols.app_exe_commit = record.app_exe_commit;
151 cols.app_vm_commit = record.app_vm_commit;
152 cols.final_transcript_state = final_transcript_state;
153
154 if deferral_enabled {
155 let rec_cols: &mut RecursiveDeferredVerifyCols<_> = def_cols_slice.borrow_mut();
156 let def_verifier_pvs: &VerifierDefPvs<_> = def_pvs_slice.borrow();
157 let def_pvs: &DeferralPvs<_> = proof.public_values[DEF_PVS_AIR_ID].as_slice().borrow();
158 rec_cols.child_def_verifier_pvs = *def_verifier_pvs;
159 rec_cols.child_def_pvs = *def_pvs;
160 }
161
162 let mut public_values = vec![F::ZERO; DeferralCircuitPvs::<u8>::width()];
163 let deferral_pvs: &mut DeferralCircuitPvs<F> = public_values.as_mut_slice().borrow_mut();
164
165 let (left, right) = poseidon2_input_to_digests(final_transcript_state);
168 deferral_pvs.input_commit = poseidon2_compress_with_capacity(left, right).0;
169 deferral_pvs.output_commit = output_commit;
170 deferral_pvs.def_idx = F::from_usize(def_idx);
171
172 AirProvingContext {
173 cached_mains: vec![],
174 common_main: RowMajorMatrix::new(trace, width),
175 public_values,
176 }
177}