check a proof
A grade's or a call's, here in your browser. Nothing is sent anywhere, and a saved copy works without us.
How it checks a grade
- The claim is the proof without
signatureandanchor, as canonical JSON: keys sorted, no spaces, empty fields left out. - The signature is Ed25519 over the claim's UTF-8 bytes, in base64, by the key in its
key(crayons.gg's are below). Each key's SHA-256 is also on Midnight, as a line of crayons.gg's log (below), itschallengeKeySHA-256 ofcrayons.gg proof key <key>. - The leaf is SHA-256, in hex, of the canonical JSON of
{"kind":"crayons.gg grade record","v":1,"playerId","period","grade","reachedAt","rating","calls","entryId"}, valued from the claim (playerIdis its player's id). - The path leads from the leaf to the day's root: at each step, SHA-256 of the two 32-byte hashes joined, the sibling on the side given.
- The root is a line of crayons.gg's log once that UTC day is over:
{"circuit":"sealChallenge","challengeKey","root","prev","at"}as JSON, its keys in that order, itschallengeKeySHA-256 ofcrayons.gg grades <day>. - The batch path leads from the line's SHA-256 to its batch's root, as a grade's path does. The log goes on the crayons.gg contract on Midnight in batches: each batch's root is in the contract's
sealedRootsunder SHA-256 ofcrayons.gg ledger batch <first>-<last>, its first and last line. Any Midnight indexer can confirm it. From 21 Oct the log goes on the log contract instead, whose state doesn't grow: it keeps one running head, SHA-256 of the head before a batch, its first and last line (8 bytes each, little endian) and its root, and the batches must tile the log. The proof gives the head before and after its batch; the contract's state as of the batch's block holds the head after, which any Midnight indexer can show.
How it checks a call
- The fingerprint is SHA-256 of the canonical JSON of
{"challengeId","playerId","drawing","salt","stake","sentAt"}(stakeleft out when 0;sentAt, the call'ssubmittedAt, only for rounds from 20 Oct 2026, whose id ends at 1792454400 or later). It's what was sealed when the round closed. - The round's key is SHA-256 of its id (
challengeId). - The seal path leads from the fingerprint to the round's sealed root, as a grade's path does.
- The score's leaf is SHA-256 of the canonical JSON of
{"challengeId","call","score"}(callthe fingerprint); the results path leads from it to the scores' root. - The results root is SHA-256 of the canonical JSON of
{"v":2,"challengeId","pricesHash","scores","stakes","prize"}(scoresthe scores' root;stakesandprizeleft out when there are none). - Both roots are lines of crayons.gg's log, as a grade day's root is: the sealed root's
circuitissealChallenge, the results root'spublishResults, each with the round's key. Each line goes on the crayons.gg contract on Midnight in a batch, its path to the batch's root in the proof, the batch's root insealedRootsunder its own key, as above. The player's id is sealed; their name isn't. - Before 17 Oct, on Midnight Preprod, a root went on the contract on its own, under the round's key (a results root with
publishResults). The whole record moved to Mainnet on 21 Oct, in two batches; a proof keeps its Preprod receipt asearlier, which shows when the root first reached Midnight.
crayons.gg's signing keys:
crayons.gg's contracts on Midnight: