Commitments — Pedersen, KZG, FRI TODO
Concept
A commitment is a primitive for sealing a value so it can be revealed later, requiring binding (the sealed value can't be swapped out) and hiding (the seal alone reveals nothing about the value). A Pedersen commitment is built on the discrete-log assumption using two generators and a random blinding value; it achieves information-theoretic hiding and computational binding, and is additively homomorphic, so you can verify the sum of values by adding their commitments together. KZG is a polynomial commitment that uses pairings to make both the commitment and the evaluation proof at any point constant-size, but it needs a structured reference string (a trusted setup). FRI works via hash-based proximity testing against Reed-Solomon codes, needs no trusted setup, and has proof size that grows polylogarithmically, and because its assumptions are hash-based, it's favored from a post-quantum standpoint. Whether a setup is required, proof size, verification cost, and the type of assumption are the three axes that separate these approaches.
The cost structure of rollups and ZK systems, their data-availability design, and their trust assumptions all essentially come down to which commitment scheme is used, so without understanding this tradeoff you can't ground an architecture decision.
Code & Formula
# 커밋먼트 — Pedersen 커밋먼트를 모듈러 지수 연산으로 구현해 binding·hiding·덧셈 준동형을 시연.
# 이산로그 가정 기반 토이 그룹 (실제 EC 대신 소수체 위 지수 연산으로 개념만 재현, 교육용).
import secrets
P = 2**127 - 1 # 토이 소수 (실제로는 소수인지 별도 검증 필요 — 데모 목적)
G, H = 5, 7 # 서로 이산로그 관계를 모르는 두 "생성원" (토이 값)
def commit(value, blinding):
return (pow(G, value, P) * pow(H, blinding, P)) % P
def open_commitment(commitment, value, blinding):
return commit(value, blinding) == commitment
# --- hiding: 커밋먼트만 봐서는 값을 알 수 없다 ---
secret_value = 1000
blinding = secrets.randbelow(P)
c = commit(secret_value, blinding)
print("commitment (looks random, reveals nothing):", c)
# --- binding: 다른 값으로는 같은 커밋먼트를 열 수 없다 ---
print("opens correctly with real (value, blinding):", open_commitment(c, secret_value, blinding))
print("fails to open with a different value:", not open_commitment(c, secret_value + 1, blinding))
# --- 덧셈 준동형: 커밋먼트끼리 곱하면 값의 합에 대한 커밋먼트가 된다 ---
v1, b1 = 30, secrets.randbelow(P)
v2, b2 = 12, secrets.randbelow(P)
c1, c2 = commit(v1, b1), commit(v2, b2)
c_sum_direct = commit(v1 + v2, (b1 + b2) % P)
c_sum_from_commitments = (c1 * c2) % P
print()
print("commit(v1)*commit(v2) mod P:", c_sum_from_commitments)
print("commit(v1+v2, b1+b2) directly:", c_sum_direct)
print("additively homomorphic:", c_sum_from_commitments == c_sum_direct)
print("=> lets a verifier check sums (e.g. 'inputs balance outputs') without seeing v1, v2")
docs/code/algorithms/algorithms-87.py
Exercise
Implement a Pedersen commitment with an elliptic-curve library and verify its homomorphism, then build a Merkle-tree commitment over the same values and tabulate commitment size, proof size, and verification time for comparison.
Practical Connection
When Verex compresses off-chain state or order batches onto the chain at settlement, which commitment it uses directly decides calldata/blob cost, on-chain verification gas, and the trust assumptions required.
If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.