No one can stack the deck.
Every player shuffles in turn, and so does the house at house games. Each shuffle is checked before the game goes on, so no single person decides the order of the cards.
Ice Cold Casino · Patent pending
A casino you don’t have to trust. The locks, the shuffle, the sealed openings, the result, and the payout come with a receipt anyone can check. The cards, a folded hand, and the balances stay private. No one else sees them: not the other players, not the house, and not us.
Why it’s fair
Every player shuffles in turn, and so does the house at house games. Each shuffle is checked before the game goes on, so no single person decides the order of the cards.
The receipt covers every lock, the shuffle, each opening, the result, and the payout. The check stands on its own.
Chips are held by a neutral vault that no single computer controls. Winnings are paid only after the result checks out, so no one can quietly change who won.
Bets and showdowns run on a clock. If a player walks away, they are folded or the hand closes without them, so nobody can hold a table hostage.
Privacy
A proof of gamble shows that the gamble was fair, and it keeps the gamble itself confidential. The public record carries the receipt. The faces, the folds, and the balances stay off it.
The deck is locked with every player’s key at once. A card opens only for whoever should see it, and the face never lands on the public record.
The table learns that you folded. The cards you folded stay sealed, and showing them is your choice.
Chips sit as encrypted balances in a vault no single computer controls. Paying the result leaves those balances confidential.
How it works
Three steps. The gamble stays checkable, and the faces stay private.
Each player puts their own lock on every card, then shuffles the deck. A card opens only when every lock on it is turned, so no one can open one alone.
Before the deal, each player gives a neutral vault a sealed envelope for every card, addressed to whoever may see it. The vault can’t read them. It delivers each one when the game reaches that card, so no one can open a card early or refuse to open it later.
When the hand ends, the result comes with a short mathematical proof that anyone can check without seeing a single card. The vault pays out only if the proof matches.
Games
Against other players
Against the house
Dice rolls, roulette spins, slot reels, and bingo balls are the same proof of gamble as cards, dealt from a locked deck that everyone shuffled. At house games the house helps lock and shuffle too, and the faces stay private from the house as well.
History
A fair hand for people who are not in the same room, with nothing revealed but the result. Years are the year of the paper. The last date is the day proof of gamble was filed.
Whitfield Diffie and Martin Hellman show that two people can agree on a secret while everyone else is listening. Public-key cryptography starts here, on the discrete logarithm.
Adi Shamir, Ron Rivest, and Len Adleman deal a fair hand with no cards and no dealer. The deck is locked with the commutative form of RSA, which they had published in 1978, so each player can shuffle it without seeing a face. They also show that a perfectly private deal is impossible unless some problem is hard to compute.
Adi Shamir splits a secret into shares. A large enough group of shares restores it, and a smaller group learns nothing. Threshold keys, and computation on shared data, are built on this.
Richard Lipton shows that the 1979 protocol reveals partial information about a hidden card, including its color.
Shafi Goldwasser and Silvio Micali define encryption that hides every partial fact about a message, and a two-player poker protocol with that guarantee.
Andrew Yao asks how people can compute a function of their private numbers and learn only the answer. His case is which of two millionaires is richer. He treats mental poker as the same kind of problem.
Moti Yung extends mental poker past two players.
Shafi Goldwasser, Silvio Micali, and Charles Rackoff define a proof that convinces a checker and reveals nothing else. The journal version appears in 1989.
Taher ElGamal builds encryption and signatures on the discrete logarithm. A ciphertext can be randomized again without the key, which is what a hidden shuffle needs. This shoe is locked with a threshold form of that encryption.
Claude Crépeau gives a zero-knowledge poker protocol whose check does not require every hand to be opened at the end. A player’s strategy can stay secret.
Andrew Yao shows two parties with private inputs can compute any function together. Each learns its own output and nothing further about the other’s input.
Oded Goldreich, Silvio Micali, and Avi Wigderson extend that to any number of parties and any function. Honest players learn the output and nothing more, provided most of them are honest. The chips here move under that rule. An Arcium cluster runs each instruction, and the balances stay encrypted.
Michael Ben-Or, Shafi Goldwasser, and Avi Wigderson prove the same from shares alone, with no computational assumption. If fewer than half the parties pool what they see while following the protocol, they learn nothing beyond the output. If fewer than a third may cheat, they still learn nothing and cannot change the result. David Chaum, Claude Crépeau, and Ivan Damgård give an unconditional protocol the same year.
Manuel Blum, Paul Feldman, and Silvio Micali show a zero-knowledge proof that is a single message. Anyone can check it later.
Yvo Desmedt and Yair Frankel split a private key so that opening a ciphertext takes several holders.
Paulo Barreto and Michael Naehrig construct pairing-friendly elliptic curves of prime order. Proofs here are checked with a pairing on BN254, a curve from that family.
Rosario Gennaro, Craig Gentry, Bryan Parno, and Mariana Raykova show that any computation can have a succinct non-interactive proof. Pinocchio, by Parno, Jon Howell, Gentry, and Raykova, makes it a working system. The proof is a few hundred bytes, whatever the computation was.
Jens Groth brings that proof down to three elliptic-curve points. Checking it is a pairing equation, small enough to run on Solana. Every phase of this casino is a Groth16 proof.
Barry Whitehat, Marta Bellés-Muñoz, and Jordi Baylina specify a twisted Edwards curve over the scalar field of BN254, named for Zcash’s Jubjub. A circuit can prove pk = sk · G in the same field the proof uses. The formal paper, with Vanesa Daza and Jose Luis Muñoz-Tapia, is published in 2021.
Jordi Baylina and iden3 release Circom, a language for the arithmetic circuits those proofs check. The circuits for these games are written in it.
Lorenzo Grassi, Dmitry Khovratovich, Christian Rechberger, Arnab Roy, and Markus Schofnegger design a hash that lives in the proof’s field. A commitment to the private witness, carried from one phase to the next, is cheap to prove.
Anatoly Yakovenko proposes a ledger that records the passage of time between events, so the network can order transactions without every node consulting every other node. Solana is that design.
The network starts on March 16, 2020. A program on it runs in a virtual machine and asks the runtime for the heavy cryptography through syscalls.
Light begins building zero-knowledge programs on Solana. The work includes contributions to the zero-knowledge syscalls in the Solana client.
In May 2024 Yannik Schrade, Julian Deschler, Nicolas Schapeler, and Lukas Steiner, the team behind Elusiv, announce Arcium. A multiparty execution environment runs a computation on encrypted data across nodes, and the plaintext stays split across them. This casino queues its chip instructions to an Arcium cluster. The balances are Rescue ciphertexts, and a signed callback writes the new ciphertext back.
In June 2024 Light Protocol and Helius put ZK compression on Solana mainnet. An account can be stored as a hash in a Merkle tree, checked with a small proof, instead of paying for a full account. Shuffle and share artifacts here can be stored that way.
Later in 2024 the runtime turns on the two calls the verifier
needs. At mainnet epoch 638,
sol_alt_bn128_group_op adds two BN254 points,
multiplies a point by a scalar, and checks a pairing. At epoch
644, sol_poseidon hashes up to twelve BN254 field
elements. light-casino verifies every Groth16 proof with the
pairing call, and computes the on-chain Poseidon commitments
with the hash call.
Proof of gamble. Filed September 18, 2026. Patent pending. Each party proves a key, the shoe is shuffled and re-encrypted under the sum of those keys, and a partial decryption stays sealed until a value should open. The opened values are evaluated in a proof, and the faces stay off the public record. A card, a die, a reel stop, and a bingo ball are the same shoe with a different evaluation. The payout is multiparty computation on encrypted balances.
Proof of gamble · USPTO 19/811,546
Proof of gamble is a zero-knowledge mental-poker stack on Solana. Players jointly encrypt and shuffle the shoe, seal partial decryptions to one another, and prove each phase in Groth16. An Arcium MPC cluster holds the chips and pays out only what the proof attests. The faces, the folded hands, and the balances stay confidential.
In the plain version above, the locks are threshold ElGamal keys. The sealed envelopes are partial decryptions staged with the cluster. The receipt is a Groth16 proof verified on Solana, and the neutral vault is the Arcium cluster.
Four phases
Every game runs the same sequence. Taken together, the four phases are a proof of gamble. Each phase is a Circom circuit, and every proof is verified on Solana. A Poseidon commitment threads the private witness from one phase to the next, so the witness is never written onto the public tape.
Each party proves pk = sk · G on BabyJubJub and
emits a padding ciphertext for seats that are empty.
The encrypted shoe is permuted under a private matrix and re-randomized under the aggregate key. The public statement is that the output is a re-encryption of a permutation of the input.
Each registered key computes its partial decryption and seals that payload to every other key. The proof commits the sealed partials as Poseidon hashes, grouped so one card, street, or ball can open alone. The partial itself is not published.
Partials are aggregated, opened values are checked against the legal encoding, and the game function runs in-circuit. The result leaves as one field element, weighted by two coefficients the MPC cluster sealed to the prover.
Threshold ElGamal
A shoe index — card, pocket, die, reel stop, or ball — is a curve
point P(v) = (v + 1) · G. The shoe is encrypted under
the sum of every registered public key. Recovering a plaintext
takes a contribution from each secret. The public tape carries
ciphertexts, commitments, and the result. The plaintext stays
confidential.
Aggregate decryptionP = c1 − Σ (sk_i · c0)
Poseidon over the shoe, the keys, and the designation. At showdown the seal commitment is hashed last.
Groth16 on BN254. light-casino runs the pairing on Solana and writes a receipt.
Share publishes a Poseidon fold of the sealed partials. Showdown publishes the result under the sealed coefficients.
Arcium MPC + Groth16
Groth16 proves what happened to the shoe. An Arcium MXE cluster holds the chips, the staged partials, and the showdown coefficients, and changes them only through encrypted instructions. Three parts split the work on Solana, and neither side does the other’s job.
light-casino
Runs the Groth16 pairing for register, shuffle, share, showdown, and each bet or action circuit. A valid proof becomes a receipt, which it hands to casino by CPI. Shuffle and share artifacts can be stored as Light Protocol compressed accounts.
casino
Owns rooms, tables, the SPL vault, escrow, the hand, and the dealer pool. It consumes each receipt, enforces the phase, latches the showdown hash, and queues every encrypted instruction.
Arcium cluster
Runs the Arcis instructions that casino queues. Balances are Rescue ciphertexts. Each result comes back in a signed callback, and a callback that fails its signature check writes nothing.
Each step below is queued by casino, run by the cluster, and written back by a callback.
lock_table_buyinverify_deck_hash_chunkvalidate_betreveal_cardseal_showdown_pairdistribute_and_settleSealed showdownout = (r0 + 1) · c0 + (r1 + 1) · c1
seal = Poseidon(row0, row1, row2, row3)
c0 and c1 come from
the cluster’s randomness, so the prover cannot choose them. Only
the four row sums are public.
out. The cluster recomputes out from
the encrypted result and pays only on a match.
Wider results are packed before they are weighted. Poker’s nine
winner masks become Σ mask_i · 1024^i, and roulette’s
twelve bets become Σ code_i · 36^i. The cluster never
runs a pairing, and the verifier never sees the result. The sealed
coefficients are what tie the two together.
Who sits
Poker and bingo are player against player. The other seven games seat the house, which joins the shuffle and the share but never bets.
Poker and bingo
Two to ten poker players register, shuffle, and share. Any seat still in the pot may prove showdown, and one proof completes the hand. Winners are paid from the chips the seats committed, and bingo pays from a pot of card prices. There is no dealer pool.
House games
Baccarat, blackjack, war, roulette, craps, keno, and slots reserve a seat for the house. It registers, shuffles, and shares, so its secret is part of the aggregate key, but it places no bet. Winners are paid from an encrypted dealer pool, and a hand cannot start until the pool is funded to cover it.
Showdown opens a three-minute window, and the bettor proves inside
it. After that the house may submit the same showdown proof, since
its build keeps that circuit, so a player who walks away does not
hold the table. If no proof arrives, forfeit_showdown
closes the hand without one. It never invents a proof, and a later
proof is rejected. At poker and bingo tables, the operator who
opened the game signs it. Blackjack adds a second three-minute clock
for actions, and a seat that leaves is stood. Poker gives each
betting decision one minute, and after that anyone can fold the seat
with expire_bet_turn.
Example
Alice is seat 0 and Bob is seat 1. The poker circuits are compiled for ten seats, so the other eight stay padding. Each step is a Groth16 proof, an Arcium computation, or both.
Each deposit is credited to an encrypted room wallet, and lock_table_buyin moves the buy-in into table escrow. The cluster refuses any move the wallet cannot cover.
Each player proves a key. The shoe will be encrypted under their sum.
pk_A = sk_A · G
pk_B = sk_B · G
Each permutation is a private witness. The public statement is that the output shoe is a re-encryption of a permutation of the input.
pk_A + pk_B.The deal window is 25 positions. Each player seals a partial of every position to the other. The card mask picks a real partial, sk · c0, or the identity, which leaves that position closed. The proof commits the sealed partials by hole pair and by street, and the same partials are staged with the cluster.
Hole slots 4 through 19 belong to the empty seats and stay padding.
Every action runs through validate_bet against the encrypted stack. reveal_card opens each card when the hand reaches it.
validate_bet callback. Cards 20–22, then 23, then 24 open to both.The seat that will prove asks the cluster for its seal. The prover can open the coefficients. Everyone else sees only their row sums.
c0, c1
row0 … row3
That seat aggregates both partials, checks each opened card against P(v), scores both seven-card hands, and packs the winner masks. Alice does not need to be online for it. Her partials for Bob are already with the cluster, so Bob can open her live hole cards and prove alone.
out
light-casino verifies the proof, and casino latches out. distribute_and_settle recomputes it from the encrypted winner masks and the seal, then credits each seat’s encrypted escrow. A mismatch pays nothing.
Parameters
Encryption does not change. The shoe size, which positions open, and the evaluation function do. Poker and bingo pay from the players’ own chips. The rest pay from the dealer pool.
Stack
The macOS app is a Zig shell around a Svelte front end. Keys, decryption, witnesses, and proofs run in native code. Transactions and cluster encryption run in the WebView.
Zig 0.17 on the zero-native framework. An AppKit host embeds the system WKWebView. Chromium through CEF is optional.
Svelte 5 and Vite. The Solana web3 and Anchor clients send transactions straight to RPC. The Arcium client derives an X25519 key for each game, seat, and purpose, and encrypts to the cluster with Rescue.
player runs keygen, decryption, and proving on a worker thread with a 64 MB stack, off the AppKit main thread. zk.witness.generate and zk.prove expose the witness generator and the prover.
Zig. The BN254 field from rapidsnark’s C++ and arm64 assembly, Poseidon, BabyJubJub, decryption, the shuffle permutation, and a witness library for each game.
libgroth16, loaded at run time. Zig on the CPU and Metal on the GPU, described below.
casino on Anchor 1.0 with arcium-anchor 0.14. light-casino on Pinocchio with groth16-solana and Light Protocol. The Arcis instructions run on the MXE cluster.
One Linux arm64 image per house game, built with -Dhouse=true and proved with rapidsnark. Bet circuits are left out. The showdown circuit stays.
Host tests prove every phase of every game. Nine two-player hands run through Arcis on localnet. CI runs on arm64 Linux and macOS.
Lean 4 with DyLean: a symbolic model of the four phases with secrecy and authentication theorems, plus integer semantics for all nine showdown evaluators. CI runs lake build.
Toolchain
The prover was rewritten and the compiler patched for circuits this size. Each piece is a public repository.
IceColdCasino/groth16 · v0.2.1
A Groth16 prover and proving-key tool written in Zig, with Metal
on the GPU. libgroth16 is a drop-in for
librapidsnark: the same groth16_* C calls, the same
JSON, the same return codes. zkey replaces snarkjs
for setup, contribution, and verification-key export, and its
exported verification keys match snarkjs byte for byte.
Metal runs the G1 multiscalar multiplications and computes
H = A·B − C. Zig threads take a 64k-point chunk of
G2 and the QAP at the same time. Circuits with a domain of 4096
or less stay on the CPU.
Homebrew · macOS 14+brew trust --tap IceColdCasino/groth16
brew tap IceColdCasino/groth16 https://github.com/IceColdCasino/groth16
brew install icecoldcasino/groth16/zkey
Blackjack showdown keySetup and contribution
10.9×Blackjack showdown proof661,104 signals
1.9×Poker showdown proof2,244,633 signals
1.5×IceColdCasino/circom · 2.2.4
--O2 linear simplification no longer joins clusters
through private inputs or public signals. Chains that meet only
there are simplified in parallel, then a second pass simplifies
the residuals together. Large shuffle circuits now finish
instead of running Gaussian elimination on one cluster.
Constraint and wire counts are unchanged, but the R1CS differs
from upstream, so proving keys are regenerated. Bitwise
complement now reduces its operand modulo the field first.
IceColdCasino/circomspect · 0.11.0
Static analysis for these circuits, forked from Circomspect 0.9.
signal-dependent-assert errors on asserts whose
conditions depend on signals. parallel-output-in-loop
warns when a parallel component is read in the loop that starts
it. The LessThan and Num2Bits checks
report fewer false positives, including on hash-bound signals.
Audit
The code repository holds the whole system. Circuits and protocol notes, the Zig library, the TypeScript host and its tests, the casino and light-casino programs, the Arcis instructions, the macOS app, the Lean model, and the proving keys in Git LFS.
It is published for audit and transparency. Copyright © 2026 Barrett Harber. All rights reserved. USPTO application 19/811,546 is patent pending. No copyright license and no patent license are granted.
The proving keys come from one local contribution, not a multi-party ceremony. The circom and circomspect forks are GPL-3.0.