"Provably fair" gets used as a marketing badge. It's actually a specific technique, and it proves one specific thing. This article explains how it works, using the real code from our stake-game add-ons, shows how a player can check a round step by step, and is clear about what it doesn't prove.

Games where players stake money for a chance of a payout are gambling in most countries, whatever the fairness method. Running them needs the right licence where you and your players are, and that's your responsibility. Nothing here is legal advice: check with a lawyer. Our game add-ons are marked adults-only, which raises your site's minimum sign-up age to 18.

The idea: commit, then reveal

The problem provably fair solves is simple. When a game server picks a random outcome, how does the player know it wasn't changed after they placed their bet? The answer is a commitment:

  1. The server picks a secret random value (the server seed) and shows the player its SHA-256 hash, a fingerprint, before the round is played.
  2. The outcome is computed from the server seed and a value from the player's side (the client seed).
  3. When the round ends, the server reveals the server seed.
  4. The player hashes the revealed seed and checks it matches the fingerprint they saw earlier. Then they recompute the outcome themselves.

Because a different seed would produce a different fingerprint, the server can't swap the seed after showing the fingerprint without being caught.

How our games derive each result

Our stake-game add-ons for PrizeX are Tower, Crossing, Flip and Train. They're add-ons, sold separately; none is included in an edition. All four use the same building block. Here it is from Tower's engine:

// Uniform [0, 1) from the HMAC of client_seed:index: 52 bits over 2^52.
function tower_draw(string $serverSeed, string $clientSeed, string $index): float
{
    $h = hash_hmac('sha256', $clientSeed . ':' . $index, $serverSeed);
    return hexdec(substr($h, 0, 13)) / 4503599627370496.0;
}

Before any draw, the player's seed is joined with the round number (the nonce, which counts that player's rounds of that game), so $clientSeed above is really yourSeed:roundNumber. In words: take HMAC-SHA256 of the text yourSeed:roundNumber:index, keyed with the server seed. Take the first 13 hex characters, which is 52 bits, and divide by 252 to get a number between 0 and 1. Each game uses a different index for each random event. Tower uses floor:slot, Crossing the lane number, Flip the toss number, and Train the car number.

In Tower, every floor's traps are placed when the round starts, before the player's first pick, using a Fisher–Yates shuffle driven by those draws:

for ($f = 1; $f <= $floors; $f++) {
    $order = range(0, $tiles - 1);
    for ($i = $tiles - 1; $i > 0; $i--) {
        $j = (int) floor(tower_draw($serverSeed, $clientSeed, $f . ':' . $i) * ($i + 1));
        [$order[$i], $order[$j]] = [$order[$j], $order[$i]];
    }
    $traps[$f] = array_slice($order, 0, $trapCount); // first slots are the traps
}

For each player and game, the server makes the seed for the next round in advance (32 random bytes) and shows its fingerprint before that round starts. When a round starts, it takes that committed seed and immediately commits a fresh one for the round after. Your seed is made in your browser when you open the game. Once you set your own, it's saved there, and you can change it at any time in the fairness panel. Changing it never changes the server seed, because the server's seed was already fixed and shown before your seed arrived.

How a player verifies a round

Each game page has a "How every round is decided" panel. It shows the next round's fingerprint, a box for your seed, and, for the current round, its fingerprint, round number and, once it ends, the secret seed. To check a Tower round:

  1. Before you start, note the next round's fingerprint. Change your seed first if you like.
  2. Start the round. Its fingerprint must be the one you noted. The start request carries the fingerprint you were shown, and the server refuses to start a round with any other seed. If the committed seed had changed, you're shown the new fingerprint and asked to start again.
  3. After the round, copy the secret seed, your seed and the round number.
  4. Check the fingerprint: the SHA-256 of the secret seed, hashed as text, must equal the fingerprint you noted. If it doesn't, the seed was changed.
  5. Rebuild the tower: run the shuffle above with the secret seed, yourSeed:roundNumber in place of the client seed, the difficulty's tile and trap counts, and its number of floors. The traps you get must match where the game put them.

Any language with HMAC-SHA256 can do this. The PHP above works once you fill in the seeds, the round number and the difficulty's numbers. We don't host a verifier, on purpose: checking with your own tool is the point.

What provably fair does not prove

This is the part most "provably fair" pages leave out.

If you're running these games

Common questions

What does provably fair mean?

The game server commits to a secret seed by showing its hash before you play, then reveals the seed afterwards. You can check the hash matches and recompute the result yourself, which proves the result wasn't changed after the round started.

How do I verify a provably fair game?

Note the next round's fingerprint (hash) before playing. After the round, hash the revealed server seed and check it matches. Then recompute the outcome from the server seed, your seed and the round number, using the game's published formula, such as HMAC-SHA256 of "yourSeed:roundNumber:index".

Does provably fair mean I can't lose?

No. It proves the outcome wasn't changed after the round began. It says nothing about the odds, and every game has a house edge set by its RTP.

Are lottery draws provably fair too?

They can be checked, with a different scheme. With Verified draws on (Plugins › Lottery; on for a new store), each draw is committed to a secret seed when it's made, and only the seed's fingerprint is shown. Its result comes from that seed, the list of tickets that could win and public drand randomness published after the draw closes, and anyone can recalculate it on the draw's Verify page. With Verified draws off, draws use a secure random generator at the draw time and can't be checked this way.

PrizeX — the platform our game add-ons run on Auctions, draws, mystery boxes, a shop and rewards in one self-hosted platform. The stake-game add-ons are sold separately.