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 ledgerThe 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
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
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
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
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.
Or paste the three values yourself
The revealed seed matches the fingerprint
Dice reproduced
No proof under that number. Games are numbered in the order they finish, and only a finished game has a published seed.
The proof could not be fetched. That is a connection problem, not a failed check — nothing has been disproved.
That is not a game number, or the pasted values are not two 64-character hashes and a client seed.
Working…
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.
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.