the Elixir version uses an ASN.1 based format, but the support in other languages (besides C) for ASN.1 is surprisingly bad. So I'll resort to a hard-coded format. Again. ---- InitMessage ::= capabilities:ShortList (* the InitMessage is the first thing sent on a newly established connection. * both sides are expected to send the capabilities they support * then wait for the other side to send theirs (meaning they don't * block each other during this), and then use just the capabilities * which both peers support *) ProtoMessage ::= algorithm:SigAlgo pubkeylen:u16(big-endian) length:u16(big-endian) data:[length]u8=ProtoMsgKind ProtoMsgKind ::= (* xfer *) [0x00] XferSlice | (* summary-pull *) [0x01] SummaryList | (* summary-ihave *) [0x02] SummaryList (* after the initial capabilities are sent, both sides are expected to send * summaries for all public keys they know + all available slices for these * pubkeys *) ShortList ::= length:u16(big-endian) data:[length]T XSList ::= length:u8 data:[length]T (* "raw" summary header overhead = 41 bytes, per 65535 slices *) SummaryList ::= data:[*]Slice (* uses all remaining space in the packet *) Slice ::= pubkey:[pubkeylen]u8 start:u64 length:u16 XferSlice ::= pubkey:[pubkeylen]u8 siglen:u16(big-endian) start:u64 data:[*]XferBlob (* uses all remaining space in the packet *) XferBlob ::= signature:[siglen]u8 (* signature gets calculated over `blid ++ data` *) ttl:u8 data:XferInner XferInner ::= (* normal *) [0x00] XferNormal | (* prune *) [0x01] (* empty; NOTE: this packet indicates that * all packets before it should be deleted on all servers; * used for data protection/privacy compliance; * although it is possible to delete such packets after a grace period * (e.g. 1 year) during which every peer should've had a chance to retrieve * it, doing that is discouraged *) XferNormal ::= attrs:ShortList data:ShortList KeyValuePair ::= key:XSList value:ShortList SigAlgo ::= (* ed25519 *) [0x65, 0x64, 0xff, 0x13]