Pawnshake v0.1.0 · draft

Protocol

Genesis

Three signed messages start a game. Afterwards both players hold the same genesis, its hash names the game, and nobody could choose the colours.

The handshake

Peer to peer, no server needed. A server, when there is one, just relays these three.
Player A Player Bpick nonce_A, keep it secretCHALLENGE · commit = SHA-256(nonce_A)check cert, profile, time controlACCEPT · nonce_BSTART · reveals nonce_Acolours = SHA-256(nonce_A | nonce_B)[0] Player A Player Bpick nonce_A, keep it secretCHALLENGE · commit = SHA-256(nonce_A)check cert, profile, time controlACCEPT · nonce_BSTART · reveals nonce_Acolours = SHA-256(nonce_A | nonce_B)[0]
  1. CHALLENGE (A) A's certificate, the time control, rated or not, the arbiter level, the colour wish, the full rules profile, and a commitment to a secret nonce. Signed by A.
  2. ACCEPT (B) The hash of the challenge (so B signs the exact same profile and terms), B's certificate, and B's own random nonce. Signed by B.
  3. START (A) The hash of the accept and A's nonce, revealed. Signed by A. The game begins.
genesis      = CHALLENGE | ACCEPT | START
genesis_hash = SHA-256(genesis)
game_id      = first 16 bytes of genesis_hash

The vectors' game: 87740b24538374c5b4f953aae4976758.

Fair colours with commit and reveal

With random colours, White is A when the first byte of SHA-256(nonce_A | nonce_B) is even.

A cannot choose

A committed to nonce_A before seeing nonce_B. Changing it later breaks the commitment.

B cannot choose

B picked nonce_B without knowing nonce_A, only its hash. Any choice is a coin flip.

A can still refuse to send START after computing the colours. That only cancels a game that never began, and an app can count such refusals.

What the genesis guarantees

  • No replay between games. Every record's header names the genesis_hash, and both nonces make every genesis unique. A record from one game is meaningless in another.
  • Both signed the same rules. ACCEPT signs the hash of CHALLENGE, profile included. Verifiers judge the game by the values written there, never by their own defaults.
  • Known keys. Both device keys come from certificates the server signed. Offline, a device can still play with a certificate that is valid; an expired one can only start unrated games.
CHALLENGE284 bytes in the vectors
PSCHAL01 8 B
cert_A ~124
initial_ms 4 B
increment_ms 4 B
rated 1 B
arbiter 1 B 0 none, 1 checkpoints, 2 full
color 1 B 0 random, 1 white, 2 black
profile var
commit 32 B
sig_A 64 B

Device certificates

A player's records are signed with a device key made on the device and never exported. While online, the server certifies it: "this public key belongs to user X until date Y". The server's own public keys ship inside the apps, by key_id, so certificates can be checked offline.

  • Valid 30 days, renewed silently whenever the app is online.
  • One key per device and account, not per game: offline, nobody could certify a fresh one.
  • Revocation (a lost phone, "sign out everywhere") is checked when a game is anchored or reported: a game signed by a revoked key is not rated.