Rust · RFC 5114 Schnorr group · no crypto crates · no curves
Veilproof proves you know a secret, or that a hidden number satisfies a property, without ever revealing it. SHA-256, the Fiat-Shamir transform, and every Sigma protocol are written from scratch. No black box. Below is the real math, running live in your browser, animated so you can watch each move land.
Pick a secret x. The page computes y = gx mod p and proves knowledge of x with a Schnorr proof, without ever putting x itself in the proof. Watch the commitment, challenge, and response cross the channel between prover and verifier.
prover and verifier, connected only by what is sent below
Pick a secret value from 0 to 255. The page commits to it with Pedersen commitments, decomposes it into 8 bits, proves every bit is honestly 0 or 1 with an OR-proof, and ties the bits back to the commitment. The value itself never leaves its sealed commitment.
each cell is one OR-proof: honestly 0 or 1, never which
C ?= ∏i Ci2^i
Chaum-Pedersen. From a single secret x the page publishes y1 = g^x and y2 = h^x on two different bases, then proves the same x sits behind both, without revealing x. This is the check behind honest re-encryption and verifiable shuffles.
one secret, two bases, one shared response
A ring of public keys is generated and the page proves knowledge of the secret behind exactly one of them, without revealing which. The proof has the same shape at every position, so it cannot leak the index, not even in this visualization.
every key looks the same to the verifier, including yours
running g^q mod p == 1 self-check and a sample proof verification…
Every step below is code you can read, no dependency does the cryptography for you.
All arithmetic happens mod a 2048-bit RFC 5114 prime, inside the 256-bit prime-order subgroup generated by g, self-checked on load.
The compression function, message schedule, and padding are written from the FIPS 180-4 spec, no crates, matching a known-answer vector.
The verifier's random challenge becomes a SHA-256 hash of the full transcript and statement, reduced mod q, so no interaction is needed.
Knowledge of a discrete log x is proven with a commitment t, a challenge c, and a response z, checked by g^z == t · y^c.
A bit commitment is proven to open to 0 or 1 by genuinely proving the true branch and simulating the false one.
n bit proofs, tied back to one commitment through the Pedersen homomorphism, prove a value lies in [0, 2^n) bit by bit.
Veilproof solves a deliberately smaller problem than a general proving framework, and that is the point. The comparison is about comprehensibility and footprint, not capability.
Builds succinct proofs over arbitrary circuits on elliptic curves and pairings. Powerful and necessarily large, spanning many crates. Best for production succinct proofs over general circuits.
A circuit compiler plus a JavaScript toolchain, elliptic curves and pairings, usually with a trusted setup. Best for production circuits and dapps.
A fixed menu of Sigma protocols in a Schnorr group over a finite field, no curves, no trusted setup, three dependencies. About 2,800 lines with tests, readable in one sitting. Best for learning how zero-knowledge proofs actually work.
Teaching-grade, not audited, not reviewed outside this project. It makes convenience choices a real deployment should not inherit blindly, most notably the derivation of the second Pedersen generator h. Do not use it to protect anything that matters.
veilproof prove-dlog, verify-dlog, and demo, plus a plain Rust library with typed errors, never a panic.
The demo above is the same p, q, g, h, the same hand-written SHA-256, and the same Fiat-Shamir logic, ported to JavaScript with native BigInt.
cargo test checks completeness, soundness against wrong witnesses and tampered bytes, determinism, and that the witness never appears in a serialized proof.
Exposes the verifiers (verify_dlog, verify_dleq, verify_range, verify_ring) as tools, so an agent can produce a proof and then mathematically verify its own output against the Rust binary.
# prove knowledge of a secret veilproof prove-dlog --secret 424242 # verify it veilproof verify-dlog --statement <hex> --proof <hex> # run the full range-proof demo veilproof demo
$ veilproof demo veilproof demo: proving a committed value lies in a range, without revealing it secret value: withheld (that is the point) public claim: the committed value fits in 16 bits, i.e. [0, 2^16) commitment C = g^m * h^r mod p: 12ef947a73b4b599585e1597ffc625e3a10aa0385aafa1bdd077fd52381bd2f4... blinding factor r: withheld (not printed, this is what makes C hiding) range proof: 16 bit commitments, each with an OR-proof of being 0 or 1 bit 0 commitment: 73909ca5ac24f7a8... bit 1 commitment: 09d0367bf83bc8a8... ... 14 more ... bit 15 commitment: 2f2f53e91c799158... verifier recomputes the weighted product of bit commitments, checks it equals C, and checks every bit OR-proof: ACCEPT $ veilproof verify-dlog --statement <hex> --proof <hex> accept