Under Construction

This page is under construction

Existing content is being updating and will be changed soon.

Commitment Schemes

Commitment schemes are essential for many cryptographic protocols, especially in zero-knowledge proofs where a prover needs to commit to certain values without revealing them immediately. They provide a way to “lock” a value in a way that can be verified later.

Definition (Commitment scheme). A commitment scheme is a tuple Γ=\Gamma= (Setup, Commit, Open) of PPT algorithms where:

  • Setup(1λ)pp\operatorname{Setup}\left(1^{\lambda}\right) \rightarrow \mathrm{pp}

    takes security parameter λ\lambda (in unary) and generates public parameters pp\mathrm{pp};

  • Commit(pp;m)(C;r)\operatorname{Commit} (\mathrm{pp} ; m) \rightarrow(C ; r)

    takes a secret message mm and outputs a public commitment CC and (optionally) a secret opening hint rr (which might or might not be the randomness used in the computation).

  • Open(pp,C;m,r)b{0,1}\operatorname{Open} (\mathrm{pp}, C ; m, r) \rightarrow b \in\{0,1\}

    verifies the opening of the commitment CC to the message mm provided with the opening hint rr.

💡 Key Properties:

  • 🔒 Binding: The committer cannot change the committed value after the commitment is made.
  • 🔍 Hiding: The commitment does not reveal information about the committed value.

A commitment scheme Γ\Gamma is 🔒 binding if for all PPT\mathrm{PPT} adversaries A\mathcal{A} :

Pr[ppSetup(1λ)b0=b10m0m1:(C,m0,m1,r0,r1)A(pp)b0Open(pp,C,m0,r0)b1Open(pp,C,m1,r1)]neg(λ)\operatorname{Pr}\left[\begin{array}{ll} & \mathrm{pp} \leftarrow \operatorname{Setup}\left(1^{\lambda}\right) \\ b_{0}=b_{1} \neq 0 \wedge m_{0} \neq m_{1}: & \left(C, m_{0}, m_{1}, r_{0}, r_{1}\right) \leftarrow \mathcal{A}(\mathrm{pp}) \\ & b_{0} \leftarrow \operatorname{Open}\left(\mathrm{pp}, C, m_{0}, r_{0}\right) \\ & b_{1} \leftarrow \operatorname{Open}\left(\mathrm{pp}, C, m_{1}, r_{1}\right) \end{array}\right] \leq \operatorname{neg}(\lambda)

Informally, this states that a valid commitment CC to a message m0m_{0} is binding if no adversary can produce a valid opening to some different message m1m_{1}.

A commitment scheme Γ\Gamma is 🔍 hiding if for any polynomial-time adversary A\mathcal{A} :

Pr[ppSetup(1λ)(m0,m1,st)A(pp)b0=b:b${0,1}(Cb;rb)Commit(pp;mb)bA(pp,st,Cb)]1/2=negl(λ)\operatorname{Pr}\left[\begin{array}{cl} & \mathrm{pp} \leftarrow \operatorname{Setup}\left(1^{\lambda}\right) \\ & \left(m_{0}, m_{1}, s t\right) \leftarrow \mathcal{A}(\mathrm{pp}) \\ b_{0}=b^{\prime}: & b \stackrel{\$}{\leftarrow}\{0,1\} \\ & \left(C_{b} ; r_{b}\right) \leftarrow \operatorname{Commit}\left(\mathrm{pp} ; m_{b}\right) \\ & b^{\prime} \leftarrow \mathcal{A}\left(\mathrm{pp}, s t, C_{b}\right) \end{array}\right]-1 / 2 \mid=\operatorname{negl}(\lambda)

Informally, this states that if a commitment is hiding if an adversary cannot “reverse-engineer” which of their messages was committed to.

Definition (Commitment scheme). A commitment scheme is a tuple Γ=\Gamma= (Setup, Commit, Open) of PPT algorithms where:

  • Setup(1λ)pp\operatorname{Setup}\left(1^{\lambda}\right) \rightarrow \mathrm{pp}

    takes security parameter λ\lambda (in unary) and generates public parameters pp\mathrm{pp};

  • Commit(pp;m)(C;r)\operatorname{Commit} (\mathrm{pp} ; m) \rightarrow(C ; r)

    takes a secret message mm and outputs a public commitment CC and (optionally) a secret opening hint rr (which might or might not be the randomness used in the computation).

  • Open(pp,C;m,r)b{0,1}\operatorname{Open} (\mathrm{pp}, C ; m, r) \rightarrow b \in\{0,1\}

    verifies the opening of the commitment CC to the message mm provided with the opening hint rr.

Vector Commitment

A vector commitment scheme for the message space MM is a commitment scheme for a vector m=(m1,,mk)Mk\vec{m}=\left(m_{1}, \ldots, m_{k}\right) \in \mathrm{M}^{k}.

The main security property for a vector commitment is position binding:

Definition (Position binding). A vector commitment scheme Γ\Gamma is position binding if for any PPT adversary A\mathcal{A} :

Pr[ Open (pp,C,m,i)1 Open (pp,C,m,i)pp$Setup(1λ)mmA(pp)(c,m,m,i)]negl(λ)\operatorname{Pr}\left[\begin{array}{l|l} \text { Open }(\mathrm{pp}, C, \vec{m}, i) \rightarrow 1 \\ \text { Open }(\mathrm{pp}, C, \vec{m^{\prime}}, i) & \mathrm{pp} \stackrel{\$}{\leftarrow} \operatorname{Setup}(1^\lambda) \\ m \neq m^{\prime} & \mathcal{A}(\mathrm{pp}) \rightarrow(c, \vec{m}, \vec{m^{\prime}}, i) \end{array}\right] \leq \operatorname{negl}(\lambda)

Informally, this states that no adversary can open CC to two different values at the same position.

Pedersen Commitment

Vector Pedersen commitment. The Pedersen commitment [9] is a binding and hiding commitment scheme for the message space Fq\mathbb{F}_{q}. For a secret message mZqm \in \mathbb{Z}_{q} :

  • Pedersen.Setup(1λ,q)pp:pp=G,HG\operatorname{Pedersen.Setup} \left(1^{\lambda}, q\right) \rightarrow \mathrm{pp}: \mathrm{pp}=G, H \in \mathbb{G}, where G\mathbb{G} is a cryptographic group of order qq.

  • Pedersen.Commit(pp;m)(C;r):C=[m]G+[r]H\operatorname{Pedersen.Commit} (\mathrm{pp} ; m) \rightarrow(C ; r): C=[m] G+[r] H, where rZqr \in \mathbb{Z}_{q} is a random secret.

  • Pedersen.Open(pp,C;m,r){0,1}:\operatorname{Pedersen.Open} (\mathrm{pp}, C ; m, r) \rightarrow\{0,1\}: the prover P\mathcal{P} reveals mm and rr, and the verifier V\mathcal{V} checks C=?[m]G+[r]HC \stackrel{?}{=}[m] G+[r] H

Note that the Pedersen commitment is additively homomorphic:

Commit(m,r)+Commit(m,r)=[m]G+[r]H+[m]G+[r]H=[m+m]G+[r+r]H=Commit(m+m,r+r).\begin{aligned} \operatorname{Commit}(m, r)+\operatorname{Commit}\left(m^{\prime}, r^{\prime}\right) & =[m] G+[r] H+\left[m^{\prime}\right] G+\left[r^{\prime}\right] H \\ & =\left[m+m^{\prime}\right] G+\left[r+r^{\prime}\right] H \\ & =\operatorname{Commit}\left(m+m^{\prime}, r+r^{\prime}\right) . \end{aligned}

Interactive Pedersen Calculator

Commitment Result:

This is a simplified implementation using:

  • Generator g = 7
  • Generator h = 11
  • Prime modulus p = 2147483647

In real applications, these would be carefully chosen cryptographic parameters.

Vector Pedersen Commitment

Vector commitments allow committing to a vector of values while being able to open the commitment at specific positions. They are particularly useful in applications where you need to commit to multiple values at once.

🔢 Mathematical Definition:

Commit(m,r)=hri=1ngimi\text{Commit}(\vec{m}, r) = h^r \cdot \prod_{i=1}^{n} g_i^{m_i}

Where:

  • m=(m1,m2,,mn)\vec{m} = (m_1, m_2, \ldots, m_n) is the vector to commit to
  • rr is a random value (blinding factor)
  • g1,g2,,gng_1, g_2, \ldots, g_n are independent group generators
  • hh is another independent group generator

🔍 Applications: Vector commitments are used in:

  • Verifiable databases where you need to prove membership of elements
  • Zero-knowledge proofs for multiple values
  • Blockchain systems for committing to multiple transactions

⚡ Efficiency Considerations: The main challenge with vector commitments is efficiency, especially as the vector size grows. Various optimizations exist to make vector commitments more practical:

  • Merkle trees for logarithmic-sized proofs
  • Polynomial commitments for batch openings
  • Specialized constructions like KZG for vectors

Vector Commitment Example

Consider a vector of 3 values: [5, 12, 7]

g₁ = 3, g₂ = 5, g₃ = 7
h = 11
r = 9

Commit([5, 12, 7], 9) = 11⁹ · 3⁵ · 5¹² · 7⁷
= 2,357,947,691 (mod p)

To open just the second position (value 12), the prover would provide the value 12 and a proof that this value is indeed at position 2 in the committed vector.

Polynomial Commitment

A univariate polynomial commitment scheme (PCS) is a commitment scheme for the message space Fd[X]\mathbb{F}^{\leq d}[X], the ring of univariate polynomials with maximum degree dNd \in \mathbb{N} and coefficients in the field F=Zp\mathbb{F}=\mathbb{Z}_{p}

It supports an argument of knowledge for proving the correct evaluation of a committed polynomial at a given point. A lot of information can be encoded in a polynomial: an arbitrary relation can be represented as a polynomial.

🔗 Pairing-based cryptography

Given cyclic groups G1,G2,GT\textcolor{red}{\mathbb{G}_{1}}, \textcolor{green}{\mathbb{G}_{2}}, \textcolor{blue}{\mathbb{G}_{T}}, all of the same prime order pp, a pairing is a nondegenerate bilinear map

e:G1×G2GTe: \textcolor{red}{\mathbb{G}_{1}} \times \textcolor{green}{\mathbb{G}_{2}} \rightarrow \textcolor{blue}{\mathbb{G}_{T}}
  • bilinear: e([a]P,[b]Q)=e(P,Q)abe([a] P,[b] Q)=e(P, Q)^{a \cdot b}

  • nondegenerate: with generators G1G1G_{1} \in \textcolor{red}{\mathbb{G}_{1}} and G2G2,GT:=e(G1,G2)GTG_{2} \in \textcolor{green}{\mathbb{G}_{2}}, G_{T}:=e\left(G_{1}, G_{2}\right) \in \textcolor{blue}{\mathbb{G}_{T}} is a generator.

KZG Polynomial Commitment

KZG (Kate-Zaverucha-Goldberg) polynomial commitments allow committing to a polynomial and later proving evaluations of that polynomial at specific points. They are widely used in modern zero-knowledge proof systems due to their efficiency and succinctness.

Its core idea is:

  • The prover can commit to a polynomial.
  • Later, they can prove to the verifier the value of that polynomial at a specific point without revealing the underlying polynomial.

This method is so useful because any content that can be encoded as a polynomial can now be easily disclosed selectively.

We will use the shorthand notation [x]1:=[x]G1,[x]2:=[x]G2[x]_{1}:=[x] G_{1},[x]_{2}:=[x] G_{2}, for any xFpx \in \mathbb{F}_{p}.

  • KZG.Setup(1λ,d)srs\operatorname{KZG.Setup} \left(1^{\lambda}, d\right) \rightarrow srs:

    set srs=(ck,vk)=({[αi]1}i=0d1,[α]2)srs =(\mathrm{ck}, \mathrm{vk})=\left(\left\{\left[\alpha^{i}\right]_{1}\right\}_{i=0}^{d-1},[\alpha]_{2}\right). α\alpha here is a secret element and must be discarded after the Setup.

  • KZG.Commit(ck;f(X))C\operatorname{KZG.Commit} (\mathrm{ck} ; f(X)) \rightarrow C:

    for f(X)=i=0n1fiXi,C=i=0n1[fi][αi]1=[f(α)]1f(X)=\sum_{i=0}^{n-1} f_{i} X^{i}, C=\sum_{i=0}^{n-1}\left[f_{i}\right]\left[\alpha^{i}\right]_{1}=[f(\alpha)]_{1}.

  • KZG.Open(srs,C,x,y;f(X)){0,1}\operatorname{KZG.Open}(srs, C, x, y ; f(X)) \rightarrow\{0,1\}:

    To “open” the commitment at evaluation point xx to a claimed value yy

    1. the prover P\mathcal{P} computes the quotient polynomial q(X)=f(X)yXxq(X)=\frac{f(X)-y}{X-x} and sends the verifier π=KZG.Commit(ck;q(X))=[q(α)]1\pi=\operatorname{KZG.Commit} (ck; q(X))=[q(\alpha)]_{1}

    2. the verifier V\mathcal{V} checks e(C[y]1,H)=?e(π,[α]2[x]2)e\left(C-[y]_{1}, H\right) \stackrel{?}{=} e\left(\pi,[\alpha]_{2}-[x]_{2}\right).

    The 1 and 2 steps in KZG.Open\operatorname{KZG.Open} are often written as two separate algorithms:

    • Open(ck,C,x,y;f(X))π\operatorname{Open} (\mathrm{ck}, C, x, y ; f(X)) \rightarrow \pi returns an opening proof for the relation
    R:={(ck,C,x,y;f(X)):Cdeg(f(X))dy=f(x)};\mathcal{R}:=\left\{(\mathrm{ck}, C, x, y ; f(X)): \begin{array}{rl} & C \operatorname{deg}(f(X)) \leq d \\ & \wedge y=f(x) \end{array}\right\} ;
    • Verify(vk,C,x,y,π){0,1}\operatorname{Verify} (\mathrm{vk}, C, x, y, \pi) \rightarrow\{0,1\} verifies the opening proof’s correctness.

Quotient Polynomial q(X)q(X)

Goal:
Prove that y=f(z)y = f(z) without revealing what f(X)f(X) is.

Method:

  • Since f(z)=yf(z) = y, this guarantees that f(X)yf(X) - y is zero at X=zX = z.
    Therefore, (Xz)(X - z) is a factor of f(X)yf(X) - y.

  • We divide f(X)yf(X) - y by (Xz)(X - z), and the result is a polynomial of one degree lower, denoted as q(X)q(X).

Example:

Suppose f(X)=X2+2X+1f(X) = X^2 + 2X + 1, and we know f(1)=4f(1) = 4, i.e., y=4y = 4. Then:

f(X)y=(X2+2X+1)4=X2+2X3f(X) - y = (X^2 + 2X + 1) - 4 = X^2 + 2X - 3

Now we verify that f(X)yf(X) - y is zero at X=1X = 1:

f(1)y=(12+213)=0f(1) - y = (1^2 + 2 \cdot 1 - 3) = 0

So X=1X = 1 is a root of f(X)yf(X) - y.

Therefore, we can factor f(X)yf(X) - y as:

f(X)y=(X1)(X+3)f(X) - y = (X - 1)(X + 3)

In this case, the quotient polynomial is:

q(X)=X+3q(X) = X + 3

Interactive KZG Example

Define a polynomial by entering its coefficients (from constant term to highest degree)

Polynomial:

Polynomial Evaluation:

Quotient Polynomial:

This example demonstrates the polynomial division that forms the basis of KZG proofs. In a real KZG implementation:

  • The polynomial and quotient would be committed to using elliptic curve operations
  • The verification would use bilinear pairings
  • The proof would be a single group element

Commitment Resources

Polynomial Commitments: Building Block for Universal SNARKsExternal Link

Includes a taxonomy of PCS based on the cryptographic primitives used (hash, pairing, etc.).

KZG Polynomial CommitmentsExternal Link

An introduction to the KZG polynomial commitment scheme, and how to extend it to multiproofs and vector commitments.

Inner Product ArgumentsExternal Link

An introduction to the inner product argument (IPA) protocol, a primitive used to build PCS. Often instantiated with the vector Pedersen commitment.

Inner Product Proof Notes (Bulletproofs)External Link

An excellent write-up on inner product arguments in the context of Bulletproofs.

Anatomy of a STARK, Part 3: FRIExternal Link

An introduction to the FRI (Fast Reed-Solomon IOP of Proximity) protocol, an oracle proof of proximity used in STARKs.

arkworks-rs/poly-commitExternal Link

A Rust library supporting four polynomial commitment schemes.

Polynomial Commitment BenchmarkExternal Link

Benchmarks for the Commit algorithm in KZG, IPA-based, and FRI-based polynomial commitment implementations.

References

  1. Shuang Liang, zkShanghai. " Commitment Schemes ". 2023.