Cum funcționează corectitudinea demonstrabilă la Keno
Iată cum se joacă Keno pe Cloudbet și cum poți verifica dacă fiecare extragere este într-adevăr corectă și demonstrabilă.
Cum se joacă Keno
Keno este un joc de extragere de numere: alegi un set de numere de pe tablă, apoi jocul extrage propriul set de numere. Cu cât mai multe dintre numerele alese coincid cu cele extrase, cu atât mai mare este câștigul — iar mărimea acestuia depinde de câte numere ai ales inițial. După ce ai făcut alegerile și ai plasat pariul, extragerea are loc, iar eventualele potriviri sunt afișate instantaneu.
Cloudbet Originals Keno
Jocul propriu Cloudbet Originals Keno folosește o tablă cu 40 de numere: alegi între 1 și 10 numere, iar jocul extrage 10. Are un RTP de 99% și acceptă pariuri de la 0,01 $. Alegerea unui număr mai mic de numere înseamnă volatilitate mai mare și câștiguri mai mari per potrivire; alegerea mai multor numere înseamnă câștiguri mai frecvente, dar câștiguri mai mici per potrivire. Poți folosi Auto Bet ca să automatizezi mai multe runde la rând.
Extragerea Keno este generată prin aceeași metodă verificabilă ca orice alt joc Cloudbet Original — vezi prezentarea noastră generală despre corectitudinea demonstrabilă pentru a afla cum se combină Server Seed, Client Seed și Nonce pentru a forma un Round Signature și apoi un flux de numere aleatorii prin SHAKE256. Această pagină acoperă ceea ce este specific pentru Keno: cum devine acea secvență de numere aleatorii setul efectiv de numere extrase.
Transformarea numerelor aleatorii într-o extragere Keno
Tabla de Keno este numerotată de la 1 la 40. Zece dintre aceste 40 de numere trebuie extrase, unul câte unul, fără a repeta niciun număr.

Numim numărul de numere neextrase încă rămase P. P începe de la 40 și scade cu 1 de fiecare dată când este extras un număr.

Pentru fiecare dintre cele 10 extrageri se generează un număr aleatoriu de 4 octeți (32 de biți) din rezultatul SHAKE256, cuprins între 0 și 4.294.967.295. Pentru a alege în mod corect dintre cele P numere rămase, aplicăm eșantionarea prin respingere — rejection sampling (vezi ghidul nostru despre rejection sampling), apoi luăm rezultatul modulo P pentru a obține poziția următorului număr extras. Dacă mai trebuie extrase numere, numărul ales este eliminat din grup, P scade cu 1, iar procesul se repetă.

Acest proces continuă până când toate cele 10 numere sunt extrase.


Modul de joc
Setul complet de 10 numere extrase este generat și ascuns pe server înainte să faci alegerile — acesta nu poate fi modificat sau alterat pe nesimțite ulterior, datorită Commitment-ului deja partajat cu tine. Alegerile tale sunt pur și simplu verificate în raport cu acest set extras în prealabil odată ce runda se încheie, iar câștigul tău este calculat în funcție de câte potriviri ai.
Cod pentru a-ți verifica singur rezultatele Keno pe Cloudbet
Introdu Server Seed, Client Seed și Nonce pentru a-ți verifica propriile rezultate. Instalează singura dependință și rulează-l tu însuți pentru a reconstitui rezultatul jocului tău.
Notă: pentru a dezvălui Server Seed-ul unui joc finalizat pe Cloudbet, trebuie să fi început deja o rundă nouă (aceasta rotește către o nouă pereche de seed-uri).
Dependințe:
npm install js-sha3
Codul:
// 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);
})();
