Ζάρια για τα οποία δεν χρειάζεται να μας πιστέψεις
Πριν αρχίσει το παιχνίδι κλειδώνουμε έναν μυστικό αριθμό και δημοσιεύουμε το αποτύπωμά του. Όταν τελειώσει, δημοσιεύουμε τον ίδιο τον αριθμό. Ανάμεσα σε αυτές τις δύο στιγμές κάθε ζαριά είναι ήδη καθορισμένη — και μετά ο καθένας μπορεί να τις ξαναϋπολογίσει όλες και να δει ότι τίποτα δεν μετακινήθηκε.
Άνοιξε το μητρώοΤο κομμάτι που δεν το λύνει ούτε μια καλή γεννήτρια τυχαίων αριθμών
Τα ζάρια μας προέρχονται από την κρυπτογραφική γεννήτρια του λειτουργικού συστήματος — την ίδια πηγή που προστατεύει μια τραπεζική σύνδεση, όχι τη συντόμευση που χρησιμοποιούν τα περισσότερα παιχνίδια. Αυτό λύνει το πόσο τυχαίοι είναι οι αριθμοί. Δεν λύνει τίποτα από το ερώτημα που όντως θέτουν οι παίκτες.
Ένα ζάρι που έπεσε τίμια και ένα ζάρι που επιλέχθηκε επίτηδες μοιάζουν ίδια εκ των υστέρων. Και τα δύο είναι απλώς ένας αριθμός σε ένα αρχείο.
Άρα το χρήσιμο ερώτημα δεν είναι «είναι καλή η γεννήτριά σας;» αλλά «μπορώ να το ελέγξω;» Ό,τι ακολουθεί υπάρχει για να είναι η απάντηση ναι, χωρίς να σου ζητάμε να πιστέψεις ούτε μια λέξη μας.
Σφραγισμένο πριν, ανοιχτό μετά
Τέσσερα βήματα. Τα δύο μπορείς να τα κάνεις μόνος σου — και αυτά ακριβώς θα μας έπιαναν.
- 1
Σφράγιση
Πριν την πρώτη ζαριά ο διακομιστής τραβά έναν μυστικό αριθμό 32 byte — τον σπόρο του διακομιστή — και δημοσιεύει το αποτύπωμα SHA-256 του και στους δύο παίκτες. Το αποτύπωμα δεν προδίδει τίποτα, αλλά ο σπόρος είναι πλέον κλειδωμένος: κάθε άλλος θα έδινε άλλο αποτύπωμα.
commit0df0916cb0…2904e706 - 2
Ανάμειξη
Η εφαρμογή σου παράγει τον δικό της τυχαίο σπόρο και τον στέλνει όταν κάθεσαι στο τραπέζι. Οι σπόροι και των δύο παικτών μπαίνουν σε κάθε ζάρι, οπότε δεν μπορούμε να ψάξουμε εκ των προτέρων σπόρο με ζαριές που μας βολεύουν — τη στιγμή που δεσμευόμαστε, δεν ξέρουμε τι θα προσθέσεις.
clientSeeda26460084a0ef89b:d4f28bac6efd1b6e - 3
Παραγωγή
Κάθε ζάρι διαβάζεται από ένα HMAC-SHA256 των σπόρων και του αριθμού της ζαριάς. Τίποτα δεν αποθηκεύεται και τίποτα δεν επιλέγεται: οι ίδιες τρεις είσοδοι δίνουν πάντα το ίδιο ζάρι, και καμία άλλη δεν το δίνει.
die(n) = (HMAC-SHA256(serverSeed, "clientSeed:n:round")[0] < 252) % 6 + 1 - 4
Άνοιγμα
Όταν τελειώσει το παιχνίδι δημοσιεύουμε τον σπόρο. Πάρε το hash του, σύγκρινέ το με το αποτύπωμα που σου δόθηκε πριν την πρώτη ζαριά, και μετά ξαναϋπολόγισε κάθε ζάρι. Ένας διακομιστής που θα είχε διαλέξει έστω μία ζαριά κόβεται σε έναν από τους δύο ελέγχους.
serverSeed5cde3365be…7b6b2bd5
Οι τιμές παραπάνω είναι η πραγματική απόδειξη του παιχνιδιού #148, ενός τελειωμένου παιχνιδιού που μπορεί να δει ο καθένας. Βάλε τον αριθμό στο πλαίσιο πιο κάτω και δες το να βγαίνει σωστό.
Έλεγξε ένα παιχνίδι — εδώ, τώρα
Γράψε έναν αριθμό παιχνιδιού. Η σελίδα φέρνει την απόδειξή του, ύστερα ξαναπαίρνει το hash του σπόρου και ξαναϋπολογίζει κάθε ζάρι με την κρυπτογραφία του δικού σου περιηγητή.
Ή επικόλλησε μόνος σου τις τρεις τιμές
Ο αποκαλυμμένος σπόρος ταιριάζει με το αποτύπωμα
Τα ζάρια αναπαράχθηκαν
Δεν υπάρχει απόδειξη με αυτόν τον αριθμό. Τα παιχνίδια αριθμούνται με τη σειρά που τελειώνουν, και μόνο ένα τελειωμένο παιχνίδι έχει δημοσιευμένο σπόρο.
Η απόδειξη δεν κατέβηκε. Είναι πρόβλημα σύνδεσης, όχι αποτυχημένος έλεγχος — τίποτα δεν διαψεύστηκε.
Αυτό δεν είναι αριθμός παιχνιδιού, ή οι τιμές που επικόλλησες δεν είναι δύο hash 64 χαρακτήρων και ένας σπόρος πελάτη.
Υπολογίζεται…
Γιατί καμία έδρα δεν είναι ούτε ελάχιστα πιο πιθανή
Ένα byte είναι αριθμός από 0 έως 255 — 256 δυνατότητες. Το 256 δεν είναι πολλαπλάσιο του έξι· είναι 6 × 42 και περισσεύουν 4. Αν πάρεις το υπόλοιπο της διαίρεσης με το έξι, τέσσερις έδρες παίρνουν αθόρυβα 43 ευκαιρίες στις 256 και οι άλλες δύο 42. Ελάχιστη μεροληψία — σε ένα εκατομμύριο ζαριές, πραγματικό πλεονέκτημα. Γι’ αυτό οι τέσσερις αυτές τιμές πετιούνται.
252 = 6 × 42. Κάθε έδρα παίρνει ακριβώς τον ίδιο αριθμό byte, άρα κάθε έδρα είναι ακριβώς μία στις έξι.
Πού σταματά η απόδειξη
Δύο είδη ζαριών σε αυτόν τον ιστότοπο δεν καλύπτονται από την αλυσίδα. Αναφέρονται εδώ αντί να παραλειφθούν, γιατί ένας ισχυρισμός δικαιοσύνης με μια σιωπηλή τρύπα αξίζει λιγότερο από κανέναν ισχυρισμό.
- TelegramΖαριές στη συνομιλία του botΑν ρίξεις με το δικό του animation ζαριού το Telegram, αυτός ο αριθμός έρχεται από το Telegram, όχι από εμάς· κανένας σπόρος μας δεν τον αναπαράγει. Η δημοσιευμένη απόδειξη απαριθμεί ακριβώς ποιες θέσεις ήταν αυτές, και το μητρώο βάζει εκεί το σύμβολο του Telegram αντί για έδρα. Για πλήρως ελέγξιμο παιχνίδι, ρίξε μέσα στην εφαρμογή.
- ΕξάσκησηΠαιχνίδια με τον υπολογιστήΤο offline παιχνίδι εξάσκησης ρίχνει στη δική σου συσκευή, χωρίς σπόρο και χωρίς απόδειξη. Δεν υπάρχει αντίπαλος ούτε στοίχημα, άρα τίποτα να αποδειχθεί και τίποτα σε κίνδυνο.
Όλα τα υπόλοιπα — online 1v1, δωμάτια φίλων και τουρνουά, δωρεάν ή με στοίχημα — τρέχουν στην αλυσίδα που περιγράφηκε.
Ο ίδιος έλεγχος, χωρίς αυτή τη σελίδα
Δώδεκα γραμμές και καμία βιβλιοθήκη. Επικόλλησέ τες σε οποιαδήποτε κονσόλα περιηγητή μαζί με τις τρεις τιμές ενός παιχνιδιού και θα σου πουν ακριβώς ό,τι λέει αυτή η σελίδα — γι’ αυτό δημοσιεύεται η μέθοδος και όχι μόνο το αποτέλεσμα.
const enc = new TextEncoder();
const hex = (b) => [...new Uint8Array(b)].map((x) => x.toString(16).padStart(2, '0')).join('');
// 1. the seed we revealed must hash to the commitment you were given first
const commitOk = hex(await crypto.subtle.digest('SHA-256', enc.encode(serverSeed))) === commit;
// 2. every die, re-derived from that seed
const key = await crypto.subtle.importKey(
'raw', enc.encode(serverSeed), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
async function die(n) {
for (let round = 0; round < 16; round++) {
const mac = new Uint8Array(
await crypto.subtle.sign('HMAC', key, enc.encode(`${clientSeed}:${n}:${round}`)));
for (const b of mac) if (b < 252) return (b % 6) + 1;
}
}Κάθε απόδειξη είναι δημόσια στο /fair/<id> — χωρίς κλειδί, χωρίς λογαριασμό, χωρίς ονόματα παικτών και χωρίς ποσά. Μόνο τα ζάρια.
Ερωτήσεις που όντως γίνονται
Έχασα τέσσερα παιχνίδια στη σειρά. Είναι τα ζάρια εναντίον μου;+
Δεν γίνεται. Κάθε ζάρι ενός τελειωμένου παιχνιδιού ήταν καθορισμένο πριν αρχίσει, από σπόρο δεσμευμένο εκ των προτέρων, και μπορείς να τα ξαναϋπολογίσεις όλα παραπάνω. Τα σερί μοιάζουν στοχευμένα και δεν είναι: με δύο ζάρια, το να σε ξεπεράσει ο αντίπαλος τέσσερα παιχνίδια στη σειρά συμβαίνει πολύ πιο συχνά απ’ όσο νομίζει ο κόσμος.
Θα μπορούσε ο διακομιστής να διαλέξει μια ζαριά τη στιγμή που μετράει;+
Θα έπρεπε να σπάσει έναν από δύο ελέγχους. Ή δημοσιεύει σπόρο που δεν δίνει το αποτύπωμα που σου έδωσε πριν το παιχνίδι — κάτι που το βλέπει ο καθένας — ή δημοσιεύει τον πραγματικό, οπότε τα ζάρια που παράγει είναι αυτά που έπαιξες και δεν υπήρχε τίποτα να διαλέξει.
Κι αν η εφαρμογή μου δεν έστειλε ποτέ δικό της σπόρο;+
Παράγεται τυχαίος στη θέση του, ώστε η αλυσίδα να είναι πάντα σωστά σχηματισμένη. Αυτό αποδυναμώνει μόνο τη δική σου συνεισφορά· η δέσμευση και όλοι οι έλεγχοι παραπάνω ισχύουν.
Επηρεάζει ένας αποκαλυμμένος σπόρος το επόμενο παιχνίδι μου;+
Όχι. Για κάθε παιχνίδι, και για τη ρεβάνς, τραβιέται νέος σπόρος και δημοσιεύεται νέο αποτύπωμα. Σπόρος που δημοσιεύτηκε δεν καθορίζει ποτέ άλλη ζαριά.
Γιατί κάποια ζάρια έχουν το σύμβολο του Telegram;+
Αυτά ρίχτηκαν με το animation ζαριού του Telegram στη συνομιλία του bot, άρα ήρθαν από το Telegram και κανένας σπόρος μας δεν τα αναπαράγει. Σημειώνονται αντί να κρύβονται, και ο αριθμός που θα έδινε η αλυσίδα μας σε εκείνη τη θέση επίτηδες δεν εμφανίζεται — δεν είναι το ζάρι που έριξε κανείς.