In this post, we will discuss about halo2 proving system and EVM verifier code of halo2 proof. Since I worked on EVM verifier written in Yul assembly, there were significant progress on making EVM verifier more readable, auditable, reusable, and scalable. The most recent work on this is the great work from EZKL team which made EVM verifier to be reusable from many application circuits by abstracting the circuit-specific information (verification key) from the verifier. I will review their architecture in depth later.
It is crucial to correctly understand how halo2 proving system works to understand how EVM verifier works. Let's dive into the halo2 proving system step-by-step. However, I will assume the reader of this post is already familiar with PLONK arithmetization, KZG polynomial commitment scheme and some basic arguments that constitute the protocol.
Below is the basic material for the explanation of halo2 proving system. Let's say proving system is instantiated on the scalar field of the elliptic curve that supports bilinear pairing that is required by KZG polynomial commitment scheme. The circuit has columns and each of column has size of rows. We have to make sure that for the prime , is divisible by , since it guarantees that -th primitive root of unity exists in (otherwise, it does not exist). Thus, we will assume for odd integer and . Let's denote as -th primitive root of unity and as -th primitive root of unity. I will also denote as the -th Lagrange basis polynomial for .

There are basic lookup argument and permutation argument that are used for proving the correctness of the circuit. Let's see each of them.
halo2's lookup argument is also called subset argument since halo2's lookup argument ensures that for some vectors , every element of is contained in . This statement is slightly weaker than indexed lookup argument, which ensures that each element of is positioned at the index in . However, we can tweak subset argument to work like indexed lookup argument. We will see this later.
To prove the statement for vectors , every element of A is contained in , the prover will first sort the vectors into to meet the following rules.
- The first element of should be the same with the first element of .
- Every element of should be the same with the corresponding element of or the previous element of it in .
So the rules force that every element of is the same with some element in and the elements with the same values are consecutive in the row.
The prover should prove the following:
- are some permutations of .
- meet the rules that are specified as above.
To prove the permutation, the prover uses product argument and produces new polynomial that satisfies the following:
Next, to prove that meet the rules that are specified as above, the prover should prove the following relations:
In permutation argument, the prover will permute the values of the cells for which the equality constraints are enabled. To express this in general, let's assume that equality constraints are enabled across columns.
The system will label each cell with the unique element in that expresses the position. For the cell in column and row , it will be labeled using . Let is the vector of polynomials that represent permutations of each column. The permutation will be composed of cycles in which the cells have the same values.
The prover of permutation argument wants to prove that for some permutation , the permutation satisfies the following:
i.e.
The equality denotes the set equality. So this can be proved using product argument, by constructing the equation:
are challenges sampled by verifier. The prover computes the polynomial that satisfies the following:
In general, satisfies:
In vanishing argument, the prover computes the quotient polynomial that attests to the various relations imposed by circuit gates, equality constraints, and lookup argument. If is the number of rows, the polynomial has the roots that are all the -th roots of unity. If the relations hold over the domain, then the polynomials should be divisible by .
is the challenge sampled by the verifier and used for random linear combination of all the relations.
Now, we can describe the first half of the protocol. In the first half of the proving, the prover must commit to all the polynomials before opening them.
