Fairness

Fixed before the bet. Checkable for years.

The seed is sealed before your first spin and published after your last, and every round can be reproduced draw for draw. Twenty-five statistical tests run on the source with every p-value printed, and a second engine, written separately, can contradict the first.

Draws tested
119,991,413

25 tests, at every range the games draw from

Raw words, per seed
2,000,000,000

two independent seeds, through dieharder, NIST STS and TestU01

Rounds replayed from a seed
9,000

identical every time, whatever the theme, language, turbo or autoplay setting

Laboratory certificates
0

in any environment. No laboratory has been engaged yet.

A player cannot audit a slot game, and neither can most of the people who regulate one. What they can check is that the outcome was fixed before the bet was placed, that the source it was drawn from behaves like a random one, and that the game which produced it is the game that was tested. This page shows how to check each of those without taking our word for it.

Every figure below is read from an artefact a run wrote: the generator's own battery, each game's evidence pack and the published API contract. Two things are entered by hand instead: the external suite results and the list of games a second engine covers. Both say so where they appear.

A round is sealed, played, opened and then kept

The commitment is a sequence of events, shown here in order. Each stage names the API call that performs it and what you hold afterwards: the hash before anybody has bet, and the seed only once nobody can bet again.

  1. Before the first bet

    The seed is sealed

    The commitment. The seed itself is revealed only at session close.

    POST /v1/session/open → serverSeedHash

    You now hold a sha256 of a 32-byte number nobody has shown you

  2. Every round, for as long as you play

    Every draw comes off that seed

    Resolving a round touches no clock, no global, no file and no network. The only source of randomness is the stream derived from the committed seed, and the round records how many draws it consumed.

    POST /v1/round/bet → events[], and drawsConsumed on the round

    You now hold the result, and the count of draws behind it

  3. When you stop

    The seed is published

    The other half of the commitment. The server seed is published here and never before. Once it is out, the session cannot resolve another round: an outcome derived from a seed the player holds would let them see the result before betting on it.

    POST /v1/session/close → serverSeed

    You now hold the number the hash was a hash of

  4. Afterwards, for years

    The round is still reproducible

    Recall hands back the tail of each round's events and, with them, the fairness block: { serverSeedHash, serverSeed, clientSeed, nonce, drawsConsumed }. It is scoped to the session token, so a player can reach their own rounds and nobody else's.

    GET /v1/round/recall → { serverSeedHash, serverSeed, clientSeed, nonce, drawsConsumed }

    You now hold everything needed to re-derive the round without us

Construction
HMAC-SHA256(key = 32-byte server seed, message = `${clientSeed}:${nonce}:${cursor}`), consumed four bytes at a time as a big-endian uint32.
Seeding
The server seed is 32 bytes from the OS CSPRNG at session open. sha256(serverSeed) is published to the player before any bet and the seed itself is revealed only at session close, so the outcome sequence is committed in advance and cannot be altered afterwards.
Generator source, hashed
24a4a27980747c528315360fd7cce4765e58f5e2c04c7c1c1d24bcbbee1f4a33

Try it: the seed decides the board

Type anything and deal. Deal it again and the board is identical, symbol for symbol. Change one character and it is a different board. This is why any round can be replayed from its seed, years later.

Deal the same seed twice: the same board. Change one character: a different one.

SHA-256not dealt yet

This illustrates the idea. It is not the game’s own deal: each cell is one byte of the seed’s SHA-256, reduced over eight symbols, and eight divides 256 exactly, so no symbol is favoured. The certified game draws from the stream in our generator specification and reads weighted reel strips. What it shares with this demo is the property you just watched.

Check it yourself, in four steps

Four calls and one keyed hash. You need no account beyond the session you already have, and nothing from us beyond the endpoints already in the API contract.

  1. Keep the hash you were handed at open

    It arrives in the session's first response, before any bet is possible. Write it down: everything after this is checked against it.

    serverSeedHash · sha256 hex

  2. Play, then ask what was recorded

    Recall returns the tail of each round's events plus the fairness block: the hash, the client seed, the nonce and the number of draws the round consumed.

    GET /v1/round/recall

  3. Close the session and take the seed

    The seed is released here and never earlier. After that, the server refuses to resolve another round in the session, because an outcome derived from a seed the player holds would let them see the result before betting on it.

    POST /v1/session/close → serverSeed

  4. Re-derive every draw and compare

    Hash the seed and check it against step one. Then, from cursor zero, keep the 32 bytes the HMAC gives you, read them four at a time as big-endian uint32s, rejection-sample each onto the range it is for, and advance the cursor when the block runs out. You should reproduce the round exactly, draw count included.

    HMAC-SHA256(serverSeed, `${clientSeed}:${nonce}:${cursor}`)

The hash a player compares against is recomputed from the seed the server holds instead of being read back from a column stored beside it, so it can only be the hash of that seed. It is one line in the recall path, and without it the commitment would be two fields that happen to sit side by side.

A draw is thrown away rather than folded

A 32-bit word has to become a position on a reel strip, and the obvious way to do that biases the game. Of the 20 ranges these games draw from, 18 do not divide 2³² evenly. With a plain remainder, those 18 would carry a permanent bias in one direction, and it would land directly on the certified return.

With a remainder operator: what this generator never does

  • 21,475 chances each, on 83.6% of the reel
  • 21,474 chances each, on the rest

167,296 of this game’s 200,000 strip positions (83.6% of the reel) would come up 0.0047% more often than the rest. That bias would be permanent and always in one direction, on a figure certified to ±0.10 percentage points.

With rejection sampling: what every draw in every game goes through

  • 21,474 chances each, for every position

Any word at or above 4,294,800,000 is discarded and the draw is taken again, so every position has exactly 21,474 of the 4,294,967,296 words behind it. The only cost is that 0.0039% of draws are thrown away.

Both bars show the same reel: 200,000 strip positions, the longest range any of these games draws from. The bias a remainder operator leaves is tiny, but it is systematic, permanent and always in one direction. The problem is not its size: any size would need defending, and discarding the tail leaves nothing to defend. The battery below still measures every range for uniformity, because a correct design and a correct implementation are separate claims.

25 tests, and every p-value printed

119,991,413 draws from the real generator (not a simulation generator) at every range the games use, in 59 seconds of wall-clock time. The range list comes from the frozen specification of every registered game, so each new game's ranges join the battery.

Uniformity at every range a game draws from, each row labelled with its range

  1. 20.332
  2. 40.230
  3. 50.976
  4. 70.173
  5. 370.856
  6. 1000.270
  7. 2400.520
  8. 9720.746
  9. 1,0000.016
  10. 8,3070.584
  11. 9,3500.418
  12. 9,9310.291
  13. 10,0000.270
  14. 10,0010.459
  15. 10,0070.878
  16. 86,5000.311
  17. 100,0000.684
  18. 200,0000.912
  19. 1,000,0000.616
  20. 4,294,967,2950.648

Order and dependence: the tests that are not about uniformity

  1. serial pairs0.245
  2. runs up down0.613
  3. gap0.732
  4. poker0.081
  5. serial correlation0.553

A p-value near 1 is no better than one near 0.5. On a sound source each of these is uniformly distributed between 0 and 1, so the picture to distrust is 25 marks bunched in the middle. That pattern points to a generator someone has tuned, or to a harness measuring itself. The lowest here is 0.0161 (uniformity of nextInt(1000)), the highest 0.9756 (uniformity of nextInt(5)), and no test recorded a hard failure.

Three external suites on two seeds, with the failure left in

Our own battery is in-house. Ksa KS.09.12, mandatory since 1 October 2024, asks for DIEHARD and (NIST STS or TestU01) over at least a million outcomes, so all three tools were run against the production stream on two independent server seeds.

Two independent server seeds, judged separately
ToolWhich limb of the clauseSeed ASeed B
dieharder 3.31.1Limb 1: DIEHARD, mandatoryPASSED97 instances, rewind-free, none weak and none failedWEAK17 passed, 1 weak, 0 failed
NIST STS 2.1.2Limb 2: either this or TestU01FAILED187 of 188 instances in bounds, read strictlyPASSED188 of 188
TestU01Limb 2: either this or NISTPASSEDevery battery in boundsPASSEDevery battery in bounds

The input is 2,000,000,000 words per seed: 32-bit words, big-endian, straight out of the production RandomStream before any scaling. The dump ships with its own reproduction manifest (server seed, client seed, the file's sha256, and the sha256 of the generator source), so a test house can run its own copies of these tools on the same bytes. The clause is a conjunction, composed across runs: limb 2 is met by either tool, and TestU01 passes on both seeds.

One NIST instance out of 188 fell outside its band, and we report it as FAILED

NIST judges each instance against a three-sigma band at α = 0.01, so about 0.27% of instances land outside it on a flawless source. Seed A ran 188 instances: 0.5 out-of-bounds results expected, 1 observed. Seed B ran 188 and observed none. Across both seeds that is 1 in 376 against 1.0 expected.

That is not a defect, and we do not report it as one. It is also not ours to call acceptable, so the harness reports the strict reading of volledig succesvol doorloopt and names the failing instance with its proportion. A laboratory can make the call from the arithmetic. The same rule covers seed B’s single dieharder WEAK: 18 instances, one p-value in the tail, exactly as often as chance produces one.

Nothing but the draws and the certified maths

A round from two years ago can be replayed because the game logic is pure, and purity can be lost without anyone noticing. So every certified rung replays a few thousand of its own rounds from their seeds and checks that nothing else changes the result.

Farmyard Heistrtp9658v2

5,000

5,000 rounds across base, ante and the bought feature, replayed from their seeds:

  • identical on replay: all
  • unchanged by configuration (theme, language, turbo, autoplay): all
  • payout proportional to stake at 10x, within the carried sub-unit remainder: all (worst gap 9 minor units)

The engine's play() takes every draw from the stream it is handed and reads no clock, no global and no I/O, which is why replay is possible at all; these runs are the check that it stayed true.

Ultimate Coin Minerrtp9560

4,000

4,000 rounds across the base game and both buys, replayed from their seeds:

  • identical on replay: all
  • unchanged by configuration (theme, language, turbo, autoplay): all
  • payout proportional to stake at 10x, within the carried sub-unit remainder: all (worst gap 9 minor units)
  • identical on a warm engine and a cold one, so the shared scratch context carries nothing between rounds: all 500

The engine's play() takes every draw from the RandomStream it is handed and reads no clock, no global and no I/O.

What is assertedFarmyard HeistUltimate Coin MinerGate
The random source passes every statistical test at every range the game draws fromMetMetrng.battery
Any past round can be reconstructed exactly from its seedMetMetengine.replay
The outcome depends on the draws and the certified maths, and on nothing elseMetMetengine.no-adaptive-behaviour

Three blocking gates, in every pack. The third is the one an operator’s compliance officer cares about most: the outcome depends on the draws and the certified maths and nothing else. The theme, the language, turbo, autoplay, the stake, the balance and a warm or cold engine make no difference. Horizon Rescue, Sleep Tight are published with their packs but have no gate-level artefact yet, so they have no column here and are not shown as passing.

A second engine, and it is allowed to say no

Written from the specification by somebody not allowed to read the first implementation, with its own generator and no shared code. It covers 1 of the 4 games published here, listed by name below.

Measuring a game with the code that implements it proves that the code agrees with itself. So there is a second implementation, with its own generator and its own resolvers, written from the specification by somebody who has not read the first one and sharing no code with it. It measures the same game and files a report that says AGREE or names the disagreement.

A published evidence pack without a fresh, complete, agreeing report beside it fails our own merge gate, and a report covering fewer than two million rounds per mode cannot count as VERIFIED, whatever it found. This is a check that stops the work. We added it because the earlier version had none: two long-standing reports said AGREE, but one had compared one mode of six and the other one mode of three.

It has already earned its place. The second engine found a prize that the paytable, the rules text and the served description all called 5,000× paying 705.03×, because the value overflowed the field that held it. The wrapped number was positive and under the round cap, so nothing crashed and the return looked plausible.

  • Farmyard HeistA second engine measures this one
  • Ultimate Coin MinerWithdrawn when the game changed
  • Horizon RescueNo second engine yet
  • Sleep TightNo second engine yet

One of them was withdrawn rather than repaired

Ultimate Coin Miner’s second engine exists. When that game’s feature model changed, we did not touch a line of the second engine’s maths: patching it to match the new resolver would have destroyed its independence while still letting it report agreement. We took the game off the covered list instead, and its pack states that no second engine covers it.

What is missing is a person who has not read the new resolver and can re-derive it. Closing that gap needs a hire.

Is the game the one that was tested?

A fair generator inside an unapproved build proves nothing. These are the four questions a sceptical reader asks next, in the order they ask them.

  1. Is this build the approved build?

    Every file that can change an outcome is hashed into a release manifest. The server re-hashes them at boot and every 24 hours and appends the result to a log with update and delete triggers on it, so the log cannot be tidied up afterwards. Sourcemaps are inside the tree hash too, because every excluded file is a place a tampered one could hide.

  2. Can an auditor check it without an account?

    Yes. GET /v1/verification takes no credential at all: it returns what the control program hashes to, component by component, with the clock skew beside it (GLI-19 §2.3.2 · §B.2.6). A regulator should not need a login from us to ask that, and every request is logged.

  3. What happens on a mismatch?

    The check answers 500 and raises an indication, and the server keeps serving. We chose this on purpose: a mismatch is far more often a botched deploy than an attack, and halting the server over one would hand anybody who can touch a single file a server-wide kill switch. The deliberate kill switch is a row in the database that a person turns.

  4. Can the maths change without anyone noticing?

    Each game's maths is hashed into a lock file, and so is every resolver underneath it. An edit without a deliberate re-lock, with a stated reason, fails the build, and every figure derived from that maths is re-checked against its hash on every run of the merge gate.

The free demo has to tell the truth as well

GLI-19 §4.9.1(a): free play must accurately represent the paid game and must not mislead about the likelihood of winning. That is harder than it sounds. We failed it once, and every gate stayed green while we did.

What went wrong

The pool advertised a return no session could reach

The demo replays recorded rounds of the same certified maths, and the whole pool did return what the chip beside the balance said. But every cabinet started the cycle at index 0, and on the flagship’s base pool the single largest win sits at index 768 of 900 carrying 27% of the payout. Replayed from the start, the realised return was 65.6% at 50 spins and 76.4% at 300. Nobody plays 900 demo spins.

Fixed by a uniform cyclic rotation per mode. With a random offset, the expected win over any n consecutive rounds equals n × the pool mean, so the advertised figure holds at every session length and not only over the full pool.

What it is now

And it is still reproducible

A demo you cannot reproduce is one you cannot file a bug against. So every load draws a seed and prints it, and ?demoseed= replays that rotation exactly. The old fixed start could only ever reproduce the first session of a run. No money goes into a demo and none comes out.

A shuffle would fix the average too, and we don't use one: the pools were recorded to carry real run structure, and a rotation keeps every adjacency except the one at the seam.

What has happened, and what has not

In the order it happens. The two steps that are not done are not engineering problems.

  1. Done
    The generator, specified to be read clean-roomthe play-time stream, each game's own HMAC domain with test vectors, the keyed strip permutation, the separate simulation generator that never plays a real round, and an explicit statement of what the construction is not
  2. Done
    Our own battery, at every range the games draw25 tests, 119,991,413 draws, every p-value published above
  3. Done
    Three external suites, on two seeds2,000,000,000 raw words per seed through dieharder, NIST STS and TestU01, with the strict verdicts and the one out-of-band instance reported as found
  4. Done
    Replay and no-adaptive-behaviour, per rung9,000 rounds replayed from their seeds across the published games, each one unaffected by theme, language, turbo, autoplay or stake
  5. Next
    A second engine on every game1 of 4 today. Each missing one needs an author who has not read that game's resolver
  6. Next
    A laboratory engagementthe dossier is assembled and no laboratory has been engaged yet. This needs a purchase order, not engineering
  7. Then
    A market certificate, per jurisdictionfour to eight weeks after the submission, and the only thing between here and a real-money launch

Every figure above is our own measurement, written by the run that produced it.

No laboratory has certified any of this

Every mechanism above is built and running. None of it has been tested by GLI, BMM, eCOGRA or iTech Labs, because no laboratory has been engaged yet. No build holds a market certificate in any environment, and the server refuses a real-money launch without one.

The register, and what is in it

Put it in front of somebody who tests things

Send your test engineer at it

The generator’s specification is written to be read clean-room, and the evidence pack and the raw dumps come with it. Every figure here is in an artefact we can hand over. Ask for the parts you want to re-run yourself.

hello@getawaygaming.com · Operators and aggregators can also use the enquiry form on the contact page.