Skip to content
commit-reveal Source  →

A cryptuon library · v1.0.0 · MIT · Python ≥ 3.8

Cryptographic commit–reveal, with zero-knowledge proofs, in pure Python.

A commitment binds you to a value without revealing it; the reveal proves you bound to that value and no other. It is the smallest, most auditable fairness primitive in crypto — the anti-MEV, sealed-bid, verifiable-AI building block that stops anyone acting on what they cannot yet see. This library implements it with the Python standard library and nothing else — eight hash algorithms, optional Schnorr ZKPs on secp256k1, and a CLI that never writes plaintext to disk.

Quickstart → Source $ pip install commit-reveal

Runtime deps in pyproject.toml

0

Only python = "^3.8". Nothing transitive.

Modules imported from stdlib

hashlib, hmac, secrets

Plus getpass for the secure CLI.

Curve, implemented from scratch

secp256k1

The same curve as Bitcoin. Hand-rolled affine arithmetic.

§ 1

Where it fits in 2026

Any protocol where one party must bind to a choice without yet announcing it. The two-phase structure removes the timing advantage that would otherwise let later participants peek at earlier ones — the shared root cause behind MEV, copy-trading, and last-look games across the agent economy.

  • Anti-MEV & fair ordering

    Order intents are committed during a sealed window, then revealed for matching. Front-runners cannot sandwich or react to orders they have not yet seen — the timing edge that MEV extracts simply is not there.

    — MEV-resistant DEX / intent design

  • Verifiable on-chain AI

    When independent agents must answer without copying each other, each commits to its output first and reveals after the window closes. A Schnorr ZKP proves "this reveal matches my commitment" without re-broadcasting the payload.

    — DFPN-style inference networks

  • Sealed-bid auctions (RWA, NFTs)

    Bidders publish a commitment to their bid; nobody, including the auctioneer, can read it. After the deadline, they reveal. No late bidder could have peeked at earlier bids.

    — docs/use-cases.md: "Auction Systems"

  • RNG & prediction-market resolution

    Parties commit to seeds or outcomes, then reveal; the result is a hash of all reveals — uniform and unmanipulable while one party is honest. Resolvers commit before an outcome is public, removing the last-look edge.

    — commit-reveal RNG / market resolution

Figure 1

Bind now, reveal later

Two moves. Commit binds you to a value without leaking it; reveal proves you bound to that value. The full construction — including the optional Schnorr proof — is on the how-it-works page.

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

§ 2

What is actually implemented

Two primitives, both grounded in the source. There are no Pedersen commitments, no KZG, no Merkle commitments, no pairing-friendly curves — if you need those, see the comparison.

Primitive § 2.1

Hash-based commitments

H(value || salt) where the hash is selectable per scheme instance. Salt is 32 random bytes from secrets.token_bytes by default. Reveal comparison uses hmac.compare_digest for constant-time equality.

sha256sha384sha512sha3_256sha3_384sha3_512blake2bblake2s

Primitive § 2.2

Schnorr zero-knowledge proofs

Non-interactive Schnorr proof of knowledge of the secret derived from (value, salt), made non-interactive via the Fiat-Shamir heuristic with SHA-256 as the challenge hash. Proves "I committed to this value" without revealing it.

secp256k1

§ 3

A worked example

Lifted verbatim from the README. The library refuses to start with an insecure hash — md5 and sha1 raise SecurityError at construction time.

Reveal is timing-safe: comparison goes through hmac.compare_digest, not ==.

Listing 1 — basic commit and reveal

from commit_reveal import CommitRevealScheme

scheme = CommitRevealScheme()

# commit: share the commitment, keep the salt secret
commitment, salt = scheme.commit("my secret value")

# reveal: prove you committed to this value
assert scheme.reveal("my secret value", salt, commitment)      # True
assert not scheme.reveal("wrong value", salt, commitment)      # False

Listing 2 — with a Schnorr ZKP on secp256k1

scheme = CommitRevealScheme(use_zkp=True)

commitment, salt = scheme.commit("secret")
public_key, R_compressed, challenge, response = scheme.create_zkp_proof(
    "secret", salt, commitment
)

# anyone can verify you know the secret — without learning it
assert scheme.verify_zkp_proof(
    commitment, public_key, R_compressed, challenge, response
)

Listing 3 — the secure CLI

# prompts via getpass; never echoes; never writes plaintext to disk
commit-reveal-secure commit my-secret
commit-reveal-secure reveal my-secret
commit-reveal-secure list

Table 1

Supported hash algorithms

Configured per scheme instance through CommitRevealScheme(hash_algorithm=...). Anything not in this table raises ValidationError; md5 and sha1 raise SecurityError.

Identifier Output length Family Notes
sha25632 bytesSHA-2Default; widely audited.
sha38448 bytesSHA-2
sha51264 bytesSHA-2Higher security margin.
sha3_25632 bytesSHA-3 / KeccakNIST post-Merkle–Damgård family.
sha3_38448 bytesSHA-3 / Keccak
sha3_51264 bytesSHA-3 / Keccak
blake2b64 bytesBLAKE2Fast on 64-bit platforms.
blake2s32 bytesBLAKE2Fast on 32-bit / embedded.

§ 4

API at a glance

One class, three pure-function methods for the commit-reveal core, three more for the ZKP path. ZKP methods raise ValueError unless the scheme was constructed with use_zkp=True.

class CommitRevealScheme:
    def __init__(
        self,
        hash_algorithm: str = "sha256",
        use_zkp: bool = False,
        enable_audit: bool = True,
    ): ...

    # commit-reveal core
    def commit(value, salt=None) -> tuple[bytes, bytes]: ...
    def reveal(value, salt, commitment) -> bool: ...
    def verify(value, salt, commitment) -> bool:    # alias of reveal
        ...

    # Schnorr ZKP on secp256k1 (requires use_zkp=True)
    def create_zkp_proof(value, salt, commitment) -> tuple: ...
    def verify_zkp_proof(
        commitment, public_key, R_compressed, challenge, response
    ) -> bool: ...
    def verify_commitment_consistency(
        value, salt, commitment, public_key
    ) -> bool: ...

# raised exceptions:
#   ValidationError  — invalid input
#   SecurityError    — insecure hash (md5, sha1) or unsafe operation

Scope

What it is — and is not

Two primitives, done carefully. Not a general-purpose ZKP toolkit. If you need pairings, BLS, or SNARK circuits, the py_ecc comparison says so plainly.

It is

  • Hash commitments, 8 algorithms
  • Timing-safe reveal
  • Schnorr ZKP on secp256k1
  • A no-plaintext secure CLI
  • Zero runtime dependencies

It is not

  • Pedersen / KZG / Merkle commitments
  • Pairing curves (BLS12-381, BN254)
  • SNARK / STARK circuits
  • BLS / aggregated signatures
  • A constant-time production signer

All features Use cases Threat model FAQ

§ 5

Explore the rest

Every page of this site, one click away — the reference, the protocol shapes it fits, the written notes, and honest comparisons with the alternatives.

¶ Colophon

Read the source. It is short, typed, and audit-friendly.

Eight files under commit_reveal/, the longest of which is the secp256k1 implementation. mypy strict. Hypothesis property tests. Black formatted. Bandit clean.