Skip to main content

Provably fair vs RNG, verifying game fairness

Provably fair vs RNG, explained by the team that runs the games: server seed, client seed, nonce, and the exact steps to verify any game result yourself.

A provably fair game hands you the arithmetic that produced your result, so you can rerun it yourself and get the same answer. A plain RNG game asks you to trust that the operator ran a fair random number generator and did not look at your bet first. That is the whole difference, and it is not a marketing distinction: on Lightning Faucet every casino result is one HMAC-SHA256 line you can recompute on your own machine in about thirty seconds, with a seed the server committed to before you placed the bet.

If you just want to check a result you already have, here is the short version. Every result is derived from combined_hash = HMAC_SHA256(key = server_seed, message = client_seed + ":" + nonce). Before you play, the site shows you SHA256(server_seed), the commitment. You set the client seed. The nonce counts up by one per bet. When you rotate your seed, the old server seed is revealed, you confirm its SHA256 still matches the commitment you were shown, and then you can recompute every single result it produced. This article walks through the exact derivation for each game, including the two details people most often get backwards.

Provably fair vs RNG: what actually differs

What a conventional RNG asks of you

A conventional casino RNG is a black box. The operator says a certified generator produced the number. You get a result and no way to reconstruct it. Even when the certification is genuine, the guarantee it provides is statistical and retrospective: an auditor sampled outputs at some point and found them well distributed. It says nothing about whether the specific spin you just made was drawn before or after the server saw your bet size. You cannot check your own hand. You can only check the paperwork about someone else's sample.

What provably fair replaces it with

Provably fair replaces institutional trust with a commitment scheme. The server picks its randomness first, publishes a one-way hash of it, and only then takes your bet. Because SHA256 is one way, the published hash reveals nothing usable about the seed. Because the hash is published first, the server cannot swap the seed later: any substituted seed would hash to a different value than the one you were already shown. Add a client seed that you choose and the server cannot predict, and neither side can steer the outcome. The result becomes a deterministic function of inputs that were both locked before play.

The important shift is who does the checking. Certification means an auditor checked a sample. Provably fair means you can check your own bet, individually, without asking anyone's permission and without trusting the answer we give you.

The three inputs behind every result

Server seed and its commitment

When you first play, the server generates 32 bytes from a cryptographically secure source and stores them as a 64 character hexadecimal string. It immediately computes SHA256(server_seed) and publishes that hash to your account as the commitment. The seed itself stays secret while it is in use, because revealing it early would let you compute future results before betting. The hash is visible from the moment it exists.

Client seed

You choose the client seed. Any string of one character or more works, and it takes effect on your next bet. This is the input that makes the scheme two sided. If only the server contributed entropy, a dishonest operator could grind through candidate seeds looking for one that produces a favourable sequence. Because your seed is mixed in and the server committed to its own seed before you picked yours, grinding is not available. If you never set one, your account uses the string default, and it is worth changing it precisely so the pairing is unmistakably yours.

Nonce

The nonce is a counter that starts at zero and advances by exactly one per bet. It is what makes each result under the same seed pair different. On our side the nonce increment and the hash computation happen inside a single database transaction with a row lock, so two rapid bets can never be handed the same nonce even if they arrive milliseconds apart. From your side that matters for a practical reason: the nonces in a seed period are contiguous, so when you reveal a seed you can walk 0, 1, 2, 3 and reproduce the entire run with no gaps to explain.

The one line of math

Every casino result on Lightning Faucet starts here:

combined_hash = HMAC_SHA256(key = server_seed, message = client_seed + ":" + nonce)

Two details trip people up when they try to reproduce this.

First, the server seed is the key and client_seed:nonce is the message, not the other way round. Swapping them produces a perfectly valid looking 64 character hash that will never match anything.

Second, the server seed is used as the 64 character hex string, not as the 32 raw bytes it encodes. Do not hex-decode it before using it as the HMAC key.

With those two right, the shell version is a one liner:

printf '%s' "myclientseed:0" | openssl dgst -sha256 -hmac "<revealed_server_seed>"

Or in Python:

import hmac, hashlib
combined = hmac.new(server_seed.encode(), f"{client_seed}:{nonce}".encode(),
                    hashlib.sha256).hexdigest()

From the combined hash, a single base roll is derived by taking the first 8 hex characters as a 32 bit integer and reducing it:

roll = int(combined[:8], 16) % 100000     # 0 to 99999

Each game then maps that roll, or the full hash, into its own result space.

From hash to result, game by game

Dice

Dice reduces the base roll once more into its own range and stamps a per-game hash for display:

dice_roll = roll % 10000                                  # 0 to 9999
game_hash = sha256(f"{combined}:dice:{dice_roll}")

Your target and direction never enter the hash at all. They are only compared against dice_roll after it exists, which is the property you want: the number is fixed by the seeds and the nonce alone, and the bet is settled against it afterwards. That is why you can verify a dice roll without telling us what you bet, and why you can verify it even if you change your mind about the target between rolls. You can try a roll and then verify it at Lightning dice.

Roulette

Roulette maps the same base roll onto a single zero wheel:

number = roll % 37                                        # 0 to 36

The order of the two reductions matters, and it is the thing people most often get wrong when they verify a spin by hand. Reduce to the base roll first, then onto the wheel. 100000 is not a multiple of 37, so skipping the base roll and taking int(combined[:8], 16) % 37 straight off the hash prefix lands on a different pocket than the wheel did on roughly thirty-six spins out of thirty-seven.

Colour is then a lookup, not a random draw: 0 is green, and the standard red set {1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36} is red, everything else black. So verifying a spin at Lightning roulette is three lines: compute the combined hash, reduce it to the base roll, then take % 37. If the pocket you were paid on does not match, you have a receipt showing it.

Slots and the free spin

Slots takes the base roll, walks the published prize table in order accumulating each tier's probability scaled to the 0 to 99999 range, and returns the first tier whose cumulative bound the roll falls under. The reels are then rendered from a different slice of the same hash, bytes 16 through 24, mapped so the symbols always match the tier that the roll already selected. The symbols are cosmetic in the strict sense: they are fully determined by the hash, but the roll decided the outcome before any symbol was chosen. The free spin claim runs through exactly the same seed chain and consumes a nonce like any other bet, so a free claim is as verifiable as a wagered one.

Scratchcards

Scratchcards derive a roll value from the combined hash, compare it against the card's win threshold, and build the symbol grid deterministically from the same hash. Tournament scratchcards use a different win threshold from the standard daily card, so when you verify one you have to tell the verifier which kind it was. That is a real gotcha we hit ourselves: verify a tournament card against the standard threshold and it will look wrong when it is not.

Blackjack

Blackjack cannot use a single small roll, because it needs a whole shuffled shoe. A six deck shoe is 312 cards, so the combined hash is stretched into a hash chain: h0 = combined_hash, h1 = SHA256(h0), h2 = SHA256(h1), and so on, until there are enough bytes for 4 bytes per card. Those bytes drive a Fisher-Yates shuffle, consuming 4 bytes per swap to keep modulo bias negligible across the shoe. The deal order then falls out of the shuffled array: first card to you, second to the dealer, third to you, fourth face down to the dealer. Verifying a hand at Lightning blackjack means reproducing the shuffle and checking that the cards you were dealt are the first four out of it, in that order. The shoe was fixed before your first decision, so no hit of yours changed what came next.

Verifying a result yourself, step by step

Step 1: set your own client seed

Open the fairness panel in your account and set a client seed to something you pick. This is the step most players skip, and it is the one that turns the guarantee from theoretical into personal. It takes effect on your next bet.

Step 2: note the commitment, then play

Record the server_seed_hash shown for your current seed period, and note the nonce. Then play. Each bet advances the nonce by one.

Step 3: reveal and rotate

Ask for a seed rotation. Rotating does two things at once: it reveals the server seed you have been playing against, and it immediately generates and commits a fresh one for the next period. The revealed seed is filed in your seed history with the client seed it was paired with, the first and last nonce it covered, and how many bets it produced. Rotation is the only way a server seed is ever revealed, and it is deliberately one way: once revealed, that seed is retired and can never be used again.

Step 4: check the commitment, then recompute

First run SHA256(revealed_server_seed) and confirm it equals the commitment hash you recorded in step 2. This is the step that proves nothing was swapped. Then, for each nonce in the period, compute the combined hash and apply the game mapping above. Every result should reproduce exactly.

You can also post the seed triple to our verification endpoint, which reproduces the derivation for slots, dice, roulette, scratchcard, and blackjack and returns the intermediate values, including the combined hash and the base roll. Comparing your own computation against it is a useful way to find the mistake when the two disagree, and in practice the disagreement is almost always the key/message order or the hex decoding described above.

Poker is provably fair, with the seed on the table

Poker breaks the per-player seed model, because a poker hand deals one shared deck to several people at once. A per-player seed cannot shuffle a deck that several players share. So each table owns its own committed server seed instead. The table publishes server_seed_hash before any hand is dealt, players can set the table client seed, and the nonce advances once per hand rather than once per bet. The deck for a hand is the same hash-chain Fisher-Yates shuffle used for the blackjack shoe, driven by the same combined hash formula.

Verification works the same way: reveal and rotate the table seed, confirm the commitment, then re-derive every hand's deck from the contiguous nonces. Because the table's seed hash is committed before the client seed for any future hand can change, the shuffle cannot be ground for a favourable board. The tables at Lightning poker are sat denominated and the seeds are per table, so a verification you run covers every seat at that table, not just yours.

What provably fair does not prove

Being straight about the limits is part of the point, and operators who oversell this do the concept damage.

Provably fair proves that a specific result was derived from inputs committed in advance and not tampered with afterwards. It proves the shuffle was not stacked once you sat down and that the roll was not regenerated after seeing your bet.

It does not, on its own, prove that the published prize table is the one being applied, and it does not audit payouts. Those are separate claims. What it gives you there is a lever: because the mapping from roll to outcome is deterministic and published, a large enough sample of your own verified results is checkable against the published table by you, not just by an auditor. Verification of the individual result is what makes that statistical check meaningful, because you know each data point is genuine.

It also does not protect a seed you have already revealed. Once a server seed is public, results under it are predictable, which is exactly why rotation retires it in the same transaction that reveals it.

Prediction markets: verifiable, but not by seed

Not everything worth verifying is a hash. Markets at prediction markets do not have a server seed at all, because there is no random draw to commit to. A Bitcoin difficulty adjustment, a mempool fee level, a weather reading, a match result: these resolve against public, externally observable data. The right verification question there is not "recompute the hash" but "check the resolution source". Both models are honest, and they answer different questions. Confusing them is how people end up asking for a seed on a market that never had one, or accepting "our RNG is certified" on a game that could have given them a hash.

Verify one result, then decide

The fastest way to understand any of this is to do it once on a live result rather than read another explainer. Set a client seed you chose. Take a single spin. Rotate. Confirm the SHA256 of the revealed seed matches the commitment you wrote down. Then recompute your own result with one line of Python. After that, the difference between a provably fair game and a certified black box stops being an argument and becomes something you have personally checked.

If you want a result to check, the free spin is the cheapest place to get one, since it runs the identical seed chain without a wager, and everything else across the casino and earn surfaces verifies the same way. Deposits and withdrawals settle over Lightning by scanning a QR, denominated in sats, so the money moves as directly as the fairness check does.

Frequently asked questions

What is the difference between provably fair and a regular RNG?

A regular RNG asks you to trust that the operator drew the number fairly, and gives you no way to check your own bet. Provably fair commits the server randomness in advance by publishing SHA256 of the server seed, mixes in a client seed you choose, and derives the result deterministically, so you can recompute any individual result yourself once the server seed is revealed.

How do I verify a Lightning Faucet game result?

Set your own client seed, note the server seed hash shown for the current seed period, then play. Rotate your seed to reveal the old server seed, confirm SHA256 of the revealed seed matches the hash you recorded, then compute combined_hash = HMAC-SHA256 with the server seed as the key and client_seed:nonce as the message. Apply the game mapping to that hash and it should reproduce your result exactly.

Why does my hash not match when I try to verify?

Almost always one of two mistakes. Either the server seed and the message were swapped, since the server seed is the HMAC key and client_seed:nonce is the message, or the server seed was hex-decoded first. The seed is used as the 64 character hex string exactly as it is shown, not as the 32 raw bytes it encodes.

What is a nonce and why does it matter?

The nonce is a counter that starts at zero and advances by exactly one per bet, so every bet under the same seed pair produces a different hash. It is incremented under a database lock, so rapid bets cannot share a nonce. Because the nonces in a seed period are contiguous, you can walk 0, 1, 2, 3 and reproduce every result from that period with no gaps.

Is Lightning poker provably fair too?

Yes, but the seed lives on the table rather than on each player, because a poker hand deals one shared deck. Each table publishes its server seed hash before any hand is dealt, players can set the table client seed, and the nonce advances once per hand. The deck is a Fisher-Yates shuffle driven by a hash chain from the same combined hash formula, and you verify by revealing and rotating the table seed.

Are prediction markets provably fair in the same way?

No, and they cannot be, because there is no random draw to commit to. Prediction markets resolve against public, externally observable data such as a Bitcoin difficulty adjustment, a mempool fee level or a match result. The verification question there is whether the resolution source is correct, not whether a hash reproduces.

What does provably fair not prove?

It proves a specific result came from inputs committed before play and was not tampered with afterwards. It does not by itself audit that the published prize table is the one being applied, and it does not protect a server seed you have already revealed, which is why rotating a seed retires it permanently in the same step that reveals it.