Provably fair systems in gambling and games: how to verify randomness yourself

12 минут чтения

To verify a provably fair system yourself, you re-compute the game result from published inputs (server seed hash, your client seed, and a nonce) using the casino's stated algorithm, then confirm it matches the recorded outcome. This provably fair verification works only when the site discloses the exact hashing/HMAC rules and lets you reveal the server seed after play.

Core Verification Steps at a Glance

  • Capture the round inputs: server seed hash (pre-game), client seed, nonce, and game-specific parameters.
  • After the round, reveal the server seed and verify its hash equals the pre-game server seed hash.
  • Recompute the result locally using the published algorithm (often HMAC-SHA256) and compare to the shown outcome.
  • Verify the nonce increments predictably and is tied to the correct bet/round order.
  • Check encoding details (hex/base64/UTF-8) to avoid false mismatches.
  • Repeat across multiple rounds to confirm the process is consistent and not selectively applied.

Understanding Provable Fairness: Concepts and Cryptography

Prep item (what you need) Tool / access Expected output
Game's provably fair description (algorithm) Casino help page / fairness page Exact steps to derive a roll/number from seeds

Provably fair gambling is best when you want a user-verifiable audit trail without trusting the operator's RNG claims. It's suitable for hash/HMAC-based games (dice, limbo, wheel, some card shuffles) where every outcome can be recomputed. Skip it when the operator won't reveal the algorithm, when outcomes are influenced by real-time multiplayer state, or when only "RNG certified" is offered without reproducible inputs.

# Quick self-check: do you have enough data to verify?
# You should be able to answer YES to all:
# 1) Was a server seed hash shown before the bet?
# 2) Can you reveal the server seed after the bet?
# 3) Are client seed + nonce visible?

Expected result: You can identify the four core inputs (serverSeedHash, serverSeed, clientSeed, nonce) for at least one finished round.

  • Troubleshooting: You only see "fairness certified" text, but no algorithm or seeds-there is nothing to recompute.
  • Troubleshooting: The site shows a "server seed" before play (not a hash). That allows post-hoc changes and defeats the commitment step.
  • Troubleshooting: The round history lacks nonce or client seed. Ask support; otherwise verification will be guesswork.

How Seed Exchange and Hashing Ensure Integrity

Prep item (what you need) Tool / access Expected output
Server seed hash (pre-commitment) Bet UI / fairness panel / round history A hash string (commonly hex) shown before the outcome
Server seed reveal (post-round) Reveal button / fairness page / API export Plain server seed matching the earlier hash
Client seed + nonce Account fairness settings / bet history Your chosen seed and a per-bet counter

A provably fair casino typically uses a commit-reveal flow: the house commits to a hidden server seed by publishing its hash before you bet, then later reveals the seed so you can confirm the commitment. The final random value is derived from both parties' inputs (server seed + client seed) plus a nonce so each bet is unique, forming a provably fair random number generator pipeline you can reproduce.

What you see What it means What you verify
Server seed hash (before play) Commitment: server seed is fixed Hash(revealed server seed) == published hash
Client seed (you control) You add unpredictability from your side Outcome changes if client seed changes (for future bets)
Nonce (per bet) Separates consecutive outcomes Nonce increments and maps to the correct bet order
Algorithm statement Defines how to turn bytes into a roll Your recomputation matches the displayed result
# Verify the commitment (example with SHA-256 in Node.js)
node -e "const crypto=require('crypto'); const serverSeed='REVEALED_SERVER_SEED'; console.log(crypto.createHash('sha256').update(serverSeed,'utf8').digest('hex'))"

Expected result: The printed hex digest matches the server seed hash you saw before placing the bet.

  • Troubleshooting: Hash mismatch often comes from encoding. Confirm whether the seed is treated as UTF-8 text, hex bytes, or base64.
  • Troubleshooting: You copied extra whitespace/newlines. Use exact seed characters as displayed/exported.
  • Troubleshooting: The operator rotates seeds; ensure you're revealing the seed for the same session/round.

Step-by-Step Client-Side Verification Workflow

Prep item (what you need) Tool / access Expected output
One completed round with full fairness data Bet history export or screenshot + copyable fields A single record containing seeds, nonce, outcome
  • Open the bet/round details and copy: serverSeedHash (pre), serverSeed (revealed), clientSeed, nonce, and the displayed result.
  • Copy the published algorithm text (including HMAC key/message order, encoding, and how the roll is computed).
  • Pick a verification method: built-in verifier page (as a baseline) plus your own local script (as the real check).
  • Work on one round first; only then batch-verify multiple rounds.
  1. Confirm you have the correct round inputs. Ensure the serverSeedHash was visible before the bet, and the serverSeed is revealed only after. Record the nonce exactly as shown for that specific round.

    • Store values in a plain text note to avoid hidden formatting.
    • If the game includes extra parameters (e.g., "cursor", "roundId", "salt"), record them too.
  2. Verify the commit-reveal hash link. Hash the revealed serverSeed using the stated hash function (commonly SHA-256) and compare to serverSeedHash.

    # Node.js SHA-256 hash (same as earlier, repeated for the specific round)
    node -e "const crypto=require('crypto'); const s=process.argv[1]; console.log(crypto.createHash('sha256').update(s,'utf8').digest('hex'))" "REVEALED_SERVER_SEED"

    Expected result: The output equals the published serverSeedHash for that round.

  3. Recompute the deterministic digest used for the roll. Most implementations use HMAC-SHA256 with serverSeed as the key and a message built from clientSeed and nonce (exact ordering and separators matter).

    # HMAC-SHA256 (template; adjust message format to match the casino spec)
    node -e "const crypto=require('crypto');
    const serverSeed='REVEALED_SERVER_SEED';
    const clientSeed='YOUR_CLIENT_SEED';
    const nonce='NONCE_AS_STRING';
    const message=clientSeed+':'+nonce; // example separator; must match the spec
    const h=crypto.createHmac('sha256', Buffer.from(serverSeed,'utf8')).update(message,'utf8').digest('hex');
    console.log(h);"

    Expected result: You get a stable hex digest; rerunning produces the same value for the same inputs.

  4. Convert the digest into the game's number format. Dice/limbo often take the first N bytes/chunks, convert to an integer, then map to a range (e.g., 0-99.99). Follow the operator's published conversion exactly.

    • Confirm whether the algorithm uses big-endian parsing and how many hex chars are consumed.
    • Confirm rounding rules (floor vs round) and decimal precision.
  5. Compare your computed result to the displayed outcome. Match must be exact under the same rounding rules. If the site displays fewer decimals, compare at the correct precision.

    • If the game shows a "roll" and a "multiplier", compute both only if both are defined by the spec.
  6. Repeat with the next bet to validate nonce progression. Verify that the next round uses the next nonce (or the documented increment scheme) and that the recomputed outcome matches again.
  • Troubleshooting: Your HMAC matches but the final roll doesn't-conversion/range mapping (bytes consumed, modulo bias handling, or rounding) is likely different.
  • Troubleshooting: You used nonce as a number but the spec treats it as a string (or vice versa). Use the exact representation stated.
  • Troubleshooting: The message format is wrong (missing separators, wrong order, extra salt). Copy the spec literally.

Building a Local Verifier: Tools, Libraries and Patterns

Prep item (what you need) Tool / access Expected output
A repeatable runtime environment Node.js or Python 3 on your machine Same results every time, independent of the casino UI
Round data export CSV/JSON export, API, or copied history Batch verification across many rounds

For how to verify provably fair outcomes reliably, treat the casino's built-in verifier as a reference, not as proof. A local verifier is just a deterministic function: (serverSeed, clientSeed, nonce, parameters) → outcome. Keep it small, versioned, and strict about parsing/encoding so you can reproduce results months later.

Approach Best for Trade-offs
Node.js script (crypto) Fast iteration; easy HMAC/SHA Must be careful with Buffer/encoding
Python script (hashlib/hmac) Readable; good for batch checks Same encoding pitfalls; watch bytes vs str
Offline verifier notebook Explaining steps to others More setup; ensure reproducibility
# Python HMAC-SHA256 template
python3 - <<'PY'
import hmac, hashlib
server_seed = "REVEALED_SERVER_SEED"
client_seed = "YOUR_CLIENT_SEED"
nonce = "NONCE_AS_STRING"
message = f"{client_seed}:{nonce}"  # adjust to match spec
digest = hmac.new(server_seed.encode("utf-8"), message.encode("utf-8"), hashlib.sha256).hexdigest()
print(digest)
PY

Expected result: The digest matches your Node.js output for the same inputs (if both follow the same message format and encoding).

  • Troubleshooting: Node and Python digests differ-your message construction or encoding differs; print the exact message bytes in both environments.
  • Troubleshooting: Batch verification fails on some rows-those rows likely have different seed pairs (rotations) or a different nonce base.
  • Troubleshooting: CSV import trims leading zeros-treat nonce and hex strings as text, not numeric fields.

Local verifier checklist before you trust it

  • It verifies the server seed hash against the pre-game commitment.
  • It reproduces at least 3 historical rounds exactly (same displayed precision).
  • It logs the exact message string/bytes used for HMAC (for debugging).
  • It enforces one encoding path (UTF-8 vs hex vs base64) and fails loudly on invalid input.
  • It treats nonce as the spec defines (string vs integer) and preserves formatting.
  • It supports seed rotation (new serverSeedHash/seed pair) without mixing sessions.
  • It can run offline from a saved export (no dependency on the casino's verifier page).
  • It labels the algorithm version (some sites change separators/salts over time).

Interpreting Statistical Tests and Measuring Entropy

Prep item (what you need) Tool / access Expected output
A dataset of verified rounds Exported history + your verifier A file of computed rolls you can analyze
Basic analysis tooling Python + simple scripts Sanity checks (distribution, repeats, correlations)

Statistical checks are a sanity layer after provably fair verification, not a replacement. If you can't deterministically recompute outcomes, passing a histogram test doesn't prove fairness. If you can recompute outcomes, statistics can still reveal implementation bugs (like reused nonces or truncated entropy) that deterministic checks might not highlight.

# Minimal distribution sanity check (example: count last hex nibble)
python3 - <<'PY'
from collections import Counter
import sys
data = [line.strip() for line in sys.stdin if line.strip()]
nibbles = [d[-1] for d in data]  # last hex char of digest
c = Counter(nibbles)
for k in sorted(c):
    print(k, c[k])
PY < digests.txt

Expected result: Counts are not concentrated in a tiny subset; large imbalances suggest a bug in extraction/parsing (or a non-random input pipeline).

Common mistakes when interpreting randomness

  • Using statistics to "prove fairness" without first matching the deterministic algorithm round-by-round.
  • Analyzing displayed outcomes (rounded) instead of the underlying computed values, creating artificial patterns.
  • Mixing rounds across different server seed rotations or algorithm versions, corrupting the dataset.
  • Assuming "no repeats" means random; true random streams can repeat, especially in small ranges.
  • Ignoring modulo bias or rejection sampling details when mapping bytes to a bounded range.
  • Testing too few samples and over-interpreting noise; treat results as diagnostic, not definitive.
  • Failing to control for nonces not starting at 0/1 (some systems use per-game or per-client counters).
  • Comparing outputs from different games (dice vs cards) as if they share the same mapping.
  • Troubleshooting: Histogram looks "wrong" but deterministic checks pass-your analysis likely used rounded UI values or merged incompatible sessions.
  • Troubleshooting: Strong patterns appear-first confirm you aren't slicing the digest incorrectly (wrong bytes/chunks).
  • Troubleshooting: Correlation with time-verify you're not accidentally using timestamps/IDs as part of the message.

Common Attacks, Implementation Pitfalls and Mitigations

Prep item (what you need) Tool / access Expected output
Threat model for your use case Clear notes: what you trust vs verify Decision on whether provably fair is sufficient

Most "breaks" are not cryptographic; they are product and implementation gaps: missing disclosures, ambiguous encodings, nonces that don't map to bets, or selective application (some games provably fair, others not). A correct commit-reveal plus reproducible HMAC flow makes outcome tampering detectable, but it does not guarantee good game rules, honest RTP, or player-protective policies.

Alternatives and when they are a better fit

  1. Third-party RNG certification (labs): Useful when the game is too complex to expose deterministic inputs (live games, multiplayer). It helps, but you can't personally recompute each round.
  2. Open-source game logic + reproducible builds: Best when you can verify the exact code running (or at least the algorithm) and ensure the published verifier matches the deployed version.
  3. On-chain randomness / verifiable randomness beacons: Appropriate for blockchain games where randomness proofs are part of consensus. Not a fit for most traditional provably fair casino products.
  4. Use only games with full transparency: When the operator won't disclose mapping steps, choose games where seeds, nonce, and conversion rules are fully documented, enabling independent verification.
  • Troubleshooting: The site provides a verifier but not the mapping math-treat it as incomplete; you can't independently validate outcomes.
  • Troubleshooting: Nonce resets unexpectedly-look for per-game nonces or seed-rotation boundaries and verify within each segment.
  • Troubleshooting: Different results across devices-ensure you're not relying on the casino UI's locale formatting or rounding display.

Practical Answers for On-the-Spot Verification

What makes a game truly provably fair rather than just "random"?

You can recompute each outcome from published inputs and confirm the server seed commitment via a pre-shown hash and post-round reveal. If you can't reproduce the result locally, it's not provably fair in practice.

Is using the casino's built-in verifier enough?

It's a useful baseline, but not independent proof. Real provably fair verification means you can run the same algorithm yourself and match the outcome without trusting the site's verifier implementation.

How do I know the server seed wasn't changed after I bet?

Hash the revealed server seed and confirm it equals the server seed hash that was displayed before the bet. If those don't match exactly, the commitment failed.

Why does my recomputed value differ by a small amount?

Provably Fair Systems in Gambling and Games: How to Verify Randomness Yourself - иллюстрация

Most mismatches come from conversion and rounding rules (bytes consumed, decimal precision, floor vs round). Ensure your mapping matches the published spec, not the UI formatting.

What is the nonce and why does it matter?

Provably Fair Systems in Gambling and Games: How to Verify Randomness Yourself - иллюстрация

The nonce is a counter (or per-round index) that ensures each bet produces a different outcome even with the same seeds. If the nonce doesn't map cleanly to bet order, verification becomes unreliable.

Can a provably fair random number generator still be used in an unfair game?

Yes. Provable fairness detects outcome tampering, but it doesn't guarantee favorable rules, honest payout tables, or that the game isn't designed to disadvantage players beyond the stated odds.

What should I store for an audit if I'm verifying multiple rounds?

Save serverSeedHash, revealed serverSeed, clientSeed, nonce, game parameters, algorithm version, and the displayed outcome for each round. This lets you rerun verification later even if the site UI changes.

Scroll to Top