18+ only. Plinko is gambling with real money. Play safely

PROVABLY FAIR

Verify a Plinko drop yourself: a 9-line Python script

A 9-line Python script that checks a Plinko seed commitment and rebuilds the ball path from the hash, with 8 test vectors and 4 common mistakes.

You can verify a provably fair Plinko drop with nine lines of Python: hash the revealed server seed and compare it with the commitment, then compute the HMAC of your client seed and nonce and read one byte per row as left or right. With the fictional seeds in this guide, the script prints a matching commitment, the path RRLRRLLL and slot 4.

This guide gives you the script, eight test vectors to check your copy, and the mistakes that most often cause a mismatch. The method is one common convention, not the only one. Every seed here is fictional and made for this guide.

Key takeaways

  • The whole check is 9 lines and needs only Python's standard library.
  • With the fictional seeds, nonce 42 on 8 rows gives path RRLRRLLL, which is slot 4.
  • The same hash read for 12 rows gives slot 5, and for 16 rows slot 9. Extra rows only read more bytes.
  • One trailing space in the client seed moves the result from slot 4 to slot 5.
  • Over 10,000 nonces the script produced 49.94% right bounces and 84 edge hits, against about 78 expected.

The script

Save this as a file called verify.py. Replace the five input values with your own.

import hmac, hashlib

server_seed, client_seed = "fictional-server-seed-7f3a", "fictional-client-seed"

commitment = "ef13903aceeb84bda8d244d672648893b9f24c283e82700f41f31282393ee7a3"

nonce, rows = 42, 8

ok = hashlib.sha256(server_seed.encode()).hexdigest() == commitment

msg = f"{client_seed}:{nonce}".encode()

h = hmac.new(server_seed.encode(), msg, hashlib.sha256).hexdigest()

path = "".join("R" if int(h[2*i:2*i+2], 16) >= 128 else "L" for i in range(rows))

print("commitment ok:", ok, "| hmac:", h[:16], "| path:", path, "| slot:", path.count("R"))

Run it with python3 verify.py. This is the exact output we got:

commitment ok: True | hmac: dde3438f937d296a | path: RRLRRLLL | slot: 4

What each line does

  1. Imports. Both modules are built into Python.
  2. Seeds. The revealed server seed and your client seed.
  3. Commitment. The hash you were shown before playing. You need your own saved copy.
  4. Nonce and rows. The drop number from your history and the board size.
  5. Commitment check. SHA-256 of the server seed must equal the commitment. True means the seed wasn't swapped afterwards.
  6. Message. In this convention, client seed, a colon, then the nonce.
  7. HMAC. HMAC-SHA256 keyed with the server seed, giving 64 hex characters.
  8. Path. One byte (two hex characters) per row. A value of 128 or more is right; below 128 is left.
  9. Print. The slot is the number of rights.

The reasoning behind each step is in how provably fair Plinko works. This page is the tool that goes with it.

Test vectors: check your copy first

Before you check a real drop, make sure your script reproduces known answers. These rows are pasted from our test run: same fictional seeds, 8 rows, nonces 0 to 7.

NonceHMAC (first 16 hex)PathSlot
09b567529c16ca2bfRLLLRLRR4
1438b97fa6528e804LRRRLLRL4
2f96453177eb4f56aRLLLLRRL3
3fe9582ba4ef1ea6bRRRRLRRL6
40765713506f64265LLLLLRLL1
5a4e3d29510bbf540RRRRLRRL6
68e5f8e2bd5ffede6RLRLRRRR6
75d9155b560516d1bLRLRLLLL2

There is nothing to read into the sequence. Slot 4, then 4, 3, 6, 1: each nonce gives an unrelated hash, and each drop is unaffected by earlier drops.

Same hash, more rows

Change rows on line 4 and the script simply reads further into the same hash.

RowsBytes readPathSlot
8dde3438f937d296aRRLRRLLL4
12dde3438f937d296ad23d3106RRLRRLLLRLLL5
16dde3438f937d296ad23d310681c5c6f4RRLRRLLLRLLLRRRR9

A 16-row board uses 16 of the 32 bytes. What each board size means for odds and swings is covered in 8 vs 12 vs 16 rows.

Four mistakes that break a check

When a result doesn't match, the cause is usually the input. We ran each mistake through the same script, all for nonce 42 on 8 rows.

MistakeHMAC startsPathSlotvs correct slot 4
None (correct inputs)dde3438fRRLRRLLL4match
Trailing space in client seeda2a0d9e0RRRRLLLR5mismatch
Client seed in uppercasea27b2a01RLLLLRRL3mismatch
Nonce 43 instead of 4206ddafefLRRRLLRR5mismatch
Server seed with trailing newline12924e80LRLRLLRL3mismatch

The newline case also fails the commitment check: the hash of the seed with a newline starts e29bc9b554071590, not ef13903a. So a failed commitment can be a copy-paste error. Re-copy the seed before drawing conclusions.

Two more traps are in the mapping itself:

  • Reading one hex character per row instead of two. That gives RRRLLLRR here, which happens to count four rights but is a different path. On other drops the slot changes too.
  • Off-by-one nonce. Some games count drops from 0, others from 1. If your path matches the row above or below in your history, that is a counting difference, not tampering.

A distribution check

We ran the script over nonces 0 to 9,999 on 8 rows and counted the slots.

SlotDropsShareExpected share
0450.45%0.39%
13303.30%3.12%
21,13811.38%10.94%
32,15121.51%21.88%
42,64826.48%27.34%
52,22022.20%21.88%
61,11311.13%10.94%
73163.16%3.12%
8390.39%0.39%
Total10,000100%100%

Out of 80,000 bounces, 39,953 went right: 49.94%. The two edge slots were hit 84 times against about 78 expected. The counts follow the binomial shape described in how Plinko works.

This is a sanity check that the byte rule gives 50/50 bounces. It is not a fairness test of any game.

How we calculated this

One Python file holds the script exactly as printed above, then loops it over other nonces, row counts and deliberately wrong inputs. Every hash, path and count on this page is pasted from its output. Hashing uses Python's standard hmac and hashlib modules; the expected shares are the binomial values for 8 rows, for example 70 รท 256 = 27.34% for slot 4.

Adapting it to another game

Three parts of the script depend on the game. Its fairness page should state each one.

  • Message format (line 6). The separator, the order, or an added round counter.
  • Bytes per row (line 8). Some methods use several bytes or a float per decision.
  • Threshold or mapping (line 8). Some games turn the hash into one number and pick the slot directly.

If the page doesn't give you all three, you can't write the script, and you can't verify the drop.

Checklist for a real drop

  • Save the server seed hash and your client seed before you play.
  • Note the nonce of any drop you want to check.
  • Rotate the seed so the old server seed is revealed.
  • Run the script: the commitment must print True.
  • Compare the path and slot with what the game showed.
  • If something doesn't match, re-copy the inputs once, then stop playing and keep your records.

What a match does and doesn't show

A True commitment and a matching path show one thing: the drop came from a seed fixed before you played, combined with your client seed and nonce by the stated rule.

It doesn't show that the pay table is reasonable. A fully verifiable board still returns less than 100% over time, and no risk level, row count or staking pattern beats the edge; see Plinko RTP explained. It also can't predict a future drop.

Checking a result is not a reason to keep playing. Plinko is for adults 18+ only. If play stops being fun, our responsible gambling page lists free tools and support.

FAQ

Do I need to install anything to run the script?

No. It uses only hmac and hashlib, which ship with every standard Python 3 install. Save it as a file and run it with python3. It works offline and sends nothing anywhere.

How do I know the script is right before I check a real drop?

Run it against known answers first. With the fictional seeds in this guide, nonce 42 on 8 rows must print the path RRLRRLLL and slot 4. If your copy also reproduces the eight test vectors below, it is working.

The commitment matches but my slot is different. Why?

The seed is genuine, but the game maps the hash to a path with a different rule from this one. Check the message format, how many bytes each row uses and the left or right threshold in the game's own documentation.

Can a matching path show that Plinko is good value?

No. A match shows the drop came from a seed fixed before you played, by the stated formula. The house edge comes from the pay table and still applies to every drop.

Can the script predict my next drop?

No. You only get the server seed after it has been retired. While a seed is active you see its hash, which cannot be reversed to find the seed.

18+. Plinko is gambling. Examples on this page are fictional and for explanation only; nothing here is a promise of any result. Set a limit before you play. Responsible gambling