Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
The simplest concrete commitment scheme is where is a cryptographic hash. It's used everywhere — STARKs, Merkle trees, Fiat–Shamir transcripts, sealed-bid auctions — because it's fast, post-quantum-friendly, and has no trusted setup. But it's only secure under non-trivial assumptions about : collision resistance gives binding, and 'random-oracle-like' behaviour gives hiding. Spelling out exactly which property of buys which property of the commitment is the point of this task. Once you can do that, you can read every Merkle-based ZK paper and immediately see which assumptions are doing the work.
Let be a cryptographic hash. Define where is uniform in . Binding follows from collision resistance of . Hiding follows from being a one-way function on the high-entropy input — formally, modelled as a random oracle, is uniform and independent of .
// main.go
package main
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
)
func commit(m, r []byte) []byte {
h := sha256.New()
h.Write(m)
h.Write(r)
return h.Sum(nil)
}
func open(c, m, r []byte) bool {
got := commit(m, r)
if len(got) != len(c) {
return false
}
for i := range got {
if got[i] != c[i] {
return false
}
}
return true
}
func main() {
// Honest flow
m := []byte("pay alice 100 sats")
r := make([]byte, 32) // 256-bit randomness
rand.Read(r)
c := commit(m, r)
fmt.Printf("commitment : %s ...\n", hex.EncodeToString(c)[:32])
fmt.Printf("open : %v\n", open(c, m, r))
// Without randomness, the scheme is NOT hiding (low-entropy m is brute-forceable).
mLow := []byte("yes") // only a few likely messages
sum := sha256.Sum256(mLow)
cNoR := sum[:]
// Attacker tries all small messages:
for _, guess := range [][]byte{[]byte("yes"), []byte("no"), []byte("maybe")} {
gs := sha256.Sum256(guess)
if hex.EncodeToString(gs[:]) == hex.EncodeToString(cNoR) {
fmt.Printf("Recovered low-entropy message without randomness: %s\n", guess)
break
}
}
}go run main.go