Skip to main content

openvm_stark_backend/
engine.rs

1use std::sync::Arc;
2
3use itertools::Itertools;
4
5use crate::{
6    air_builders::debug::{debug_constraints_and_interactions, AirProofRawInput},
7    keygen::{
8        types::{MultiStarkProvingKey, MultiStarkVerifyingKey},
9        MultiStarkKeygenBuilder,
10    },
11    memory_metering::ProvingMemoryConfig,
12    proof::*,
13    prover::{
14        AirProvingContext, ColMajorMatrix, Coordinator, DeviceDataTransporter,
15        DeviceMultiStarkProvingKey, MultiRapProver, OpeningProver, Prover, ProverBackend,
16        ProverDevice, ProvingContext, StridedColMajorMatrixView,
17    },
18    verifier::{verify, VerifierError},
19    AirRef, FiatShamirTranscript, StarkProtocolConfig, SystemParams,
20};
21
22/// Data for verifying a Stark proof.
23#[derive(Debug)]
24pub struct VerificationData<SC: StarkProtocolConfig> {
25    pub vk: MultiStarkVerifyingKey<SC>,
26    pub proof: Proof<SC>,
27}
28
29pub type ProverError<E> =
30    <<E as StarkEngine>::PD as ProverDevice<<E as StarkEngine>::PB, <E as StarkEngine>::TS>>::Error;
31
32/// Convenience alias for the device context type of a `StarkEngine`.
33pub type EngineDeviceCtx<E> = <<E as StarkEngine>::PD as ProverDevice<
34    <E as StarkEngine>::PB,
35    <E as StarkEngine>::TS,
36>>::DeviceCtx;
37
38/// A helper trait to collect the different steps in multi-trace STARK
39/// keygen and proving.
40pub trait StarkEngine
41where
42    <Self::PD as MultiRapProver<Self::PB, Self::TS>>::Artifacts:
43        Into<<Self::PD as OpeningProver<Self::PB, Self::TS>>::OpeningPoints>,
44    <Self::PD as MultiRapProver<Self::PB, Self::TS>>::PartialProof:
45        Into<(GkrProof<Self::SC>, BatchConstraintProof<Self::SC>)>,
46    <Self::PD as OpeningProver<Self::PB, Self::TS>>::OpeningProof:
47        Into<(StackingProof<Self::SC>, WhirProof<Self::SC>)>,
48{
49    type SC: StarkProtocolConfig;
50    type PB: ProverBackend<
51        Val = <Self::SC as StarkProtocolConfig>::F,
52        Challenge = <Self::SC as StarkProtocolConfig>::EF,
53        Commitment = <Self::SC as StarkProtocolConfig>::Digest,
54    >;
55    type PD: ProverDevice<Self::PB, Self::TS> + DeviceDataTransporter<Self::SC, Self::PB>;
56    type TS: FiatShamirTranscript<Self::SC>;
57
58    /// Constructor from only system parameters. In particular, the transcript and hasher must have
59    /// a default configuration.
60    fn new(params: SystemParams) -> Self;
61
62    fn config(&self) -> &Self::SC;
63
64    fn params(&self) -> &SystemParams {
65        self.config().params()
66    }
67
68    fn proving_memory_config(&self) -> ProvingMemoryConfig {
69        ProvingMemoryConfig::from_protocol_config(self.config(), true)
70    }
71
72    fn device(&self) -> &Self::PD;
73
74    /// Creates transcript with a deterministic initial state.
75    fn initial_transcript(&self) -> Self::TS;
76
77    fn prover_from_transcript(
78        &self,
79        transcript: Self::TS,
80    ) -> Coordinator<Self::SC, Self::PB, Self::PD, Self::TS>;
81
82    fn prover(&self) -> Coordinator<Self::SC, Self::PB, Self::PD, Self::TS> {
83        let transcript = self.initial_transcript();
84        self.prover_from_transcript(transcript)
85    }
86
87    fn keygen(
88        &self,
89        airs: &[AirRef<Self::SC>],
90    ) -> (
91        MultiStarkProvingKey<Self::SC>,
92        MultiStarkVerifyingKey<Self::SC>,
93    ) {
94        let mut keygen_builder = MultiStarkKeygenBuilder::new(self.config().clone());
95        for air in airs {
96            keygen_builder.add_air(air.clone());
97        }
98
99        let pk = keygen_builder.generate_pk().unwrap();
100        let vk = pk.get_vk();
101        (pk, vk)
102    }
103
104    fn prove(
105        &self,
106        pk: &DeviceMultiStarkProvingKey<Self::PB>,
107        ctx: ProvingContext<Self::PB>,
108    ) -> Result<Proof<Self::SC>, ProverError<Self>> {
109        let mut prover = self.prover();
110        prover.prove(pk, ctx)
111    }
112
113    /// Verifies using a default instantiation of the Fiat-Shamir transcript.
114    fn verify(
115        &self,
116        vk: &MultiStarkVerifyingKey<Self::SC>,
117        proof: &Proof<Self::SC>,
118    ) -> Result<(), VerifierError<<Self::SC as StarkProtocolConfig>::EF>> {
119        let mut transcript = self.initial_transcript();
120        verify(self.config(), vk, proof, &mut transcript)
121    }
122
123    /// The indexing of AIR ID in `ctx` should be consistent with the order of `airs`. In
124    /// particular, `airs` should correspond to the global proving key with all AIRs, including ones
125    /// not present in the `ctx`.
126    fn debug(&self, airs: &[AirRef<Self::SC>], ctx: &ProvingContext<Self::PB>) {
127        let mut keygen_builder = MultiStarkKeygenBuilder::new(self.config().clone());
128        for air in airs {
129            keygen_builder.add_air(air.clone());
130        }
131        let pk = keygen_builder.generate_pk().unwrap();
132
133        let transpose = |mat: ColMajorMatrix<<Self::SC as StarkProtocolConfig>::F>| {
134            let row_major = StridedColMajorMatrixView::from(mat.as_view()).to_row_major_matrix();
135            Arc::new(row_major)
136        };
137        let (inputs, used_airs, used_pks): (Vec<_>, Vec<_>, Vec<_>) = ctx
138            .per_trace
139            .iter()
140            .map(|(air_id, trace_ctx)| {
141                let common_main = self
142                    .device()
143                    .transport_matrix_from_device_to_host(&trace_ctx.common_main);
144                let cached_mains = trace_ctx
145                    .cached_mains
146                    .iter()
147                    .map(|cd| {
148                        transpose(
149                            self.device()
150                                .transport_matrix_from_device_to_host(&cd.trace),
151                        )
152                    })
153                    .collect_vec();
154                let common_main = Some(transpose(common_main));
155                let public_values = trace_ctx.public_values.clone();
156                (
157                    AirProofRawInput {
158                        cached_mains,
159                        common_main,
160                        public_values,
161                    },
162                    airs[*air_id].clone(),
163                    &pk.per_air[*air_id],
164                )
165            })
166            .multiunzip();
167
168        debug_constraints_and_interactions(&used_airs, &used_pks, &inputs);
169    }
170
171    /// Runs a single end-to-end test for a given set of chips and traces partitions.
172    /// This includes proving/verifying key generation, creating a proof, and verifying the proof.
173    fn run_test(
174        &self,
175        airs: Vec<AirRef<Self::SC>>,
176        ctxs: Vec<AirProvingContext<Self::PB>>,
177    ) -> RunTestResult<Self::SC, Self::PB, Self::PD, Self::TS> {
178        let (pk, vk) = self.keygen(&airs);
179        let device = self.prover().device;
180        let d_pk = device.transport_pk_to_device(&pk);
181        let ctx = ProvingContext::new(ctxs.into_iter().enumerate().collect());
182        let proof = self.prove(&d_pk, ctx).map_err(StarkTestError::Prover)?;
183        self.verify(&vk, &proof).map_err(StarkTestError::Verifier)?;
184        Ok(VerificationData { vk, proof })
185    }
186}
187
188type RunTestResult<SC, PB, PD, TS> = Result<
189    VerificationData<SC>,
190    StarkTestError<<PD as ProverDevice<PB, TS>>::Error, <SC as StarkProtocolConfig>::EF>,
191>;
192
193/// Error type for end-to-end tests that can fail in either the prover or verifier.
194#[derive(Debug)]
195pub enum StarkTestError<
196    PE: std::error::Error,
197    EF: std::fmt::Debug + std::fmt::Display + PartialEq + Eq,
198> {
199    Prover(PE),
200    Verifier(VerifierError<EF>),
201}
202
203impl<PE: std::error::Error, EF: core::fmt::Debug + core::fmt::Display + PartialEq + Eq>
204    core::fmt::Display for StarkTestError<PE, EF>
205{
206    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
207        match self {
208            Self::Prover(e) => write!(f, "Prover error: {e:?}"),
209            Self::Verifier(e) => write!(f, "Verifier error: {e}"),
210        }
211    }
212}
213
214impl<PE: std::error::Error, EF: core::fmt::Debug + core::fmt::Display + PartialEq + Eq>
215    std::error::Error for StarkTestError<PE, EF>
216{
217}