openvm_sdk/verifier/common/
non_leaf.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use std::{array, borrow::Borrow};

use openvm_circuit::arch::PUBLIC_VALUES_AIR_ID;
use openvm_native_compiler::ir::{Array, Builder, Config, Felt, RVar, Usize, DIGEST_SIZE};
use openvm_native_recursion::{
    challenger::duplex::DuplexChallengerVariable, fri::TwoAdicFriPcsVariable, stark::StarkVerifier,
    types::MultiStarkVerificationAdvice, vars::StarkProofVariable,
};
use openvm_stark_sdk::openvm_stark_backend::p3_field::PrimeField32;

use crate::verifier::{
    common::{
        assert_or_assign_connector_pvs, assert_or_assign_memory_pvs,
        assert_required_air_for_agg_vm_present, assert_single_segment_vm_exit_successfully,
        get_program_commit, types::VmVerifierPvs,
    },
    internal::types::InternalVmVerifierPvs,
    utils::{assign_array_to_slice, eq_felt_slice},
};

pub struct NonLeafVerifierVariables<C: Config> {
    pub internal_program_commit: [Felt<C::F>; DIGEST_SIZE],
    pub leaf_pcs: TwoAdicFriPcsVariable<C>,
    pub leaf_advice: MultiStarkVerificationAdvice<C>,
    pub internal_pcs: TwoAdicFriPcsVariable<C>,
    pub internal_advice: MultiStarkVerificationAdvice<C>,
}

impl<C: Config> NonLeafVerifierVariables<C> {
    /// Verify proofs of internal verifier or leaf verifier.
    /// Returns aggregated VmVerifierPvs and leaf verifier commitment of these proofs.
    #[allow(clippy::type_complexity)]
    pub fn verify_internal_or_leaf_verifier_proofs(
        &self,
        builder: &mut Builder<C>,
        proofs: &Array<C, StarkProofVariable<C>>,
    ) -> (VmVerifierPvs<Felt<C::F>>, [Felt<C::F>; DIGEST_SIZE])
    where
        C::F: PrimeField32,
    {
        // At least 1 proof should be provided.
        builder.assert_ne::<Usize<_>>(proofs.len(), RVar::zero());
        let pvs = VmVerifierPvs::<Felt<C::F>>::uninit(builder);
        let leaf_verifier_commit = array::from_fn(|_| builder.uninit());

        builder.range(0, proofs.len()).for_each(|i, builder| {
            let proof = builder.get(proofs, i);
            assert_required_air_for_agg_vm_present(builder, &proof);
            let proof_vm_pvs = self.verify_internal_or_leaf_verifier_proof(builder, &proof);

            assert_single_segment_vm_exit_successfully(builder, &proof);
            builder.if_eq(i, RVar::zero()).then_or_else(
                |builder| {
                    builder.assign(&pvs.app_commit, proof_vm_pvs.vm_verifier_pvs.app_commit);
                    builder.assign(
                        &leaf_verifier_commit,
                        proof_vm_pvs.extra_pvs.leaf_verifier_commit,
                    );
                },
                |builder| {
                    builder.assert_eq::<[_; DIGEST_SIZE]>(
                        pvs.app_commit,
                        proof_vm_pvs.vm_verifier_pvs.app_commit,
                    );
                    builder.assert_eq::<[_; DIGEST_SIZE]>(
                        leaf_verifier_commit,
                        proof_vm_pvs.extra_pvs.leaf_verifier_commit,
                    );
                },
            );
            assert_or_assign_connector_pvs(
                builder,
                &pvs.connector,
                i,
                &proof_vm_pvs.vm_verifier_pvs.connector,
            );
            assert_or_assign_memory_pvs(
                builder,
                &pvs.memory,
                i,
                &proof_vm_pvs.vm_verifier_pvs.memory,
            );
            // This is only needed when `is_terminate` but branching here won't save much, so we
            // always assign it.
            builder.assign(
                &pvs.public_values_commit,
                proof_vm_pvs.vm_verifier_pvs.public_values_commit,
            );
        });
        (pvs, leaf_verifier_commit)
    }
    fn verify_internal_or_leaf_verifier_proof(
        &self,
        builder: &mut Builder<C>,
        proof: &StarkProofVariable<C>,
    ) -> InternalVmVerifierPvs<Felt<C::F>>
    where
        C::F: PrimeField32,
    {
        let flatten_proof_vm_pvs = InternalVmVerifierPvs::<Felt<C::F>>::uninit(builder).flatten();
        let proof_vm_pvs_arr = builder
            .get(&proof.per_air, PUBLIC_VALUES_AIR_ID)
            .public_values;

        let program_commit = get_program_commit(builder, proof);
        let is_self_program =
            eq_felt_slice(builder, &self.internal_program_commit, &program_commit);

        builder.if_eq(is_self_program, RVar::one()).then_or_else(
            |builder| {
                StarkVerifier::verify::<DuplexChallengerVariable<C>>(
                    builder,
                    &self.internal_pcs,
                    &self.internal_advice,
                    proof,
                );
                assign_array_to_slice(builder, &flatten_proof_vm_pvs, &proof_vm_pvs_arr, 0);
                let proof_vm_pvs: &InternalVmVerifierPvs<_> =
                    flatten_proof_vm_pvs.as_slice().borrow();
                // Handle recursive verification
                // For proofs, its program commitment should be committed.
                builder.assert_eq::<[_; DIGEST_SIZE]>(
                    proof_vm_pvs.extra_pvs.internal_program_commit,
                    program_commit,
                );
            },
            |builder| {
                StarkVerifier::verify::<DuplexChallengerVariable<C>>(
                    builder,
                    &self.leaf_pcs,
                    &self.leaf_advice,
                    proof,
                );
                // Leaf verifier doesn't have extra public values.
                assign_array_to_slice(
                    builder,
                    &flatten_proof_vm_pvs[..VmVerifierPvs::<u8>::width()],
                    &proof_vm_pvs_arr,
                    0,
                );
                let proof_vm_pvs: &InternalVmVerifierPvs<_> =
                    flatten_proof_vm_pvs.as_slice().borrow();
                builder.assign(&proof_vm_pvs.extra_pvs.leaf_verifier_commit, program_commit);
            },
        );
        *flatten_proof_vm_pvs.as_slice().borrow()
    }
}