A bizonyíthatóan tisztességes szerencsejáték egy az online kaszinók kezdete óta fennálló problémát old meg: hogyan bízhat egy játékos abban, hogy a játék kimenetelét utólag nem manipulálták? A válasz pedig, mint kiderül, ugyanaz az eszköz, amelyhez a kriptográfusok nyúlnak, amikor két félnek meg kell egyeznie valamiben anélkül, hogy megbíznának egymásban — egy commit-reveal séma.
Az alábbiakban részletesen bemutatjuk a Cloudbet által a Mines játékban használt folyamatot – a seed generálásától az aknák elhelyezéséig –, valamint azt, hogy bármely, némi programozási ismeretekkel rendelkező játékos hogyan tudja önállóan ellenőrizni az összes eddigi játékában elért eredményt.
Ez a cikk egy tervezett technikai sorozat első része, amely a Cloudbet Originals mögött álló bizonyíthatóan tisztességes mechanizmusokat mutatja be részletesen. Bármely kör (beleértve a Mines játékot is) gyakorlati ellenőrzéséhez tekintsd meg a Cloudbet Provably fair kalkulátorát.
Contents
Az eredmény rögzítése a játék kezdete előtt
Minden kör előtt a szerver generál egy véletlenszerű, 32 bájtos szerver seedet, és azonnal közzéteszi annak SHA3-256 hash értékét – az úgynevezett commitmentet. Ez a hash egy egyirányú ujjlenyomat: bizonyítja, hogy a seed abban a pillanatban már létezett, anélkül, hogy felfedné, mi is az.
A játék befejeztével a Cloudbet közzéteszi a szerver seedet. Bárki elkészítheti ennek a hash értékét, és ellenőrizheti, hogy az egyezik-e a játék előtti commitmenttel, ami pedig bizonyítja, hogy a seed – és így az aknák elhelyezése – már az első mező kiválasztása előtt rögzítésre került. Nincs olyan időablak, amelyben a kaszinó egy kedvezőbb értékre cserélhetné azt.
A játékosi entrópia hozzáadása
Ha csak a szerver seedje lenne, a játékosok teljes mértékben a kaszinó véletlenszerűségére lenne utalva. Ennek megakadályozása érdekében két további adatot is bevonnak a számításba: egy client seedet (amelyet a játékos állít be) és egy nonce-ot (egy egész szám, amely minden fogadással egyre növekszik).
Mindhárom érték összefűzésre kerül, majd SHA3-256 algoritmussal hash készül belőlük, amely létrehozza a kör aláírását:
roundSignature = SHA3-256(`${serverSeed}:${clientSeed}:${nonce}`)
A client seed biztosítja, hogy a kaszinó ne tudja előre kiszámítani az eredményt a commitment létrehozásakor, mivel a szerver seed generálásakor a játékos által megadott érték még nem ismert. A nonce biztosítja, hogy minden kör egyedi aláírást hozzon létre, még akkor is, ha mindkét seed változatlan marad a fogadások között.
Véletlenszerűség generálása SHAKE256 használatával
A kör aláírása a SHAKE256 algoritmusba kerül, amely a SHA-3 családhoz tartozó, bővíthető kimeneti függvény (XOF). A hagyományos hash-függvényektől eltérően a XOF egy adott rögzített bemenetből tetszőlegesen hosszú pszeudo-véletlenszerű bájtfolyamot képes előállítani – ez itt azért hasznos, mert több akna elhelyezéséhez több egymástól független véletlenszerű értékre van szükség.
A megvalósítás egyszerre 4 bájtot vesz ki az adatfolyamból. Amikor a kezdeti kimenet kifogy, az állapothoz hozzáfűzi a „next” értéket, majd újra lekéri az adatokat. Bár a gyakorlatban egy 25 mezőből álló rács bármilyen reális aknaszám mellett is bőven az első 256 bit határain belül marad.
Az aknák torzításmentes elhelyezése: elutasításos mintavétel
Egy véletlenszerű 32 bites egész szám rácspozícióvá alakítása egyszerű modulo művelettel egy finom, de valós problémát vezet be: amennyiben a 2^32 nem osztható maradék nélkül a fennmaradó pozíciók számával ( P), egyes pozíciók kis mértékben nagyobb valószínűséggel kerülnek kiválasztásra, mint mások.
A Cloudbet ezt elutasításos mintavétellel küszöböli ki:
const maxAcceptable = Math.floor(0x100000000 / P) * P;
let rand;
do { rand = rng.next().value; } while (rand >= maxAcceptable);
const index = rand % P;
A P legnagyobb többszörösébe nem illeszkedő, de 32 biten belül elérhető legnagyobb értékeket elveti a rendszer, és helyettük a SHAKE256 adatfolyam következő értéket használja. Ami marad, az egyenletes eloszlás pontosan P pozíció között.
Minden akna elhelyezése után az adott pozíció kikerül a készletből, és a P értéke 1-gyel csökken — ez egy részleges Fisher–Yates-keverés a 25 elemből álló lapos rácstömbön.
Egy kör ellenőrzése
A játék utáni ellenőrzéshez négy értékre van szükség, amelyeket a Cloudbet a kör után tesz közzé:
szerver seedclient seednonce- A deklarált
minePositions
Az ellenőrzés lépései:
A szerverSeed értékSHA3-256 hashelése, majd az ellenőrzés, hogy megegyezik-e a játék előtti commitmenttel.- A
a roundSignature előállítása: SHA3-256(serverSeed:clientSeed:nonce). - A SHAKE256 adatfolyam inicializálása a
roundSignatureértékkel, majd az elutasításos mintavételi ciklus futtatása aminePositions értékekönálló reprodukálásához.
Egy egyezés igazolja, hogy a rácsot a kör kezdete után nem módosították.
Mintamegvalósítás (Node.js)
npm install js-sha3
const crypto = require('crypto');
const { sha3_256, shake256 } = require('js-sha3');
function generateServerSeed() {
const seed = crypto.randomBytes(32).toString('hex');
return { serverSeed: seed, commitment: sha3_256(seed) };
}
function createRoundSignature(serverSeed, clientSeed, nonce) {
return sha3_256(`${serverSeed}:${clientSeed}:${nonce}`);
}
function* createShake256Stream(signature) {
const byteStream = shake256.create(32);
byteStream.update(signature);
while (true) {
const buf = Buffer.from(byteStream.digest({ buffer: true }));
for (let i = 0; i < buf.length; i += 4) {
if (i + 4 <= buf.length) yield buf.readUInt32BE(i);
}
byteStream.update('next');
}
}
function pickUniquePositions(count, totalTiles, rng) {
const available = Array.from({ length: totalTiles }, (_, i) => i);
const result = [];
for (let i = 0; i < count; i++) {
const P = available.length;
const maxAcceptable = Math.floor(0x100000000 / P) * P;
let rand;
do { rand = rng.next().value; } while (rand >= maxAcceptable);
const index = rand % P;
result.push(available[index]);
available.splice(index, 1);
}
return result;
}
const { serverSeed, commitment } = generateServerSeed();
const clientSeed = 'player-provided-seed';
const nonce = 0;
const sig = createRoundSignature(serverSeed, clientSeed, nonce);
const rng = createShake256Stream(sig);
const mines = pickUniquePositions(5, 25, rng);
console.log('Commitment:', commitment);
console.log('Server seed (post-game):', serverSeed);
console.log('Mine positions:', mines);
Néhány fontos megjegyzés
Miért SHA3, és nem SHA2? Egy egyszerű commitment esetében bármelyik megoldás megfelelne. Az SHA3 sponge felépítése azonban kiküszöböli a hosszabbításos támadásokat, és az, hogy a folyamat egészében ugyanazt alkalmazzák – mind a commitment során, mind pedig a SHAKE256 alapjaként –, biztosítja a kriptográfiai felület egységességét.
Miért SHAKE256 egy seedelt PRNG helyett? A válasz a determinisztikusság és az ellenőrizhetőség. A SHAKE256 egy szabványosított primitív, amelynek pontosan meghatározott specifikációja van. Ez azt jelenti, hogy bármely programozási nyelven készült független megvalósítások ugyanabból a bemenetből azonos kimenetet állítanak elő. Egy egyedi PRNG viszont implementációfüggő viselkedést vezethet be, ami megnehezíti a harmadik felek általi ellenőrzést.
Kijátszhatja a játékos a rendszert azzal, hogy kedvező client seedet választ? Elméletben igen – a játékos kipróbálhat különböző client seedeket, hogy megtalálja azt, amelyik kedvező rácsot eredményez. A rendszer kialakításában ez elfogadottnak minősül, hiszen a játékos seedválasztási joga funkció, nem pedig biztonsági rés. A kaszinó kitettsége szimmetrikus, és ami a legfontosabb, ugyanaz a mechanizmus, amely lehetővé teszi a játékosok számára, hogy jó seedet válasszanak, egyúttal azt is lehetővé teszi számukra, hogy bebizonyítsák: a kaszinó soha nem manipulálta a saját seedjét.
A Mines játék éppen azért jelent kiváló bevezetőt a bizonyíthatóan tisztességes játékok rendszerébe, mert véletlenszám-generáló folyamata viszonylag önálló: egyetlen commit-reveal ciklusból, egy egyszerű bájtfolyamból és egy jól ismert mintavételi technikából áll. Ahogy a sorozat folytatódik, látni fogjuk, hogy a többi Cloudbet Originals-játék hogyan alkalmazza és bővíti ki ezeket az alapokat – néha további entrópiaforrásokkal, eltérő kimeneti leképezésekkel vagy többlépcsős ellenőrzéssel –, miközben megőrzi ugyanazt az alapvető garanciát: egyetlen eredményt sem lehet módosítani azután, hogy a játékos véglegesítette a saját műveletét.


