Provably Fair

Every classic-game outcome is derived deterministically from three values: a server seed, a client seed, and a nonce. The server seed is committed (hashed) before play and revealed afterward, so a player can recompute any past result and confirm it wasn't altered.

Seed Pairs

Each player holds one seed pair per game, with a lifecycle:

upcoming  ──rotate──►  active  ──rotate──►  retired
(hash only)         (in use, nonce++)   (server seed revealed)
State What's visible Notes
Active serverHash, clientSeed, nonce The pair in use. nonce increments by one each round.
Upcoming serverHash only Pre-committed. Its hash lets the player verify the next seed before they switch to it.
Retired full serverSeed revealed A rotated-out pair. The revealed seed is what makes past rounds verifiable.

Pairs are created automatically on first use, so the client doesn't have to bootstrap them.

Seed Endpoints

All are POST with the session token.

Endpoint Purpose Returns
/seed/current The active pair + the upcoming hash. serverHash, clientSeed, nonce, upcomingServerHash
/seed/upcoming Just the upcoming server hash. serverHash
/seed/rotate Retire the active pair and promote the upcoming one with a player-chosen client seed. previousServerSeed, new active { serverHash, clientSeed, nonce }, upcomingServerHash
/seed/reveal Reveal the server seed of a retired pair by id. serverSeed, serverHash, clientSeed, nonce

Rotating Seeds

To let a player set their own client seed and reveal the old server seed:

POST /seed/rotate
Authorization: Bearer <token>
{ "clientSeed": "my-chosen-seed" }
{
  "previousServerSeed": "a1b2…",
  "active": { "serverHash": "c3d4…", "clientSeed": "my-chosen-seed", "nonce": 0 },
  "upcomingServerHash": "e5f6…"
}

Rotation is blocked while a round is open (active_round_exists). Finish or cash out the active round first. The new active pair starts at nonce: 0.

Verifying a Result

Once a pair is retired and its server seed revealed, the player can recompute any round it produced via POST /game/verify. The RGS re-runs the same game math with the supplied seeds and returns the raw outcome — no wager, no balance change.

POST /game/verify
Authorization: Bearer <token>
{
  "seed": { "serverSeed": "a1b2…", "clientSeed": "my-chosen-seed", "nonce": 42 },
  "message": { /* game-specific VerifyRequest */ }
}
{
  "message": { "roll": 7421 }
}

The message request and response are game-specific — each game page documents its verify contract. Some verify requests need parameters that shape the result space (e.g. Plinko needs rows + risk; Keno/Wheel/Towers need difficulty), while card games return the resolved deck so the player can replay the deal. Re-running with the same seed triple always yields the same outcome — that's the proof.

How the Outcome Is Derived

The game engine seeds a PRNG with serverSeed, clientSeed, and nonce to produce a deterministic stream of values, which it maps to the game outcome (a roll, a drop path, a shuffled deck). Identical inputs → identical output, every time. Because the server hash is published before the round (commit) and the seed revealed after (reveal), the operator cannot change the seed to alter a result without breaking the hash.