Skip to Content
Provably FairCrash, Slide & Double

Crash, Slide & Double

Crash, Slide and Double are played in rounds shared by every player. One result decides everyone’s bet, so the result cannot depend on any single player’s seed pair. Instead, each round gets its randomness from two sources the casino cannot control:

  • a server seed that is committed (as a hash) before bets open, and
  • a drand beacon, a public random value published by an independent network after bets close.

The casino fixes its seed before the beacon exists, and nobody (the casino included) knows the beacon while bets are open. Neither side can steer the result.

How a round is built

  1. Commit. When a round opens, a fresh random server seed S is drawn (64 hex characters) and its hash sha256(S) is published. This is the Server Seed (Hashed) of the round, the same kind of commitment as in the other games.
  2. Fix the beacon. While bets are open, the round announces which drand round R will decide it, and bets close one second before R is published. Nobody can place a bet knowing randomness(R).
  3. Draw. When R is published, the randomness is verified against the drand public key and the result is computed from it (below).
  4. Reveal. The server seed S is published with the result, so anyone can check the commitment and recompute the outcome.

The drand beacon

drand  is a public randomness beacon run by the League of Entropy. The rounds use its quicknet chain:

Chain hash52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971
Periodone round every 3 seconds
GenesisUnix time 1692803367
Schemebls-unchained-g1-rfc9380 (BLS signatures, unchained)
Public key83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a

Round R is published at Unix time 1692803367 + (R − 1) × 3. Each round’s signature is a BLS threshold signature over the round number, and its randomness is sha256(signature). Nobody can produce the signature before the network does, and anybody can check it against the public key above.

You can read any round from a public relay:

https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971/public/10000000
{ "round": 10000000, "randomness": "5e6508f1a1f689accfc8b027dec7eb999b20b4f66582b2621231cabf9601bf57", "signature": "a187c9f5800521e986b5658924696682071ce7ae965486e8fd08bc2c4758bdbb9ed9ecb7beee392a38214e321ecd434f" }

The server checks the BLS signature of the beacon before it uses it, and any relay (api.drand.sh, api2.drand.sh, api3.drand.sh, drand.cloudflare.com) gives the same values. To check the signature yourself, use a drand client library with the chain hash above.

From beacon to result

The result uses the same generator as the other games, with these inputs:

InputValue in a shared round
Server seedThe round’s committed seed S
Client seedThe beacon’s randomness (64 hex characters)
NonceThe drand round number R
Cursor0, one float
float = first float of HMAC_SHA256(key = S, message = `${randomness}:${R}:0`)

That float is then mapped by the game:

import Decimal from "decimal.js"; // Crash and Slide: the same formula, with the round's house edge. function crashPoint(float, houseEdgePercent) { const edge = Math.min(99, Math.max(0, houseEdgePercent)); const point = (1e8 / (float * 1e8)) * ((100 - edge) / 100); return Math.max(new Decimal(point).times(100).floor().div(100).toNumber(), 1); } // Double: 15 fixed segments, 0 is green, 1 to 7 are red, 8 to 14 are black. function doubleSegment(float) { const segment = Math.floor(float * 15); return { segment, color: segment < 1 ? "green" : segment < 8 ? "red" : "black" }; }
  • Crash and Slide return a multiplier of at least 1.00×, with a default house edge of 1% (Crash) and 2% (Slide). The edge used by a round is recorded with the round, and the round modal shows it.
  • Double has a fixed wheel of 15 segments: 1 green (pays 14×), 7 red and 7 black (pay 2×).

If the beacon does not arrive

If a round’s beacon is not available 30 seconds after its publication time, the round has no result. It is cancelled and every bet is refunded. The server seed of a cancelled round is published as well, since it decided nothing.

Verify a round

In the game

Open a finished round from the game’s history. Its modal has a Provably Fair section with the round’s Server Seed (Hashed), Server Seed (Revealed), Client Seed (drand randomness) and Nonce (drand round), and your browser runs three checks:

  • Server seed matches its hash: sha256(serverSeed) equals the hash published before bets opened.
  • drand randomness matches its signature: sha256(signature) equals the beacon’s randomness.
  • Recomputed result: the result recalculated from the revealed seed, the randomness and the round number equals the one the game showed.

The server seed is revealed when the round ends; before that the modal says so. A finished round remains available afterwards, not only while it is in the recent history.

By hand

You need the round’s revealed server seed, its hash, and the drand round number. Everything else (randomness, signature) comes from drand.

import { createHash } from "node:crypto"; import { generateFloats, hashServerSeed } from "./fairness.mjs"; // from the round modal const { serverSeed, hashedServerSeed, drandRound } = round; // from api.drand.sh/<chain hash>/public/<drandRound> const { randomness, signature } = beacon; const committed = hashServerSeed(serverSeed) === hashedServerSeed; const beaconLinked = createHash("sha256").update(Buffer.from(signature, "hex")).digest("hex") === randomness; const [float] = generateFloats({ serverSeed, clientSeed: randomness, nonce: drandRound, cursor: 0, count: 1, }); console.log(committed, beaconLinked, crashPoint(float, 1));

fairness.mjs is the reference code.

Worked example

This example pairs a real beacon, drand round 10000000 (published on 4 August 2024 at 20:29:24 UTC), with a made-up server seed. Real round seeds are random.

Server seed S3f1c9a52d7e84b60a1c5e2f9087b4d63c0a9e1f25b7d8c4e6a30912f5d7b8ce1
Hash sha256(S)4ef210e8bede0521e7e318c889dcd226dd2203d1e3e1a1838ac8c0a3722d4459
Beacon randomness5e6508f1a1f689accfc8b027dec7eb999b20b4f66582b2621231cabf9601bf57
Nonce R10000000
HMAC message5e6508f1a1f689accfc8b027dec7eb999b20b4f66582b2621231cabf9601bf57:10000000:0
First float0.37639040639624
  • Crash at a 1% house edge: (1 / 0.37639…) × 0.99 = 2.630…, floored to 2.63×.
  • Slide at a 2% house edge: (1 / 0.37639…) × 0.98 = 2.603…, floored to 2.60×.
  • Double: floor(0.37639… × 15) = 5, a red segment: red.

EC-VRF mode

When an operator uses EC-VRF mode, the round has no secret seed to reveal. The engine’s VRF key takes the place of the server seed (its public key is the commitment), the client seed becomes the beacon randomness joined to the round’s group (${randomness}:${group}, so that two groups landing on the same drand round cannot share a float), and the round carries a VRF proof and output.

Last updated on