Learn / Math / Commitment Schemes
15. Commitment Schemes
Commitments · Lesson 16 of 18 · 5:43
The second building block alongside hashing that almost every ZK proof system is built from — how to lock in a value now, keep it completely secret, and still prove later you never changed it.

The last lesson showed a hash replacing a live verifier with a single computation. This lesson tackles a different problem entirely: how does someone lock in a value now, prove later they never changed it, while keeping that value completely secret the whole time in between? That’s a commitment scheme — the second building block, alongside hashing, that almost every ZK proof system is built from.

The core idea: commit, then reveal

Think of a sealed envelope. Write something down, seal it, hand it over — nobody can see what’s inside, but it also can’t be swapped for a different piece of paper later. A commitment scheme does exactly that with numbers instead of paper.

lock it in now, open it later COMMIT PHASE m = 42 (secret) Commit(m, r) C Receiver receiver sees C — learns nothing about m REVEAL PHASE (later) m = 42 r (opening key) ?= C receiver verifies m and r actually produce C LOCK IT IN, PROVE IT LATER the committer can't be shown to lie about m once C is sent
Fig. 1 — commit now, locked and sealed. Reveal later, and the receiver can check it against what was sent.
A commitment scheme

Two phases: C=Commit(m,r)C = \text{Commit}(m, r) sends only CC — the receiver learns nothing about mm yet. Later, revealing mm and the opening key rr lets the receiver check that they really do produce that same CC.

Two promises: hiding and binding

That envelope metaphor only holds together if two separate promises are both kept at once. Break either one, and the scheme is useless.

two promises, both have to hold at once HIDING m = 42 Commit C C alone reveals NOTHING about m m = 42 ? m = 7 ? both are equally plausible BINDING m₁ = 42 ≠ m₂ = 7 Commit BLOCKED same C cannot open to two different messages TWO PROMISES, NEVER BROKEN hiding: C reveals nothing — binding: C can only ever open to one message
Fig. 2 — hiding: C alone could belong to any message. Binding: once C is sent, it can never be reopened to a different one.
Hiding and binding

Hiding — CC on its own reveals nothing about mm; every possible message stays equally plausible. Binding — the committer can never produce a valid opening of CC to a message other than the one they actually started with.

A real construction — the Pedersen commitment

So far this has all been conceptual. Here’s an actual working construction, built entirely from tools already in this series: elliptic curve points, from topic 12.

The Pedersen commitment

C=g⋅m+h⋅rC = g \cdot m + h \cdot r

gg and hh are two fixed generator points — both public, known to everyone. mm is the secret message being committed to. rr is a random blinding factor, chosen fresh and kept secret too.

a real construction, built from elliptic curve points C = g·m + h·r g, h — two fixed generator points (public) m — the secret message r — a random blinding factor (secret) ONE POINT, TWO SECRETS BAKED IN C is a single curve point — recovering m or r is exactly the discrete log problem
Fig. 3 — one curve point, two secrets baked in. Pulling m or r back out of C is exactly the discrete log problem from topic 11.

Why the blinding factor matters

That rr in the formula might look like an unnecessary extra ingredient. It isn’t — it’s the entire reason hiding actually works. Watch what happens committing to the exact same message three separate times, with three different random rr values.

same message, different commitments m = 42, r = 7 C₁ = m = 42, r = 91 C₂ = m = 42, r = 5,006 C₃ = same m every time — but C₁, C₂, C₃ look totally unrelated RANDOMNESS IS WHAT HIDES YOU without r, committing to the same value twice would look identical — and leak that fact
Fig. 4 — same m = 42 every time. Three different r values produce three completely unrelated-looking commitments.

Without rr, committing to the same value twice would produce the exact same CC both times — and that repetition alone would leak the fact that the hidden values matched.

KZG — committing to an entire polynomial

A Pedersen commitment locks in a single number. KZG does something far more powerful: it commits to an entire polynomial — the exact object this series spent its second phase building — and compresses it down to one point.

committing to an entire polynomial COMMIT p(x) — could have thousands of terms C = commitment to p(x) just ONE elliptic curve point OPEN / PROVE verifier picks random x = a prover reveals y = p(a), plus proof π verifier checks e(…) = e(…) …without ever seeing the rest of p(x) PROVE ONE POINT, WITHOUT SHOWING THE POLYNOMIAL this is what a Groth16 or PLONK proof actually sends you — not the polynomial, just this
Fig. 5 — a polynomial with thousands of terms compresses to one curve point. Opening it at a random location proves a value without revealing the rest.

The verifier picks a random evaluation point x=ax = a; the prover reveals y=p(a)y = p(a) along with a short proof π\pi; the verifier checks a pairing equation — the exact tool built in topic 13. This is what a Groth16 or PLONK proof actually sends: not the polynomial, just this.

Why this matters for ZK

Here’s how commitments and the Fiat-Shamir transform from the last lesson fit together into one system — and why the order of operations is the whole point.

why the order of operations is the whole point prover commits to their polynomials FIRST C₁ C₂ C₃ THEN the random challenge is generated c = H(commitments) Fiat-Shamir, Topic 14. prover can't go back and change their polynomials — they're already locked in by binding COMMIT BEFORE YOU SEE THE QUESTION this exact ordering — commit, then challenge — is what stops a prover from cheating in Groth16, PLONK, and KZG
Fig. 6 — commitments lock in first. Only then does the challenge exist. There's no path back to change what was already sealed.

The prover commits to their polynomials first — those are sealed by binding. Only then does the random challenge get generated, as c=H(commitments)c = H(\text{commitments}), straight from the Fiat-Shamir transform built last lesson. Commit before seeing the question. This exact ordering — commit, then challenge — is what stops a prover from cheating in Groth16, PLONK, and KZG alike.