Proving setup phase
All preprocessing happens in the Setup phase. This means all artifacts needed for generating proofs are created in this phase.
This includes the generation of intermediate circuits, which are a finite set of circuits that allow arbitrary combinations of proof recursions and aggregations.
Building the zkEVM STARK¶
The first step in building the zkEVM STARK is to build the ROM of the zkEVM state machine, where this ROM is nothing but a program containing instructions for the executor to generate a specified execution trace of the zkEVM. And it is written in JSON as rom.json.
The PIL code, zkevm.pil, is built for validating the execution trace.
The executor uses both the rom.json and zkevm.pil to generate all the constant polynomials for the execution trace of the zkEVM, rom.const.
Observe that, as previously mentioned, committed polynomials are not needed in the setup phase, so at this stage there is no need to run the executor of the zkEVM in order to generate them.
See the below schematic diagram of the process used when building a zkEVM STARK.
Next to be built is the Merkle tree of evaluations of the constant polynomials, zkevm.consttree.
The root of this Merkle tree, which is a hash that serves as a cryptographic fingerprint of all the fixed parameters of the computation, is stored as a parameter in a file called zkevm.verkey.
The last piece of data that needs to be generated, before building the STARK, is the starkInfo necessary for automatically generating the circuit that verifies the zkEVM STARK.
In this case, a blowup factor of \(2\) and \(128\) queries are used to generate the proof.
The artifacts marked in gray, in the above figure, are those being used in generating the proof.
Further delineation of the proof generation is provided in later sections.
Setup S2C for zkEVM STARK¶
The next step in the setup phase is to generate the circuit that verifies the zkEVM STARK (see the below Figure).
The pil2circom process fills a CIRCOM EJS template, called \(\mathtt{stark\_verifier.circom.ejs}\), with all the necessary information needed to validate the zkEVM STARK.
We henceforth need to add the zkevm.pil in order to capture
- polynomial names,
- the zkevm.starkinfo file which specifies the blowup factor,
- the number of queries,
- the steps of the FRI-verification procedure,
- the constRoot in the zkevm.verkey file,
and to automatically generate a circuit in CIRCOM.
The CIRCOM output file zkevm.verifier.circom is then compiled into R1CS constraint system, written in a file called zkevm.verifier.r1cs.
These constraints are used in the next step to generate the PIL code and the constant polynomials for the next proof.
On the other hand, the CIRCOM compilation also outputs a witness calculator program called zkevm.verifier.witnesscalc.
As it can be observed in the picture, the witness calculator program is marked in gray because it is used when the proof is generated.
Since the aim in the next proof generation is compression (that is, proof size reduction), a blowup factor of 4 is used in this step, with 64 queries.
This information is contained in the c12a.starkstruct file located in the proverjs repository.
Setup c12a¶
The zkEVM STARK is verified by a circuit called zkevm.verifier. This is the c12a circuit previously seen in the compression stage, at the beginning of the Proving Architecture.
It is so called because the PIL code that verifies the c12a circuit, is a PlonKish circuit with custom gates and \(12\) polynomials, aiming at compression.
Given the above-mentioned R1CS description of the verification circuit zkevm.verifier.r1cs, a machine-like construction whose correct execution is equivalent to the validity of the previous circuit is obtained. This construction is described in the PIL file, c12a.pil.
The process starts through a service called \(\mathtt{compressor12\_setup}\) (which is part of the c12a setup component, seen in the above figure), where the corresponding PIL file c12a.pil for verifying the trace is an output, together with a binary c12a.const for all the constant polynomials.
Moreover, a helper file called c12a.exec is generated by the same service.
This helper file contains all the necessary rules that allow the shuffling of all the witness values, which are computed later on, into the corresponding position of the execution trace.
The design of this shuffling, together with the connections defined in the constants polynomials c12a.const ensures that, for an honest prover, this newly generated trace is valid whenever the previous circuit is valid.