Executive Summary
This investigation evaluates three of BetFury’s in-house “Original” games — Limbo, Dice and Plinko — against two independent questions:
1Provably Fair Evaluation
1.1What provably fair should look like
serverSeed and publishes SHA256(serverSeed) before any bet.clientSeed — or another source of entropy outside the operator’s unilateral control, such as a public randomness beacon.nonce increments each bet, binding every outcome to a unique index.RNG = HMAC_SHA256(serverSeed, clientSeed:nonce), mapped to a result by a published formula.serverSeed; the player checks it against the hash and recomputes every outcome from the committed inputs.1.2What BetFury actually does
Captured from the live game socket — the complete outgoing bet, everything the browser sends to place a wager:
// games.dice.bet — the entire wager sent to BetFury
{ "is_under": true, "prediction": 50, "amount": "0.10000000",
"isFast": false, "isAuto": false, "frontID": 1784114526766 }frontID is a timestamp — a millisecond request id, never recorded, and it can’t affect a result whose hash is committed before the bet lands.1.3The revealed proof contains the result
BetFury’s bet record reveals a randomSeed and a hash where SHA256(randomSeed) == hash. But read the seed:
Limbo: 1.91_XiLQkYQZxcwNxF → 1.91 was the multiplier Dice: 52_FcqvWBAQrkwQbZ → 52 was the roll Plinko: 1000101001000011_owOW… → the 16-step ball path
Every proof is <result>_<server string>. It contains the finished result — not the inputs and formula needed to derive it. BetFury’s own docs confirm the shape: “Random seed is a combination of Random winning number and Server seed.”
1.4The RNG certificate
The public BetFury testing document we located — SIQ Test Report T-J0068-I0003, from 2022 — provides laboratory testing and software analysis of a submitted Math.random()-based PRNG sample, and states its own scope:
The report does include a Limbo section — and it’s worth being precise about what that section checks, because it’s easy to mistake for a fairness guarantee. It tests that the game’s underlying random draw is statistically uniform: that the raw numbers come out evenly, with no bias. The sample passes. That is a real and useful test — but it answers a narrower question than fairness.
The report provides evidence that the submitted PRNG sample passed its statistical and software checks. It does not establish that the live games used the same implementation, or that their payout maths produced the represented RTP — the two things that decide what a player actually receives. A generator can pass every randomness test and still underpay if the payout constant that converts those numbers into a return is set below the advertised rate, which is exactly the Limbo pattern we measured: fair-looking numbers, a house edge ~2.7× the advertised rate.
1.5Provably fair requirements vs BetFury
| Requirement | Conventional provably fair model | What we observed on BetFury | Verdict |
|---|---|---|---|
| Server-seed hash shown before betting | SHA256(serverSeed), pre-bet | Hash shown pre-bet, but it commits the result itself, not a seed | partial |
| Player-controlled client seed | Yes | None in UI, bet, history or verifier | missing |
| Disclosed per-bet nonce | Yes | None disclosed | missing |
| Documented derivation formula | HMAC_SHA256(server, client:nonce) | None — the “proof” simply contains the finished result | missing |
| Player can replay a bet | Fully reproducible | Nothing to recompute | impossible |
| Secure live RNG demonstrated | CSPRNG, tested on the live game | 2022 report covers a sample, not the live game | not established |
| Player-verifiable fairness | Yes | Mechanisms absent | unsupported |
2RTP Measurement
2.1Method & conditions
Because a BetFury result can’t be recomputed by a player, the only remaining check is statistical: place a large, fixed number of bets and compare what the games actually pay against what they advertise. Money RTP = total paid ÷ total staked — mechanism-agnostic, identical for all three games. Dice and Plinko serve as controls; both are checkable against a fixed reference.
Why 60,000 bets at these settings. The precision of a measured RTP depends on per-bet variance as much as on bet count, so the run was designed around a low-variance setting: at a 1.10× target the game pays on roughly nine bets in ten, and 60,000 fixed-stake rounds bring the standard error on measured RTP down to ±0.135 points — a 95% confidence interval of ±0.26 points around the advertised 99.02%. That is quarter-point resolution on a question asked in whole points; the same count at high cash-out targets would resolve RTP only to within several points. The fixed 0.001 USDT stake keeps money RTP a pure function of the win count, and Dice and Plinko ran through the same account, window and stake, so the controls share identical exposure to any capture artefact.
2.2Results
| Game | Bets | Measured RTP | Advertised | Result |
|---|---|---|---|---|
| Limbo | 60,000 | 97.33% | 99.02% | shortfall |
| Plinko | 60,000 | 99.01% | 99.02% | no discrepancy |
| Dice (control) | 60,000 | 99.39% | 99.02% | no discrepancy |
2.3Limbo — detail
Limbo shows a “Win Chance” on every bet — 90.01818% at the 1.10× setting. Over 60,000 bets those odds predict about 54,011 wins; players actually won 53,087, roughly 924 fewer than the game’s own displayed odds promise. This is the cleanest evidence in the report, because it needs no assumptions about BetFury’s formula — it holds them to the number printed on their own button. And 924 is not a rounding error: at BetFury’s displayed odds the standard deviation over 60,000 bets is about 73 wins, so a shortfall of roughly 924 wins is 12.58 standard deviations below expectation — far outside any credible run of ordinary bad luck (the exact odds are in the note below).
The clearest single symptom: the 1.00× instant bust
At 1.00× Limbo ends before the multiplier moves — an outright loss on the first tick. Under the standard two-decimal Limbo formula consistent with a displayed 99.02% RTP, about 1.96% of rounds should land there — roughly one bust every 51 bets. We recorded far more.
| 1.00× instant losses | Expected under 99.02% | Observed |
|---|---|---|
| Number of rounds | ~1,176 | 2,130 |
| Share of all bets | ~1.96% | 3.55% |
| What a player feels | 1 bust in 51 | 1 bust in 28 |
Within the 60,000 multipliers generated while betting at 1.10×, the implied return remained below 99.02% at every tested threshold from 1.01× to 10×. Individual estimates ranged from 96.24% to 97.41% and became noisier as the target rose. Fitting the captured multiplier distribution to the standard two-decimal Limbo model produces an underlying RTP estimate near 97.4%. We did not separately place bets at other targets; the exploratory run below did, at 2.00×, and also came back short.
| Cash-out target | Implied win rate | Win rate × target | Effective RTP | vs 99.02% |
|---|---|---|---|---|
| 1.01× | ≈96.4% | 96.4% × 1.01 | ≈97.4% | −1.6 pts |
| 1.10× (instrumented run) | 88.48% | 88.48% × 1.10 | 97.33% | −1.69 pts |
| 1.25× | ≈77.7% | 77.7% × 1.25 | ≈97.1% | −2.0 pts |
| 1.50× | ≈64.8% | 64.8% × 1.50 | ≈97.2% | −1.8 pts |
| 2.00× | ≈48.4% | 48.4% × 2.00 | ≈96.7% | −2.3 pts |
| 3.00× | ≈32.2% | 32.2% × 3.00 | ≈96.7% | −2.4 pts |
| 5.00× | ≈19.2% | 19.2% × 5.00 | ≈96.2% | −2.8 pts |
| 10.00× | ≈9.65% | 9.65% × 10.0 | ≈96.5% | −2.5 pts |
The statistical backing, for the technically minded
2.4A standard Limbo reference model (R ≈ 0.974) closely fits the captured pattern
BetFury does not publish a player-reproducible Limbo formula, so we cannot state what exact code or constant was running on its servers. But the standard two-decimal Limbo model can be fitted to the recorded results — and under that model, a single RTP constant controls the whole multiplier distribution:
// simplified standard reference model — NOT BetFury source code rawMultiplier = R / (1 − u) // u uniform in [0,1); R = RTP constant displayedMultiplier = max(1.00, floor(rawMultiplier × 100) / 100) // 2-dp floor; below 1.00 = instant bust
In this model, one constant — R — sets the whole payback. With R = 0.9902 the model returns 99.02%, exactly what BetFury advertises and what its own bet panel encodes. A lower R shifts the entire distribution the same way: fewer wins at every cash-out target, and more first-tick busts. The question is simply which R best fits what we recorded.
And 0.9902 is not just the advertised number — it is the constant BetFury’s own bet panel encodes at every cash-out target. At each of the eight targets below, the displayed win chance is exactly 0.9902 ÷ target to five decimal places:
| Target | Win chance BetFury shows | Win chance × target |
|---|---|---|
| 1.01× | 98.03960% | 0.9902 |
| 1.10× (tested) | 90.01818% | 0.9902 |
| 1.50× | 66.01333% | 0.9902 |
| 2.00× | 49.51000% | 0.9902 |
| 5.00× | 19.80400% | 0.9902 |
| 10.00× | 9.90200% | 0.9902 |
| 100.00× | 0.99020% | 0.9902 |
| 1000× | 0.09902% | 0.9902 |
Three separate readouts of the same 60,000-bet capture point to the same range — related views of one distribution, each expressing the discrepancy differently:
| What we measured | If R = 0.9902 (advertised) | Observed | Implied R |
|---|---|---|---|
| Win rate at the 1.10× target | 90.02% | 88.48% | 0.973 |
| Instant 1.00× bust rate | ~1.96% | 3.55% | 0.974 |
| Return across targets 1.01×–10× | 99.02% | ~97.3% | 0.974 |
2.5Corroboration — the signal appeared twice
Before the fully instrumented investigation, we ran an exploratory 60,000-bet Limbo capture at a 2.00× target. It recorded results, payouts and timestamps but not the seed/hash fields, so it is not pooled into the headline figure — it is published separately as corroboration.
| Run | Target | Instant busts | Rate | Frequency |
|---|---|---|---|---|
| Exploratory | 2.00× | 2,072 | 3.453% | 1 in 29 |
| Confirmatory | 1.10× | 2,130 | 3.550% | 1 in 28 |
| Advertised-model expectation | either | ~1,176 | ~1.96% | 1 in 51 |
2.6Why it isn’t variance — the controls
BetFury’s displayed odds already rule out ordinary variance — no assumption about its formula required. At a displayed 90.02% win chance, 60,000 bets predict about 54,011 wins; we recorded 53,087, roughly 924 short. A shortfall that large or larger has a probability of about 4.1 × 10⁻³⁵ under the displayed odds. This calculation holds BetFury to the number on its own button and nothing else.
The multiplier distribution shows where the shortfall appears. Under the standard 99.02% two-decimal Limbo model, about 1,176 rounds should end immediately at 1.00×; we recorded 2,130. An earlier, separate run recorded another 2,072 instant busts — again almost twice the expected count. Two captures, two different targets, the same excess: that is not a credible ordinary-variance explanation.
The controls reduce the remaining concern. Dice and Plinko don’t establish the Limbo result — Limbo’s own win count does that — and they don’t independently authenticate the Limbo capture. What they do show is that the same collection-and-analysis pipeline did not systematically produce low results across every game: run identically, both were statistically consistent with their expected mathematics, strongly arguing against a general account-wide or pipeline issue and isolating the detected discrepancy to Limbo.
Same 60,000 bets, radically different statistical meaning
The three games cannot be compared by asking whether each sample finished above or below 99.02%. Their payout distributions have different variance, so ordinary luck moves each game’s 60,000-bet average by a different amount. The right yardstick is each game’s own normal sampling swing:
| Game | Measured RTP | vs 99.02% | Normal 1σ swing | Deviation | Assessment |
|---|---|---|---|---|---|
| Dice | 99.393% | +0.373 pts | ±0.404 pts | +0.92σ | normal |
| Plinko | 99.008% | −0.012 pts | ±0.609 pts | −0.02σ | normal |
| Limbo | 97.326% | −1.694 pts | ±0.135 pts | −12.58σ | not variance |
| Control check | Measured | Expected if fair | |
|---|---|---|---|
| Dice roll uniformity (0–99) | consistent | uniform | |
| Dice win rate (roll under 50) | 50.19% | 50.00% | |
| Plinko peg fairness (~960k L/R) | 50.014% | 50.000% | |
| Plinko landing distribution | consistent | Binomial(16, 0.5) |
3Findings & Recommendations
3.1Scope of the claim
3.2What BetFury needs to explain
3.3Recommendations
SHA256(serverSeed) before each bet; reveal serverSeed on rotation.HMAC_SHA256(serverSeed, clientSeed:nonce).4Reproducibility
Every figure is recomputable from the published data. Because the seeds contain the results and SHA-256 is unkeyed, a matching hash proves internal consistency, not origin — so anyone can run the scripts on a fresh capture of their own to test whether the shortfall reproduces.
$ node scripts/verify.mjs limbo 60000 | SHA256(seed)==hash 60000/60000 | result-in-seed 60000/60000 ✓ plinko 60000 | SHA256(seed)==hash 60000/60000 | result-in-seed 60000/60000 ✓ dice 60000 | SHA256(seed)==hash 60000/60000 | result-in-seed 60000/60000 ✓ TOTAL 180000 rounds | 180000/180000 seed matches its hash $ node scripts/analyze.mjs limbo RTP 97.326% win 88.478% vs 90.018% shown binomial p=4.1e-35 plinko RTP 99.008% no discrepancy dice RTP 99.393% no discrepancy (control)
Sample verified rounds — seed, hash, result (the “seed” already holds the answer)
| Game | randomSeed | SHA256 = hash | Result |
|---|---|---|---|
| Limbo | 1.91_XiLQkYQZxcwNxF | b593674471f49bd7…42086aa3b8cc | 1.91× |
| Limbo | 1.13_eRABOoyYnxIfVm | b2e0724bae7a52ba…3823adb0278cdc28 | 1.13× |
| Dice | 52_FcqvWBAQrkwQbZ | 74a65e7dff528412…99e0049defcf1 | roll 52 |
| Plinko | 1000101001000011_owOWuUgQaZegSbjIVckdaEBBhuGGwUfu | a4cf0ee400b823cc…3044cdaf65f | path → 1.0× |
data/*-60000.jsonl)data/limbo-exploratory-60000.json)data/*.precommit.json)data/siq-rng-certificate-2022.pdf)verify.mjs · analyze.mjs · exploratory.mjs — Node.js only, no deps, no network