Research

Random Number Generation in DiceGem Games

DiceGem team · Published

Abstract. Every shuffle, roll and spin on DiceGem comes from one small, deterministic generator that is seeded from the browser's cryptographic random source. This paper describes the seed, the generator, how its output becomes cards and dice, the size of the remaining bias, and the tests that keep game rules from using any other source of chance.

Summary

1. Seed

When you start a game, the page calls crypto.getRandomValues for 16 random bytes and writes them as a 32-character hexadecimal string. That string is the seed of the session. In daily challenges everyone gets the same seed on purpose, so everyone plays the same deal.

The seed is turned into the generator’s starting state with cyrb128, a hash that mixes the text into four 32-bit words. Different seeds give unrelated starting states.

2. Generator

The generator is sfc32 (Small Fast Chaotic, 32-bit variant) by Chris Doty-Humphrey, the author of the PractRand test suite. Its whole state is four 32-bit unsigned integers, and each step mixes them with additions, shifts and rotations plus a counter. The counter means the generator cannot fall into a short cycle.

We chose it for three reasons:

  1. Small, plain state. Four numbers fit in the game’s saved state as plain JSON. A game can be saved, resumed or replayed without any hidden generator object.
  2. Speed. Card and slot games draw many numbers per round, and bots in our tests play hundreds of games.
  3. Statistical quality. sfc32 is a well-studied generator that holds up in standard statistical test batteries, far beyond what a game needs.

sfc32 is not a cryptographic generator: someone who knew its full state could compute every future draw. The state is part of the game’s internal data and is never included in what the game shows you (see section 5). Credits on DiceGem are virtual and have no cash value, so there is nothing to gain by predicting a draw.

3. From numbers to cards and dice

Each step of sfc32 gives a 32-bit integer k. It becomes:

The second step has a very small bias: 2³² is not a multiple of n, so some results get one more of the 2³² possible inputs than others. The probability of every result stays within 1 / 2³² (about 0.00000002%) of the exact 1 / n. For a 52-card deck the difference is far below anything a player or a test could ever measure.

One limit is worth stating. A deck of 52 cards has 52! orders, about 8.1 × 10⁶⁷. A 128-bit seed can lead to at most 2¹²⁸ different sessions, about 3.4 × 10³⁸. So not every possible order of a shuffled deck can appear as the first deal of a session. This is true of every game that uses a seeded generator. It has no practical effect, because nobody can tell which orders are reachable without knowing the seed.

4. Determinism and replay

A game’s rules are a pure function: they take the current state and a move and return the next state. The generator’s four numbers are part of that state, so the rules never ask the outside world for anything.

This is why an exact figure is possible for every casino-style bet: the odds are a property of the rules alone. The exact return-to-player paper explains how those figures are computed.

5. What the game shows you

The game keeps two things apart: its full internal state, and the observation it shows each player. The observation never contains the generator state, the cards left in the deck or other players’ hidden cards. The same bot tests check every observation for a leaked generator state and fail if one appears.

Our games run in your browser, so the code that deals the cards runs on your device. We do not claim that the internal state is impossible to inspect with developer tools; we make sure it is never displayed, and the virtual credits make inspecting it pointless.

6. Where to check