Skip to content
xCanopy

Provably fair draws

How every pull is committed, mixed with your seed, and revealed so anyone can recompute it.

Commit, mix, reveal

  1. Commit. Before any draw, the server publishes sha256(serverSeed), the seed hash, together with the time the seed will be revealed.
  2. Mix. Each pull uses your own client seed and your next nonce under that commit. Nonces count per wallet: your first pull under a commit is nonce 0, then 1, 2, … Nobody else's pulls move your count.
  3. Draw. u is the first 52 bits of HMAC-SHA256(serverSeed, "clientSeed:nonce"), divided by 2⁵², a number in [0, 1). The desk is the first one whose running total of weights passes u × total weight, in the order recorded with the pull.
  4. Reveal. At the published time (every hour by default), the server seed is revealed and a new commit opens. A commit with no draws yet just moves its time on by an hour. Your receipt then recomputes the hash, u and the pick in your browser.

Why nobody can steer a draw

  • The seed hash comes first. The server can't pick a server seed after seeing your client seed.
  • Your seed comes after the hash. Your browser makes a fresh client seed for each commit, after that commit's hash is published, so the server can't have chosen its seed with yours in mind. It keeps that seed until the commit is revealed.
  • The inputs are pinned. Every pull sends the commit hash and the nonce your browser expects. If either doesn't match, the server refuses the pull instead of drawing (nothing is drawn). Trying again uses the same seed, commit and nonce, so it gives the same draw: refusing a pull gains the server nothing.
  • Your nonces have no gaps. The fairness page shows your nonces under the open commit (signed in). They should read 0, 1, 2… A gap would mean a draw was made in your name that you didn't make.
  • Reveals are on a schedule. The reveal time is published with the hash. A commit revealed before its time is marked Early in the fairness page's table, so cutting one short can't go unnoticed.

You can't game it either, because you don't know the server seed until after the commit's draws are done.

Your seed

Your browser makes the client seed for you and keeps it for the whole commit. To use your own, open Fairness and boosts on the pack page and type it in; it's kept until the commit is revealed. When you open two or more packs at once, they all use the same seed with consecutive nonces.

What the receipt stores

Each pull stores the exact desk order and weights it used (the draw snapshot), so the check doesn't depend on today's inventory.

Verify one yourself

Open any receipt: from the Pulls tab on your profile, the Just pulled tickers on the home page and pack pages, the reveal screen, or a desk's page.

Until its seed is revealed, the receipt says Waiting for the seed reveal. Seeds are revealed at the time published with the commit (the fairness page counts down to it). After that, the receipt marks the hash, u and the desk ✓, shows Verified in your browser, and links to the fairness page with the pull loaded.

The fairness page

The fairness page follows the same four steps:

  • Active commit. The open commit's hash, drawn as a seal (one spoke per hex digit), when it was committed, how many draws it has taken and a countdown to its reveal. Signed in, you see your own nonces under it. A chart plots each recent draw: its place in the commit across, its u up. Fair draws scatter evenly with no pattern. Show these draws as a table lists the same numbers.
  • Draw distribution. Every u, counted in equal slices of [0, 1). Fair draws fill each slice about equally; the shaded band is where about 95% of slices land by chance. A chi-square test turns the spread into one verdict (a p-value of 0.01 or more passes). The test runs on a fixed sample: the first 100 draws, then the first 200, and so on. Retesting on every new draw would, by chance alone, sometimes flag a fair system, so the verdict only changes every 100 draws. Before the first 100, the chart shows every draw untested. Cumulative shows the same check as a curve along the diagonal, and Table lists the slices.
  • Recompute. Load a receipt (its link or pull ID), pick a quick fill (a real draw under a revealed commit, a revealed seed, example values), or paste a server seed, client seed and nonce. Your browser runs the hash, the HMAC and u step by step and says whether the hash matches a published commit. With a receipt, it goes on to show which desk u picks from the pull's recorded weights, and whether that's the desk on the receipt.
  • Revealed seeds. The last five revealed commits with their server seeds, each re-hashed in your browser and ticked off against the hash published first, and a chart of how many draws each commit took.

Checking by hand

You can recompute a draw with any SHA-256 and HMAC tool:

  • The server seed is a 64-character hex string. Use it as text, not as decoded bytes, both for the hash and as the HMAC key.
  • The HMAC message is clientSeed:nonce, for example 9f3a0c1d2e4b5a6c:41.
  • Take the first 13 hex characters of the HMAC (52 bits), read them as a number and divide by 2⁵² to get u.
  • Walk the recorded desks in order, adding up their weights, and stop at the first one where the running total passes u × total weight.

On this page