Provably Fair

How Ticket Clash is Fair

Every raffle result on Ticket Clash is determined by a seeded pseudo-random number generator. The seed is recorded on-chain at lock time, and every shuffle and match can be independently reproduced by anyone with the seed โ€” including you.

Step-by-step: how a raffle resolves

  1. 01

    Registration closes

    When the countdown hits zero, registration is locked. No new tickets can enter. The final list of ticket IDs is frozen.

  2. 02

    Seed is generated

    A seed is derived from the current Unix timestamp at the moment of execution. This value is immediately written to the database โ€” it cannot be changed after the fact.

  3. 03

    Tickets are shuffled

    The full list of ticket IDs is shuffled using Fisher-Yates with the seeded RNG. This determines the bracket order.

  4. 04

    Bracket rounds run

    Shuffled tickets are paired up. Each pair has a winner selected by the RNG. Unpaired tickets (odd counts) get a free bye to the next round. This repeats until one ticket remains.

  5. 05

    Results are stored

    Every round, every match, and every outcome is stored immutably in the database. The winner, 2nd and 3rd place are recorded.

The RNG algorithm

We use Mulberry32, a well-known, fast, and statistically high-quality 32-bit seeded PRNG. Given the same seed, it always produces the exact same sequence of numbers โ€” making every shuffle and match outcome fully reproducible.

function seedRng(seed: number) {
  let s = seed;
  return () => {
    s |= 0;
    s = (s + 0x6d2b79f5) | 0;
    let t = Math.imul(s ^ (s >>> 15), 1 | s);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

The Fisher-Yates shuffle ensures every permutation of tickets is equally likely:

function shuffle(arr, rng) {
  const a = [...arr];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(rng() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

Verify any result yourself

Every finished raffle exposes its seed in the results page. You can copy the seed and the list of ticket IDs, then run the same Mulberry32 + Fisher-Yates shuffle locally to confirm the bracket matches what we recorded. No trust required.

What you need to reproduce a result:

  • The raffle's seed (shown on each finished raffle)
  • The ordered list of ticket IDs as stored at lock time
  • The Mulberry32 + Fisher-Yates code above (copy-paste into any JS console)

What we cannot do

๐ŸšซChange a seed after registration closes
๐ŸšซAdd or remove tickets after lock
๐ŸšซRe-run a raffle with a different outcome
๐ŸšซSelect a winner manually
Questions? Reach us at hello@ticketclash.io or visit our About page.