banner
social-twittersocial-githubsocial-github

KZG Commitments - theory, applications

Kate, Zaverucha and Goldberg (KZG) commitments serve as both a vector and functional commitment scheme. Using it, you can commit to a vector of values using a polynomial's coefficients or evaluations. Additionally, by enabling the revelation of arbitrary polynomial evaluations later, it can also work as a functional commitment scheme.

KZG proofs have the advantage of being constant size: it is independent of the polynomial's degree or of the number of evaluations we prove - using "multiproofs". Thus, KZG makes commmunication costs between a prover and a verifier quite low. The tradeoff is the requirement to carry out a (re-usable) trusted setup.

Some of the steps laid out here can be followed with accompanying toy arkworks code here. If you want to jump to the cool stuff directly, we review KZG in an applied context at the end of this post.

Algorithm

Recall that a pairing is a bilinear function ee such that a,bFr\forall a,b \in \mathbb{F}_r and P,QP, Q two elements of groups G1G_1 (of order rr) and G2G_2, we have:

e(aP,bQ)=e(P,Q)abe(aP, bQ) = e(P, Q)^{ab}.

where Fr\mathbb{F}_r is the scalar field of G1G_1.

KZG can be instantiated with any type of pairing group (type 1, type 2 or type 3). Most of recent pairing-based protocols use type 3 curves though. This is today's recommended way of designing things.

In the literature, a polynomial commitment scheme is often defined as a collection of six distinct algorithms: Setup\mathcal{Setup}, Commit\mathcal{Commit}, Open\mathcal{Open}, VerifyPoly\mathcal{VerifyPoly}, CreateWitness\mathcal{CreateWitness} and VerifyEval\mathcal{VerifyEval}. Let's go through each of them.

1. Setup\mathcal{Setup}

Select a pairing friendly curve consisting of groups G1G_1, G2G_2. Choose public generators g1G1g_1 \in G_1 and g2G2g_2 \in G_2. Sample at random a secret value τFr\tau \in \mathbb{F}_r. We will commit to a univariate polynomial ϕ(x)\phi(x) of degree mm, taken from Fr[x]\mathbb{F}_r[x]; i.e. a polynomial with coefficients in the integers modulo rr.

Compute the trusted setup parameters:

{[τ0]1 ,[τ1]1,...,[τn]1}\{ [\tau^0]_1 \ , [\tau^1]_1, ..., [\tau^n]_1 \}

where n>mn \gt m. We note [τi]1=τig1[ \tau^i ]_{1} = \tau^i * g_1. Hence, [τ0]1[\tau^0]_1 will be equal to g1g_1).

Set the verification key:

vk=[τ]2vk = [ \tau ]_{2}

Where [τ]2[ \tau ]_{2} is τg2\tau * g_2. Finally, get rid of τ\tau.

2. Commit\mathcal{Commit}

Compute the commitment C\mathcal{C} to ϕ\phi with:

C=[ϕ(τ)]1\mathcal{C} = [ \phi(\tau) ]_{1}

This is possible to compute without knowing τ\tau since:

[ϕ(τ)]1=g1(Σi=0naiτi) [\phi(\tau)]_1 = g_1 * (\Sigma_{i = 0}^{n} a_i * \tau^i) =Σi=0naiτig1= \Sigma_{i = 0}^{n} a_i * \tau^i * g_1 =Σi=0nai[τi]1= \Sigma_{i = 0}^{n} a_i * [\tau^i]_1

Elements [τi]1[\tau^i]_1 are from the trusted setup. The commitment C \mathcal{C} is a single group element in g1g_1.

3. Open\mathcal{Open}

The prover outputs a polynomial ϕ~(x)\tilde{\phi}(x). The verifier can run VerifyPoly\mathcal{VerifyPoly} to ensure that this opened polynomial corresponds to the commitment C\mathcal{C}.

4. VerifyPoly\mathcal{VerifyPoly}

This algorithm is run by the verifier. It takes as input the commitment C\mathcal{C} and a polynomial ϕ~(x)\tilde{\phi}(x) sent by the prover. It checks:

Σi=0na~i[τi]1=?C\Sigma_{i = 0}^{n} \tilde{a}_i * [\tau^i]_1 \stackrel{?}{=} \mathcal{C}

where each a~i\tilde{a}_i is a coefficient of ϕ~(x)\tilde{\phi}(x). Outputs 11 if the equality holds, 00 otherwise.

5. CreateWitness\mathcal{CreateWitness}

Creates the evalution proof, proving evaluations of ϕ(x)\phi(x) at a point rr. The prover computes a new univariate polynomial ψr(x)\psi_r(x) :

ψr(x)=ϕ(x)ϕ(r)xr \psi_r(x) = \frac{\phi(x) - \phi(r)}{x - r}

where ϕ(r)\phi(r) is the evaluation of ϕ(x)\phi(x) at rr. The proof π\pi is [ψr(τ)]1[\psi_r(\tau)]_1. The prover does not need to know τ\tau to compute π\pi since:

[ψr(τ)]1=Σi=0nbi[τi]1[\psi_r(\tau)]_1 = \Sigma_{i = 0}^{n} b_i * [\tau^i]_1

where each bib_i is a coefficient of ψr(x)\psi_r(x). It outputs the tuple (r,ϕ(r),π)(r, \phi(r), \pi).

6. VerifyEval\mathcal{VerifyEval}

The verifier wants to check whether the claimed ϕ(r)\phi(r) is true. The verifier does not have access to ϕ(x)\phi(x), but only to the commitment C\mathcal{C}, the value rr, the claimed ϕ(r)\phi(r) and the proof π\pi.

The verifier checks whether this equality holds:

e(π,vk[r]2)=?e(C[ϕ(r)]1,g2) e(\pi, vk - [r]_2) \stackrel{?}{=} e(\mathcal{C} - [\phi(r)]_1, g_2)

To see why, the verifier's check actually boils down to:

e(π,vk[r]2)=?e(C[ϕ(r)]1,g2)e(ψr(τ)g1,τg2rg2)=?e(ϕ(τ)g1ϕ(r)g1,g2)e(g1,g2)ϕ(τ)ϕ(r)(τr)(τr)=?e(g1,g2)ϕ(τ)ϕ(r) \begin{aligned} e(\pi, vk - [r]_2) &\stackrel{?}{=} e(\mathcal{C} - [\phi(r)]_1, g_2) \\ e(\psi_r(\tau) * g_1, \tau * g_2 - r * g_2) &\stackrel{?}{=} e(\phi(\tau) * g_1 - \phi(r) * g_1, g_2) \\ e(g_1, g_2)^{\frac{\phi(\tau) - \phi(r)}{(\tau - r)} \cdot (\tau - r)} &\stackrel{?}{=} e(g_1, g_2)^{\phi(\tau) - \phi(r)} \\ \end{aligned}

Applications

Here is a quick list of interesting KZG applications.

1. Credentials

This is detailed in section 4.3 of the seminal paper, along with other cool applications. The idea is to have a trusted authority sign a commitment to a polynomial. Evaluations (0,ϕ(0)),,(n,ϕ(n)){(0, \phi(0)), \dots, (n, \phi(n))} of this polynomial would correspond to the vector of information which build up a credential's content. Using this signed commitment, a user can then selectively prove a value or a subset of values of his/her credentials information. The verifier will only have to check that the signature of the commmitted polynomial it receives is valid and that the evaluation proof is correct.

2. Proto-danksharding

Ethereum uses the BLS12-381 type-3 pairing friendly curve for EIP-4844 which leverages KZG commitments under the hood. Blob data consists in a vector of 4096 field elements from the scalar field Fr\mathbb{F}_r. This vector of field elements is interpreted as coefficients of a polynomial and committed to using KZG. To this end, a point evaluation precompile is being introduced in the EVM. Its use is mainly intended for L2 rollups. Given the large application surface of KZG, I would not be surprised if this precompile were to deviate from its initial purpose in the near future, though.

3. Halo2

Scroll L2 switched Halo2's initial polynomial commitment scheme (a variant of IPA) for KZG. Roughly, KZG is used to commit to witness values and to a quotient polynomial attesting to the fact that the constraint systems is satisfied with this witness. There is a nice post here going over the nitty-gritty.

4. Proof of solvency protocols

V. Buterin described a proof of solvency protocol where a CEX's users and balances would be committed to using KZG. Users would then be able to verify that they have been included into the commitment using evaluation proofs. An additional auxiliary polynomial is used to also prove properties of the exchange's balance sheet - namely that it is solvent. Summa is a project working on this. We also did a simpler example implementation here.

5. Extractable Witness Encryption

As I'm currently updating this blog, let me add this more recent application. In this paper, the authors show how to encrypt a message so that only someone with the knowledge of a valid KZG opening can decrypt it. There is a nice presentation done by Nils Fleischhacker himself here.