So funktioniert Provably Fair bei Roulette

So spielst du Roulette auf Cloudbet, und so überprüfst du, dass jeder Spin provably fair ist.

So spielst du Roulette

Roulette ist ein klassisches Casinospiel, bei dem du darauf wettest, wo ein rotierender Ball auf einem nummerierten Rad landen wird. Du platzierst eine oder mehrere Wetten auf dem Zahlentisch, dann dreht sich das Rad und der Ball wird eingeworfen. Sobald er in einem nummerierten Fach zur Ruhe kommt, ist das die Gewinnzahl — alle Wetten, die sie abdecken, werden ausgezahlt, alle anderen verlieren.

Wetten platzieren

Du kannst auf verschiedene Arten auf das Ergebnis wetten, und du kannst mehrere Wetten in derselben Runde kombinieren. Innenwetten (auf bestimmte Zahlen) zahlen mehr, sind aber schwerer zu treffen; Außenwetten (auf breitere Gruppen) zahlen weniger, treffen aber häufiger:

  1. Vollzahl / Einzelzahl (35:1): Wette auf eine exakte Zahl (0–36, oder 00 beim amerikanischen Roulette).
  2. Split (17:1): zwei benachbarte Zahlen.
  3. Straße (11:1): drei Zahlen in einer Reihe.
  4. Eckwette (8:1): vier Zahlen, die an einer Ecke zusammentreffen.
  5. Erste Vier / Kopfzeile (8:1 europäisch / 6:1 amerikanisch): deckt 0 (und 00 beim amerikanischen Roulette), 1, 2, 3 ab.
  6. Sechserreihe (5:1): zwei benachbarte Reihen, sechs Zahlen.
  7. Kolonne (2:1): eine von drei vertikalen Kolonnen.
  8. Dutzend (2:1): 1–12, 13–24 oder 25–36.
  9. Rot/Schwarz, Ungerade/Gerade, Hoch/Niedrig (jeweils 1:1).

Europäisches vs. amerikanisches Roulette

Cloudbet bietet beide Versionen an. Europäisches Roulette hat eine einzelne Null (37 mögliche Ergebnisse, 97,30 % RTP); amerikanisches Roulette fügt ein zweites „00"-Fach hinzu (38 mögliche Ergebnisse, 97 % RTP), was den Hausvorteil leicht erhöht. Welche Version du spielst, sollte dir deutlich angezeigt werden, bevor du eine Wette platzierst. Beide beinhalten einen Autoplay-Modus für fortlaufende Spins mit voreingestellten Chipwerten und Spin-Anzahlen.

Sobald deine Wetten platziert sind und die Runde entschieden ist, werden alle Gewinnwetten automatisch entsprechend ihrer Quoten ausgezahlt, und der Tisch wird für die nächste Runde zurückgesetzt.

Diese Seite behandelt, wie Roulette eine provably faire Zufallszahlenfolge in eine Gewinnzahl umwandelt. Wie diese Zufallsfolge überhaupt erst generiert wird — Server-Seed, Client-Seed, Nonce, Hashing, SHAKE256 —, erfährst du unter Cloudbets Erklärung zur Provable Fairness.

Zufallszahlen werden zu einem Roulette-Ergebnis

Bei Roulette muss das Provably-Fair-System beweisen, dass die Gewinnzahl durch verifizierbaren Zufall gewählt wird, nicht im Nachhinein festgelegt.

Der Vorgang ist einfach: Beim europäischen Roulette wird eine ganze Zahl zwischen 0 und 36 aus der Zufallszahlenfolge gezogen — das ist die Gewinnzahl. Beim amerikanischen Roulette kann die gezogene Zahl zwischen 0 und 37 liegen, wobei „37" auf die doppelte Null, „00", abgebildet wird; die Ergebnisse 0 bis 36 werden unverändert übernommen.

So wird die Gewinnzahl ausgewählt

Die von SHAKE256 generierten Zufallsbytes (siehe unsere Provable-Fairness-Seite) werden in vorzeichenlose 4-Byte-Ganzzahlen aufgeteilt, im Bereich von 0 bis 2³²−1. Roulettes Gewinnzahl wird aus 37 möglichen Ergebnissen (europäisch) oder 38 (amerikanisch) gewählt — in den folgenden Schritten ist P also 37 oder 38.

Um fair eine Gewinnzahl aus diesen P Ergebnissen zu wählen, wenden wir Rejection Sampling an (siehe Wie Provably Fair funktioniert) und nehmen dann die resultierende Zahl modulo P — der Rest wird zur Gewinnzahl (beim amerikanischen Roulette wird „37" als „00" angezeigt).

Flussdiagramm, das zeigt, wie Cloudbets nachweisbar faires Roulette-System Rejection Sampling und eine Modulo-Operation nutzt, um die Gewinnzahl zu bestimmen.

Einmal generiert, wird die Gewinnzahl serverseitig gespeichert und verborgen — sie kann nach Rundenbeginn nicht unbemerkt geändert oder verändert werden. Sobald du deine Wette platziert hast, wird sie mit dieser vorab festgelegten Zahl verglichen, um die Runde zu entscheiden.

Verifiziere deine eigenen Roulette-Ergebnisse

Wir haben ein kleines Node.js-Programm geschrieben, das exakt Cloudbets Roulette-Implementierung entspricht (sowohl europäisch als auch amerikanisch). Gib deinen Server-Seed, Client-Seed und Nonce ein, um dein Ergebnis zu reproduzieren. (Erinnerung: Um den Server-Seed einer Runde auf Cloudbet offenzulegen, musst du bereits zu einem neuen Seed-Paar rotiert haben.)

Abhängigkeiten:

npm install js-sha3

Der Code:

// 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);
})();

Weitere Provably-Fair-Spielerklärungen:

  1. Provably Fair Mines
  2. Provably Fair Pump
  3. Provably Fair Plinko
  4. Provably Fair Dice
  5. Provably Fair Dice: Golden Ticket
  6. Provably Fair Limbo
  7. Provably Fair Keno