Tõestatavalt aus
Kontrolli ise iga jagamist, iga viset ja iga kohtade jaotust.
Meie lauamängud on osavusmängud: seeme otsustab ainult segamise, täringud ja selle, kes kus istub. Iga käik pärast seda on sinu. Enne kui midagi jagatakse, seob server end salajase seemnega, avaldades selle SHA-256 räsi. Sinu enda kliendi seeme segatakse sisse, nii et server ei saa jagamist valida pärast selle nägemist. Kui seeme on avalikustatud, saab igaüks iga kaardi, täringu ja kivi uuesti välja arvutada.
Kuidas see töötab
- Kohustus: server valib salajase seemne (32 juhuslikku baiti) ja näitab sulle selle SHA-256 räsi enne esimest kaarti või täringut.
- Sinu seeme: sinu brauser lisab kliendi seemne (juhusliku või sinu salvestatud). See saadetakse alles pärast räsi näitamist.
- Arvud: iga juhuslik arv on HMAC-SHA256(serveri seeme, sõnum kõigi kliendi seemnete ja loenduriga). Selle esimesed 52 bitti moodustavad ühe arvu.
- Avalikustamine: pärast mängu avaldatakse serveri seeme. Selle SHA-256 räsi peab võrduma kohustusega ja ümberarvutus peab andma täpselt need jagamised, mis mängiti.
Arvudest kaartideks, täringuteks ja kohtadeks
52-bitine arv muudetakse tagasilükkamisvalimi abil täisarvuks, mis on väiksem kui n: vahemiku 2^52 ülemisse mittetäielikku plokki jääv arv jäetakse vahele ja kasutatakse järgmist loendurit, nii et iga tulemus on täpselt võrdse tõenäosusega. Segamine on Fisher–Yates ülevalt: i jaoks viimasest positsioonist alla kuni 1-ni valitakse j, mis on väiksem kui i + 1, ja need kaks vahetatakse.
Mäng mängult
- Backgammon: avavise ja iga käigu mõlemad täringud on int(6) + 1, käikude järjekorras.
- Kabe ja Xiangqi: täringuid ega kaarte pole. Seeme määrab, kes alustab (kohtade järjekord).
- Tarneeb, Trix ja Bridž: üks 52-kaardilise paki Fisher–Yates segamine iga jagamise kohta; koht i saab kaardid 13i kuni 13i + 12.
- Baloot: üks 32-kaardilise paki segamine iga käe kohta; ülejäänud pakk segatakse teise jagamise jaoks uuesti.
- Mahjong: iga võetud kivi on int(kive alles) müürist selle kindlas järjekorras – segamine ühe kivi kaupa.
- Pokker: iga laud kasutab seemnesessiooni. Enne iga jagamist seob laud end pakiga: Merkle'i juur üle selle 52 positsiooni, kus iga positsioon on kaart koos oma soolaga. Kui lahkud laua tagant, saad oma käekaardid, ühiskaardid ja nende Merkle'i tõendid, et saaksid neid selle kohustuse alusel kontrollida; teiste mängijate kaarte ei avalikustata. Kogu pakk ja seeme avaldatakse sessiooni vahetumisel: iga 24 tunni järel, pärast 500 kätt, kui laud tühjeneb või kui server taaskäivitub.
- Male: sinu ühendusel on seotud seeme juba enne, kui otsid mängu, esitad väljakutse või alustad mängu boti vastu. Värvid tulenevad mõlema mängija seemnetest ja kliendi seemnetest.
Enne seda skeemi mängitud matšid (match_seed_v1) jäävad kontrollitavaks: kontrollija valib skeemi kirje põhjal.
Kontrolli
Kleebi matši kirje (sinu mängude nupp Kontrolli täidab selle). Iga jagamine ja vise mängitakse mängu enda reeglite järgi uuesti läbi ja võrreldakse sellega, mida mängiti.
Sisesta matši seemned, et näha, mida need alguses jagavad.
Sisesta käe seemned, et kogu selle pakk uuesti välja arvutada, või kleebi laua tagant lahkudes saadud kaarditõendid, et kontrollida oma kaarte ja ühiskaarte.
Sisesta mõlema poole seemned, et uuesti välja arvutada, kes mängib valgetega.
Pool A (otsingu või väljakutse looja)
Pool B
Kontrolli ise
// Node.js 18+ — check a table-game match yourself (scheme match_seed_v2)
const { createHash, createHmac } = require('crypto');
const sha256 = (s) => createHash('sha256').update(s).digest('hex');
const word = (key, msg) => BigInt('0x' + createHmac('sha256', key).update(msg).digest('hex').slice(0, 13));
console.log(sha256(serverSeed) === commitment); // 1. the reveal matches the commitment
let k = 0; // 2. the draw stream: one counter per match
const seeds = clientSeeds.map((s, i) => i + '=' + s).join(',');
const next = () => word(serverSeed, 'pf2:' + game + ':' + matchId + ':' + seeds + ':' + (k++));
const SPAN = 1n << 52n;
function int(n) { // 3. whole number below n, no modulo bias
const N = BigInt(n), limit = SPAN - (SPAN % N);
for (;;) { const w = next(); if (w < limit) return Number(w % N); }
}
const die = () => int(6) + 1;
function shuffle(a) { // 4. Fisher–Yates from the top
a = a.slice();
for (let i = a.length - 1; i > 0; i--) { const j = int(i + 1); [a[i], a[j]] = [a[j], a[i]]; }
return a;
}
// seat order (pairings): shuffle([0, 1]) first, then the game's opening deal / roll
// Poker (scheme poker_hmac_v1): hand n of seed session S at table T
const handValue = createHmac('sha256', serverSeed).update('pk1:hand:' + T + ':' + S + ':' + n).digest('hex');
console.log(sha256(handValue) === handCommitment); // stored before the deal
// deck = shuffle([0..51]); key = handValue; message = pk1:T:S:n:{seat}={seed},…:{k}; seats ↑
// rank = id % 13 → 23456789TJQKA; suit = Math.floor(id / 13) → c d h s
// deck commitment (before the deal): salt_i = HMAC(handValue, 'pk1:salt:' + i); leaf_i = sha256('pk1:leaf:' + i + ':' + card_i + ':' + salt_i)
// 64 leaves (52..63 = sha256('pk1:pad')), parent = sha256('pk1:node:' + left + right) → root; on leave you get your leaves + paths
// Chess colour (scheme chess_colour_v1): A = owner of the seek / challenge, B = the other side (a bot adds no seed)
const m = (k) => 'cc1:' + commitA + ':' + (commitB || '-') + ':0=' + clientA + ',1=' + clientB + ':' + k;
// w = word(seedA, m(k)) XOR word(seedB, m(k)); int(2) over w as above → 0 means A plays White
Selle lehe kontrollija töötab sinu brauseris ega pöördu serveri poole. Laadi see alla, et käivitada see võrguühenduseta: verifier.js