Skip to content
DiceSim

Tools and scripting

How provably fair dice works

This guide explains how provably fair dice works, one step at a time. The casino commits to a secret server seed before you bet, you supply a client seed, and each roll is computed from the two seeds and a bet counter called the nonce. Once the server seed is revealed, anyone can repeat the calculation and check that every roll matches.

The worked example below is computed by the same engine code that produces rolls in the DiceSim simulator, so the numbers on this page are real outputs.

The three inputs

Every roll in a provably fair dice game is a function of three values.

  • The server seed is a random string the casino generates and keeps secret while you bet. Only its hash is shown to you.
  • The client seed is a string on your side. Most sites fill one in for you and let you change it. It is mixed into every roll.
  • The nonce counts the bets made with the current pair of seeds. It starts at 0 and goes up by one per bet, so no two bets hash the same message.

The calculation itself is public. Given the same three inputs, any computer produces the same roll, which is what makes the result checkable later.

Step 1: the casino commits to a server seed

Before the first bet, the casino shows the hash of its server seed. DiceSim uses SHA-256 for this commitment and displays it as 64 hexadecimal characters. A hash is one-way: it does not reveal the seed, but any change to the seed, even one character, produces a completely different hash.

The hash works like a sealed envelope. The casino cannot swap the server seed later without the published hash giving it away, and you cannot work out the seed in advance to predict rolls.

Your client seed adds the other half. The casino fixed its seed before it knew yours, so it had no way to search for a server seed that produces losing rolls for your particular client seed.

Step 2: HMAC turns the seeds and nonce into bytes

For each bet the engine computes an HMAC, a keyed hash. The key is the server seed. The message is the client seed, the nonce and a cursor joined with colons:

textDiceSim default
hash = HMAC-SHA512(key = serverSeed, message = clientSeed + ":" + nonce + ":" + cursor)

The cursor is 0 in the normal one-roll-per-bet mode. HMAC-SHA512 returns 64 bytes that look random but are fully determined by the inputs. Without the key, nobody can predict them, and with the key, anybody can reproduce them.

Step 3: four bytes become a roll

Only the first four bytes of the hash are used for a dice roll. Call them b0 to b3, each a whole number from 0 to 255. They are combined into a fraction between 0 and 1:

textBytes to roll
float = b0/256 + b1/256^2 + b2/256^3 + b3/256^4      (0 <= float < 1)
roll  = floor(float * 10001) / 100                   (0.00 to 100.00)

Multiplying by 10,001 and rounding down gives a whole number from 0 to 10,000. Dividing by 100 gives a roll with two decimals between 0.00 and 100.00. The roll then settles the bet: betting under wins when roll < chance, and betting over wins when roll > 100 - chance.

Worked example

Take the server seed dicesim-example-server-seed-0001 and the client seed my-client-seed. Before any bet, the casino would publish the SHA-256 hash of the server seed:

textCommitment (SHA-256 of the server seed)
bff65fde3f96a6989d593d9fd4e6515d3cd313b2adeaf2773f56e290d4acefe3

For the first bet the nonce is 0, so the HMAC message is my-client-seed:0:0. The HMAC-SHA512 digest starts with b9a461ca. Those four bytes are 185, 164, 97 and 202 in decimal, so:

textNonce 0
float = 185/256 + 164/65536 + 97/16777216 + 202/4294967296 = 0.7251645201
roll  = floor(0.7251645201 * 10001) / 100 = 7252 / 100 = 72.52

The next bets use nonces 1, 2, 3 and 4 with the same seeds. Each gets its own digest and its own roll:

Provably fair worked example: HMAC-SHA512 rolls for nonces 0 to 4
NonceHMAC messageFirst 4 bytes (hex)Bytes (decimal)Roll
0my-client-seed:0:0b9a461ca185, 164, 97, 20272.52
1my-client-seed:1:04dfe3b8377, 254, 59, 13130.46
2my-client-seed:2:02b9bd5dc43, 155, 213, 22017.03
3my-client-seed:3:070464499112, 70, 68, 15343.86
4my-client-seed:4:0a06093a4160, 96, 147, 16462.65

Change a single character of either seed and every roll in the table changes. That is why the casino cannot alter one bet without the revealed seed failing to reproduce it.

Step 4: reveal and verify

While a seed pair is in use, you only hold the hash of the server seed. To check your bets, rotate the seed pair. The casino then reveals the old server seed and starts a new one with a new hash. Verification has two parts:

  1. Hash the revealed server seed with SHA-256 (or the hash function your casino documents) and compare it with the hash you were shown before betting. They must be identical.
  2. For each bet, recompute the HMAC with the revealed server seed, your client seed and that bet’s nonce, turn the first four bytes into a roll, and compare it with the roll in your bet history.

The provably fair verifier does both steps in the browser. The Lua reference has a short TypeScript implementation of the roll function if you prefer to run the check yourself.

DiceSim's HMAC-SHA512 scheme and the HMAC-SHA256 scheme

DiceSim’s engine uses HMAC-SHA512 by default. It also implements HMAC-SHA256 for checking histories from sites that use it. The two schemes share everything except the hash function:

  • The same message, clientSeed:nonce:cursor, with the server seed as the key.
  • The same conversion of the first four bytes into a roll from 0.00 to 100.00.
  • A different digest: SHA-512 returns 64 bytes and SHA-256 returns 32. Only the first four are used per roll, but the bytes themselves differ, so the same seeds give different rolls.
Same seeds and nonces, rolled with HMAC-SHA512 and HMAC-SHA256
NonceHMAC-SHA512 rollHMAC-SHA256 roll
072.5244.96
130.4669.47
217.0395.67
343.8650.95
462.6520.97

Many casinos use HMAC-SHA256. Sites can also differ in the message format, the order of fields, how bytes become a roll and how the server seed hash is computed, so check your casino’s own documentation before comparing results.

The engine also has a throughput mode for long simulations that draws eight rolls from one digest, using bytes 0 to 3, then 4 to 7, and so on up to 28 to 31, and advances the cursor every eight rolls. It needs fewer hashes but its rolls do not line up with a one-roll-per-nonce bet history.

What provably fair proves, and what it does not

What it proves

A successful check shows that each roll was fixed by the committed server seed, your client seed and the nonce before the bet was placed, and that it was not changed afterwards. Because the casino committed before seeing your client seed, it also could not choose a seed that loses for you in particular.

What it does not prove

  • It does not change the house edge. A verified 49.5% bet still pays 2.00x at a 1% edge, and its expected value is still a loss of 1% of the stake.
  • It does not check the payout. Confirm that the multiplier you were paid matches the advertised formula for your win chance.
  • It does not help predict future rolls. The next roll depends on a server seed you have not seen.
  • It says nothing about bets you never verify. A seed pair that is never rotated is never revealed.

Seeds in DiceSim scripts

Every DiceSim simulation runs on a seed pair, and Lua scripts can read the nonce of the next bet. Calling resetseed() rotates to a fresh random server seed and sets the nonce back to 0, which is how a script imitates seed rotation at a casino.

Because rolls depend only on the seeds, the same script with the same seeds produces exactly the same run. The server uses this to verify runs before they rank on the leaderboard. It is also why math.random should be avoided in scripts: it is not derived from the seeds, so a run that uses it cannot be replayed. The dice bot tutorial shows a reproducible alternative.

FAQ

Does provably fair mean I can win at dice?

No. It shows that a roll was fixed before you bet and was not changed afterwards. The payout still includes the house edge, so the expected result of every bet is a small loss.

Why do I need to change my client seed?

The casino commits to the server seed before it knows your client seed. Setting your own client seed means the casino could not have chosen a server seed that gives particular results for your seed pair.

Can I verify a bet before the server seed is revealed?

No. While the seed pair is active you only have the hash of the server seed. Rotate the seed pair to reveal it, then recompute each roll and check that the revealed seed hashes to the value you were shown.

Does DiceSim use the same algorithm as my casino?

DiceSim uses HMAC-SHA512 by default and also supports HMAC-SHA256 with the same message format and byte conversion. Many casinos use HMAC-SHA256, but details differ between sites, so check your casino's own documentation before comparing results.

What is the nonce?

A counter of bets made with the current seed pair. It starts at 0 and goes up by one per bet, so each bet hashes a different message and gets a different roll.