> ## Documentation Index
> Fetch the complete documentation index at: https://docs.prizerail.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How a draw is decided

> How the winner list, the random value and a fixed formula decide every prize, so nobody can pick who wins what.

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:

```
winnerHash  = keccak256(bytes(winner))
fingerprint = keccak256(abi.encode(bytes32[] winnerHashes))
```

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:

```
randomValue = keccak256(abi.encode(bytes32 entropy, bytes32 campaignId,
                                   uint64 drawingId, uint256 i, uint256 k))
roll        = randomValue mod denominator
```

`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](/campaigns/prize-tables) is the prize. With the default table, a roll of 3,000 falls in 411 to 4,410, so that winner gets $20. 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.