openvm_continuations/circuit/deferral/hook/verifier/
trace.rs1use std::borrow::{Borrow, BorrowMut};
2
3use openvm_cpu_backend::CpuBackend;
4use openvm_stark_backend::{proof::Proof, prover::AirProvingContext};
5use openvm_stark_sdk::config::baby_bear_poseidon2::{
6 poseidon2_compress_with_capacity, BabyBearPoseidon2Config, DIGEST_SIZE, F,
7};
8use openvm_verify_stark_host::pvs::{DeferralPvs, VerifierBasePvs};
9use p3_field::{Field, PrimeCharacteristicRing, PrimeField32};
10use p3_matrix::dense::RowMajorMatrix;
11
12use crate::{
13 circuit::{
14 deferral::{
15 hook::verifier::air::DeferralHookPvsCols, DeferralAggregationPvs, DEF_AGG_PVS_AIR_ID,
16 DEF_AGG_VERIFIER_AIR_ID,
17 },
18 root::NUM_DIGESTS_IN_VM_COMMIT,
19 subair::hash_slice_trace,
20 SingleAirTraceData,
21 },
22 utils::{digests_to_poseidon2_input, pad_slice_to_poseidon2_input, zero_hash},
23 SC,
24};
25
26pub struct DeferralHookVerifierTraceCtx {
27 pub trace_data: SingleAirTraceData<CpuBackend<BabyBearPoseidon2Config>>,
28 pub def_circuit_commit: [F; DIGEST_SIZE],
29}
30
31pub fn def_circuit_commit_from_verifier_pvs(verifier_pvs: &VerifierBasePvs<F>) -> [F; DIGEST_SIZE] {
32 let hash_elements = [
33 verifier_pvs.app_vk_commit.cached_commit,
34 verifier_pvs.app_vk_commit.vk_pre_hash,
35 verifier_pvs.leaf_vk_commit.cached_commit,
36 verifier_pvs.leaf_vk_commit.vk_pre_hash,
37 verifier_pvs.internal_for_leaf_vk_commit.cached_commit,
38 verifier_pvs.internal_for_leaf_vk_commit.vk_pre_hash,
39 ];
40 hash_slice_trace(&hash_elements, None, None).1
41}
42
43pub fn generate_proving_ctx(
44 proof: &Proof<SC>,
45 input_onion: [F; DIGEST_SIZE],
46 output_onion: [F; DIGEST_SIZE],
47) -> DeferralHookVerifierTraceCtx {
48 let verifier_pvs: &VerifierBasePvs<F> = proof.public_values[DEF_AGG_VERIFIER_AIR_ID]
49 .as_slice()
50 .borrow();
51 let def_pvs: &DeferralAggregationPvs<F> =
52 proof.public_values[DEF_AGG_PVS_AIR_ID].as_slice().borrow();
53
54 let hash_elements = [
55 verifier_pvs.app_vk_commit.cached_commit,
56 verifier_pvs.app_vk_commit.vk_pre_hash,
57 verifier_pvs.leaf_vk_commit.cached_commit,
58 verifier_pvs.leaf_vk_commit.vk_pre_hash,
59 verifier_pvs.internal_for_leaf_vk_commit.cached_commit,
60 verifier_pvs.internal_for_leaf_vk_commit.vk_pre_hash,
61 ];
62
63 let width = DeferralHookPvsCols::<u8>::width();
64 let mut trace = vec![F::ZERO; width];
65 let cols: &mut DeferralHookPvsCols<F> = trace.as_mut_slice().borrow_mut();
66 cols.verifier_pvs = *verifier_pvs;
67 cols.def_pvs = *def_pvs;
68 let depth_minus_one = verifier_pvs.recursion_depth - F::ONE;
69 cols.recursion_depth_minus_one_inv = if depth_minus_one == F::ZERO {
70 F::ZERO
71 } else {
72 depth_minus_one.inverse()
73 };
74 let range_check_inputs = vec![depth_minus_one.as_canonical_u32() as usize];
75 cols.num_merkle_leaves =
76 F::from_usize(1usize << def_pvs.merkle_depth.as_canonical_u32() as usize);
77 cols.input_onion = input_onion;
78 cols.output_onion = output_onion;
79
80 let mut poseidon2_compress_inputs = Vec::with_capacity(6);
81 let mut poseidon2_permute_inputs = Vec::with_capacity(NUM_DIGESTS_IN_VM_COMMIT - 1);
82 let (intermediate_vk_states, def_circuit_commit) = hash_slice_trace(
83 &hash_elements,
84 Some(&mut poseidon2_permute_inputs),
85 Some(&mut poseidon2_compress_inputs),
86 );
87 cols.intermediate_vk_states = intermediate_vk_states.try_into().unwrap();
88 cols.def_circuit_commit = def_circuit_commit;
89
90 const ZERO_DIGEST: [F; DIGEST_SIZE] = [F::ZERO; DIGEST_SIZE];
91 let def_circuit_commit_padded =
92 poseidon2_compress_with_capacity(def_circuit_commit, ZERO_DIGEST).0;
93 let input_onion_padded = poseidon2_compress_with_capacity(input_onion, ZERO_DIGEST).0;
94 let output_onion_padded = poseidon2_compress_with_capacity(output_onion, ZERO_DIGEST).0;
95 cols.def_circuit_commit_padded = def_circuit_commit_padded;
96 cols.input_onion_padded = input_onion_padded;
97 cols.output_onion_padded = output_onion_padded;
98
99 let zero_hash = zero_hash(1);
100 let initial_acc_hash = poseidon2_compress_with_capacity(def_circuit_commit_padded, zero_hash).0;
101 let final_acc_hash =
102 poseidon2_compress_with_capacity(input_onion_padded, output_onion_padded).0;
103
104 let mut public_values = vec![F::ZERO; DeferralPvs::<u8>::width()];
105 let root_pvs: &mut DeferralPvs<F> = public_values.as_mut_slice().borrow_mut();
106 root_pvs.initial_acc_hash = initial_acc_hash;
107 root_pvs.final_acc_hash = final_acc_hash;
108 root_pvs.depth = F::ONE;
109 root_pvs.node_idx = def_pvs.def_idx;
110
111 poseidon2_compress_inputs.extend_from_slice(&[
112 pad_slice_to_poseidon2_input(&def_circuit_commit, F::ZERO),
113 pad_slice_to_poseidon2_input(&input_onion, F::ZERO),
114 pad_slice_to_poseidon2_input(&output_onion, F::ZERO),
115 digests_to_poseidon2_input(def_circuit_commit_padded, zero_hash),
116 digests_to_poseidon2_input(input_onion_padded, output_onion_padded),
117 ]);
118
119 DeferralHookVerifierTraceCtx {
120 trace_data: SingleAirTraceData {
121 air_proving_ctx: AirProvingContext {
122 cached_mains: vec![],
123 common_main: RowMajorMatrix::new(trace, width),
124 public_values,
125 },
126 poseidon2_compress_inputs,
127 poseidon2_permute_inputs,
128 range_check_inputs,
129 },
130 def_circuit_commit,
131 }
132}