openvm_continuations/circuit/deferral/hook/verifier/
trace.rs

1use 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}