Imagine you’re coding a poker game. You’ve got a shuffled deck, players around a virtual table, and you need to deal secret cards, reveal community cards, and determine the winner. Everything can be handled in a game server. Easy, right?
Now remove the dealer, and the server, and any notion of trust between players. How would you make sure the deck is fairly shuffled? How do you ensure that only Alice can see her cards and not Bob? How do you prevent cheating without a referee watching? This is where Mental Poker comes in — and it’s kind of magical.
Mental Poker
So, what is Mental Poker? Mental Poker is what happens when cryptographers try to play cards without trusting anyone — and succeed. It’s a set of cryptographic protocols that let players play a card game like poker without a central dealer, e.g. a traditional game server. All players participate in shuffling and encrypting the deck, and no one can see or manipulate the cards unfairly.
Before we dive deep into the cryptographic problem, let’s do some math firstly.
A Bit of Math
In math, an operation is commutative if the order doesn’t matter. For example:
1 + 2 ≡ 2 + 1Both equal 3. That’s a commutative operation.
Now apply that to encryption, let’s say we have an encryption function f, which converts a plain text m using a key k into a cipher text c. And, it is also commutative, meaning we encrypt the plain text twice using two different keys (e.g. k1, k2), no mater what order is applied, the result is always the same. We can express this mathematically:
And, we can also conclude that, the decryption function f^-1 is also commutative.
Why Is This Useful?
Let’s imagine everyone in a poker game has a padlock, which is using a commutative encryption described above. Think of it like putting all the cards in sealed envelopes, then everyone locks the envelopes with their own padlocks and shuffles. No one can open a card unless everyone else agrees and provides their keys. Since the order of the keys provided doesn’t matter, one can see his own cards if others agree and provide the keys, and later he can decrypt his cards secretly using his unrevealed key.
The Algorithm Step-by-Step
Let’s walk through how two players, say Alice and Bob, can shuffle a deck together without trusting each other and without either of them learning the card order.
Here’s the idea, broken into three key phases:
Phase 1: Encrypt and Shuffle
Alice and Bob begin by agreeing on a deck, say numbers 0 through 51 to represent a standard 52-card deck (which excludes the Jokers).
- Alice starts by choosing a secret encryption key (A) and encrypting every card in the deck.
- Then, she shuffles the encrypted cards and sends them to Bob.
- Bob applies his own encryption key (B) on top of Alice’s and shuffles the deck again.
At this point, each card is encrypted twice, in a randomized order that neither Alice nor Bob can trace.
Phase 2: Prepare for Dealing
Now it’s time to make each card privately decryptable.
- Bob sends the double-encrypted, shuffled deck back to Alice.
- Alice removes her encryption layer (encrypted by key A) from each card, leaving only Bob’s.
- Then, she encrypts each card again individually with a fresh key (A₁, A₂, A₃…), so that even Bob doesn’t know what card is what.
- She sends this deck back to Bob.
- Bob removes his encryption layer (encrypted by key B) from each card (still can’t read them because of Alice’s per-card encryption).
- Now, he encrypts each card individually with his own fresh keys (B₁, B₂, B₃…).
- The deck goes back to Alice one final time.
Phase 3: Done — A Fair, Encrypted Deck
Finally, Alice publishes the encrypted deck to all players. The cards are:
- Fully encrypted with per-card keys.
- Shuffled fairly and unpredictably.
- Ready to be dealt: when it’s time for a player to receive a card, others share the keys to gradually decrypt only that card.
No one knows any card value unless it’s their own or intentionally revealed.
You might be wondering — what kind of encryption allows all this collaboration without leaking information?
In the Mental Poker I implemented, I use a cryptographic scheme called Shamir–Rivest–Adleman (SRA). It’s a lesser-known cousin of the famous RSA encryption, and it has a special property that makes it perfect for multiplayer card games: commutativity.
A Primer on RSA and Modular Exponentiation
To understand the SRA encryption in Mental Poker, we need to take a short dive into some classic cryptography: RSA encryption and its mathematical core — modular exponentiation.
What Is Modular Exponentiation?
Modular exponentiation means computing:
where,
- x is your input (e.g., a card)
- e is your exponent (i.e., your encryption key)
- n is the modulus (a large number, often a product of two primes)
How RSA Encryption Works
RSA is based on the idea that exponentiation is easy, but reversing it (finding roots) is hard — unless you know a special secret.
Here’s how RSA is set up:
- Choose two large primes: P and Q
- Compute their product: N = P × Q
- Compute Euler’s totient function: φ = (P — 1) × (Q — 1)
- Choose a public exponent e, such that: 1 < e < φ, and gcd(e, φ) = 1
- Calculate the private key d: d ≡ e⁻¹ mod φ
- Encrypt a message m: c = m^e mod N
- Decrypt the cipher text c: m = c^d mod N
How SRA Is Different from RSA
In RSA:
- The encryption key e is public.
- The decryption key d is private and computed using Euler’s totient.
- You encrypt with e, decrypt with d, and the math guarantees correctness.
In SRA:
- Both P and Q (used to compute N) are public.
- Each player chooses their own private exponent e.
- Encryption is simply: m^e mod N
- Decryption is: c^d mod N (where d is the modular inverse of e with respect to φ)
Most importantly, SRA is commutative, meaning that encrypting a message multiple times with different keys can be done in any order, and decrypted in any order, too:
This is what makes SRA ideal for mental poker:
- Each player encrypts the deck with their private exponent (e1, e2, etc.).
- Cards remain secret until all players cooperate to decrypt them.
- No one can decrypt a card on their own, and no card’s value is known prematurely.
All the aforementioned core cryptographic logic that powers Mental Poker has been extracted into a standalone open-source library: predatorray/mental-poker-toolkit on GitHub.
This toolkit implements the full mental poker protocol in TypeScript (JavaScript):
- The commutative SRA encryption using modular exponentiation
- Multi-party deck encryption and collaborative shuffling
- Per-card encryption/decryption for secure distribution
- Built with performance and browser support in mind
It’s designed to be plug-and-play. You can use it to:
- Build your own P2P card game
- Add mental poker to a multiplayer board game
- Experiment with privacy-preserving turn-based mechanics
Example Usage
const deck = getStandard52Deck();const deckEncoded = new EncodedDeck(
deck.map((card) => BigInt(encodeStandardCard(card)))
);
const alice = await createPlayer({
cards: deck.length,
bits: 32,
});
const bob = await createPlayer({
cards: deck.length,
publicKey: alice.publicKey,
bits: 32,
});
const encryptedWithKeyA = alice.encryptAndShuffle(deckEncoded);
const encryptedWithKeyAKeyB = bob.encryptAndShuffle(encryptedWithKeyA);
(for more examples, please see the README on GitHub)
This post (Part 1) focused on how the Mental Poker protocol works — from the cryptographic math to the design philosophy. But that’s only half the story.
In Part 2, I’ll walk you through how I built a real, working, peer-to-peer Texas Hold’em game that runs entirely in the browser, using:
- mental-poker-toolkit for cryptographic fairness
- PeerJS and WebRTC for networking
And yes — it’s open source too on GitHub: predatorray/mental-texas-holdem. Feel free to explore the code, try the live demo, or use the library in your own project. If you find it useful, I’d love a ⭐ or a comment on GitHub!