Ice Cold casino

Ice Cold Casino · Patent pending

Proof of gamble.

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.

See how it works Technical details

Why it’s fair

Fair by design, not by promise.

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.

Anyone can check.

The receipt covers every lock, the shuffle, each opening, the result, and the payout. The check stands on its own.

Payouts follow the proof.

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.

No one can stall the game.

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

Confidential by default.

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.

Your cards stay yours.

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.

A fold stays sealed.

The table learns that you folded. The cards you folded stay sealed, and showing them is your choice.

Balances stay encrypted.

Chips sit as encrypted balances in a vault no single computer controls. Paying the result leaves those balances confidential.

How it works

Lock. Shuffle. Prove.

Three steps. The gamble stays checkable, and the faces stay private.

  1. 01

    Everyone locks the deck.

    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.

  2. 02

    Cards open right on time.

    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.

  3. 03

    Proof, then payout.

    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

Nine games. One gamble.

Against other players

  • Texas Hold’em
  • Bingo

Against the house

  • Blackjack
  • Baccarat
  • War
  • Roulette
  • Craps
  • Keno
  • Slots

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

Fifty years to a receipt.

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.

  1. A fair deal, with no dealer

  2. A secret, agreed in public.

    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.

  3. Mental poker.

    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.

  4. A secret in pieces.

    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.

  5. The color of a card leaks.

    Richard Lipton shows that the 1979 protocol reveals partial information about a hidden card, including its color.

  6. Every bit stays hidden.

    Shafi Goldwasser and Silvio Micali define encryption that hides every partial fact about a message, and a two-player poker protocol with that guarantee.

  7. Who is richer.

    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.

  8. Any number of players.

    Moti Yung extends mental poker past two players.

  9. Zero knowledge.

    Shafi Goldwasser, Silvio Micali, and Charles Rackoff define a proof that convinces a checker and reveals nothing else. The journal version appears in 1989.

  10. ElGamal.

    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.

  11. The fold stays hidden.

    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.

  12. Any function, two parties.

    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.

  13. Multiparty computation.

    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.

  14. Computation on shares.

    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.

  15. One message.

    Manuel Blum, Paul Feldman, and Silvio Micali show a zero-knowledge proof that is a single message. Anyone can check it later.

  16. A key with several holders.

    Yvo Desmedt and Yair Frankel split a private key so that opening a ciphertext takes several holders.

  17. A proof the size of a receipt

  18. A curve made for pairing.

    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.

  19. A short proof of a whole computation.

    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.

  20. Groth16.

    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.

  21. Baby Jubjub.

    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.

  22. Circom.

    Jordi Baylina and iden3 release Circom, a language for the arithmetic circuits those proofs check. The circuits for these games are written in it.

  23. Poseidon.

    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.

  24. On Solana

  25. Proof of history.

    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.

  26. Mainnet beta.

    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.

  27. Light Protocol.

    Light begins building zero-knowledge programs on Solana. The work includes contributions to the zero-knowledge syscalls in the Solana client.

  28. Arcium.

    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.

  29. ZK compression.

    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.

  30. The syscalls.

    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.

  31. This protocol

  32. USPTO 19/811,546.

    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

A shoe no single party can open.

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.

GitHub organization Code repository groth16 prover

Four phases

One protocol.

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.

01 · Register

Prove the key.

Each party proves pk = sk · G on BabyJubJub and emits a padding ciphertext for seats that are empty.

02 · Shuffle

Permute, then re-encrypt.

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.

03 · Share

Seal every partial.

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.

04 · Showdown

Open, evaluate, commit.

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

Every key, or no face.

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)
Input hash

Poseidon over the shoe, the keys, and the designation. At showdown the seal commitment is hashed last.

Proof

Groth16 on BN254. light-casino runs the pairing on Solana and writes a receipt.

Output

Share publishes a Poseidon fold of the sealed partials. Showdown publishes the result under the sealed coefficients.

Arcium MPC + Groth16

Proofs for the cards. MPC for the chips.

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

Verifies.

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

Orders.

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

Holds.

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.

Where they meet.

Each step below is queued by casino, run by the cluster, and written back by a callback.

Buy-inlock_table_buyin
A deposit is credited to the encrypted room wallet, and the buy-in moves to table escrow only when the wallet covers it. A failed check leaves both ciphertexts as they were. The cluster never mints chips to make a move succeed.
Stagingverify_deck_hash_chunk
During share, each seat hands its sealed partials to the cluster in four-limb chunks, and the cluster re-seals them to itself. The share proof commits to the same partials.
Bettingvalidate_bet
Each action is checked against the encrypted stack and the current bet, and the new stack comes back as a ciphertext. Only the bet delta, the current bet, fold, all-in, and whether the street closed are revealed. The program rebuilds side pots from those deltas and opens the next street inside the callback.
Cardsreveal_card
Opens one staged card to one recipient: your hole cards first, the board as each street closes, and live hole cards at showdown. Folded and mucked hands never open. The chain checks the opened bytes against the share proof’s hash, and the face stays sealed to the recipient. A seat that goes quiet cannot hold back a card the hand has reached.
Sealseal_showdown_pair
Draws two 128-bit coefficients with the top bit set, seals both to the seat that will prove, and reveals four weighted sums of their bits.
Settlementdistribute_and_settle
Recomputes the showdown value from the encrypted result and the sealed coefficients, and compares it with the hash casino latched from the proof. A match credits the seat’s encrypted escrow. A mismatch moves nothing. Only the match bit is revealed.
Sealed showdownout  = (r0 + 1) · c0 + (r1 + 1) · c1
seal = Poseidon(row0, row1, row2, row3)
  1. The cluster draws. The low 127 bits of c0 and c1 come from the cluster’s randomness, so the prover cannot choose them. Only the four row sums are public.
  2. The circuit binds. It splits each coefficient into 128 bits, checks the top bit, rebuilds the four rows from the same public weights, and hashes them last into its input hash.
  3. The cluster settles. light-casino checks the pairing and casino latches 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

Two kinds of table.

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

Every seat is a player.

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

The house holds a key.

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

A hand with two players.

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.

  1. 1

    Buy in MPC

    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.

  2. 2

    Register ZK

    Each player proves a key. The shoe will be encrypted under their sum.

    Alice pk_A = sk_A · G
    Bob pk_B = sk_B · G
  3. 3

    Shuffle ZK

    Each permutation is a private witness. The public statement is that the output shoe is a re-encryption of a permutation of the input.

    1. Alice permutes the 52 ciphertexts and re-encrypts them under pk_A + pk_B.
    2. Bob permutes that output and re-encrypts it under the same key.
  4. 4

    Share ZKMPC

    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.

    Alice
    01
    Bob
    23
    Board
    2021222324

    Hole slots 4 through 19 belong to the empty seats and stay padding.

  5. 5

    Bet and deal MPC

    Every action runs through validate_bet against the encrypted stack. reveal_card opens each card when the hand reaches it.

    1. Preflop Blinds are 10 and 20. Alice’s hole cards open to Alice, and Bob’s to Bob.
    2. Flop · turn · river Each street closes inside the validate_bet callback. Cards 20–22, then 23, then 24 open to both.
    3. Showdown Each player’s live hole cards open to the other.
  6. 6

    Seal MPC

    The seat that will prove asks the cluster for its seal. The prover can open the coefficients. Everyone else sees only their row sums.

    Sealed to the prover c0, c1
    Public row0 … row3
  7. 7

    Showdown ZK

    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.

    Public Input hash Groth16 proof Sealed result out
  8. 8

    Settle MPC

    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.

    Revealed Match bit Encrypted Escrow credit

Parameters

The game is the shoe.

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.

Hold'em
Peer to peer. Best five-card hand.
Blackjack
Player against the dealer, with hit, stand, and split.
Baccarat
Player, banker, or tie under the tableau.
War
Higher rank, and a second card when the first ties.
Roulette
One pocket on a 37- or 38-number wheel.
Craps
Two dice, come-out or point, against table bets.
Keno
Twenty draws against an encrypted ticket.
Slots
A three- or five-reel window against a paytable.
Bingo
Peer to peer. Called balls on a 75- or 90-ball card.

Stack

Native on the Mac.

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.

App shell

Zig 0.17 on the zero-native framework. An AppKit host embeds the system WKWebView. Chromium through CEF is optional.

Front end

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.

Native bridge

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.

libzkcasino

Zig. The BN254 field from rapidsnark’s C++ and arm64 assembly, Poseidon, BabyJubJub, decryption, the shuffle permutation, and a witness library for each game.

Prover

libgroth16, loaded at run time. Zig on the CPU and Metal on the GPU, described below.

Programs

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.

House

One Linux arm64 image per house game, built with -Dhouse=true and proved with rapidsnark. Bet circuits are left out. The showdown circuit stays.

Tests

Host tests prove every phase of every game. Nine two-player hands run through Arcis on localnet. CI runs on arm64 Linux and macOS.

Formal model

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

A rewritten prover. A patched compiler.

The prover was rewritten and the compiler patched for circuits this size. Each piece is a public repository.

IceColdCasino/groth16 · v0.2.1

groth16

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×
groth16 · 31.32 s
snarkjs · 340.69 s

Blackjack showdown proof661,104 signals

1.9×
groth16 · 1.75 s
rapidsnark · 3.28 s

Poker showdown proof2,244,633 signals

1.5×
groth16 · 6.58 s
rapidsnark · 10.02 s
Apple M1 Max, second run. The method is in the repository README.

IceColdCasino/circom · 2.2.4

circom, patched.

--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

circomspect, extended.

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

What is published.

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.