Comment fonctionne l'équité vérifiable au Keno
Voici comment jouer au Keno sur Cloudbet, et comment vérifier que chaque tirage est équitable et vérifiable.
Comment jouer au Keno
Le Keno est un jeu de tirage de numéros : vous choisissez une série de numéros sur une grille, puis le jeu tire sa propre série de numéros. Plus vous trouvez de numéros parmi ceux tirés, plus votre gain est important — le montant du gain dépend du nombre de numéros choisis au départ. Une fois vos numéros choisis et votre mise placée, le tirage a lieu et vos numéros trouvés sont révélés instantanément.
Cloudbet Originals Keno
Le Keno Originals de Cloudbet utilise une grille de 40 numéros : vous choisissez de 1 à 10 numéros, et le jeu en tire 10. Il offre un RTP de 99% et accepte les mises à partir de $0.01. Moins vous choisissez de numéros, plus la volatilité est élevée et plus vous gagnez par numéro trouvé ; plus vous en choisissez, plus les gains sont fréquents mais chacun rapporte moins. La fonction Auto Bet permet d'automatiser plusieurs parties.
Le tirage du Keno est généré de la même manière vérifiable que tous les autres Cloudbet Original — consultez notre aperçu de l'équité vérifiable pour voir comment le Server Seed, le Client Seed et le Nonce se combinent pour former une Round Signature, puis une suite de nombres aléatoires via SHAKE256. Cette page traite de ce qui est spécifique au Keno : comment cette suite de nombres aléatoires devient la série de numéros réellement tirés.
Comment les nombres aléatoires deviennent un tirage du Keno
La grille du Keno est numérotée de 1 à 40. Dix de ces 40 numéros doivent être tirés, un par un, sans répétition.

Nous appelons P le nombre de numéros non encore tirés restants. P commence à 40 et diminue de 1 à chaque numéro tiré.

Un nombre aléatoire de 4 octets (32 bits) est tiré de la sortie SHAKE256 pour chacun des 10 tirages, allant de 0 à 4 294 967 295. Pour choisir équitablement parmi les P numéros restants, nous appliquons l'échantillonnage par rejet (voir notre guide sur l'échantillonnage par rejet), puis nous prenons le résultat modulo P pour obtenir la position du prochain numéro tiré. S'il reste des numéros à tirer, le numéro choisi est retiré du groupe, P diminue de 1, et le processus se répète.

Ce processus continue jusqu'à ce que les 10 numéros soient tirés.


Déroulement du jeu
La série complète des 10 numéros tirés est générée et dissimulée sur le serveur avant que vous ne fassiez vos choix — elle ne peut être modifiée ou altérée sans être détectée par la suite, grâce au Commitment déjà partagé avec vous. Vos choix sont simplement comparés à cette série pré-tirée une fois la partie terminée, et votre gain est calculé en fonction du nombre de numéros trouvés.
Code pour vérifier vous-même vos résultats Keno sur Cloudbet
Saisissez votre Server Seed, votre Client Seed et votre Nonce pour vérifier vos propres résultats. Installez l'unique dépendance requise et exécutez-la vous-même pour reconstituer le résultat de votre partie.
Remarque : pour révéler le Server Seed d'une partie terminée sur Cloudbet, vous devez déjà avoir démarré une nouvelle partie (ce qui fait passer à une nouvelle paire de seeds).
Dépendances :
npm install js-sha3
Le 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);
})();
