Skip to content

Protocol v1.0

This is the v1.0 specification. For the normative text, see the docs/ directory.

Framing & Encoding

All NXFR communication after TLS establishment uses a binary framing format. Each frame consists of a fixed 28-byte header followed by a variable-length payload.

Frame Header

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          magic (4 bytes): 'N'  'X'  'F'  'R'                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   version     |     kind      |           flags               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         session_id                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         stream_id                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                        message_id                             +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        payload_len                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Offset Size Field Description
0 4 magic Always 0x4E584652 ("NXFR").
4 1 version Frame format version. 0x01 for v0.1.
5 1 kind 0x01 = CONTROL, 0x02 = CHUNK, 0x03 = KEEPALIVE.
6 2 flags Bit flags, semantics depend on kind. Big-endian.
8 4 session_id Session identifier. 0 before HELLO_ACK. Big-endian.
12 4 stream_id 0 for session-level. >0 for file stream. Big-endian.
16 8 message_id Monotonically increasing per direction. Big-endian.
24 4 payload_len Payload length in bytes. Big-endian.

Frame Kinds & Size Limits

Kind Code Payload Format Max Size
CONTROL 0x01 CBOR-encoded map containing a "type" key. 64 KiB (65,536 bytes)
CHUNK 0x02 40-byte header (offset, hash) + raw file data. 4 MiB (4,194,304 bytes)
KEEPALIVE 0x03 Empty (PING/PONG) or 8-byte timestamp (u64 BE). 8 bytes

For CHUNK frames, the 40-byte header format within the payload is: - offset (8 bytes, u64 BE): Byte offset of this chunk. - chunk_hash (32 bytes): SHA-256 of the data portion only. - data (variable): Raw file data.

CBOR Encoding Rules

All control message payloads (frames with kind = 0x01) MUST follow strict CBOR rules ([RFC 8949]):

Rule Requirement Rationale
Definite-length only MUST use definite-length encoding for all items Enables bounded memory allocation
String keys Map keys MUST be UTF-8 text strings (major type 3) Debuggability, consistency
Binary data Binary values MUST use byte strings (major type 2) Efficiency for hashes, IDs
Integer minimality Integers MUST use the smallest valid CBOR encoding Interoperability
No tags CBOR tags (major type 6) MUST NOT be used in v0.1 Simplicity
Max nesting Maximum nesting depth: 6 (RESUME_STATUS requires depth 6) Prevents stack overflow
Unknown fields Receivers MUST ignore unknown map keys Forward compatibility
Deterministic keys Map keys SHOULD be sorted lexicographically Reproducible test vectors