Odkryj Cloudbet.com
certified checkmark stamp next to cloudbet logo

Techniczne aspekty mechaniki Provably Fair, na których opiera się gra Mines Cloudbet


Rozgrywka Provably Fair rozwiązuje problem, który od samego początku był nieodłącznym elementem kasyn internetowych: w jaki sposób gracz może mieć pewność, że wynik gry nie został zmanipulowany po jego zakończeniu? Okazuje się, że odpowiedzią jest to samo narzędzie, po które sięgają kryptografowie, gdy dwie strony muszą dojść do porozumienia w jakiejś sprawie, nie darząc się wzajemnym zaufaniem — schemat „commit-reveal”.

Poniżej przedstawiono szczegółowy opis procesu wykorzystywany przez Cloudbet w grze Mines — od generowania początkowych seedów po rozmieszczanie min — oraz wyjaśniono, w jaki sposób każdy gracz posiadający podstawową wiedzę z zakresu programowania może samodzielnie zweryfikować każdy wynik, jaki kiedykolwiek uzyskał w tej grze.

Ten artykuł jest pierwszym z planowanej serii szczegółowych omówień technicznych dotyczących mechanizmów Provably Fair, na których opierają się gry oryginalne Cloudbet. Aby samodzielnie zweryfikować dowolną rundę (w tym grę Mines), skorzystaj z kalkulatora Provably Fair serwisu Cloudbet.

Zdecydowanie się na wynik przed rozpoczęciem gry

Przed każdą rundą serwer generuje losowy 32-bajtowy klucz początkowy i natychmiast publikuje jego skrót SHA3-256 — tzw. commitment. Ten hash jest jednokierunkowym odciskiem palca: potwierdza, że wartość początkowa istniała w danym momencie, nie ujawniając jednak, jaka to wartość.

Po zakończeniu gry Cloudbet ujawnia surowy seed serwera. Każdy może obliczyć hash i sprawdzić, czy zgadza się on z ustaleniami przed rozpoczęciem gry, co dowodzi, że rozstawienie – a tym samym układ min – zostało ustalone przed wybraniem pierwszego kafelka. Nie ma żadnego okresu, w którym kasyno mogłoby wymienić to na korzystniejszą wartość.

Uwzględnienie entropii graczy

Gdyby uwzględniono wyłącznie seed serwera, gracze byliby całkowicie uzależnieni od losowości zapewnianej przez kasyno. Aby temu zapobiec, uwzględniane są dwa dodatkowe parametry: seed klienta (ustalany przez gracza) oraz nonce (liczba całkowita, której wartość zwiększa się przy każdym zakładzie).

Wszystkie trzy elementy są łączone i poddawane funkcji skrótu SHA3-256 w celu uzyskania podpisu rundy:

roundSignature = SHA3-256(`${serverSeed}:${clientSeed}:${nonce}`)

Seed klienta gwarantuje, że kasyno nie jest w stanie przewidzieć wyniku w momencie zawarcia zakładu, ponieważ dane wprowadzone przez gracza nie są znane w momencie generowania wartości początkowej serwera. Wartość nonce gwarantuje, że w każdej rundzie generowany jest unikalny podpis, nawet jeśli oba seedy pozostają niezmienione między kolejnymi zakładami.

Generowanie liczb losowych za pomocą algorytmu SHAKE256

Podpis rundy jest wprowadzany do funkcji SHAKE256, funkcji o rozszerzalnym wyniku (XOF) z rodziny SHA-3. W odróżnieniu od standardowego hasha funkcja XOF może generować dowolnie długi pseudolosowy strumień bajtów na podstawie stałych danych wejściowych — co jest tutaj przydatne, ponieważ umieszczenie wielu min wymaga wielu niezależnych wartości losowych.

W tej implementacji dane są pobierane ze strumienia po 4 bajty na raz. Gdy wyczerpie się początkowy wynik, do stanu dodawane jest słowo „next”, a następnie następuje kolejne kompresowanie, choć w praktyce siatka składająca się z 25 kafelków przy dowolnej realistycznej liczbie min mieści się w granicach pierwszych 256 bitów.

Umieszczanie min bez stronniczości: próbkowanie odrzucenia

Przekształcenie losowej liczby całkowitej 32-bitowej w pozycję na siatce za pomocą prostej operacji modulo wiąże się z subtelnym, ale realnym problemem: o ile liczba 2^32 nie jest podzielna bez reszty przez liczbę pozostałych pozycji P, niektóre pozycje będą nieznacznie bardziej prawdopodobne niż inne.

Cloudbet eliminuje ten problem dzięki metodzie próbkowania odrzucenia:

javascript
const maxAcceptable = Math.floor(0x100000000 / P) * P;
let rand;
do { rand = rng.next().value; } while (rand >= maxAcceptable);
const index = rand % P;

Każda wartość wykraczająca poza największą wielokrotność P, która mieści się w 32 bitach, jest odrzucana, a zamiast niej pobierana jest kolejna wartość ze strumienia SHAKE256. Pozostaje nam jednolity rozkład na dokładnie P pozycjach.

Po umieszczeniu każdej miny jej pozycja jest usuwana z puli, a wartość P zmniejsza się o 1 — jest to częściowe przetasowanie metodą Fishera-Yatesa w płaskiej tablicy o wymiarach 25 elementów.

Weryfikacja rundy

Weryfikacja po zakończeniu gry wymaga podania czterech wartości, z których wszystkie są publikowane przez Cloudbet po zakończeniu rundy:

  • serverSeed
  • clientSeed
  • nonce
  • Zadeklarowane minePositions

Etapy weryfikacji są następujące:

  1. Wykonaj hash serverSeed przy użyciu algorytmu SHA3-256 i sprawdź, czy jest on zgodny z zobowiązaniem ustalonym przed rozpoczęciem gry.
  2. Oblicz roundSignature = SHA3-256(serverSeed:clientSeed:nonce).
  3. Zainicjuj strumień SHAKE256 przy użyciu funkcji roundSignature i uruchom pętlę próbkowania odrzuceń, aby niezależnie odtworzyć minePositions.

Wynik meczu potwierdza, że siatka nie uległa zmianie po rozpoczęciu rundy.

Przykładowa implementacja (Node.js)

bash
npm install js-sha3
javascript
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);

Kilka kwestii, na które warto zwrócić uwagę

Dlaczego SHA3, a nie SHA2? W przypadku prostego zobowiązania każde z tych rozwiązań byłoby odpowiednie. Konstrukcja typu sponge algorytmu SHA3 faktycznie eliminuje ataki polegające na wydłużaniu długości, a zastosowanie go w całym łańcuchu przetwarzania — zarówno w fazie commit, jak i jako podstawy algorytmu SHAKE256 — pozwala zachować spójność powierzchni kryptograficznej.

Dlaczego SHAKE256, a nie generator liczb losowych z seedem (PRNG)? Determinizm i możliwość weryfikacji. SHAKE256 to znormalizowana funkcja podstawowa o ściśle określonej specyfikacji, co oznacza, że niezależne implementacje w dowolnym języku programowania będą generować identyczne wyniki na podstawie tych samych danych wejściowych. Niestandardowy generator liczb losowych (PRNG) wprowadza zachowanie zdefiniowane przez implementację, co utrudnia weryfikację przez podmioty zewnętrzne.

Czy gracz może oszukać system, wybierając korzystny seed klienta? W zasadzie tak — gracz mógłby wypróbować różne wartości początkowe klienta, aby znaleźć taką, która generuje korzystną siatkę. W ramach wzoru uznaje się to za dopuszczalne: prawo gracza do wyboru swojego rozstawienia jest funkcją, a nie luką w zabezpieczeniach. Ryzyko ponoszone przez kasyno ma charakter symetryczny, a co najważniejsze – ten sam mechanizm, który pozwala graczowi wybrać dobry seed, umożliwia mu również udowodnienie, że kasyno nigdy nie manipulowało swoim.

Gra Mines stanowi doskonały punkt wyjścia do zapoznania się z mechaniką Provably Fair, właśnie dlatego, że jej mechanizm generowania liczb losowych (RNG) jest stosunkowo samodzielny: składa się z pojedynczego cyklu commit-reveal, prostego strumienia bajtów oraz dobrze znanej techniki próbkowania. W miarę rozwoju serii zobaczymy, w jaki sposób inne tytuły z serii gier oryginalnych Cloudbet dostosowują i rozszerzają te same podstawy — czasami poprzez dodanie dodatkowych źródeł entropii, inne mapowania wyników lub wieloetapową weryfikację — zachowując jednocześnie tę samą podstawową gwarancję: że żaden wynik nie może zostać ustalony po podjęciu przez gracza decyzji o wykonaniu akcji.

Share this post


You may also like

Zobacz nasze kasyno i zakłady sportowe w akcji
Cloudbet Academy
Get smarter
Get rewarded

Complete free Academy lessons and earn exclusive promo codes.

Premier League
Rynki na żywo