mentalpoker

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 12, 2026 License: MIT Imports: 2 Imported by: 0

README

mentalpoker

Dealerless card shuffle ("mental poker") for two untrusting peers: a commutative cipher lets both players jointly shuffle and deal a deck so that neither player — nor any relay between them — learns the deck order or the other's hand, yet every card can be revealed and verified at showdown.

Scheme: Pohlig–Hellman / SRA over a 2048-bit safe prime (RFC 3526 group 14). Each card is a distinct quadratic-residue token; a player's secret is an exponent, encryption is modular exponentiation, and because exponentiation commutes the players can layer and strip encryption in either order. Cheating is caught at showdown: both reveal their exponents and anyone (including spectators) recomputes the shuffle and verifies the deck.

key, _ := mentalpoker.NewKey()
deck := mentalpoker.EncryptAll(key, mentalpoker.FreshDeck())
_ = mentalpoker.Shuffle(deck) // crypto/rand Fisher–Yates
// exchange decks, strip layers with key.Decrypt, verify with VerifyDeck

Pure logic — no networking, no I/O. Compiles to WASM. Extracted from kibitz, where it powers Gin Rummy over an end-to-end-encrypted relay.

MIT licensed.

Documentation

Overview

Package mentalpoker implements the cryptographic core of a dealerless card shuffle ("mental poker"): a commutative cipher that lets two players jointly shuffle and deal a deck so that neither player — nor the blind relay — learns the deck order or the other's hand, yet every card can be revealed and verified at showdown.

Scheme (Pohlig–Hellman / SRA over a safe prime). p is a 2048-bit safe prime (RFC 3526 group 14); q=(p-1)/2 is prime and the quadratic residues mod p form the unique subgroup of order q. Each card i is encoded as a distinct QR token_i. A player's secret is an exponent k in [2,q-1]; encryption is c = m^k mod p and decryption c^(k⁻¹ mod q) mod p. Because the subgroup has prime order q every k is invertible mod q, and exponentiation commutes, so

Eₐ(E_b(m)) = m^(kₐ·k_b) = E_b(Eₐ(m)).

To deal a doubly-encrypted card m^(kₐk_b) to A, B strips its layer (Decrypt_b → m^kₐ) and A strips its own (Decrypt_a → m); B never sees m because it would need kₐ. Cheating is caught at showdown: both players reveal their exponents and anyone (including spectators) recomputes the shuffle and checks the fully-decrypted deck is exactly the 52 tokens — see VerifyDeck.

Index

Constants

View Source
const DeckSize = 52

DeckSize is a standard 52-card deck.

Variables

This section is empty.

Functions

func Decode

func Decode(m *big.Int) int

Decode maps a fully-decrypted plaintext back to a card index, or -1.

func EncryptAll

func EncryptAll(key Key, deck []*big.Int) []*big.Int

EncryptAll returns a new deck with every card raised to key (order preserved).

func FreshDeck

func FreshDeck() []*big.Int

FreshDeck returns the 52 plaintext card tokens in card order.

func Marshal

func Marshal(deck []*big.Int) [][]byte

Deck marshals to/from the wire as big-endian byte slices.

func Shuffle

func Shuffle(deck []*big.Int) error

Shuffle permutes deck in place with a crypto/rand Fisher–Yates.

func Token

func Token(i int) *big.Int

Token returns the QR encoding of card i (0..51).

func Unmarshal

func Unmarshal(raw [][]byte) []*big.Int

func VerifyDeck

func VerifyDeck(deck []*big.Int, a, b Key) bool

VerifyDeck checks that a doubly-encrypted deck, decrypted with both revealed keys, is exactly the 52 distinct card tokens — proving both players used a single consistent key and the deck contains no duplicated or forged cards.

Types

type Key

type Key struct {
	// contains filtered or unexported fields
}

Key is a player's secret exponent and its inverse mod q.

func KeyFromExponent

func KeyFromExponent(k *big.Int) (Key, bool)

KeyFromExponent reconstructs a key from a revealed exponent (for showdown verification). Returns ok=false if the exponent isn't a valid unit mod q.

func NewKey

func NewKey() (Key, error)

NewKey draws a fresh random secret key.

func (Key) Decrypt

func (key Key) Decrypt(c *big.Int) *big.Int

func (Key) Encrypt

func (key Key) Encrypt(m *big.Int) *big.Int

Encrypt raises m to the secret exponent; Decrypt strips one layer.

func (Key) Exponent

func (key Key) Exponent() *big.Int

Exponent returns the raw secret exponent, to be revealed only at showdown.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL