Draw verification

Halloween Wheel · drawn 31 Oct 2026, 20:00

Back to the competition

Was this draw fair? Check it yourself.

Before entries closed on 31 Oct 2026, 19:30, we locked in two secret starting values for the draw and published a sealed record of each, which would show if they were ever changed. On their own those values pick nothing: the winning ticket comes from running them through a fixed calculation together with the final list of entries, which did not exist until entries closed. After the draw we published the starting values, the full list of entries and the result. Press the button and your own browser runs that same calculation from the published facts and checks that it lands on the same winner we announced.

  • £200 cash: winning ticket #3532
Runs in your browser, not on our servers, using a small piece of open code you can read. It shares nothing with the program that ran the draw.

Enter a ticket number to confirm it was in the draw.

Could someone use this to cheat?

No. Everything on this page is published after the draw has happened. The secret starting values were locked in before entries closed, every competition has its own, and knowing how a finished draw was worked out does not help anyone with a future one. The only way to change a result would be to change our records themselves, and the sealed records published before the draw are what would show that up.

Show the technical detail

1. The ticket-number seed

Fixed when the competition was created and sealed at that moment: its SHA-256 fingerprint was published on the competition page from the start, and the seed itself is revealed only here, after the draw. It maps internal indices to the ticket numbers players see, and is the same for every attempt below.

Proof (fingerprint) — SHA-256 of the seed as UTF-8, published 15 Oct 2026, 17:41 (entries opened 15 Oct 2026, 19:30):

d480eefb0283767ceb34e1c51ff4b783b08750ac786c2cc99e39f9da6db93bd8

Secret ticket numbers code (seed) — revealed after the draw:

a9867a5e9144dc082690f5d1493859ec5919664650a7976c9391584baa6ca6d2

✓ The revealed seed hashes to the published fingerprint — it did not change after it was sealed.

2. The selection, step by step

For prize i (0-based, in rank order): compute HMAC-SHA256(key = the draw seed as UTF-8, message = i as a 4-byte big-endian integer), read its first 4 bytes as a big-endian integer, and reduce that modulo the number of still-available tickets. That picks the pos-th unused index counting through the ranges in ascending order (skipping indices already won). The visible winning ticket number is the permutation of that index under the ticket-number seed (section 3).

The original draw · 31 Oct 2026, 20:00

Proof of the secret draw code (fingerprint) — SHA-256 of the seed, sealed and published 15 Oct 2026, 19:30 (entries closed 31 Oct 2026, 19:30):

aeec649678e24ea424e0018a2015d2a47e0eef96ef75cc2b0e6feb287ba380a0

Secret draw code (seed) — 64 hex characters, kept encrypted until the draw, revealed here:

305a8308a6e9e8419bccb3fdf863aad76c3e78f0c8c26d7306400998402e38cc

✓ The revealed draw seed hashes to the fingerprint published before entries closed — it could not have been chosen with the entries in view.

Entry pool — 1,585 tickets in 1 run of consecutive sold indices (paid and free entries alike, in the same pool), frozen at draw time.

Pool fingerprint — SHA-256 of the published ranges file, byte for byte (download ranges.json, then shasum -a 256 it):

826576c30ef148d0e13ab5e21988e17ceea92539741f6f4fdd23d36b0e5e7926
Show the entry ranges (JSON)
[{"start_index":1,"quantity":1585}]

Each range is a run of consecutive sold internal indices; adjacent purchases are merged, so the file shows what was sold, not who bought what or how much. Ownership is personal data and is not published; it is not needed to reproduce the winning numbers.

Internal snapshot hash (audit only — not publicly recomputable)
fc8644e1b4f37026e7bf7cd284363160cacb964f49d30bd559218f3b7fcfb7cd

SHA-256 of the full frozen snapshot including purchase ids and ownership, which we do not publish. Auditors with database access use it; the public check is the pool fingerprint above.

£200 cash
HMAC(seed, 0)[0:8] = 2444e416 → 608,494,614 mod 1,585 = pos 434 → index 435 → perm(index) = ticket #3532

3. The results on record

  • £200 cash: winning ticket #3532

These are the numbers shown on the competition page and in the winner records. If your own re-computation disagrees with any figure on this page, contact us and quote the pool fingerprint above.

Show the exact maths and the code

The ticket-number permutation, exactly

Ticket numbers are a keyed permutation of the internal indices — a bijection on [1, N] where N = 6,660. To reproduce it (0-based on [0, N), add 1 back at the end):

  1. Let w be the smallest integer with 2w ≥ N. Split as a = 2⌈w/2⌉, b = 2⌊w/2⌋.
  2. Write x as L = ⌊x / b⌋, R = x mod b.
  3. Run 8 alternating Feistel rounds, i = 0…7: even i → L = (L + PRF(i, R)) mod a; odd i → R = (R + PRF(i, L)) mod b.
  4. PRF(i, v) = the first 8 bytes, read big-endian, of HMAC-SHA256(key = the ticket-number seed as UTF-8, message = i as a 4-byte big-endian integer followed by v as an 8-byte big-endian integer).
  5. Result y = L·b + R. If y ≥ N, feed y back through step 2 (cycle-walking) until y < N.
  6. The inverse (a ticket number back to its index) runs the rounds in reverse with subtraction, and cycle-walks with the inverse the same way — this is what “Check a ticket number” does.

The selection walk, exactly

For prize i in rank order over a pool of remaining unused tickets: value = HMAC-SHA256(key = draw seed as UTF-8, message = uint32be(i)); pos = the first 4 bytes of value as a big-endian integer, mod remaining; the winner is the pos-th unused index walking the ranges (sorted by start) in ascending order; its ticket number is the permutation above of that index. A redraw’s seed is SHA-256(draw seed as UTF-8 ‖ uint32be(attempt)) for attempt ≥ 2, and the redraw walks its own reduced pool with i = 0.

Reference implementation

Everything the button above does is in verify-core.js (plain JavaScript, WebCrypto, no dependencies). To run the same checks outside a browser, download the published record and verify-draw.mjs, put them in one folder with verify-core.js, and run:

node verify-draw.mjs record.json

Neither file shares code with our draw program; both were written from the text on this page. Any HMAC-SHA256 implementation in any language reproduces the same numbers.