Draw verification
Halloween Wheel · drawn 31 Oct 2026, 20:00
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
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):
Secret ticket numbers code (seed) — revealed after the draw:
✓ 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):
Secret draw code (seed) — 64 hex characters, kept encrypted until the draw, revealed here:
✓ 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):
Show the entry ranges (JSON)
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)
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.
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):
- Let w be the smallest integer with 2w ≥ N. Split as a = 2⌈w/2⌉, b = 2⌊w/2⌋.
- Write x as L = ⌊x / b⌋, R = x mod b.
- 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.
- 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).
- Result y = L·b + R. If y ≥ N, feed y back through step 2 (cycle-walking) until y < N.
- 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:
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.