You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An under-optimized implementation of Groth16 protocol. To use it with Circom, check the examples.
Introduction
Over the last decade, SNARKs (succinct, non-interactive arguments of knowledge) and STARKs (scalable, transparent arguments of knowledge) have been gaining attention due to their applications in verifiable private computation and scalability of blockchains.
Groth introduced this proof system in 2016 and saw an early application in ZCash. The protocol relies on pairing-friendly elliptic curves, such as BN254, BLS12-381, and BLS12-377 (more later). Its proof size is among the smallest (consisting of only three elliptic curve elements) and fastest to verify. The main drawback is that it needs a trusted setup per program. In other words, we need to regenerate all the parameters whenever we want to prove a new program (or change the original one).
Arithmetization
To prove the execution of a given program, we have to transform it to a SNARK (succinct, non-interactive argument of knowledge) friendly form. One of such forms is arithmetic circuit satisfiability, where one can prove knowledge of a valid circuit assignment. This first step, known as arithmetization, is the program's transformation into an arithmetic circuit or equivalent form.
R1CS
Arithmetic circuits can be expressed equivalently as (quadratic) rank one constraint systems (R1CS), which are systems of equations of the form:
where are matrices of size rows by columns, is a (column) vector of size and indicates the componentwise product of the resulting vectors.
We can alternatively view this compact form as
We could express these equations more compactly by using polynomials and prove the solution of the R1CS system more concisely. To this end, we will introduce quadratic arithmetic programs, QAP.
Quadratic Arithmetic Program
We can interpret each column of the matrix as evaluations of some polynomial over some suitable domain. This is a common practice in many SNARKs, where we try to encode a vector as a polynomial; see, for example, our post about STARKs. We sample over the finite field and define the polynomial as the polynomial of at most degree such that .
For performance reasons, it is convenient to select as interpolation domain the n-th roots of unity since we can use the Fast Fourier Transform to interpolate. Similarly, we can interpret the columns of and as polynomials and . Taking advantage of these polynomials, we can express the R1CS system in polynomial form,
We can see that if we have a valid solution for the R1CS, the polynomial evaluates to over (since we require the polynomial to interpolate the values of the columns of the matrices). Therefore, we can express the condition as
for
We now introduce the vanishing polynomial over the set ,
So, if the polynomial evaluates to over , it is divisible by . This can be written as there is some polynomial such that
The degree of the polynomial is the degree of minus the degree of . An honest prover should be able to find the resulting quotient and use it to show that he correctly executed the program.
Transforming QAP into a zero-knowledge proof
We need to make some transformation to the above problem if we want to turn it into a zero-knowledge proof. For a more detailed description of this process, see here. We must ensure that the prover cannot cheat and that the verifier cannot learn anything about the private input or witness. One key ingredient is a polynomial commitment scheme (PCS): we can make the prover commit to a given polynomial so that he cannot change it later. One such commitment scheme is the KZG commitment, where we use pairing-friendly elliptic curves to bind the prover to a polynomial. The scheme's security relies on the hardness of the discrete logarithm problem over the curve. Pairings can be considered an operation that allows a one-time multiplication between points in an elliptic curve. In our case, we will work over type3 III pairings, , which have the following nice property (bilinearity):
To commit to a polynomial using KZG, we need to sample a random scalar (which is considered toxic waste and should be forgotten, or we could forge proofs) and generate the following sequence of points in the elliptic curve, whose generator is ,
,
Then, given a polynomial we compute the commitment as
which is the same as , that is, hiding the evaluation of inside the elliptic curve. Because the discrete log problem is hard, we cannot use our knowledge of and to obtain .
To check that the polynomial evaluates to at we can use the fact that
where is the quotient polynomial of the division of by . The prover can produce proof of such evaluation by committing to using the same trick. Still, the verifier will need some additional information (included in the verifying key), (the generator of the group ), and (remember, nobody must know ). Then, using pairings, the verifier can check the evaluation using the points in the elliptic curves,
If and are the same, and since is a random point with high probability, we assume that (This depends on the Schwartz-Zippel lemma).
Remember that we want to prove that the verifier knows some and a polynomial of degree such that if , the following condition holds
If we force the prover first to commit to the polynomials and and then produce the quotient polynomial, we have to make sure that he cannot forge to fulfill the previous condition. To do so, we are going to introduce random shifts ( and ) to the evaluations:
The are committed to using group so that we can compute the product on the left-hand side through a pairing,
Because we introduce these shifts, we need to modify the term accordingly,
$\begin{equation}\left( \alpha + \sum_k A_{k} (x) z_k \right) \left( \beta + \sum_k B_{k} (x) z_k \right) = \ \alpha \beta + \left( \sum_k (C_{k} (x) + \beta A_k (x) + \alpha B_k (x)) z_k \right) + h(x)Z_D (x) \end{equation}$
Since the prover cannot know and , we need to provide them hidden as part of the trusted setup, as and , so that we can compute
so that we can compare this result to the pairing between the shifted and .
Also, since the prover does not have and , he needs to be supplied with all the elements of the form . However, when we want to calculate the product between these terms and , we must recall that contains both the public input and the witness. The verifier cannot learn anything about the witness (therefore, the evaluations involving the witness should be provided by the prover). We introduce two additional variables, , and , to split the variable between public input and witness. The first terms correspond to the public input, and these are encoded as
for . For the witness, we have
With these new parameters, we get
$\begin{equation}\left( \alpha + \sum_j A_{j} (x) z_j \right) \left( \beta + \sum_j B_{j} (x) z_j \right) = \ \alpha \beta + \gamma \left( \sum_i^k \gamma^{- 1} (C_{i} (x) + \beta A_i (x) + \alpha B_i (x)) x_i \right) + \
\delta \left( \sum_{j = k + 1}^n \delta^{- 1} (C_{i} (x) + \beta A_i (x) + \alpha B_i (x)) x_i \right) + h(x)Z_D (x) \end{equation}$
We can combine the last two terms into one (since they contain all the information that the verifier must not learn)
Since we want to compute the product with the help of one pairing, we can compute the following group elements,
With these changes, the right-hand side of the QAP is the sum of 3 terms:
A constant (related to the random shifts).
A term involving the public input.
A term that contains the secret terms (known only to the prover).
Setup
Groth16 requires sampling five random field elements to generate the proving and verifying key, . These are toxic waste and should be discarded and wholly forgotten once the keys have been generated.
We will use a pairing-friendly elliptic curve (with type III pairing), with subgroups and of prime order . We will call the generators and , respectively. To make notation easier, we will write
to denote points in and , where means the scalar product of and the generator of the group (i.e., applying x times the elliptic curve group operation to the generator). We will follow the notation given by DIZK. First, we compute the following vectors,
for ,
for and
for .
The proving key consists of the following elements:
The verifying key is much shorter and will contain in addition the value of one pairing because that value is constant:
Proof generation
The prover receives the proving key and knows the polynomials representing the program and the public input, and he wants to prove that he has a witness satisfying that program. First, the prover needs to calculate the quotient polynomial or, more precisely, its coefficients. The prover has to calculate
The best way to evaluate this quotient is by choosing a domain , of size at least the degree of the quotient polynomial plus one and not containing elements from (the interpolation domain) and evaluating numerator and denominator at all the elements of . Since we have at least as many evaluations of the polynomial as its degree plus one, we can reconstruct via interpolation. In practice, the fastest way to do this is by using the Fast Fourier Transform for evaluation and interpolation. The prover now possesses a vector of coefficients .
To ensure that the proof is zero-knowledge, the prover sample two random scalars, and .
The prover can compute the three elements of the proof, by doing the following calculations,
Verification
The verifier has the verifying key, the public input and parses the proof as and computes the following:
The proof is valid if and coincide. This is equivalent to checking the modified QAP.