Security · Cryptography · Audit-ready
Cryptographic Verifiable Random Selection for Giveaways
Commit-reveal with SHA-256, deterministic CSPRNG, public verifier endpoint. Every winner ships with a mathematical proof anyone can re-run from a terminal.
Sample verified result
Winner
@maria.rivas
Drawn 2026-06-11 14:23:45 UTC · 8,412 entrants
SHA-256 commitment
a3f1c9b2d4e8f0a7c61b9d2e4f5a8c0b3d7e2f4a6c8b1d3f5e7a9c2b4d6e8f0a1
Seed (revealed)
7c9d…b3f4
Verifier
/api/verify/a3f1…
Why SHA-256 makes a draw verifiable
SHA-256 is a collision-resistant hash function specified in NIST FIPS 180-4. In a giveaway context, the host computes a hash of the canonical input — the comment list, draw timestamp, winner count, exclusion list, and a nonce — and publishes it before the draw runs. After the draw, the host reveals every field. Anyone can recompute the hash; if a single byte changed, the hash would diverge and the draw is provably invalid.
This converts trust from social ("I promise the screenshot is real") to mathematical ("here is the preimage, recompute it yourself"). The host loses the ability to silently substitute a winner.
What "fair draw" means in cryptographic terms
A fair draw satisfies three properties at once:
- Uniformity — every eligible entrant has identical probability 1/N of being selected. The CSPRNG must produce shuffled positions statistically indistinguishable from a true-random permutation.
- Determinism — the same input always produces the same winner, so verifiers reach the same conclusion the host did.
- Tamper-evidence — any modification to the input invalidates the published commitment, leaving an auditable trail.
Math.random(), spreadsheet RAND(), or "I closed my eyes and scrolled" satisfy zero of the three. Commit-reveal with SHA-256 + HMAC-DRBG satisfies all three.
Commit-reveal flow, end to end
1. Commit (before draw)
commitment = SHA256(canonical_json({
post_url, comments, timestamp,
winner_count, exclusions, nonce
}))
publish(commitment) // post on social, save to /commit/<id>2. Reveal (after draw)
seed = SHA256(canonical_json(input)) drbg = HMAC_DRBG(seed) // NIST SP 800-90A shuffled = fisher_yates(input.comments, drbg) winners = filter_exclusions(shuffled)[:N] publish(input, seed, winners)
3. Verify (anyone, anywhere)
GET /api/verify/<commitment>
→ 200 {
verified: true,
canonical_input,
seed,
winners
}The public verifier endpoint
Rafflecopter exposes /api/verify/{commitment} as a stateless re-derivation endpoint. It does not return a stored winner; it recomputes the draw from the revealed input and returns the result. If the recomputed winner differs from the published winner, the endpoint returns verified: false and flags the draw publicly.
Because the verifier is stateless and the algorithm is open (VGP v1.0), you do not need to trust Rafflecopter to trust the result. You can self-host the verifier from the reference implementation and reach the same conclusion.
Frequently asked questions
What is cryptographic verifiable random selection in a giveaway context?
It is a winner-selection protocol where the host publishes a SHA-256 commitment of the input set before the draw, then reveals the seed and entrants list after. Any third party can re-run the deterministic CSPRNG with the revealed seed and arrive at the exact same winner, mathematically proving the host did not handpick the result.
How does commit-reveal prevent the host from cheating?
Before the draw, the host publishes SHA-256(canonical_input + nonce). Because SHA-256 is collision-resistant, the host cannot later substitute a different input that yields the same hash. After the draw, the host reveals the input and nonce. Verifiers recompute the hash, recompute the draw, and confirm both match the original commitment.
Why use a deterministic CSPRNG instead of Math.random()?
Math.random() is non-deterministic and platform-dependent — two verifiers running the same code on different machines would get different winners, defeating verifiability. A deterministic CSPRNG like HMAC-DRBG with SHA-256 (NIST SP 800-90A) is seedable, reproducible, and statistically indistinguishable from true random, so the same seed always produces the same shuffle on any device.
What does the public verifier endpoint actually return?
GET /api/verify/{hash} returns the canonical input JSON, the revealed seed, the computed winners, and a boolean verified flag. The endpoint is stateless — it does not trust any stored result; it re-derives everything from the published commitment, so even Rafflecopter cannot tamper with past draws without breaking SHA-256.
Is this the same as a blockchain-based giveaway?
No, and that is intentional. Blockchain randomness (e.g., Chainlink VRF) adds gas fees, on-chain dependencies, and a single point of failure for the audience to verify. Commit-reveal with SHA-256 achieves equivalent tamper-evidence using only standard cryptographic primitives that any developer can audit in a few lines of Python or JavaScript.
Run a draw that ships with its own proof
Paste a post URL. We collect entrants, publish a SHA-256 commitment, run the draw under HMAC-DRBG, and hand you a verifier URL you can post next to the winner's @username. No accounts, no trust assumptions, no "take our word for it."