Skip to content
Ludo Vest

Provably fair Ludo dice Fair by construction

Every Ludo Vest match commits to its entire dice sequence before the first roll and hands you the proof at the end. If we ever changed a roll, anyone could catch it.

A Ludo Vest eight player match on a round board with eight coloured home bases and eight seated players, with the dice tray, undo, emoji and chat buttons, under the banner 8 Player Ludo.

Are Ludo Vest's dice rigged?

No, and you can check it yourself. Before the first roll the server publishes SHA-256 of a secret 32-byte seed; every roll is HMAC-SHA256(seed, "matchId:n") reduced to a face from 1 to 6 by rejection sampling, and the seed is revealed when the match ends. If any roll you were dealt does not recompute from the revealed seed, or the seed does not hash to the commitment, the match was tampered with.

Read next:Is Ludo rigged? The full walkthroughHow Ludo games compare on dice fairness

Last updated

The scheme

Commit, roll, reveal, verify

This is the whole thing. It rests on one property of a hash function: easy to compute forwards, infeasible to reverse.

  1. 1

    Before the first roll

    The server draws a secret 32-byte seed and publishes only its SHA-256 hash: the commitment. You have it before anyone touches the board.

  2. 2

    Every roll is derived

    Roll number n is HMAC-SHA256(seed, "matchId:n"), reduced to a face from 1 to 6. Your device never generates a number, and the server cannot pick one.

  3. 3

    At the end, the seed

    The match-end payload carries the seed and the full roll list. A live match never leaks its seed through the API. Only a finished one does.

  4. 4

    You recompute it

    Hash the seed and compare it to the commitment, then recompute each roll. If either disagrees, the sequence was not what we published.

Fair by construction

Don't trust us. Check.

Every match commits to its entire dice sequence before the first roll and hands you the proof at the end. If we ever changed a roll, anyone could catch it.

The whole scheme

commitment = SHA-256(seed)            // published before roll 1
roll(n)    = HMAC-SHA256(seed, id:n)  // reduced to 1-6, no bias
seed                                   // revealed when the match ends

Reduction discards any byte of 252 or above before taking it modulo 6, so all six faces are exactly equally likely rather than nearly so.

  • Committed, seeded dice

    Before roll one the server draws a 32-byte seed and publishes its SHA-256. Every roll is HMAC-SHA256(seed, match:n), reduced to a face from 1 to 6 with no bias. The seed is handed to you when the match ends.

  • Server authoritative

    Clients send intent: roll, move, play a card. The server produces every outcome and rejects anything not on the list of legal actions. A modified client gets an error, never a state change.

  • Tables too

    Jackaroo decks and Dominos tiles are shuffled by the same committed scheme, every position exactly equally likely, the seed revealed at the end.

  • Money never reaches the board

    Hearts, Gems, Gold and prestige are inputs to rewards and cosmetics, never to randomness. An undo re-draws a value that was already fixed.

Structural, not promised

Four things that are true by construction

These are not policies we intend to keep. They are properties of how the code is shaped.

  • The generator has two inputs

    The match seed and the roll index. Not your level, your league, your spending, your prestige tier or your club. There is no code path from a wallet to a die.

  • The server decides everything

    Clients send intent: roll, move, play a card. The server produces every outcome, so a modified client asking for an illegal move gets an error rather than a state change.

  • Actions are sequenced

    Every broadcast carries a sequence number, and a move is checked against it. A stale, duplicated or replayed action is rejected and the real board is re-sent.

  • A live match never leaks its seed

    The match endpoint returns the seed, the rolls and the event log only once the match is no longer active. Before that, nobody (including us) can read ahead.

Verification

How to check a match

A finished match returns its seed, its full roll list and its event log. You need three things from it, and about fifteen lines of code.

  1. Step 1: Hash the revealed seed and compare it with the commitment you were shown before the first roll. If they differ, stop. Nothing else matters.

  2. Step 2: Recompute each roll from the seed and the match id, and compare with what you were dealt. Both halves have to pass.

  3. Step 3: There is also a public verification endpoint that does the same thing. It is useful for debugging your own implementation, but it is our server checking our claim. The version that protects you is the one you run.

Straight answers

The questions people actually ask

Does spending change my dice?
It cannot. The only inputs to the generator are the match seed and the roll index. Level, league, spending, win rate and club membership are inputs to rewards, never to randomness. There is no code path from your wallet to the dice.
Why do losing streaks still happen?
Because real randomness is streaky. Fair dice feel less fair than rigged ones precisely because nothing smooths them out. Over 60,000 rolls the six faces come out exactly equiprobable, which is asserted in the test suite, but 60,000 rolls is not a Tuesday evening.
Why does the "modulo 6" detail matter?
Taking a random byte modulo 6 makes faces 1 to 4 about 0.4% likelier than 5 and 6, because 256 is not divisible by 6. We discard every byte of 252 or above before reducing, so all six faces are exactly equally likely. It is a small bias, and it is exactly the kind of thing nobody would ever notice.
Can an undo improve my luck?
No, and this is the clearest test of the whole design. The sequence is fixed before the first roll, so undoing re-draws the next value from a list that was already determined. An undo buys you a different move, not a different die.
What stops someone cheating with a modified client?
Clients send intent (roll, move) and the server produces every outcome. An illegal move gets an error, never a state change. Moves also carry the sequence number of the board they were made against, so a stale or replayed action is rejected outright.
Does anyone at the table get better dice?
No. Every seat at a table plays from the one sequence committed before the first roll, in turn order, whoever is sitting there. A player's level, league, Vest & Crown tier, purchases and stake are not inputs to the dice: the generator reads only the match seed and the roll index.