Så fungerar provably fair i Roulette
Så här spelar du Roulette på Cloudbet, och så kontrollerar du att varje snurr är provably fair.
Så spelar du Roulette
Roulette är ett klassiskt casinospel där du satsar på var en snurrande boll landar på ett numrerat hjul. Du placerar en eller flera insatser på nummertabellen, sedan snurrar hjulet och bollen släpps. När den lägger sig i en numrerad ficka är det den vinnande siffran — alla insatser som täcker den betalas ut, och allt annat förlorar.
Att placera insatser
Du kan satsa på utfallet på flera olika sätt, och du är fri att kombinera flera insatser i samma omgång. Inside bets (på specifika nummer) betalar mer men är svårare att träffa; outside bets (på bredare grupper) betalar mindre men träffar oftare:
- Straight-up / enskilt nummer (35:1): satsa på ett exakt nummer (0–36, eller 00 i amerikansk roulette).
- Split (17:1): två intilliggande nummer.
- Street (11:1): tre nummer i rad.
- Corner (8:1): fyra nummer som möts i ett hörn.
- First Four / Top Line (8:1 europeisk / 6:1 amerikansk): täcker 0 (och 00 i amerikansk), 1, 2, 3.
- Six Line (5:1): två intilliggande rader, sex nummer.
- Column (2:1): en av tre vertikala kolumner.
- Dozens (2:1): 1–12, 13–24, eller 25–36.
- Rött/Svart, Udda/Jämnt, Högt/Lågt (1:1 vardera).
Europeisk vs. amerikansk roulette
Cloudbet erbjuder båda varianterna. Europeisk roulette har en enda nolla (37 möjliga utfall, 97,30 % RTP); amerikansk roulette lägger till en andra "00"-ficka (38 möjliga utfall, 97 % RTP), vilket ökar husets fördel något. Vilken variant du spelar bör visas tydligt innan du placerar en insats. Båda inkluderar ett Autoplay-läge för kontinuerliga snurr med förinställda marker-värden och antal snurr.
När dina insatser är placerade och omgången avgörs betalas alla vinnande insatser ut automatiskt enligt sina odds, och bordet återställs inför nästa omgång.
Den här sidan handlar om hur Roulette omvandlar en provably fair-talföljd till ett vinnande nummer. För hur den talföljden i första hand genereras — server seed, client seed, nonce, hashning, SHAKE256 — se Cloudbets förklaring av provably fair.
Så blir slumptal ett Roulette-resultat
För Roulette måste provably fair-systemet bevisa att det vinnande numret väljs genom verifierbar slumpmässighet, inte väljs i efterhand.
Processen är enkel: i europeisk roulette hämtas ett heltal mellan 0 och 36 från slumptalsföljden — det är det vinnande numret. I amerikansk roulette kan det hämtade talet variera mellan 0 och 37, där "37" motsvarar den dubbla nollan, "00"; resultaten 0 till 36 tas som de är.
Så väljs det vinnande numret
De slumpmässiga bytesen som genereras av SHAKE256 (se vår sida om provably fair) delas upp i 4-byte osignerade heltal, från 0 till 2³²−1. Roulettes vinnande nummer väljs bland 37 möjliga utfall (europeisk) eller 38 (amerikansk) — så i stegen nedan är P antingen 37 eller 38.
För att rättvist välja ett vinnande nummer bland dessa P utfall tillämpar vi rejection sampling (se Så fungerar provably fair), och tar sedan det resulterande talet modulo P — resten blir det vinnande numret (för amerikansk roulette visas "37" som "00").

När det väl är genererat sparas och döljs det vinnande numret serversidan — det kan inte ändras eller manipuleras oupptäckt efter att omgången har startat. När du har placerat din insats jämförs den mot detta i förväg fastställda nummer för att avgöra omgången.
Verifiera dina egna Roulette-resultat
Vi har skrivit ett litet Node.js-program som motsvarar Cloudbets Roulette-implementation (både europeisk och amerikansk). Ange din Server Seed, Client Seed och Nonce för att återskapa ditt resultat. (Påminnelse: för att avslöja en omgångs Server Seed på Cloudbet måste du redan ha roterat till ett nytt seed-par.)
Beroenden:
npm install js-sha3
Koden:
// If you are running this yourself, then you can input your own data here
// You can then compare:
// 1) Cloudbet's provided Commitment to the Commitment outputted here. This proves that the Server Seed was not altered during gameplay.
// 2) Cloudbet's provided game outcome to the game outcome outputted here. This proves that your game's outcome was determined solely by the pre-game seeds and was not altered afterwards.
const Version = Object.freeze({ AMERICAN: "american", EUROPEAN: "european" }); // Here the possible versions are listed
let myServerSeed = 'your_server_seed'; // ✍️YOUR_INPUT✍️: Enter your (unhashed) Server Seed here
let myClientSeed = 'your_client_seed'; // ✍️YOUR_INPUT✍️: Enter your Client Seed here
let myNonce = 1; // ✍️YOUR_INPUT✍️: Enter your Nonce here
let myRouletteVersion = Version.AMERICAN; // ✍️YOUR_INPUT✍️: Enter your roulette version (either Version.AMERICAN or Version.EUROPEAN)
const usingCustomData = false; // Change this to true if you are using your own data
// Load libraries
const crypto = require('crypto');
const { sha3_256, shake256 } = require('js-sha3');
// Step 1: Generate a Server Seed and Commitment
// And generate a Client Seed - either by player input or by the player's browser
function generateServerSeed() {
let seed = crypto.randomBytes(32).toString('hex');
if (usingCustomData) { seed = myServerSeed; }
const commitment = sha3_256(seed);
return { 'serverSeed': seed, 'commitment': commitment };
}
function getClientSeed() {
let seed = crypto.randomBytes(32).toString('hex');
if (usingCustomData) { seed = myClientSeed; }
return seed;
}
// Step 2: Create a Round Signature with SHA3 using a Server Seed, Client Seed and Nonce
function createRoundSignature(serverSeed, clientSeed, nonce) {
return sha3_256(`${serverSeed}:${clientSeed}:${nonce}`);
}
// Step 3: Create a SHAKE256 stream generator from a Round Signature.
// To simplify this example program, this function doesn't create a stream, but instead a sequence of custom length.
function* createRandomNumberSequence(numbersToGenerate, roundSignature) {
const numOfBytes = 4 * numbersToGenerate; // 4 bytes (32 bits) per random number we generate
const byteStream = shake256.create(8 * numOfBytes); // shake takes bits as input
byteStream.update(roundSignature); // Use the Round Signature to seed the generator
const buf = Buffer.from(byteStream.digest()); // The Buffer class lets us package every 4 bytes into one 32-bit integer
for (let i = 0; i < numbersToGenerate; i++) {
yield buf.readUInt32BE(i * 4); // Read buf in 4-byte steps
}
throw new Error("No more numbers in the random number sequence! Fix: make 'numbersToGenerate' larger.");
}
// Step 4: Draw from the random number sequence to calculate the game result
function getGameResult(rouletteVersion, rng) {
let numOfOutcomes = 0;
if (rouletteVersion === Version.EUROPEAN) {
numOfOutcomes = 37;
} else if (rouletteVersion === Version.AMERICAN) {
numOfOutcomes = 38;
}
let result = String(sample(numOfOutcomes, rng))
// Convert the result '37' to '00'
if (result === '37') {
result = '00';
}
return result;
}
// Sample a number from P number of outcomes using Rejection Sampling
function sample(P, rng) {
const maxAcceptable = Math.floor(0x100000000 / P) * P;
// Rejection sampling
let rand;
do {
rand = rng.next().value;
} while (rand >= maxAcceptable);
// Modulo operation
const sampled_number = rand % P;
return sampled_number;
}
// Example usage
(function main() {
let nonce = 1;
let rouletteVersion = Version.AMERICAN;
if (usingCustomData) { nonce = myNonce; rouletteVersion = myRouletteVersion; }
const { serverSeed, commitment } = generateServerSeed();
const clientSeed = getClientSeed();
const roundSignature = createRoundSignature(serverSeed, clientSeed, nonce);
const numbersToGenerate = 1 * 2; // We need 1 random number, but there is an improbable case we'll need two
const rng = createRandomNumberSequence(numbersToGenerate, roundSignature);
const value = getGameResult(rouletteVersion, rng);
console.log('📝 Commitment (shown before the game):', commitment);
console.log('🔒 Server Seed (revealed after the game):', serverSeed);
console.log('🎲 Client Seed:', clientSeed);
console.log('🔢 Nonce:', nonce);
console.log(`🎯 Winning Number (in the ${rouletteVersion} version):`, value);
})();

