Hermes Games

Fairness

The bot rolls the dice, so you have every reason to want proof rather than a promise. Here is the proof, and how to check it without trusting us.

What is actually in doubt

Not the quality of the random numbers. They come from the operating system's cryptographic source, and we measure them: a million rolls of 1–100 land exactly where a fair die lands, neither player in a duel wins more often than the other, and no roll gives away the next.

The real question is different, and fair to ask of any bot: could whoever runs it make it roll a 1 for you? Measurements cannot answer that. A rigged bot would post the same cards as an honest one. So every game of chance here commits to its numbers before they are known, and publishes the secret behind them afterwards.

How a game is played, from the proof's point of view

  1. Before play, the bot commits. It draws a secret, and posts a fingerprint of it — a SHA-256 hash — on the challenge card, below the buttons, before anybody has accepted. The numbers are fixed from that moment, though nobody can read them yet.
  2. You contribute. When a player accepts, their click supplies a second value, published on the next card. The bot could not have known it when it committed — which is what stops it drawing secrets over and over until one pays out.
  3. Every number carries its range, and its place in the order. Each roll is sealed into the channel showing what it was rolled from — rolled between 1–42 — and they appear in the order they were drawn, so the first is draw 1. The proof panel says how many draws there were, so a number generated and quietly thrown away would leave the count higher than the rolls you can count.
  4. When the game ends, the secret is published. Every ending — someone wins, a challenge is declined, an organizer clears a stuck game. Anyone can now hash the secret, compare it with the fingerprint posted before play, and recompute every roll.

A plain roll

/roll dice and /roll dice max:48484 are one instant each — there is no challenge card to commit on before anybody plays. So each roll's card carries the fingerprint for the next roll in that channel, under next roll here. When somebody rolls, the bot uses that secret, takes the id of their /roll dice as the player seed, draws one number from 1 to the max, and publishes the secret on the new card.

To check one, follow the link on its card to the card before it. The fingerprint printed there must match the hash of the secret this card reveals, and it must have been posted before this roll — Discord's own timestamps say so. The number is draw 1, over 1 to the max printed beside it.

The first roll in a channel cannot be checked, because no card came before it. Its card says so instead of showing a link, and so does any roll whose card-before landed after the roller pressed. A raffle host who wants every roll provable can make one throwaway roll first.

The method, in full

Published because a proof you can only check on our website is not a proof. Each number is:

block(n, c) = HMAC-SHA256(key = secret,
                          message = "<game>:<code>:<player seed>:<n>:<c>")

value(n)    = walk block(n, 0) four bytes at a time, big-endian, then block(n, 1), …
              take the first word below floor(2^32 / range) * range
              value = (word mod range) + min

n is the draw number and range is max - min + 1 for the range printed beside the roll. The rejection step — skipping words at or above that limit — is what keeps the result even; reducing a 32-bit number into a range that does not divide it would quietly favour the low end.

Checking a game yourself

Every result card carries a 🔒 Provably fair button. Press it and the bot shows you — privately — the commitment, your seed, the revealed secret and the commands below. /verify code:K4M2QP prints the same thing for any game, at any time.

If you would rather not take the bot's word for its own arithmetic, these are the two commands, and they need nothing but OpenSSL:

# 1. does the secret match the fingerprint posted before play?
printf '%s' "$SECRET" | openssl dgst -sha256

# 2. does draw #1 follow from it? (range 1-100, as printed beside the roll)
printf '%s' "deathroll:K4M2QP:<player seed>:1:0" \
  | openssl dgst -sha256 -mac HMAC -macopt hexkey:"$SECRET"

Take the first four-byte group of that output, read as a big-endian number. If it is below floor(2^32 / 100) * 100, then (word mod 100) + 1 is the roll. Otherwise skip to the next four bytes.

What this proves, and what it does not

ProvesDoes not prove
The numbers came from a secret fixed before anyone knew the outcome. That the game is a good bet. That is what the odds below are for.
No roll was swapped, and none was generated and discarded. That the operator is honest in every other way — they can still refuse to run games, or switch the bot off. That is visible, at least.
The player's contribution was fixed before any roll was made. Anything about a game that never finished. An unpublished secret proves nothing, which is why unfinished games are counted openly.

The odds, published

Death Roll is not a symmetric game, and pretending otherwise would be its own kind of dishonesty. The player who rolls first is more likely to lose, because they face the full range before it collapses:

Starting numberChance the first roller loses
266.7%
652.4%
100 (the default)50.01%
100050.0001%

Which is exactly why the order is drawn rather than given to the challenger: both players get the same coin flip for a seat that is not equal. Win the roll-off and you have, very slightly, drawn the short straw.

Games nobody finishes

A duel with no roll for a day is closed by the bot. Nothing settles — no score moves, no result is recorded against anyone — but the secret is published, so the rolls that did happen can still be checked. A challenge nobody accepts is closed the same way.

This exists because of the promise above: a game that hung open forever would be one whose secret was never published, and "every game can be checked" would quietly stop being true. Walking away from a duel costs you nothing here — it simply cannot leave an unfinished proof behind.

Games played before this existed

They have no commitment and cannot be checked. Nothing is being hidden — there is simply nothing to check, and claiming otherwise would be the exact dishonesty this page exists to avoid.