Pokerni: fiche senza valore monetario, non acquistabili, non convertibili, non trasferibili; avversari IA segnalati da un distintivo. Poiché il banco fornisce gli avversari, vi dobbiamo una trasparenza totale sulla distribuzione.
Il calcolo avviene interamente nel tuo browser; nulla viene inviato al server. Questo browser conserva l'impronta ricevuta prima della mano e il seme ricevuto dopo; se hai effettuato l'accesso, viene consultata anche la tua cronologia. Puoi anche incollare tu stesso i due valori: al tavolo, l'impronta compare passando il mouse sul distintivo «Distribuzione verificabile».
Che cosa dimostra questa verifica: che l'impronta pubblicata prima della prima carta è proprio quella del seme rivelato dopo l'ultima. Il mazzo era dunque fissato prima che tu vedessi una sola carta, e nessuno ha potuto cambiarlo durante la mano.
Che cosa non dimostra: l'ordine esatto delle 52 carte derivato dal seme. Quella mescolata usa il generatore di NumPy, che il browser non sa riprodurre; lo script Python della versione tecnica la ricostruisce carta per carta.
Gli avversari IA portano sempre il distintivo IA sul loro posto, con il loro livello. Un'IA riceve esattamente le stesse informazioni di un giocatore umano seduto al suo posto: le sue due carte, le carte comuni e le mosse pubbliche; mai le carte degli altri né quelle ancora da uscire. Il codice della distribuzione è verificabile, come spiegato sopra. Il coach è un sistema automatizzato: i suoi consigli sono calcolati da un programma, mai dati da una persona, solo a partire dalle tue carte e dalle mosse pubbliche.
Prima di ogni mano, il server estrae un seme di 63 bit con il generatore crittografico del sistema (secrets.randbits(63) in Python, imprevedibile, anche per noi). Quel seme alimenta una permutazione deterministica delle 52 carte (numpy.random.default_rng(seme).permutation(52)). Le due carte di ogni giocatore e poi le 5 carte comuni sono servite nell'ordine del mazzo, senza carte bruciate.
Il server non può cambiare le carte durante la mano, e lo dimostra:
1. Prima della mano, ogni messaggio di stato contiene un impegno: commit = SHA-256("selfpoker:" + seme). L'impronta fissa il mazzo completo senza rivelare nulla.
2. Dopo la mano, il messaggio di fine (hand_end) rivela il seme. Chiunque può allora verificare che l'impronta corrisponda e ricostruire l'intero mazzo, comprese le carte non distribuite.
import hashlib
import numpy as np
graine = 1234567890123456789 # campo "fairplay.seed" di hand_end
commit = "..." # campo "commit" dei messaggi di stato
assert hashlib.sha256(f"selfpoker:{graine}".encode()).hexdigest() == commit
paquet = list(np.random.default_rng(graine).permutation(52))
# n giocatori: carte 0..2n-1 = mani (2 per giocatore), 2n..2n+4 = carte comuni
# valore = carta // 4 (0=2 … 12=asso), seme = carta % 4 (♣♦♥♠)
Ogni mano giocata è archiviata con il suo seme: l'intera cronologia si può rigiocare in modo identico.
Domande? Il codice del server è ispezionabile sulla macchina che lo ospita: è un sito privato, tra persone che si fidano.
Musica di sottofondo: Jason Shaw, audionautix.com, licenza Creative Commons BY 4.0 (« Big Swing Band », « Closer To Jazz », « Dirt Road Traveler », « Nice And Easy », « Acoustic Rock », « Feel Good Rock »).