Open VM STARK back-end
STARK engine trait
StarkEngine
is a helper trait to collect the different steps in multi-trace STARK keygen and proving.
run_test_impl
is a testing method that runs a single end-to-end test for a given set of chips and traces partitions:
- Verifying key generation,
- Creating the proof,
- Verifying the proof.
MultiStarkProvingKey
generation
MultiStarkProvingKey
is a proving key that aggregates multiple STARK proving keys (StarkProvingKey
) for different AIRs (Algebraic Intermediate Representations). It enables a prover to generate proofs for multiple AIRs in a single proof system while ensuring all constraints are satisfied.
The MultiStarkProvingKey
is generated through a builder pattern via MultiStarkKeygenBuilder
.
- Creation of the keygen builder
MultiStarkKeygenBuilder
.
- Add all AIRs to the builder via
add_air
.
- Compute the highest constraint degree accross all AIRs.
- Compute symbolic constraints for each AIR.
- Use RAP (Randomized AIR with Preprocessing) to compute partial proving keys.
- Generate proving keys for each AIR, containing:
- Verification key (vk) – Stores constraints, preprocessed data, and parameters.
- Preprocessed data – Required for faster proof generation.
- RAP partial proving key – Enforces permutation constraints across AIR instances.
- Constructs the final
MultiStarkProvingKey
, which aggregates:
- Proving keys for each AIR.
- Maximum constraint degree to ensure polynomial validity.
Proof generation
The STARK proof is generated from the MultiStarkProvingKey
and the ProofInput
.
- Extract AIR IDs from proof input.
- Commits execution traces to the STARK proof system:
- If traces are missing, they are computed and stored in the prover's memory.
- If traces exist, the commitment data (
PcsData
) is reused.
- Prepare the proving context for each AIR, we store:
- Committed traces
- Common main trace
- Public values (e.g., boundary constraints)
- The proving key (
mpk
) is transferred to the computational device (CpuDevice
).
- Calls
prove()
on the prover, passing:
- The proving key view (
mpk_view
).
- The proving context (
ctx
).
Specialized proving phase
Then we enter the specialized proving phase for interactive AIRs. It assumes that the main traces have been generated and committed already, only handling the trace generation of the permutation traces.
- Validation: Ensures that the proving context (
ctx
) is compatible with the proving key (mpk
).
- Extracts execution trace data for each AIR:
cached_commits_per_air
: Commitments for the main trace segments.
cached_views_per_air
: Data views of cached execution traces.
common_main_per_air
: Common execution traces (if shared across AIRs).
pvs_per_air
: Public values (boundary conditions for verification).
- Commitment of main traces, ordered by AIR id (all traces commitment that do not require challenges).
- Prepare trace views
- Maps execution traces into
PairView
structures.
- Extracts logarithmic trace heights (for STARK polynomial commitments).
- Prepares public values for inclusion in the proof.
- The cryptographic challenger observes:
- Public values (inputs to the proof).
- Commitments of preprocessed data and main traces.
- Trace domain sizes (encoded as logarithmic values).
- Partially proving RAP (randomized AIR with preprocessing) phases
- Uses verifier randomness for probabilistic constraint checks.
- Stores data after challenge phases (
prover_data_after
).
- Observes additional commitments generated during RAP phases.
- Extracts prover-exposed values for verification.
- Compute and commit quotient polynomial
- Computes the quotient polynomial to ensure constraints hold.
- Commits the quotient polynomial and makes it observable to the verifier.
- Uses polynomial commitment schemes (PCS) to create opening proofs.
- Assemble the proof with:
- Commitments (traces, challenges, quotient polynomial).
- Opening proofs (polynomial openings).
- RAP proof data.
Verify the proof
The verify()
function in MultiTraceStarkVerifier
is responsible for verifying a STARK proof by checking constraints, commitments, and polynomial evaluations. Below is a step-by-step explanation of how the verification process works.
- Initial setup and observations
- Extracts relevant verifying keys for the AIRs present in the proof.
- Calls
verify_raps()
, which handles the verification of RAP (Randomized AIR with Preprocessing) constraints.
- Challenger observes public values
- Observes public values that were committed by the prover.
- This ensures the prover did not tamper with known public values.
- Challenger observes preprocessed commitments
- Observes commitments of preprocessed trace data (if any).
- This ensures that the commitments match what was expected.
- Challenger observes main trace commitments
- Observes the main execution trace commitments to verify that they match the prover’s claim.
- Observes trace domain sizes, which encode the length of the execution trace for each AIR.
- Prepares data for RAP constraint verification, including:
- Exposed values from the proof.
- Permutation check values (which verify trace consistency).
- Partially verifies RAP constraints, ensuring:
- Random challenges were correctly incorporated into the proof.
- Interaction constraints between different AIRs were respected.
- Sampling challenges (
alpha
and zeta
)
- Samples a random challenge
alpha
, which will be used in quotient polynomial checks.
- Observes the commitment to the quotient polynomial.
- Samples another challenge
zeta
, which is used for polynomial evaluations.
- Verify polynomial opening proofs
- Computes the polynomial evaluation domains for:
- The main execution trace.
- The quotient polynomial.
- Splits quotient polynomial domains for batched polynomial evaluations.
- Verify commitment openings
- Build the opening rounds:
- The preprocessed trace openings
- The main trace openings
- Then we handle the trace openings that take place after challenges
- Checks that the prover’s opening proofs match the claimed commitments.
- If an opening proof fails, the function returns an invalid proof error.
- Verifies all STARK constraints for each AIR:
- Preprocessed trace constraints.
- Main execution trace constraints.
- After-challenge constraints.
- Quotient polynomial consistency.
Let us now detail the partially_verify
phase which only supports LogUp for now.
FRI LogUp partially_verify
The partially_verify
function in FriLogUpPhase
is responsible for partially verifying the STARK proof's RAP (Randomized AIR with Preprocessing) phase by checking the cumulative sum constraint that ensures correctness across multiple AIRs. It is part of the logup phase in STARK proofs, which handles interactions and permutations.
- It checks that the cumulative sum of permutations across AIRs is zero, ensuring correctness.
- It samples new challenges, observes commitments, and verifies consistency.
- It transforms exposed values into constraints that must hold for the proof to be valid.
Here is a step by step explanation.
- Check if any exposed values exist
- If no interactions require verification, it exits early with a successful result.
- The verifier generates random field elements (challenges) using the challenger to ensure soundness.
- The challenger observes the exposed values from each phase, which are cumulative sums of permutation constraints.
- The verifier records the first commitment to ensure the prover cannot manipulate it.
- Extract the cumulative sum
- Extracts cumulative sum values from the proof to check correctness.
- Ensures only one phase is used (this implementation does not support multiple challenge phases).
- Check if the cumulative sum is zero
- Computes the sum of all cumulative sums across different AIRs.
- If the sum is not zero, the proof fails because the consistency check has been violated.
- Return the verification result
- The function returns the challenges used in the verification phase.
- If the sum was zero, verification succeeds; otherwise, it fails.