Skip to content
Ludo Vest

Fair play

Don't trust us. Check.

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.

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 1–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.

  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.

// What the server does, and what you can repeat.
commitment = SHA-256(seed)                       // published at match start
roll(n)    = HMAC-SHA256(seed, matchId + ":" + n) // reduced to 1-6
seed                                              // revealed at match end

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.

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 win rate or your club. There is no code path from a wallet to a die.

  • The server decides everything

    Clients send intent — roll, move. 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. 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. 2

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

  3. 3

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

A Ludo Vest victory screen listing final placements and noting that all rolls were generated server-side with roll history available in the match details.

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–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.
Do bots get better dice?
Bots draw from the same sequence as everyone else. They exist only so that humans can finish a match when someone drops, and a ranked queue never seats one — a ranked result against a bot would mean nothing.