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.

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

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.

Dies wird fortgesetzt, bis alle 10 Zahlen gezogen sind.


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