Draw Process
At Roffle, we believe that trust is earned through transparency. We don’t expect you to just take our word for it—we’ve built a system where the fairness of every single draw can be independently verified.
The Participant List
Before any winner is chosen, Roffle generates a final, digitally signed list of every valid ticket entered into the draw. This list is "frozen" and made available for public view on the specific Roffle listing page. This ensures that no tickets can be added or removed once the "countdown" to the draw has begun.
Provable Randomness
We don’t use internal "random number generators" that could be biased. Instead, we use Drand, a distributed, public randomness beacon.
- Drand is not affiliated with Roffle; it is a global network that generates a new random number every 30 seconds.
- Because the number is generated by a distributed network, no one—including the Roffle team—can predict or influence the outcome.
- We assign a specific future "round" of Drand to each Roffle. The winner is decided by the number generated at that exact moment.
The Winner Selection
Once the Drand number is generated, our public algorithm uses it to select a winning index from the sorted list of participants.
- Because the participant list and the Drand number are both public, the result is transparent and can be checked by anyone.
- Every ticket has an equal mathematical chance of being selected based on the total number of entries in the list.
Finalising the Result
The draw happens in the afternoon on the first working day after entries close.
- This window allows our team to scan any final postcards that arrived in the morning mail to ensure every valid entry is included in the final participant list.
- Winners are notified immediately via email and have 7 days to claim their prize.
The Algorithm
- Roffle hosts its public key at /public-key path
- An hour before the draw, Roffle releases a digitally signed list of all participating tickets at <draw url>/participants, referred to as Participants
- a link to this list will appear on a product page when it becomes available
- the signature of this list is sent to all participants via email
- the signature can be verified using Roffle public key and standard Ed25519 algorithm
- list contains ordered tickets, along with anonymized IDs of their owners
- list also contains details of the draw: exact date, drand chain, public keys used for verification and some other metadata
- there is no difference between paid and free entries; the list does not disclose the type of each ticket
- After Participants list is generated, Roffle may create ticket list revocations, referred to as Updates, in a similar format (public signed document). These state which tickets, and for what reason, are revoked
- Roffle does not send out emails for every Update, as that could be considered spam
- note that these revocations can happen even after the draw, and may trigger redraws if they happen to revoke a winning ticket.
- each Update specifies its own Round number, independent of the original draw
- Updates are released at least one hour before their respective Rounds
- they are available on the same page as the original Participant list
- At the time of draw, drand generates a random number, referred to as Round
- drand is not affiliated with Roffle, and is as independent and random as it gets
- Round numbers are generated both for original Participants, as well as future Updates
- The draw results can be calculated using Rounds, Participants and Updates with the following algorithm:
- verify the signature of Participants, all available Updates and all generated drand Rounds
- verification of Participants and Updates uses Ed25519 as described above
- verification of drand Rounds is more complex and beyond the scope of this document
- sort all tickets by their number, ascending (i.e. #1 goes before #2), further reffered to as List
- for each prize in the draw:
- count tickets in the List as Count
- prepare Info bytes by concatenating Count as 32-bit unsigned integer (4 bytes), and roffleId parameter encoded with UTF8
- calculate Result as 64 bytes of HKDF-SHA512 with the Round as input key material (64 bytes), empty salt, and the above Info as info parameter
- calculate Index as Result modulo Count (simple math, although on a very large number)
- remainder bias is ignored as it's astronomically small and doesn't justify complicating the algorithm
- find the ticket at the Index position in the sorted List - this is the winning ticket
- remove from the List all tickets belonging to the same owner (i.e. having the same anonymous ID) as the winning ticket, including the winning ticket
- repeat these steps for the next prize draw, if any
- once all prizes from the original Participant list are drawn, for each ticket revocation Update available:
- remove all revoked tickets from the List
- if this removes a winning ticket, immediately draw another prize using instructions in 5.3 and Round specified in the Update
- note that it's not necessary to wait for drand Round of an Update when it doesn't revoke any winning tickets
- also note that this step is allowed to select a ticket that will get immediately revoked by some future Update
- the drawn prizes become final when they are delivered to the winners, as it's no longer possible to revoke any of them at this point
- verify the signature of Participants, all available Updates and all generated drand Rounds