Skip to main content
Prizerail never picks who wins, only what each winner gets. The partner’s list is locked before the random value exists, and each prize follows from the two by a fixed formula.

The steps

  1. The partner sends the winners. Until the cutoff, a few minutes before the draw, the list can change.
  2. The list locks. At the cutoff, Prizerail records a fingerprint of the list, a hash of every winner in order. From then on the list can’t change without the fingerprint changing.
  3. A random value is drawn. Only after the lock is a random value requested from a source Prizerail doesn’t control.
  4. Each winner rolls. Each winner’s roll comes from the random value, the campaign, the draw’s number and the winner’s position in the list. The roll picks a prize from the campaign’s prize table.
  5. The proof is published, with every input and result.

The formulas

These are the same formulas the Prizerail contract runs onchain. The hashes are keccak256, as Ethereum and Solidity use it, over Solidity’s abi.encode of the values. Each winner is hashed on its own, and the winner list fingerprint covers those hashes in position order:
Each winner at position i (0 for the first) gets a random value and a roll from 0 to one less than the prize table’s total rolls. campaignId is the campaign’s ID (on its page and in the proof) as ASCII padded to 32 bytes, and drawingId is the draw’s number:
k starts at 0. A random value below 2^256 mod denominator is discarded and k goes up by one, which keeps every roll exactly as likely as any other. It almost never happens, but a check has to do the same. The roll’s run in the prize table is the prize. With the default table, a roll of 3,000 falls in 411 to 4,410, so that winner gets 20.AmountsintheproofareUScents,so‘2000‘is20. Amounts in the proof are US cents, so `2000` is 20.

Gotchas

  • Order matters. The fingerprint hashes the winners in position order, 0 first. Sorting them changes it.
  • Rolls start at 0 and run to one less than the total.
  • Tiers run top prize first. The biggest prize owns the lowest rolls, and the proof lists tiers in that order with each one’s threshold.
  • The winner’s id isn’t in the random value. It’s in the fingerprint, which is locked before the random value exists, so the same winner listed twice still gets two separate rolls.
  • Python’s hashlib.sha3_256 isn’t keccak256. They pad differently, so a check written with it always fails.