kibitz

module
v0.26.0 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2026 License: MIT

README

kibitz

Pull up a chair.

kibitz is croc-style pairing for long-lived, end-to-end-encrypted sessions — chat and a dozen turn-based games instead of file transfer.

  • Pair like croc: the host gets a code phrase like lion-42-maple, plus a share link and QR code. Friends join by clicking or typing.
  • The relay can't read anything: the phrase seeds a PAKE key exchange; the relay only forwards opaque encrypted frames. Self-host it or use a hosted one — either way it's blind.
  • One binary: the relay embeds the whole web client. kibitz --listen :8080, open a browser, play.
  • Spectators welcome: sessions hold two players and any number of kibitzers, all in the same encrypted chat.

Status

Twelve games. Chess, backgammon (provably fair commit-reveal dice), checkers, reversi, Connect Four, Gomoku, Hex, Dots & Boxes, Go, Xiangqi, and two games where cheating is cryptographically impossible:

  • Battleship — each player commits to every cell of their board before the first shot; every reveal is verified by every participant (spectators included), and both full boards are opened and legality-checked at game end.
  • Gin Rummy — dealt by a "mental poker" shuffle: the two players jointly encrypt and shuffle the deck with a commuting cipher, so neither of them (nor the relay) learns the order or the opponent's hand, yet the deck is proven to be a fair, untouched 52 cards when keys are revealed at showdown. Full match play to 100 with lay-off and dealer alternation.

All of it runs without any server ever seeing a thing, because the relay only forwards ciphertext. Games start on demand from the picker and run side by side in one session; rematches swap seats. Eleven of the twelve ship with a "Hard" computer opponent for solo play (Gin is networked-two-player only).

How it works

The relay forwards frames it can never read. The code phrase seeds a PAKE handshake (as in croc); the host wraps a session group key to each joiner; all chat and moves are XChaCha20-Poly1305 envelopes. Games are both-sides-validate: every client runs the same rules engine and checks a position hash on every move — there's no server to cheat past, because the server is blind. Details: docs/THREAT-MODEL.md.

Hosted instance

A public relay runs at https://kibitz-play.fly.dev — open it, start a table, share the phrase. (Remember: the relay is blind either way; you never have to trust it.)

Self-hosting

Grab a release binary (or go install github.com/richardwooding/kibitz/cmd/kibitz@latest) and:

kibitz --listen :8080

Or run the container image:

docker run -p 8080:8080 ghcr.io/richardwooding/kibitz

Put TLS in front with your reverse proxy of choice. That's it — the web UI, relay, and everything else is in the one binary. Useful flags: --max-sessions (default 1000), --version.

Development

make serve    # build the WASM client and run the relay on :8080
make test     # go test -race ./...

License

MIT

Directories

Path Synopsis
cmd
compress-assets command
Command compress-assets precompresses the built web client into .br (brotli) and .gz (gzip) siblings, so the relay can serve the smallest encoding each client accepts.
Command compress-assets precompresses the built web client into .br (brotli) and .gz (gzip) siblings, so the relay can serve the smallest encoding each client accepts.
kibitz command
Command kibitz is the relay server.
Command kibitz is the relay server.
kibitz-wasm command
Native stub so `go build ./...` and `go vet ./...` succeed on the host — the real entrypoint is main.go, built only under GOOS=js GOARCH=wasm.
Native stub so `go build ./...` and `go vet ./...` succeed on the host — the real entrypoint is main.go, built only under GOOS=js GOARCH=wasm.
internal
bot
Package bot is the solo "Play the computer" opponent.
Package bot is the solo "Play the computer" opponent.
crypto
Package crypto is kibitz's security boundary.
Package crypto is kibitz's security boundary.
dashboard
Package dashboard serves a read-only admin view of the relay's blind-safe internal state, gated by GitHub OAuth and restricted to an allowlisted set of usernames.
Package dashboard serves a read-only admin view of the relay's blind-safe internal state, gated by GitHub OAuth and restricted to an allowlisted set of usernames.
ginrummy
Package ginrummy is a pure-logic rules and scoring library for two-player Gin Rummy, operating on plain card indices (0..51) with no crypto, networking, or service dependencies.
Package ginrummy is a pure-logic rules and scoring library for two-player Gin Rummy, operating on plain card indices (0..51) with no crypto, networking, or service dependencies.
mentalpoker
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.
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.
phrase
Package phrase generates croc-style code phrases and derives session IDs from them.
Package phrase generates croc-style code phrases and derives session IDs from them.
pushfwd
Package pushfwd is a keyless Web Push forwarder.
Package pushfwd is a keyless Web Push forwarder.
relay
Package relay implements the kibitz relay server: a blind frame forwarder.
Package relay implements the kibitz relay server: a blind frame forwarder.
service
Package service defines the layered-service abstraction and the mux that routes decrypted envelopes to services.
Package service defines the layered-service abstraction and the mux that routes decrypted envelopes to services.
service/backgammon
The backgammon service: engine + fair dice + turn protocol.
The backgammon service: engine + fair dice + turn protocol.
service/battleship
The battleship service — kibitz's flagship: hidden ship placement with NO trusted server anywhere.
The battleship service — kibitz's flagship: hidden ship placement with NO trusted server anywhere.
service/chat
Package chat is the simplest layered service: broadcast text messages with a bounded history that late joiners receive via the ctl snapshot.
Package chat is the simplest layered service: broadcast text messages with a bounded history that late joiners receive via the ctl snapshot.
service/checkers
The checkers service: game.Table lifecycle, on-demand Start, forced-move validation by membership, applyAndHash convention (hash after advance, identical on send and receive paths).
The checkers service: game.Table lifecycle, on-demand Start, forced-move validation by membership, applyAndHash convention (hash after advance, identical on send and receive paths).
service/chess
Package chess is the first game service, wrapping corentings/chess for rules.
Package chess is the first game service, wrapping corentings/chess for rules.
service/connect4
Connect Four rules — pure logic, no protocol.
Connect Four rules — pure logic, no protocol.
service/dots
Dots and Boxes rules — pure logic, no protocol.
Dots and Boxes rules — pure logic, no protocol.
service/game
Package game holds the seat/lifecycle logic every two-player game service shares: who sits where, who may start a game, rematch seat-swapping, and forfeit-on-leave.
Package game holds the seat/lifecycle logic every two-player game service shares: who sits where, who may start a game, rematch seat-swapping, and forfeit-on-leave.
service/gin
Package gin is the Gin Rummy service: a two-player card game dealt with a dealerless "mental poker" shuffle (internal/mentalpoker) so neither player nor the blind relay ever learns the deck order or the opponent's hand, yet every card is verifiable at showdown.
Package gin is the Gin Rummy service: a two-player card game dealt with a dealerless "mental poker" shuffle (internal/mentalpoker) so neither player nor the blind relay ever learns the deck order or the opponent's hand, yet every card is verifiable at showdown.
service/gomoku
Gomoku (five-in-a-row) rules — pure logic, no protocol.
Gomoku (five-in-a-row) rules — pure logic, no protocol.
service/gomokup
Package gomokup is "Gomoku Party": five-in-a-row for 2–4 players on one shared board with rotating turns.
Package gomokup is "Gomoku Party": five-in-a-row for 2–4 players on one shared board with rotating turns.
service/hex
Hex (the connection game) rules — pure logic, no protocol.
Hex (the connection game) rules — pure logic, no protocol.
service/reversi
The reversi service: game.Table lifecycle, on-demand Start, computed passes (never sent), applyAndHash convention.
The reversi service: game.Table lifecycle, on-demand Start, computed passes (never sent), applyAndHash convention.
service/weiqi
A capture/liberty-aware 1-ply heuristic bot for the "Hard" seat.
A capture/liberty-aware 1-ply heuristic bot for the "Hard" seat.
service/xiangqi
A "Hard" Xiangqi bot: alpha-beta negamax over the engine's own legal-move generation, apply, and check/terminal helpers (engine.go).
A "Hard" Xiangqi bot: alpha-beta negamax over the engine's own legal-move generation, apply, and check/terminal helpers (engine.go).
session
Package session is the client-side engine: it dials the relay, runs the create/join handshake, performs the PAKE + group-key exchange, and moves encrypted service envelopes.
Package session is the client-side engine: it dials the relay, runs the create/join handshake, performs the PAKE + group-key exchange, and moves encrypted service envelopes.
shipcommit
Package shipcommit implements the Battleship hiding scheme: each player commits to all 100 cells of their board before the first shot, then reveals exactly the cells that get shot.
Package shipcommit implements the Battleship hiding scheme: each player commits to all 100 cells of their board before the first shot, then reveals exactly the cells that get shot.
solo
Package solo provides a relay-free, in-memory transport for the local "try a game" hot-seat: two session ends (a host and one player) wired to each other with no WebSocket, PAKE, or crypto.
Package solo provides a relay-free, in-memory transport for the local "try a game" hot-seat: two session ends (a host and one player) wired to each other with no WebSocket, PAKE, or crypto.
wire
The inner payload layer: what clients put inside Direct/Broadcast Payload fields.
The inner payload layer: what clients put inside Direct/Broadcast Payload fields.
Package web embeds the built browser client.
Package web embeds the built browser client.

Jump to

Keyboard shortcuts

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