Provably fair
Pick a game to see how its results are made, and check any of yours.
How your item is picked
Every box holds a fixed list of items, and each item owns a number of tickets. Rarer items own fewer tickets, and an item's chance is exactly its tickets divided by the box's total. Those chances are shown on every box page. When a box's odds change, the old table is kept as a numbered version and each open records the version it used, so any open can be checked against the exact odds it rolled on.
Which ticket you land on comes from three values:
- Server seed. A secret made by us. Before you open anything you are shown its SHA-256 hash, which commits us to it without revealing it.
- Client seed. Yours. You can change it to anything at any time, so we could not have prepared a result for it.
- Nonce. Counts your opens on this seed pair: 1, 2, 3 and so on. It makes every open different.
The roll is HMAC-SHA256(server seed, "client seed:nonce"). Its first 8 hex characters, divided by ffffffff, give a number from 0 to 1. That number times the total tickets is your ticket, counted along the items from rarest to most common.
When you rotate your seed pair, the old server seed is revealed. Hash it and compare it with the hash you were shown, then recompute any open made with it.
Your seeds
Log in to see your seeds and your opens.
Check an open
Independent verification
The same calculation as a Node.js script you can run yourself. It uses only Node's built-in crypto module.
const crypto = require('crypto');
// Fill these in from the Provably Fair page (after rotating your seed,
// the server seed of the old pair is revealed).
const serverSeed = 'paste the revealed server seed';
const clientSeed = 'paste your client seed';
const nonce = 1; // the open's nonce
// Battle pulls only: the battle's EOS block id, shown on the battle page.
// Leave it empty ('') for a box open.
const eosBlockId = '';
// The box's items in ticket order, rarest first, with their ticket counts.
// The "Check" tool on the Provably Fair page lists them for any box.
const items = [
// { name: 'PSA 10 vintage holo', tickets: 14 },
];
// The roll
const message = clientSeed + ':' + nonce + (eosBlockId ? ':' + eosBlockId : '');
const hash = crypto.createHmac('sha256', serverSeed).update(message).digest('hex');
const roll = parseInt(hash.slice(0, 8), 16) / 0xffffffff;
// The item it lands on
const total = items.reduce((n, it) => n + it.tickets, 0);
let left = roll * total;
let won = items[items.length - 1];
for (const it of items) {
left -= it.tickets;
if (left <= 0) { won = it; break; }
}
console.log('server seed hash:', crypto.createHash('sha256').update(serverSeed).digest('hex'));
console.log('roll hash:', hash);
console.log('roll:', roll, 'ticket:', Math.floor(roll * total), 'of', total);
console.log('item:', won && won.name);