openvm_continuations/verifier/common/
non_leaf.rs

1use std::{array, borrow::Borrow};
2
3use openvm_circuit::arch::PUBLIC_VALUES_AIR_ID;
4use openvm_native_compiler::ir::{Array, Builder, Config, Felt, RVar, DIGEST_SIZE};
5use openvm_native_recursion::{
6    challenger::duplex::DuplexChallengerVariable, fri::TwoAdicFriPcsVariable, stark::StarkVerifier,
7    types::MultiStarkVerificationAdvice, vars::StarkProofVariable,
8};
9use openvm_stark_sdk::openvm_stark_backend::p3_field::PrimeField32;
10
11use crate::verifier::{
12    common::{
13        assert_or_assign_connector_pvs, assert_or_assign_memory_pvs,
14        assert_required_air_for_agg_vm_present, assert_single_segment_vm_exit_successfully,
15        get_program_commit, types::VmVerifierPvs,
16    },
17    internal::types::InternalVmVerifierPvs,
18    utils::{assign_array_to_slice, eq_felt_slice},
19};
20
21pub struct NonLeafVerifierVariables<C: Config> {
22    pub internal_program_commit: [Felt<C::F>; DIGEST_SIZE],
23    pub leaf_pcs: TwoAdicFriPcsVariable<C>,
24    pub leaf_advice: MultiStarkVerificationAdvice<C>,
25    pub internal_pcs: TwoAdicFriPcsVariable<C>,
26    pub internal_advice: MultiStarkVerificationAdvice<C>,
27}
28
29impl<C: Config> NonLeafVerifierVariables<C> {
30    /// Verify proofs of internal verifier or leaf verifier.
31    /// Returns aggregated VmVerifierPvs and leaf verifier commitment of these proofs.
32    #[allow(clippy::type_complexity)]
33    pub fn verify_internal_or_leaf_verifier_proofs(
34        &self,
35        builder: &mut Builder<C>,
36        proofs: &Array<C, StarkProofVariable<C>>,
37    ) -> (VmVerifierPvs<Felt<C::F>>, [Felt<C::F>; DIGEST_SIZE])
38    where
39        C::F: PrimeField32,
40    {
41        // At least 1 proof should be provided.
42        builder.assert_nonzero(&proofs.len());
43        let pvs = VmVerifierPvs::<Felt<C::F>>::uninit(builder);
44        let leaf_verifier_commit = array::from_fn(|_| builder.uninit());
45
46        builder.range(0, proofs.len()).for_each(|i_vec, builder| {
47            let i = i_vec[0];
48            let proof = builder.get(proofs, i);
49            assert_required_air_for_agg_vm_present(builder, &proof);
50            let proof_vm_pvs = self.verify_internal_or_leaf_verifier_proof(builder, &proof);
51
52            assert_single_segment_vm_exit_successfully(builder, &proof);
53            builder.if_eq(i, RVar::zero()).then_or_else(
54                |builder| {
55                    builder.assign(&pvs.app_commit, proof_vm_pvs.vm_verifier_pvs.app_commit);
56                    builder.assign(
57                        &leaf_verifier_commit,
58                        proof_vm_pvs.extra_pvs.leaf_verifier_commit,
59                    );
60                },
61                |builder| {
62                    builder.assert_eq::<[_; DIGEST_SIZE]>(
63                        pvs.app_commit,
64                        proof_vm_pvs.vm_verifier_pvs.app_commit,
65                    );
66                    builder.assert_eq::<[_; DIGEST_SIZE]>(
67                        leaf_verifier_commit,
68                        proof_vm_pvs.extra_pvs.leaf_verifier_commit,
69                    );
70                },
71            );
72            assert_or_assign_connector_pvs(
73                builder,
74                &pvs.connector,
75                i,
76                &proof_vm_pvs.vm_verifier_pvs.connector,
77            );
78            assert_or_assign_memory_pvs(
79                builder,
80                &pvs.memory,
81                i,
82                &proof_vm_pvs.vm_verifier_pvs.memory,
83            );
84            // This is only needed when `is_terminate` but branching here won't save much, so we
85            // always assign it.
86            builder.assign(
87                &pvs.public_values_commit,
88                proof_vm_pvs.vm_verifier_pvs.public_values_commit,
89            );
90        });
91        (pvs, leaf_verifier_commit)
92    }
93    fn verify_internal_or_leaf_verifier_proof(
94        &self,
95        builder: &mut Builder<C>,
96        proof: &StarkProofVariable<C>,
97    ) -> InternalVmVerifierPvs<Felt<C::F>>
98    where
99        C::F: PrimeField32,
100    {
101        let flatten_proof_vm_pvs = InternalVmVerifierPvs::<Felt<C::F>>::uninit(builder).flatten();
102        let proof_vm_pvs_arr = builder
103            .get(&proof.per_air, PUBLIC_VALUES_AIR_ID)
104            .public_values;
105
106        let program_commit = get_program_commit(builder, proof);
107        let is_self_program =
108            eq_felt_slice(builder, &self.internal_program_commit, &program_commit);
109
110        builder.if_eq(is_self_program, RVar::one()).then_or_else(
111            |builder| {
112                StarkVerifier::verify::<DuplexChallengerVariable<C>>(
113                    builder,
114                    &self.internal_pcs,
115                    &self.internal_advice,
116                    proof,
117                );
118                assign_array_to_slice(builder, &flatten_proof_vm_pvs, &proof_vm_pvs_arr, 0);
119                let proof_vm_pvs: &InternalVmVerifierPvs<_> =
120                    flatten_proof_vm_pvs.as_slice().borrow();
121                // Handle recursive verification
122                // For proofs, its program commitment should be committed.
123                builder.assert_eq::<[_; DIGEST_SIZE]>(
124                    proof_vm_pvs.extra_pvs.internal_program_commit,
125                    program_commit,
126                );
127            },
128            |builder| {
129                StarkVerifier::verify::<DuplexChallengerVariable<C>>(
130                    builder,
131                    &self.leaf_pcs,
132                    &self.leaf_advice,
133                    proof,
134                );
135                // Leaf verifier doesn't have extra public values.
136                assign_array_to_slice(
137                    builder,
138                    &flatten_proof_vm_pvs[..VmVerifierPvs::<u8>::width()],
139                    &proof_vm_pvs_arr,
140                    0,
141                );
142                let proof_vm_pvs: &InternalVmVerifierPvs<_> =
143                    flatten_proof_vm_pvs.as_slice().borrow();
144                builder.assign(&proof_vm_pvs.extra_pvs.leaf_verifier_commit, program_commit);
145            },
146        );
147        *flatten_proof_vm_pvs.as_slice().borrow()
148    }
149}