Public verification of the giveaway
The short version, no fluff
Winners are picked 100% at random and the result is verifiable by anyone. You don't have to trust us: below we explain why we couldn't cheat even if we wanted to.
1 · Every ticket has its number
When you participate you get numbered tickets. Before the draw we publish the full list of numbers, like showing all the balls before spinning the drum.
2 · We don't provide the randomness
The "lucky number" is emitted by drand, a public random-number lottery of the internet (run by Cloudflare, universities and others). Nobody can predict or change it: not us, not you, nobody. Winners come from there.
3 · You can check it yourself
Everything is published forever. With one click, your own browser redoes the math and shows you the result is exactly what it had to be, without trusting our server.
For nerds: the raw data
Target drand round, SHA-256 fingerprint of the snapshot, the exact formula, the complete k-sequence history, a WebCrypto verifier in your browser, a Python snippet and the public verification API.
Giveaway data
01 · FROZEN LIST
Before the draw we publish the 5696 tickets, the prizes and their digital fingerprint (SHA-256). Nothing can be changed without being noticed.
02 · PUBLIC RANDOMNESS
The randomness comes from drand target round, a public randomness beacon; nobody (including us) can predict or manipulate it.
03 · ONE SPOT PER ROLL
ids[sha256(hash:k) mod N] repeats with k=0,1,2… filling the 20 spots in tier order. Repeated ones are skipped and recorded.
Snapshot fingerprint: published when the list is frozen
Number of round target: not emitted yet
The verifier becomes available once the snapshot is frozen and the target drand round is emitted.
Or by hand, with Python
It verifies the snapshot checksum, that the number used is EXACTLY the one published by the drand beacon, and that EVERY published iteration k comes from that number. Skips (already-awarded participant) are declared with their reason in the same API.
import hashlib, json, urllib.request
data = json.load(urllib.request.urlopen("https://sorteos.holy.gg/api/public/verificacion"))
ids = data["snapshot"]["entryIds"]
seed = data["giveaway"]["drandRandomness"] # numero aleatorio publico de drand
# 1) checksum == sha256(snapshot)
canon = json.dumps(ids, separators=(",", ":")).encode()
assert hashlib.sha256(canon).hexdigest() == data["snapshot"]["checksumSha256"]
# 2) el numero es EXACTAMENTE el que publico el faro drand (no lo pusimos nosotros)
chain = data["giveaway"]["drandChain"]
rnd = data["giveaway"]["drandRound"]
beacon = json.load(urllib.request.urlopen(f"https://api.drand.sh/{chain}/public/{rnd}"))
assert beacon["randomness"] == seed, "el seed no coincide con drand"
# 3) k -> ids[sha256(seed:k) mod N]
for r in data["rolls"]:
d = hashlib.sha256(f"{seed}:{r['k']}".encode()).hexdigest()
assert ids[int(d, 16) % len(ids)] == r["entryId"], f"k={r['k']} mismatch"
print("OK")
for r in data["rolls"]:
lot = r.get("prizeLot") or {}
seat = f"{lot.get('label')} · lugar {r['seatIndex']}" if r.get("seatIndex") else ""
print(r["k"], r["entryId"], r["status"], seat, r.get("reason") or "")Questions about the process? Write to us on the Discord · Back to the giveaway