About
Design notes & threat model.
Cryptographic libraries earn trust slowly. The right way to start is to make the surface area small, the dependency graph empty, and the code legible top-to-bottom. Everything below is a choice made to keep those three properties true.
Why pure Python
It is tempting to lean on cryptography, coincurve, or a native secp256k1
binding for performance. We deliberately did not. Three reasons:
- Supply chain. Every transitive dependency is a future incident waiting to happen. For a library whose entire job is "this commitment is what we say it is", a zero-dependency posture is itself a security property — there is nothing for an attacker to typosquat, nothing to compromise on PyPI mid-release, and nothing whose pinning behaviour we have to reason about. See why zero dependencies is a security feature for the long-form argument.
- Auditability. The whole library is small enough to print on a few sheets of paper.
secp256k1 in
commit_reveal/zkp.pyis the textbook affine implementation; the Schnorr proof is the textbook Fiat-Shamir transformation. There is no clever optimisation a reviewer has to follow. - Portability. No wheels to compile, no native ABI to track. The library installs
on any CPython that runs
pip install, and on every platform CPython supports.
The cost is throughput. The secp256k1 implementation is not constant-time at the scalar-multiply level and is not competitive with a native binding for sustained signing workloads. That is fine: commit-reveal is a protocol primitive, not a TLS terminator. If you need to verify a million proofs per second, this is not the library — and you probably do not need ZKPs at that rate.
What the threat model covers
The SECURITY.md
file is the source of truth. The summary:
In scope.
- Timing attacks on reveal. Commitment comparison goes through
hmac.compare_digest, not==. This is the bare minimum, and it is in place. - Weak randomness. Every non-deterministic step — salt generation, the ZKP
nonce k — goes through
secrets, which on every supported platform is the OS CSPRNG.randomis not imported anywhere in the runtime path. - Insecure hash selection. The constructor rejects
md5andsha1withSecurityError. Anything outside the eight-algorithm allowlist raisesValidationError. - Plaintext-at-rest leakage. The secure CLI never writes the committed value to
disk; values are entered through
getpasswith no echo; stored commitment files are created with mode0600. - Directory traversal in the CLI. Commitment names are sanitised before being used as filenames.
Out of scope.
- Hardware attacks. If your adversary has physical access to the device that holds the salt, this library cannot help. Use a hardware-isolated keystore.
- Kernel-level compromise. A compromised OS can read process memory; no userspace library can defend against that.
- Long-term key management. The library does not manage keys. It manages
commitments. If your protocol re-uses a ZKP public key across commitments, that is your
protocol's responsibility (and we recommend against it —
SECURITY.mdcalls this out explicitly). - Network transport. The library produces bytes. How you ship them between parties — TLS, gossip, a transaction — is your problem.
What it deliberately is not
commit-reveal is not a general-purpose ZKP library. There are no Pedersen commitments,
no KZG commitments, no Merkle commitments, no BLS signatures, no pairing-friendly curves, no SNARK
or STARK frontend, no circuit compiler. The README does not advertise those, the source does not
implement them, and we will not invent them on the marketing site.
What is implemented is exactly two primitives: a commitment as H(value || salt) with eight selectable hash algorithms, and a non-interactive Schnorr proof of knowledge on secp256k1 via the Fiat-Shamir heuristic. If you need more, the comparison page covers when to reach for a different library.
Audit posture
The project has not been through a formal external audit. We do not claim it has been. What we do have:
- mypy strict on the whole package.
- Property-based tests using Hypothesis — the kind that find edge cases humans miss.
- Bandit scanned, clean as of the latest release.
- 90%+ branch coverage on the core paths, including the ZKP round-trip.
- An explicit
SECURITY.mdwith a stated threat model and a coordinated-disclosure address.
That is the floor, not the ceiling. If you intend to use this in a setting where a compromise would cost real money, please read the source first, then file an issue or contact us before relying on it.
Maintenance & provenance
The project is maintained by Dipankar Sarkar under the cryptuon
organisation. The package is published to PyPI
from the cryptuon/commit-reveal repository
under MIT, with releases tagged in git and CI green on every merge to main. If you
find a vulnerability, see SECURITY.md for the disclosure address.