Skip to content
commit-reveal Source  →

How it works.

A commit-reveal scheme has two moves: bind now, reveal later. The library adds an optional third — prove you can reveal, without revealing. Here is the construction for each, grounded in the source.

Figure 1 — the two-phase flow

   COMMIT PHASE                          REVEAL PHASE
   ┌──────────────────────────┐          ┌──────────────────────────┐
   │  value                   │          │  value, salt             │
   │    │                     │          │    │                     │
   │    ▼   salt ← CSPRNG(32B) │          │    ▼                     │
   │  H(value ‖ salt)         │          │  H(value ‖ salt)         │
   │    │                     │          │    │                     │
   │    ▼                     │          │    ▼                     │
   │  commitment  ──── publish ──────────▶  compare_digest(·, commitment)
   │              (salt stays hidden)     │    │                     │
   └──────────────────────────┘          │    ▼  True / False       │
                                         └──────────────────────────┘

   OPTIONAL: prove knowledge without revealing (Schnorr, non-interactive)
   secret ← f(value, salt)   P = secret·G   k ← CSPRNG   R = k·G
   e = SHA256(P ‖ R ‖ commitment)   s = k + e·secret   →  (P, R, e, s)
   verify:  s·G  ==  R + e·P

is byte concatenation. G is the secp256k1 base point. The exact transcript the library returns is (public_key, R_compressed, challenge, response).

1 · The commitment

A commitment is H(value ‖ salt). The salt defaults to secrets.token_bytes(32) — 32 bytes from the OS CSPRNG. The hash is chosen per scheme instance from an eight-algorithm allowlist; md5 and sha1 are rejected at construction with SecurityError, and anything off the list raises ValidationError. Two properties matter:

2 · The reveal

To reveal, you re-supply value and salt; the library recomputes the hash and compares it against the stored commitment using hmac.compare_digest. That comparison is constant-time: it does not short-circuit on the first differing byte, so it does not leak how much of a guess was correct via timing. Using plain == here would be a real, exploitable bug — the library does not.

3 · The zero-knowledge proof

When you construct the scheme with use_zkp=True, you can produce a Schnorr proof of knowledge. The interactive Schnorr protocol proves "I know the discrete log of P" in three messages; the library collapses it into a single non-interactive proof using the Fiat–Shamir heuristic, deriving the verifier's challenge as SHA-256 over the transcript instead of asking a live verifier.

The curve is secp256k1 — the same curve Bitcoin uses — implemented by hand in zkp.py with the canonical parameters (p, a = 0, b = 7, G, n), affine point addition and scalar multiplication, and 0x02 / 0x03 point compression. The nonce k comes from secrets, never random.

This implementation is affine and not constant-time at the scalar-multiply level. It is built for protocol prototyping and low-throughput use, not HFT-scale proving. For pairing curves, BLS, or SNARK arithmetic, see the py_ecc comparison.

Table 1 — module map

What lives where

Seven small files under commit_reveal/. The cryptographic core and the ZKP are cleanly separated from validation, audit, and the CLIs.

FileResponsibility
commit_reveal/core.py CommitRevealScheme: commit, reveal/verify, hash selection, salt generation.
commit_reveal/zkp.py Hand-rolled secp256k1 + non-interactive Schnorr proof via Fiat–Shamir.
commit_reveal/validation.py Input validation and the hash-algorithm allowlist; ValidationError / SecurityError.
commit_reveal/audit.py Operation audit trail, separate from the cryptographic core.
commit_reveal/secure_cli.py No-plaintext-at-rest CLI: getpass entry, 0600 files, sanitized names.
commit_reveal/cli.py Deprecated legacy CLI, kept for backward compatibility.
commit_reveal/migrate.py Migrates commitment files written in older formats.

Read on

The threat model is explicit.

See exactly what is in and out of scope, or jump to the quickstart to run it.