Rotherham Chess Club

A draw nobody can rig

A detour into the bizarre cryptographic world of a chess competition secretary.

How would you conduct a provably fair random draw?

It's easy enough with balls or pieces of paper in a bag, although even this doesn't make you immune to allegations of "cooled balls" and other such fiddling1. You also need witnesses, and however many people are in the room, someone can always claim that they're all in on the scam.

Video doesn't help. I can run the draw several times and release only the recording that gives the result I want. Using a random number generator or computerised shuffle makes this even quicker and easier. I can prove that there was a draw that gave that outcome, but not that it was the only draw.

So how do you run a draw that is fair, that can be done remotely, and that anyone can check after the fact? Well, I recently hit this problem in the (admittedly) incredibly low-stakes environment of the Sheffield & District Chess Association. Historically, we made draws by shuffling bits of paper in a bag, but that takes time and needs people to get in a room together. Never one to miss an opportunity to over-engineer a solution to a simple problem, I sat down to think about it.

Verifiability

If I want anyone to be able to check the draw process afterwards, then it needs to be deterministic - the inputs must completely decide the draw outcome. Only then can someone else 'replay' the draw and see that they get the same output. This is what allows the draw to be carried out remotely without witnesses: everyone can run the process and get the same result.

Of course, if I control all these inputs, then I can still fix the draw - so we also need an unpredictable random input that is public and that I can't reasonably control. Cryptographers would call this a randomness beacon.

It so happens that in the UK we have a very well-known randomness beacon that has been running every week since 1994: the National Lottery. It's published at set times, everyone (mostly) trusts it, and nobody can honestly believe that I can predict or control it, otherwise I'd be on a yacht somewhere rather than messing around doing this kind of thing.

When I announce a draw, I say what the draw will be named (e.g. "Cup Quarter-Final 2026"), the teams that are in it (and their ball numbers), and I pick a future Lotto draw that will be the source of the random input. At that point, my involvement with the draw is basically done: I have no further discretion over the process. Everyone has all the information they need to reproduce the draw themselves. The Lotto balls will drop as they will, and that determines the draw outcome.

nobody knows the numbers yet my choices end here time Announcement draw name teams and ball numbers which Lotto draw hash of the draw code Lotto draw six numbers published Anyone checks inputs → SHA-256 → order same result every time
Everything except the Lotto numbers is fixed in public before the Lotto is drawn. Once the numbers are out, there is only one possible result, and anyone can work it out.

Fairness

The Lotto result (ignoring the bonus ball) is 6 balls from 1-59, so there are 45,057,474 combinations. But how do you get from 6 numbers to a random shuffle?

This is where cryptographic hash functions come in. These functions turn some text x into a really big number f(x). They have a few interesting properties for this application:

  • the same x always gives the same f(x) (it's a mathematical function);
  • f(x) appears completely random, with no apparent relationship to x (it behaves like a random oracle);
  • if x changes, even only slightly (say, if one Lotto number were to change), f(x) changes dramatically and unpredictably (the avalanche effect)

In our case, all the draw inputs go into one line of text called the seed: the draw name2, Lotto numbers, number of teams, and number of byes. For instance: cup quarter-final 2026 | 4 8 15 16 23 42 | 8 | 0

Each team's ball, numbered i, gets its own text (its own xi) that is seed + # + i, for example: cup quarter-final 2026 | 4 8 15 16 23 42 | 8 | 0#1 Then, we hash each ball's text, and they line up in order of f(xi), smallest first. That line is the order that the balls are 'drawn' in. Any byes needed are given to the first balls drawn, and the rest pair off.

Given that I don't know what the xs will be until the Lotto is drawn, there's no easy way for me to set the non-random inputs of the draw (like the draw name, or choosing who gets which ball) to meaningfully favour any team.3

The hash function used is called SHA-256 and is widely used to secure online banking and other websites. It produces f(x) that have about 78 decimal digits, so the values are usually written as 64 hexadecimal characters. There is no known way to steer its output, or anything to show that it has any kind of systematic bias in any direction; if such a weakness were ever found, you could wreak a lot more havoc than just fixing a cup draw.

BallTextHashDrawn
The draw

Try it. This is the real method, running in your browser, for 8 teams and no byes. Change one Lotto number by one and every hash changes, so the order is reshuffled.

Because f(x) appears random, every ball should have about the same chance of being in any particular position in the draw.

I ran the "Cup Quarter-Final 2026" draw for every one of the 45,057,474 possible Lotto results. Each square is the percentage of those draws in which that ball came out in that position. A perfectly fair shuffle would give 12.50% in every square. The small differences in the last digit are no bigger than chance alone would give.

Trust

The really nice thing about this arrangement is that nobody needs to trust anything or anyone, apart from the Lotto and SHA-256, which are beyond reasonable reproach.

I made a web page that lets anyone run the process. Now, of course, I control that page, so if I were so minded, I could surreptitiously change the process after the Lotto numbers are drawn. To guard against that, when I announce the draw by email I also give the SHA-256 value of the code that I'll use to make the draw, so anyone can check that the method hasn't changed. But you don't need my page at all: this blogpost describes the method in enough detail to write your own version, and these days you can easily get your favourite AI to write independent code to check such a draw.

This is not a new idea; the Internet Engineering Task Force have used a very similar method since 2000 to choose the members of their Nominations Committee.4

It's a lot of cryptography for very low stakes. But that's what makes it fun: you can watch the Lotto draw live and know the fixtures before I've emailed them out. And the next time someone thinks the draw is rigged, they'll have to accuse the National Lottery as well.


  1. In 2016 Sepp Blatter, by then banned from football, told the Argentine paper La Nación that he had seen European draws fixed with balls chilled beforehand, so whoever made the draw could find them by touch. UEFA called the claim "completely absurd". Nobody can prove it either way, which is the problem.↩

  2. The draw name lets the Cup and the Plate use the same Lotto draw and still come out differently. Capitals, extra spaces and the order the numbers are typed in make no difference, so nobody gets a different draw by copying the announcement slightly wrong. I also limit the draw name to plain alphanumeric characters and punctuation.↩

  3. The 45,057,474 possible results can't be shared exactly evenly between the teams, so for any draw name some outcome comes up very slightly more often than it should. Over every possible result for the example draw, the 'luckiest' ball is at home 50.008% of the time. That's about a hundredth of the bias in a tossed coin, which lands the way it started 50.8% of the time. I assign ball numbers alphabetically, so as not to give any particular team a 'lucky' or 'unlucky' ball. I could pick whichever of the few dozen reasonable names ("Cup QF", "Cup Quarter-Final", "Richardson Cup Quarter-Final"...) suited my team best, which would take a few hours of computing. That would raise my chance of drawing the weakest team from 14.29% to about 14.30%, one extra good draw in about 8,500: at a few draws a season, my cheating would pay off less than once a millennium. If this was a realistic concern, we could simply add more entropy to the mix - using both rounds of the Lotto draw, for instance.↩

  4. First as RFC 2777 in 2000, now RFC 3797. The IETF method combines three or four public sources for more entropy.↩

All news