Commitment Schemes
CryptographyCommitment Schemes
A commitment scheme is a cryptographic primitive that allows a party to commit to a chosen value while keeping it hidden from others, with the ability to reveal the committed value later. Think of it as placing a message in a sealed, tamper-proof envelope — once sealed, you can’t change the message (binding), and nobody can read it until you open it (hiding). Commitments are foundational to zero-knowledge proofs, private voting, sealed-bid auctions, and virtually every privacy-preserving protocol.
The Sealed Envelope Analogy
Imagine an auction where bidders write their bids on paper, seal them in envelopes, and hand them to the auctioneer. Once submitted:
- No one can read the bid — the envelope is opaque (hiding).
- No one can swap the paper inside — the envelope is tamper-proof (binding).
- Later, envelopes are opened and bids are verified (reveal/open phase).
A commitment scheme is the cryptographic equivalent of this envelope. The “commit” phase produces a short value (the sealed envelope), and the “reveal” phase provides the opening information so anyone can verify the committed value.
COMMIT PHASE REVEAL PHASE
value ──┐ value ──┐
├──► Commit(v, r) = C ├──► Verify(C, v, r) → ✓/✗
random ──┘ │ random ──┘ │
│ │
publish C check C == Commit(v, r)
(hides v, binds to v)
Formal Properties
A commitment scheme consists of two algorithms — Commit(v, r) → C and Verify(C, v, r) → bool — satisfying two security properties:
Hiding
The commitment C reveals nothing about the committed value v. There are two flavors:
- Computational hiding: An adversary with bounded computational resources cannot determine
vfromC. If you could break the hash function or the discrete log problem, you could break hiding — but no one can (we believe). - Information-theoretic (perfect) hiding: Even an adversary with unlimited computational power cannot learn
vfromC. This requires the randomnessrto completely maskv.
Binding
Once committed, the committer cannot open the commitment to a different value. Again, two flavors:
- Computational binding: No efficient adversary can find two different openings
(v, r)and(v', r')that produce the same commitmentC. - Information-theoretic (perfect) binding: It is mathematically impossible to find two valid openings (even with infinite computation).
Key impossibility result: A commitment scheme cannot be both perfectly hiding and perfectly binding simultaneously. Every scheme must choose which property to make unconditional and which to base on computational assumptions.
| Scheme | Hiding | Binding |
|---|---|---|
| Hash commitment | Computational | Perfect |
| Pedersen commitment | Perfect | Computational |
Hash Commitments
The simplest and most widely deployed construction.
Construction
Commit(v, r):
return H(v ‖ r) // r is random, ≥128 bits
Verify(C, v, r):
return C == H(v ‖ r)
Where H is a cryptographic hash function (SHA-256, Keccak, etc.) and ‖ denotes concatenation.
Why the randomness matters
Without r, the commitment is just H(v). If the value space is small (e.g., “yes” or “no” in a vote), anyone can hash all possibilities and match. The randomness r (sometimes called a “blinding factor” or “nonce”) prevents this brute-force attack.
Properties
- Perfect binding: SHA-256 is collision-resistant. Finding
(v, r)and(v', r')withH(v ‖ r) = H(v' ‖ r')would mean finding a collision. - Computational hiding: Given
C, an adversary would need to invert the hash to learnv. Security degrades if the value space is small andris short. - Non-homomorphic: You cannot combine two hash commitments to get a commitment to the sum.
H(a ‖ r₁) + H(b ‖ r₂) ≠ H((a+b) ‖ r₃).
When to use
Hash commitments are ideal when you need simple commit-reveal logic and don’t need algebraic operations on committed values. They’re the default choice for commit-reveal voting, random number generation, and any protocol where the committed value is eventually fully revealed.
Pedersen Commitments
When you need to do math on commitments without opening them, Pedersen commitments are the standard choice.
Group-Theoretic Construction
Choose a cyclic group G of prime order q with two generators g and h, where nobody knows the discrete logarithm of h with respect to g (i.e., no one knows x such that h = g^x).
Commit(v, r):
return g^v · h^r // v is the value, r is random in Z_q
Verify(C, v, r):
return C == g^v · h^r
Why is this secure?
- Perfect hiding: For any commitment
Cand any valuev', there exists exactly oner'such thatC = g^v' · h^r'. SoCis statistically independent ofv— even an all-powerful adversary cannot determinev. - Computational binding: To open
Cto two different values, the committer would need to findv, r, v', r'such thatg^v · h^r = g^v' · h^r'. This simplifies tog^(v-v') = h^(r'-r), which means knowing the discrete log ofhw.r.t.g. Breaking binding = solving discrete log.
The Homomorphic Property
This is what makes Pedersen commitments essential for zero-knowledge protocols:
Commit(a, r₁) · Commit(b, r₂) = g^a · h^r₁ · g^b · h^r₂
= g^(a+b) · h^(r₁+r₂)
= Commit(a + b, r₁ + r₂)
Multiplying two commitments gives a valid commitment to the sum of the values, with the sum of the randomnesses. This is additive homomorphism.
Why does this matter for ZK?
Consider a confidential transaction: Alice sends 5 tokens to Bob, and 3 tokens in change back to herself, from an input of 8. A verifier needs to check input = output₁ + output₂ without seeing amounts:
C_input = Commit(8, r₁) = g^8 · h^r₁
C_output_bob = Commit(5, r₂) = g^5 · h^r₂
C_output_change = Commit(3, r₃) = g^3 · h^r₃
Verify: C_input == C_output_bob · C_output_change
g^8 · h^r₁ == g^(5+3) · h^(r₂+r₃)
This holds when r₁ = r₂ + r₃
The verifier confirms the balance equation without learning any amounts. This is exactly how Mimblewimble and Monero’s RingCT work.
Poseidon Hash: ZK-Friendly Commitments
The Problem with SHA-256 in Circuits
Zero-knowledge proof systems work over arithmetic circuits — chains of additions and multiplications in a finite field. Traditional hash functions like SHA-256 and Keccak are designed for bitwise operations (XOR, rotations, shifts). Expressing these bitwise operations as arithmetic constraints is extremely expensive:
| Hash Function | Constraints in R1CS | Relative Cost |
|---|---|---|
| SHA-256 | ~25,000 | 100x |
| Keccak-256 | ~150,000 | 600x |
| Poseidon | ~250 | 1x |
| MiMC | ~730 | 3x |
How Poseidon Works (Simplified)
Poseidon is an algebraic hash function — it uses operations native to arithmetic circuits:
- State: A vector of field elements
[s₀, s₁, ..., sₜ] - Round function: Repeated application of:
- Add round constants:
sᵢ ← sᵢ + cᵢ - S-box (power map):
sᵢ ← sᵢ^α(typicallyα = 5) - Linear layer (MDS matrix):
s ← M · s
- Add round constants:
- Output: One or more elements of the final state
Because every operation is a native field operation (addition, multiplication, exponentiation), the constraint count is tiny compared to bitwise hashes.
When to Use What
- Outside circuits (on-chain storage, Merkle roots): SHA-256 or Keccak — battle-tested, fast in hardware, standardized.
- Inside ZK circuits (commitments, nullifiers, Merkle proofs): Poseidon — dramatically fewer constraints means faster proof generation and lower gas costs for on-chain verification.
Many protocols use a hybrid approach: Poseidon inside the circuit for efficiency, and Keccak on-chain for compatibility with Ethereum’s keccak256 opcode.
Vector Commitments
A vector commitment lets you commit to an ordered list of values and later prove that a specific value is at a specific position, without revealing the other values.
KZG (Kate-Zaverucha-Goldberg) Commitments
- Commit to a polynomial
p(x)using elliptic curve pairings. - To prove
p(i) = vᵢ, provide a single group element (constant-size proof). - Requires a trusted setup (structured reference string).
- Used in: Ethereum’s EIP-4844 (proto-danksharding), Plonk proof system.
Polynomial: p(x) encodes values [v₀, v₁, ..., vₙ₋₁]
Commitment: C = [p(τ)]₁ (evaluation at secret τ in the exponent)
Proof for position i: π = [(p(x) - vᵢ) / (x - i)]₁
Verification: e(C - [vᵢ]₁, [1]₂) == e(π, [τ - i]₂)
IPA (Inner Product Arguments)
- No trusted setup needed (transparent).
- Proof size is
O(log n)instead ofO(1), but avoids pairings. - Used in: Halo 2 (Zcash), Bulletproofs.
Comparison
| Property | KZG | IPA |
|---|---|---|
| Proof size | O(1) | O(log n) |
| Trusted setup | Yes | No |
| Verification | O(1) with pairings | O(n) naively, O(log n) amortized |
| Quantum safety | No | No (ECC-based) |
Commitments in Practice
Commit-Reveal Voting
PHASE 1 — COMMIT (voting period):
voter picks choice ∈ {yes, no}
voter generates random r
voter publishes C = H(choice ‖ r) on-chain
PHASE 2 — REVEAL (after voting closes):
voter publishes (choice, r)
contract verifies H(choice ‖ r) == C
contract tallies revealed votes
No voter can see others’ votes during the voting period (hiding). No voter can change their vote after seeing others reveal (binding).
Sealed-Bid Auctions
Same pattern as voting, but the committed value is a bid amount. After all bids are committed, everyone reveals. The highest bid wins. This prevents bid sniping and front-running.
Blockchain State Commitments
Every Ethereum block header contains a stateRoot — a commitment (via Merkle Patricia Trie) to the entire world state. Light clients verify state by checking Merkle proofs against this root, without downloading the full state.
Trading Protocols
In decentralized exchanges, commitment schemes prevent front-running: a trader commits to their order, the commitment is included in a block, and only then is the order revealed and executed.
Relationship to Nullifiers and ZK Proofs
Commitments and nullifiers form a complementary pair in privacy systems:
┌──────────────────────────────────────────────────┐
│ PRIVATE SPEND FLOW │
│ │
│ DEPOSIT: │
│ secret s, random r │
│ commitment C = H(s ‖ r) │
│ → C added to commitment tree │
│ │
│ WITHDRAW: │
│ nullifier N = H(s) │
│ ZK proof π: "I know (s, r) such that │
│ C = H(s ‖ r) is in the tree │
│ AND N = H(s)" │
│ → if N not in nullifier set, allow withdraw │
│ → add N to nullifier set │
│ │
│ RESULT: │
│ ✓ Depositor is anonymous (can't link N → C) │
│ ✓ Can't double-spend (N is unique per C) │
└──────────────────────────────────────────────────┘
The commitment hides what you deposited. The nullifier prevents you from withdrawing twice. The ZK proof links the two without revealing the connection. This is the core pattern of Tornado Cash, Zcash, and many privacy protocols. See Privacy Patterns for full protocol walkthroughs.
Summary
| Scheme | Hiding | Binding | Homomorphic | ZK-friendly | Typical Use |
|---|---|---|---|---|---|
| Hash (SHA-256) | Computational | Perfect | No | No | Simple commit-reveal |
| Hash (Poseidon) | Computational | Perfect | No | Yes | ZK circuits |
| Pedersen | Perfect | Computational | Additive | Yes | Confidential txs |
| KZG | Computational | Computational | Yes | Yes | Polynomial IOPs |
References
- Pedersen, T. P. “Non-Interactive and Information-Theoretic Secure Verifiable Secret Sharing.” CRYPTO ‘91.
- Kate, A., Zaverucha, G., Goldwasser, S. “Constant-Size Commitments to Polynomials and Their Applications.” ASIACRYPT 2010.
- Grassi, L., et al. “Poseidon: A New Hash Function for Zero-Knowledge Proof Systems.” USENIX Security 2021.
- Bünz, B., et al. “Bulletproofs: Short Proofs for Confidential Transactions and More.” IEEE S&P 2018.
Cross-links
- Nullifiers — the complement to commitments in privacy protocols
- Merkle Trees — used to organize commitments into efficiently-provable sets
- Privacy Patterns — full protocol designs using commitments
- STARKs vs SNARKs — proof systems that use commitment schemes internally