Speedrun to Groth16 Zero Knowledge Proofs

Jan 12, 2024

Introduction

Zero knowledge proofs are perhaps the one of the most noble cryptographic inventions made and popularized with the introduction of blockchains. It also is known for its notoriously complex mathematics behind it.

This article intends to cover the mathematical machinery behind it in as concisely as possible without losing the context. All the arithmetic operations in this article is implicitly assumed to be done inside a finite field with some chosen prime number, .

Note:This is not a from scratch explanation of why zero-knowledge proofs work. I assume the reader knows about finite fields, set theory, group theory and basic properties of elliptic curves.

Arithmetic Circuits

An arithmetic circuit is simply a system of equations. Needless to say, system of equations with mathematical operations like addition and multiplication.

An example of arithmetic circuit would be:

In arithmetic circuit the equality (symbol ) should be read as assertion rather than assignment. We say an arithmetic circuit to be satisfied when we have valid values for the input variables - , and in this case.

A valid assignment in our example would be: , and .

R1CS (Rank-1 Constraint System)

A rank-1 constraint system or r1cs is also a system of equations. But the difference is that each equation in the system can only have one multiplication. Although any number of additions are allowed.

Taking up from previous example, the equation remains same since it only has additions(and multiplication by constants). But we have to break the second equation since it has more than one multiplication. A valid r1cs would be:

We simply broke to introduce another variable so as to comply with r1cs.

We call witness a vector that has values that satisfies our r1cs. Lets define our witness as:

In r1cs, we generally re-arrange the variables to create it in this form:

So to take an example equation:

²

We break this into:

Our witness looks like:

Notice that instead of one simple equation of form we have multiple. All of these can be folded into matrices- , and .

Let's work out the equations in to get the matrices , and .

Equation 1

As obvious in this case we have , and .

To satisfy we have:

It satisfies:

Working out will yield the same as .

Equation 2

The equation 2 is:

If worked out in similar way as first equation we will get:

The same can be verified.

Equation 3

This is a bit different:

We can rewrite it as:

So now, is , is and is 1.

Now following the same rules considering our witness vector () we get:

This can also be verified by matrix multiplication.

Final R1CS

Now if we combine all of the representations i.e. combine , and as rows of , and similarly for and , we get:

These matrices along with the chosen witness in satisfy the equation:

where represents Hadamard product.

Bare Proof

Circuit Constraints

R1CS matrices , and .

Proof

Witness vector .

Verification

Check if holds.

But this is far from being zero knowledge proof. Because the proof is witness itself and it is revealed to verifier. Also, it is not succinct because the proof grows as the witness vector grows.

Pairings

Let us assume that , and be the generator elements of the groups , and respectively, such that pairing elements from and gives us an element in . That is:

We will use operator to represent the pairing operation. For example:

where , and . The prover is going to use property of pairing to improve the our proof.

Get into more details about pairings here.

Encrypted Witness Proof

This time the prover encrypts the witness vector to hide it. Consider the equation , we want to hide our witness . Here's how we approach it. We do an element-wise multiplication of our witness vector with both and :

Now instead of plain witness vector , prover sends and vectors as proof. The verifier cannot extract any witness value from these due to discrete logarithm problem.

Circuit Constraints

R1CS matrices , and .

Proof

Encrypted witness vectors and .

Verification

Check if equation holds:

The proof is now zero knowledge since the witness is encrypted - nobody apart from prover sees it. But the proof is still not succinct since the proof grows as the witness vector grows.

QAP (Quadratic Arithmetic Program)

QAPs are also arithmetic circuits but instead of matrices as we did before, we represent the constraints as a set of polynomials.

As we saw before, to verify we check if the following assertion must hold. But this takes time and is expensive, we want to verify it in constant time. To achieve this, we convert the matrices into polynomials and apply some useful theorems.

Lagrange Interpolation

The lagrange interpolation is the theorem that given points - there exists a unique polynomial of degree that passes through all of them. Read more here.

Lagrange interpolation is the key to make proof succinct by converting the matrices , and into polynomials. Let's take the matrix for example. The product gives us a vector of elements. The function can convert this vector into a polynomial . Same goes for and :

Interpolation is a linear operation, so it is homomorphic. That is, for any two vectors and , . If we take each column of as vector and convert these into polynomials , using and then weigh them with the witness vector items , we get the same polynomial as in . Similar argument goes for and .

Given this we can now write:

Now we have successfully converted the original r1cs at into polynomials. But we cannot just apply the same equality check to polynomials. That is,

will not hold, since degrees of the polynomials will not match, and nor will the equality.

To balance the equation we can introduce another polynomial :

such that for the correct chosen witness and hence equality holds.

A naive approach would be to just let prover choose . But it has critical flaw. The prover can choose get any random witness and calculate , r(x) and . Then prover can choose any arbitrary polynomial that balances the equation .

We restrict to have roots , so that the term vanishes to at any degree. To put this restriction is composed as:

and fix the to always be:

which forces to have roots and so do for .

Then can simply be calculated as:

Schwartz-Zippel Lemma

Schwartz-Zippel lemma says that given two polynomials and with degrees and where , the maximum number of points they can intersect is . This holds true even for polynomials in finite field.

This lemma can be exploited to check if two polynomials and are equal, succinctly. The naive way would be to check equality of all coefficients of polynomials - which would take linear time . But if polynomials are evaluated at some random variable and then comparing the evaluations and is constant time .

The check only fails for number of points where evaluations will be equal even though the polynomials are not same. But for a finite field of a very large size such that , it is very highly unlikely that a random point would be one of such points.

Succinct Proof

Now the verifier can use above property of Schwartz-Zippel lemma by choosing a random element and sends it to the prover to evaluate polynomials without revealing them. And prover calculates following:

Circuit Constraints

The polynomials , , and .

Proof

The elements , and .

Verification

Verifier checks:

This convinces verifier that prover indeed has the knowledge of a valid witness because the chances of prover randomly receiving a where polynomials intersect is close to none.

But this is still not secure since we have no way to verify that prover indeed performed the polynomial evaluations correctly.

This is where trusted setup comes in.

Trusted Setup

The trusted setup is basically a mechanism to evaluate a polynomial on a secret value such that it doesn't reveal information about the polynomial to the verifier and the prover does not get to know what value they are evaluating on.

Let be the polynomial in question. To initiate a party picks a secret scalar and calculates all the powers for :

Then to commit to it by multiplying the same by a generator point :

Theses powers of committed as elliptic curve points i.e. is called structure reference string (SRS). Using SRS anyone can compute any polynomial (of degree at most ) at without actually know the value of .

But right not there's a flaw. The person creating the SRS chose and is supposed to destroy it. It may not chose to do so and compromise or misuse it.

To tackle the problem of trusting single party for generating the SRS we make this setup multiparty. We do this by forwarding the SRS successively through multiple parties who also choose a secret scalar, say, and operate on previous SRS:

Now this process can go on and on through many number of parties. Even if one of the participating parties of this setup destroys their secret, it remains safe. The resulting artifact we get at the end of this ceremony is also called powers of tau.

QAP With Trusted Setup

Note that while we had laid out the QAP in , we didn't encrypt the witness. Now that prover has the trusted setup's SRS it can use it for encrypting the polynomials , , and .

Suppose trusted setup was performed to generate the SRS corresponding to both and groups as:

We encrypt the polynomial with , with and with . Writing for the coefficients of (highest degree first), and similarly for and , we take the dot product of the coefficient list with the matching half of the SRS from :

where operator represents dot product of two vectors.

But we can't really calculate the yet. Because we don't know the SRS for . The prover cannot use the SRS it used for and . Why? Because the degrees of polynomial differ from those. We need to figure out this SRS first. That means trusted setup needs to account for it.

Luckily, remember from that is a fixed known polynomial beforehand at the time of trusted setup, unlike . So for SRS for the polynomial , the ceremony can simply plug in the value to to get constant .

Now coming to , it has a degree of , inferred from . The ceremony can create trusted setup now as:

The whole trusted setup now gives us the SRS:

Proof With Trusted Setup

And now we can complete our previous evaluation as:

Circuit Constraints

The polynomials , , and .

Proof

The group elements , and .

Trusted Setup SRS

The elements:

Verification

The verifier checks:

The parameters , and is our proof. It is zero knowledge and succinct.

Groth16 Algorithm

The equation gives a legitimate algorithm to perform a valid zk proof verification. But right now, there is nothing stopping a prover from coming up random values to calculate , and to hand over to verifier.

and

To solve for the problem above Groth16 introduces two additional parameters and . These parameters are output of the trusted setup:

If we somehow update the verification formula to:

Now the point is unknown to everyone. The prover knows discrete logs of and . If it tries to select any such two points, to make the proof valid it will have to calculate also. But it cannot do so since is unknown and so it its discrete log. Similar argument goes if prover starts from a random .

But we cannot just randomly introduce it in our original equation. Instead let's try to come up with it by introducing the and to LHS of it.

Note that we used and to replace with .

The updated , and becomes:

The trusted setup now has to also random sample and to produce and as part of SRS.

Given our trusted setup the encrypted points become:

We've run into a problem now. To calculate , we cannot simply do point multiplication of and . Our trusted setup provides the and points, not plain values - those are discarded.

The problematic term for is part. And note that prover has to calculate without revealing the actual polynomials. Lets rewrite in summation form:

Prover cannot reveal to anyone. Trusted setup has to be independent of any witness value.

Therefore for each corresponding to each , the trusted setup must generate points as:

Notice we cannot calculate just one point. Because we have to separate witness vector item out and each term is being multiplied by a different term.

Groth16 Proof Without Public Inputs

Given new trusted setup SRS, now we can complete as:

Circuit Constraints

The polynomials , , and .

Trusted Setup SRS

The elements:

Proof

The group elements , and .

Verification

The verifier checks :

Public Inputs

Right now all of the values in witness vector remains private. But in practice, a verifier would want some of those values to be public so as to bind the prover to values of its requirements.

A naive approach would be to just let some subset of values in be exposed to verifier. Suppose, prover let subset ( size) of witness values to be public. Now instead of prover computing the commitments for this public part, verifier computes it:

So now represents public and rest represent private parts. The verification equation becomes:

But this would allow the prover to forge proofs with incorrect witness. In current form, the elements are meant to be used with the public elements of witness and rest i.e. for private. But nothing guarantees it.

For example, prover can pick a from one and calculate:

zeroing out the kth term.

And keep equation still balanced but moving over kth into the private part as:

Out original assertion with modified and in still holds. But the witness is incorrect.

Separating Public and Private Inputs: and

To segregate the public and private inputs, Groth16 introduces two more parameters and to the trusted setup. The trusted setup now generates the point differently for public and private inputs.

For public inputs:

and for private inputs:

Also since the part is also need to be private, the trusted setup also modifies the previous SRS for it from as:

Groth16 Proof With Public Inputs

As shown, the trusted setup simply divides the public and private parts by and respectively. The verifier now has to calculate as:

And the private part of is calculated as:

Circuit Constraints

The polynomials , , and .

Trusted Setup SRS

The elements:

Proof

The group elements , , and .

Verification

The verifier checks:

Note that we paired the terms with and , where the SRS was divided by and respectively - causing the terms to effectively cancel out and balance the equation.

Adding Randomness

Everything works fine so far. But there's still one flaw. An adversary can observing the proofs can run a brute force attack to find the witness, especially if the witness vector is small size. The same witness always produces exact same proof, so adversary can just keep guessing the witness until the generated proof matches the observed proof. In short, the proving algorithm is deterministic - it has no randomness.

To cope with this Groth16 introduces two random finite field elements and that prover pricks, every time it generates a proof.

Groth16 modifies the and polynomials by adding and to them:

(Note: the prover does not actually know the values of and since they are part of the trusted setup. But it can still use them to calculate and .)

Since and are modified, and also has to be modified to keep the equation balanced.

Using we can rewrite the above as:

Note that we have previously established that in and . Using that:

Now we know what and are supposed to be (the LHS parts). We need to determine the the public part and private part of the RHS. For that we need to convert RHS of in summation form, since the public and private subsets fo witness are processed differently:

As said earlier, witness public and private subsets are and respectively. So we can split the summation into two parts:

We have broken the RHS into two parts - the first part is the public part and the second part is the private part.

But remember in implementation, the public and private parts need to be divided by and and respectively. So we can rewrite the above as:

Observer now and determine our updated proof's elements in plain form:

(Note: We have extra terms and also now).

But the is in plain form. We need to convert those into group elements , , and to achieve the zero knowledge property. Lets see how.

First, trusted setup already provides and , so prover just needs to pair them as:

For the trusted setup provides and . It also provides SRS for polynomial term - . So prover can calculate as:

The element can be calculated similarly as:

For the trusted setup provides SRS for public witness part - (see ). It also yields the point. So prover calculates :

For the trusted setup provides SRS for rest () private witness part - (see ). But before calculating which must be a group element of (generator ) prover also needs to perform the point multiplication of with the term which is also part of .

Note that and are just random scalars chosen by the prover. and are already provided by trusted setup. is already calculated. But is a new term prover needs to calculate (previously we calculated ) as:

Now prover can calculate as:

Final Groth16 Proof

Now let us recall what each party has so far for the final proof generation:

Circuit Constraints

The polynomials , , and .

Trusted Setup SRS

The elements:

Proof

The group elements , , and .

Verification

The verifier checks:

This is the Groth16 proof system. It is succinct, zero knowledge and non-interactive. The proof size is constant, independent of the size of the circuit. The verification time is also constant, making it efficient for practical applications.