How Verifiable Giveaways Work

PrizePixie uses cryptographically verifiable randomness to ensure fair and transparent giveaways. Anyone can independently verify the results.

Publicly Verifiable

Anyone can verify the draw results using publicly available data

Tamper-Proof

Uses cryptographic hashing to ensure results cannot be manipulated

Distributed Randomness

Powered by drand, a public randomness beacon trusted worldwide

What are Verifiable Giveaways?

A verifiable giveaway is one where the winner selection process is completely transparent and can be independently verified. Instead of relying on trust, mathematical proof ensures fairness.

Think of it like a lottery where everyone can watch the balls being drawn, and anyone with a calculator can verify the results afterwards. For PrizePixie, the "balls being drawn" means getting an external random number from a randomness beacon called drand . These numbers are generated every three seconds and are completely unpredictable.

How It Works

A verifiable giveaway draw is based on cryptographic hashing , which can be used take any input and turn it into an essentially random output. However, each input will always produce the same output, which is what makes it verifiable. Here is the overall process:

  1. Fetch the public randomness from drand
  2. Compute the draw_seed, which is done by hashing the bot's name, the giveaway ID, and the drand randomness together
  3. Sort all participants by the time they joined the giveaway
  4. For each, compute a ticket_hash which is the hash of the draw_seed and the ticket number
  5. Sort all participants by their ticket hash
  6. Winners are the people with the lowest ticket hashes

The key insight: because everything is deterministic and based on publicly known data, anyone can reproduce the exact same results.

Technical Details

The following sections explain the algorithm technically.

0. Conventions

In the sections below, the following conventions are used:

  • H(x) is the 256-bit Blake2s  hash function of the input, returned as 64-character lower-case hexadecimal
  • The character + (plus sign) denoted string concatenation rather than arithmetic addition

1. Randomness from drand

drand  is a public randomness beacon operated by the League of Entropy , a collective of organizations maintaining a network that produces independant random numbers. PrizePixie uses the chain quicknet , which produces a new 256-bit random number every three seconds. The latest round can be found here .

When a giveaway ends, PrizePixie waits for the first round from drand at or after the giveaway's end time. For example, if a giveaway ended on 2026-05-19 05:57:03.097 UTC, the first round after that would be 28788954 , published at time 2026-05-19 05:57:06 UTC, with randomness 4da0767b3dc8ac91596db0de37a59bed660cd97acf55eb2e8bb856f3453ece0e.

2. Draw Seed

The draw seed is calculated using: H( H("PrizePixie") + H(giveaway_id) + H(drand_randomness) ).

Components:

  • H("PrizePixie"): Constant for all draws
  • H(giveaway_id): Unique per giveaway, generated by the server when the giveaway was first created. This ensures multiple giveaways ending at the same time will produce different results
  • H(drand_randomness): The published and verifiable randomness value from drand

Using the giveaway e47b686958a0e719  as an example, the calculation would be:
draw_seed = H( H("PrizePixie") + H("e47b686958a0e719") + H("4da0767b3dc8ac91596db0de37a59bed660cd97acf55eb2e8bb856f3453ece0e") )

Substituting in the intermediate hashes:
draw_seed = H( "33c0dec9e1d518c0ec1181e43a4efee4f0049123f083543deb7e0e23f5c9d844" + "4400cfa6da31768ccc699b0a0a371bc1a2fb50d8ef87fa7470c63211fa26e845" + "7b9312a935d0f4e249fa0abbdd557554506584c19fe53eda5fea5b6c42254c3e" )

And finally:
draw_seed = "66e710c4abd2aa57a7cb0a98cc74ecfb2be92c7ed48d5479412d9c77e4218f7f"

Prize Pixie exposes this information as a verifiable record  on its API.

3. Participant Ordering

Participants are sorted deterministically in this order to ensure the same arrangement every time:

  1. Primary: Entry time (join order)
  2. Secondary: Member name (alphabetical)
  3. Tertiary: Discord User ID (numeric)

It should be noted here that PrizePixie uses microsecond timestamps, so anything other than the primary ordering is unlikely to ever be used.

4. Ticket Hashes

Each participant is assigned a sequential ticket number (0, 1, 2, ...) based on their sorted position. This ticket number is then hashed with the draw seed to create their final ticket hash:

ticket_hash = H( draw_seed + H(ticket_number) )

For example, in our example we had five participants. The ticket hashes would be:

  • Ticket 0: 0c230d48bb1a9d369f207596d5c874dbb8616dab74eeaba16f870da1518b7c23
  • Ticket 1: 899ab8df0ab9b4050506df03ffccf32b27528d328158fa72566cb03607ccf1a9
  • Ticket 2: e473a3bb388dc35779e49adcc95947adb5cee2b6fb666ccea95e85279307cae6
  • Ticket 3: ed247e4cbc2b95d5eb75c01ec024df958a6390e18c2ac63bbba54243f7d53e73
  • Ticket 4: 8bbc4c2de5ba41ad3a62bd2b63466db80e0cbdc3a99955ced5a10623fa3e5645

Prize Pixie exposes ticket hashes for winners  on its API.

5. Winner Selection

After calculating all ticket hashes, they are sorted in ascending order. The winners are the N participants with the lowest hash values.

In the above example, the winning tickets would be 0, 1, 4, 2, and finally 3.

External Resources