Provably fair

Dice you do not have to take our word for

Before a game starts we lock in a secret number and publish its fingerprint. When the game ends we publish the number itself. Between those two moments every die is already decided — and afterwards anyone can recompute all of them and check that nothing moved.

Open the ledger

The part a good random number generator cannot fix

Our dice come from the operating system’s cryptographic generator — the same source that protects a bank login, not the shortcut most games use. That settles how random the numbers are. It settles nothing about the question players actually ask.

A die drawn honestly and a die chosen deliberately look identical afterwards. Both are just a number in a log.

So the useful question is not "is your generator good?" It is "can I check?" Everything below exists to make that answer yes, without asking you to believe a word we say.

Sealed before, opened after

Four steps. You can carry out two of them yourself, and those two are the ones that would catch us.

  1. 1

    Seal

    Before the first roll the server draws a secret 32-byte number — the server seed — and publishes its SHA-256 fingerprint to both players. The fingerprint gives nothing away, but the seed is now fixed: any other seed produces a different fingerprint.

    commit0df0916cb0…2904e706
  2. 2

    Mix

    Your app generates a random seed of its own and sends it when you sit down. Both players’ seeds go into every die, so we cannot hunt in advance for a seed whose rolls happen to suit us — at the moment we commit, we do not know what you are about to contribute.

    clientSeeda26460084a0ef89b:d4f28bac6efd1b6e
  3. 3

    Derive

    Each die is read out of an HMAC-SHA256 of the seeds and the roll number. Nothing is stored and nothing is chosen: the same three inputs always produce the same die, and no other input produces it.

    die(n) = (HMAC-SHA256(serverSeed, "clientSeed:n:round")[0] < 252) % 6 + 1
  4. 4

    Open

    When the game ends we publish the server seed. Hash it, compare with the fingerprint you were given before the first roll, then recompute every die. A server that had picked even one roll fails one of those two checks.

    serverSeed5cde3365be…7b6b2bd5

The values above are the real proof of game #148, a finished game anyone can look up. Put that number in the box below and watch it come out right.

Check a game — here, now

Type a game number. The page fetches its proof, then re-hashes the seed and recomputes every die using your browser’s own cryptography.

The arithmetic runs on your device. Nothing you type is sent to us, and no tick on this page is a value we transmitted — if it were, we would be asking you to trust us about whether you can trust us.
Or paste the three values yourself

Why no face is even slightly likelier

A byte is a number from 0 to 255 — 256 possibilities. 256 is not a multiple of six; it is 6 × 42 with 4 left over. Take the remainder of a byte divided by six and four faces quietly get 43 chances out of 256 while the other two get 42. It is a tiny bias, and across a million rolls it is a real edge. So those four values are thrown away.

252 = 6 × 42. Every face gets exactly the same number of bytes, so every face is exactly one in six.

Where the proof stops

Two kinds of dice on this site are not covered by the chain. They are listed here rather than left out, because a fairness claim with a quiet hole in it is worth less than no claim at all.

  • TelegramDice rolled in the bot chatRoll with Telegram’s own dice animation and that number comes from Telegram, not from us; no seed of ours reproduces it. The published proof lists exactly which positions those were, and the ledger marks them with the Telegram symbol instead of a face. For a fully checkable game, roll in the app.
  • PracticeGames against the computerThe offline practice game rolls on your own device, with no seed and no proof. There is no opponent and no stake, so there is nothing to prove and nothing at risk.

Everything else — online 1v1, friend rooms and tournaments, free or staked — runs on the chain described above.

The same check, without this page

Twelve lines and no library. Paste it into any browser console together with the three values from a game and it will tell you exactly what this page tells you — which is the point of publishing the method rather than only the result.

JavaScript
const enc = new TextEncoder();
const hex = (b) => [...new Uint8Array(b)].map((x) => x.toString(16).padStart(2, '0')).join('');

// 1. the seed we revealed must hash to the commitment you were given first
const commitOk = hex(await crypto.subtle.digest('SHA-256', enc.encode(serverSeed))) === commit;

// 2. every die, re-derived from that seed
const key = await crypto.subtle.importKey(
  'raw', enc.encode(serverSeed), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);

async function die(n) {
  for (let round = 0; round < 16; round++) {
    const mac = new Uint8Array(
      await crypto.subtle.sign('HMAC', key, enc.encode(`${clientSeed}:${n}:${round}`)));
    for (const b of mac) if (b < 252) return (b % 6) + 1;
  }
}

Every proof is public at /fair/<id> — no key, no account, no players and no amounts. Just the dice.

Questions people actually ask

I lost four games in a row. Are the dice against me?

They cannot be. Every die of a finished game was fixed before that game began, by a seed committed to in advance, and you can recompute all of them above. Streaks feel targeted and are not: with two dice, an opponent out-rolling you for four games running happens far more often than people expect.

Could the server pick a roll when it matters?

It would have to break one of two checks. Either it publishes a seed that does not hash to the fingerprint it gave you before the game — which anybody can see — or it publishes the real one, in which case the dice that seed produces are the dice you played and there was nothing to pick.

What if my app never sent a seed of its own?

A random one is generated in its place, so the chain is always well formed. That weakens only your own contribution; the commitment, and every check above, still hold.

Does a revealed seed affect my next game?

No. A new seed is drawn and a new fingerprint published for every game, including a rematch. A seed that has been published never decides another roll.

Why are some dice marked with the Telegram symbol?

Those were rolled with Telegram’s dice animation in the bot chat, so they came from Telegram and no seed of ours reproduces them. They are marked rather than hidden, and the number our chain would have produced at that position is deliberately not shown — it is not the die anybody rolled.

Opens Telegram to confirm it is you. We never see your password.

Play as guest

By continuing you agree to the Terms and confirm you are 18 or older.
TermsPrivacyResponsible play