Wie provably fair bei Keno funktioniert

So spielen Sie Keno bei Cloudbet – und so prüfen Sie, dass jede Ziehung provably fair ist.

Keno spielen

Keno ist ein Zahlenspiel: Sie wählen eine Reihe von Zahlen auf einem Spielfeld aus, dann zieht das Spiel seine eigenen Zahlen. Je mehr Ihrer gewählten Zahlen mit den gezogenen übereinstimmen, desto höher der Gewinn – wie viel höher, hängt davon ab, wie viele Zahlen Sie zu Beginn gewählt haben. Sobald Sie Ihre Auswahl getroffen und Ihren Einsatz gesetzt haben, erfolgt die Ziehung, und alle Treffer werden sofort angezeigt.

Cloudbet Originals Keno

Cloudbets eigenes Originals Keno nutzt ein Spielfeld mit 40 Zahlen: Sie wählen 1 bis 10 Zahlen, und das Spiel zieht 10. Es hat eine RTP von 99 % und akzeptiert Einsätze ab $0.01. Weniger Auswahlen bedeuten höhere Volatilität und höhere Auszahlungen pro Treffer; mehr Auswahlen bedeuten häufigere Gewinne, aber niedrigere Auszahlungen pro Treffer. Auto Bet steht zur Verfügung, um eine Reihe von Runden zu automatisieren.

Die Ziehung bei Keno wird auf dieselbe überprüfbare Weise erzeugt wie bei jedem anderen Cloudbet Original – siehe unseren Überblick zu provably fair dafür, wie Server Seed, Client Seed und Nonce zu einer Round Signature und dann über SHAKE256 zu einer Folge von Zufallszahlen kombiniert werden. Diese Seite behandelt das, was speziell für Keno gilt: wie diese Zufallszahlenfolge zur tatsächlichen Menge gezogener Zahlen wird.

Wie aus Zufallszahlen eine Keno-Ziehung wird

Das Keno-Spielfeld ist von 1 bis 40 nummeriert. Zehn dieser 40 Zahlen müssen nacheinander gezogen werden, ohne dass eine Zahl wiederholt wird.

Diagramm, das Cloudbets provably-fair Keno-Spielfeld zeigt — 40 nummerierte Felder, jedes mit eigenem Index für eine faire Zahlenauswahl.

Wir nennen die Anzahl der noch nicht gezogenen Zahlen P. P beginnt bei 40 und sinkt bei jeder Ziehung um 1.

Durchgerechnetes Beispiel des provably-fair Ziehungsalgorithmus von Keno: Die erste Zahl wird zufällig aus allen 40 Positionen auf dem Spielfeld ausgewählt.

Für jede der 10 Ziehungen wird eine zufällige 4-Byte-Zahl (32-Bit) aus der SHAKE256-Ausgabe gezogen, mit einem Bereich von 0 bis 4.294.967.295. Um unter den P verbleibenden Zahlen fair auszuwählen, wenden wir Rejection Sampling an (siehe unsere Anleitung zu Rejection Sampling), und nehmen dann das Ergebnis modulo P, um die Position der nächsten gezogenen Zahl zu ermitteln. Müssen noch weitere Zahlen gezogen werden, wird die gewählte Zahl aus dem Pool entfernt, P sinkt um 1, und der Vorgang wiederholt sich.

3. Durchgerechnetes Beispiel, das zeigt, wie der provably-fair Algorithmus von Keno die nächste Zahl aus den 39 verbleibenden Positionen zieht, nachdem die erste Ziehung entfernt wurde.

Dies wird fortgesetzt, bis alle 10 Zahlen gezogen sind.

4. Das finale provably-fair Keno-Spielfeld mit allen 10 zufällig und nachweisbar gezogenen Zahlen hervorgehoben.

5. Flussdiagramm von Cloudbets provably-fair Keno-Berechnung: Zufallsbytes und Rejection Sampling bestimmen die Position jeder gezogenen Zahl auf dem Spielfeld.

Spielablauf

Die vollständige Menge der 10 gezogenen Zahlen wird auf dem Server erzeugt und verborgen, bevor Sie Ihre Auswahl treffen – sie kann danach nicht unbemerkt verändert werden, dank der bereits mit Ihnen geteilten Commitment. Ihre Auswahl wird einfach mit dieser bereits gezogenen Menge abgeglichen, sobald die Runde abgeschlossen ist, und Ihre Auszahlung wird anhand der Anzahl Ihrer Treffer berechnet.

Code zur unabhängigen Überprüfung deiner Cloudbet-Keno-Ergebnisse

Geben Sie Ihren Server Seed, Client Seed und Nonce ein, um Ihre eigenen Ergebnisse zu überprüfen. Installieren Sie die eine Abhängigkeit, und führen Sie den Code selbst aus, um das Ergebnis Ihres Spiels nachzuvollziehen.

Hinweis: Um den Server Seed eines abgeschlossenen Spiels bei Cloudbet einzusehen, müssen Sie bereits eine neue Runde gestartet haben (wodurch zu einem neuen Seed-Paar gewechselt wird).

Dependencies:

npm install js-sha3

The 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 mine positions to the mine positions outputted here. This proves that your game's outcome was determined solely by the pre-game seeds and was not altered afterwards.
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
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
  }
}

// Step 4: Pick a number of unique positions
function pickUniquePositions(numOfPicks, totalPositions, rng) {
  const available = Array.from({ length: totalPositions }, (_, i) => i);
  const picks = [];

  for (let i = 0; i < numOfPicks; ++i) {
    const index = sample(available.length, rng);

    picks.push(available[index]);
    available.splice(index, 1); // Remove chosen pump from list of non-faulty pumps
  }
  return picks;
}
// Rejection sampling for fair results
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;
  if (usingCustomData) { nonce = myNonce; }
  const numOfHits = 10;
  const totalPositions = 40;

  const { serverSeed, commitment } = generateServerSeed();
  const clientSeed = getClientSeed();

  const roundSignature = createRoundSignature(serverSeed, clientSeed, nonce);
  const numbersToGenerate = totalPositions * 2; // We need at least one random number per position, but there is an improbable possibility  we'll need two
  const rng = createRandomNumberSequence(numbersToGenerate, roundSignature);

  let hits = pickUniquePositions(numOfHits, totalPositions, rng);
  hits = hits.map((value)=> value + 1 );
  hits.sort((a, b)=>a-b);

  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('🔁 Round Signature (can be verified after the game):', roundSignature);
  console.log(`🎯 Hits:`, hits);
})();