Elysian

Provably fair

Every result is decided before you bet, from values you can check afterwards. Nothing here needs you to trust us.

  1. 1

    Commit

    Before you bet, we pick a secret server seed and show you only its SHA-256 hash. The hash locks the seed in: it can't be swapped later without the hash changing.

  2. 2

    Play

    Each bet mixes that secret with your client seed (which you can change any time) and a nonce that counts up by one per bet.

  3. 3

    Reveal

    When you rotate your seed pair, the old server seed is revealed and a new one is committed.

  4. 4

    Check

    Hash the revealed seed and compare it with the hash you saw before. Then recompute any bet with the tool below or the code at the bottom.

Verify a roll

Runs entirely in your browser with Web Crypto. Nothing you type here is sent anywhere.

How a roll is computed

  • HMAC_SHA256(key = serverSeed, message = "clientSeed:nonce:round") gives 32 bytes (round starts at 0).
  • Every 4 bytes become one number between 0 and 1: b0/256 + b1/256² + b2/256³ + b3/256⁴.
  • A bet that needs more than 8 numbers continues with round 1, 2, …
  • Cases multiply the first number by the total of all item odds and pick the item whose range it lands in.
  • Deals point the wheel at number × 360°; with N zones it wins when the fractional part of number × N is below the win chance.
  • Battles use their own server seed (revealed when the battle ends) and, as the client seed, the public drand value published after the last seat filled. Round r, seat s uses nonce r × seats + s.
  • This is the same scheme as Stake, so third-party verifiers for it work here too.

Verify it off-site

None of our code is needed. Paste this into a browser console or Node and fill in your values.

// Paste into any browser console or Node 20+. Uses only built-in Web Crypto.
const serverSeed = "revealed-server-seed";
const clientSeed = "your-client-seed";
const nonce = 0;

const enc = new TextEncoder();
const hex = (buf) => [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, "0")).join("");

console.log("hash:", hex(await crypto.subtle.digest("SHA-256", enc.encode(serverSeed))));

const key = await crypto.subtle.importKey(
  "raw", enc.encode(serverSeed), { name: "HMAC", hash: "SHA-256" }, false, ["sign"],
);
const bytes = new Uint8Array(
  await crypto.subtle.sign("HMAC", key, enc.encode(`${clientSeed}:${nonce}:0`)),
);
const floats = [];
for (let i = 0; i < 32; i += 4) {
  floats.push(bytes[i] / 256 + bytes[i + 1] / 256 ** 2 + bytes[i + 2] / 256 ** 3 + bytes[i + 3] / 256 ** 4);
}
console.log("floats:", floats);