Every payload, field by field. The coloured dumps are the real bytes from the conformance vectors that the Go, TypeScript and Dart libraries all reproduce. Hover or tap a byte to see which field it belongs to.
Varints are unsigned LEB128 and must be minimal: 00 is 0, e8 07 is 1000. A longer encoding of the same number is rejected, so every message has exactly one byte form.
Magic tags open every signed message (PSREC001, PSCHAL01, PSCERT01 ...). A signature for one kind of message can never verify as another, and a new layout gets a new tag.
Hashes are SHA-256, signatures Ed25519 (64 bytes), verified under ZIP-215 rules.
White's first move, 1. e4, exactly as it travels from White's phone to Black's: sequence 1, nothing seen yet, signed 1000 ms after START, move code 13.
Wire record: 1. e469 bytes
00000100e8070d44fae652fdb8dbfee518d7
001012f32d796234794fc1714893d63877fb
0020171abbf997a3139789432ebaf8824d2c
003049b4e667d15b17f3a121ab8181072e83
0040f926995805
seq 1seen 1at 2op 1signature 64
Black's acknowledgement is the same shape with op 230 (ACK) and seen = 1:
The header's variable parts plus its signature. The genesis is known to everyone involved, so this is all an anchor needs, and it still commits to the whole game.
Server records carry two seen values, one per player. This one is VERDICT_RESULT (op 242) with the result, the termination and both final clocks as varints.
A name and numbered key/value pairs, both varints. This is whitepawn/1 for a 3+2 rated blitz game online, so it has no key 14 (link_settle): only games with peer clocks carry it, two bytes more.
Three messages start a game; see Genesis for the handshake. CHALLENGE carries the challenger's certificate and the rules profile in full.
CHALLENGE284 bytes
000050534348414c30315053434552543031
0010010a757365723a77686974652e28d334
0020410b2fa7d4f626d51bf1ee9fb464653b
003079090f9be0b3c82382845a946b49d19c
00406b49d2647c128ad43a826cd889403081
0050ae262b2b95d06375d6111c96763f7373
006023c05c0725634f287d5fb5faa4cb9c2f
0070d7743c2c72944a9348d2e059d1e05455
0080359a810c0002bf20000007d00102000b
009077686974657061776e2f310d011e0202
00a0031004882705fa0106e80707904e08b0
00b0ea0109010a000b010c000d075dfbabee
00c0df318bf33c0927c43d7630f51b82f351
00d0740301354fa3d7fc51f0132ebbe8b409
00e0ebf2488cf70a50cfe9d7850275401ad5
00f0b4476d73ce909588e686c7625890dde9
0100799e850a5f520094391cc623f4ef83c4
01107971ff7214d428ce8cdb5309
PSCHAL01 8cert: PSCERT01 8cert: key_id 1cert: user id length 1cert: user id 10cert: device public key 32cert: issued 4cert: expires 4cert: server signature 64initial_ms 4increment_ms 4rated 1arbiter 1color 1rules profile 45commit = SHA-256(nonce_A) 32signature A 64
ACCEPT244 bytes
0000505341435054303165bead4fb790c9db
0010ae91fdb4b39bff95666c19972e5a6e4f
0020be2bf896822222435053434552543031
0030010a757365723a626c61636b90607de6
00400a61811da61e412834cdb4fe07fca7f2
005067b615058dd11a84b0dcb2da6b49d19c
00606b49d26459215be3abc6ac8b784dc351
0070f89485238e891c195987b1308fa9f9bc
0080b7521ebccc0d77b7e94d0d903e5d6d60
00909cfd22147891b5a33552a2aa60cc6bee
00a07e033502100f0e0d0c0b0a0908070605
00b004030201d95401acc78e1f2a06fba01b
00c0764ade338be95b9d5a5a969f2b240b1b
00d08865f18cb351d2d72967f0d73a0f057d
00e0ccaf81855fc03fe6a2cf3d1299e07cd2
00f0d59abc01
PSACPT01 8SHA-256(CHALLENGE) 32cert: PSCERT01 8cert: key_id 1cert: user id length 1cert: user id 10cert: device public key 32cert: issued 4cert: expires 4cert: server signature 64nonce_B 16signature B 64
START120 bytes
00005053535452543031887f67a079cd5525
00109bfed0d6bad7b3400444cec14e6d954e
00201d06ade5dade10690102030405060708
0030090a0b0c0d0e0f100c372f256b77b7ff
00409df937b92c62a4bd0016439c3cd48edf
005030096d138c739d1f0d6e8a4310db559b
006018aa24ad4d0e2a6560cb4bbc2552ecdf
00708b986809a555d609
PSSTRT01 8SHA-256(ACCEPT) 32nonce_A (revealed) 16signature A 64
The server's signed answer to an anchor: the highest heads it holds for both players, its clock, and the hash of its previous receipt for this game.
Receipt254 bytes
00005053414e4348303101f0210b45ff8480
0010f06637feac142b51b961da55787086a8
00201ea46bb65b22e3c526000000028a5c56
0030995af759ee73e21048768a85fc0c634d
0040ef30782df17a2b5e12bf107089000000
005002b491f6f9672192e9641e68d3cbb444
00609201e5ef64e532ad11ae946a60f579b3
00705f000000000000000000000000000000
008000000000000000000000000000000000
00900000000001a3185c507b000000030700
00a000000000000000000000000000000000
00b00000000000000000000000000000c66e
00c0627a88816acce92d510ab9b7860714ca
00d00cadfb49d7d51f9f4343dd3a459d229d
00e08d91bed16388f9e1e1d01aecee33a5f6
00f047719961499da5e03051783f770e
PSANCH01 8key_id 1genesis_hash 32white_seq 4white record id 32black_seq 4black record id 32state_hash 32state_verified 1server_ms u64 8anchor_no 4prev_receipt 32server signature 64
Peer games exchange pings four times a second on every link that carries the records, inside that link's session. They are unsigned and never stored: they only feed the live checks.
While a game with peer clocks runs, each device adds a signed heartbeat to a PING, as its optional last field, at least once a second on every open link: "at my clock at, my newest record was head_seq". A record that contradicts it is a fork (see Clocks).
BEAT113 bytes
PSBEAT018 B
genesis_hash32 B
signer1 B0 white, 1 black
head_seq4 Bmy newest record
at4 Bmy clock
sig64 BEd25519, device key, over everything before
The first message on a direct link, one from each side. After it every frame on that link is sealed with ChaCha20-Poly1305 under a key per direction, derived from the two hellos, with the frame counter as the nonce (see Links).
LINK_HELLO161 bytes
PSLINK018 B
genesis_hash32 B
role1 B0 white, 1 black
eph_pk32 BX25519, fresh for this session
nonce16 Brandom
have_white4 Bhighest seq held
have_black4 Bfor the flush
sig64 BEd25519, the role's device key, over everything before