ワンクリックで
packets-wire-format
// Reticulum's packet structure and wire format. Use when working with packet headers, MTU/MDU, packet types, header types (HEADER_1/HEADER_2), packet context flags, IFAC, or binary packet encoding.
// Reticulum's packet structure and wire format. Use when working with packet headers, MTU/MDU, packet types, header types (HEADER_1/HEADER_2), packet context flags, IFAC, or binary packet encoding.
Reticulum's cryptographic primitives, identity structure, encryption tokens, and key derivation. Use when working with Ed25519, X25519, identity hashes, HKDF, token format, encryption, signatures, ratchets, or key derivation.
Reticulum's addressing system and destination types. Use when working with destination types (SINGLE, GROUP, PLAIN, LINK), destination hashes, aspect naming, or addressing.
Reticulum's hardware abstraction layer and interface types. Use when working with RNode, AutoInterface, TCP, UDP, I2P, Serial, KISS, BLE interfaces, interface modes, IFAC, bandwidth allocation, or MTU.
Reticulum's link system — encrypted channels with forward secrecy. Use when working with link establishment, link requests, ECDH, ephemeral keys, forward secrecy, channels, keep-alive, or link timeouts.
Detailed knowledge of Reticulum's announce mechanism for automatic path discovery. Use when working with announce propagation, path discovery, announce bandwidth, announce forwarding, path requests, or announce structure.
Reticulum's resource transfer system for large data over links. Use when working with resource transfers, windowing, hashmaps, segments, compression, file transfers, or resource states.
| name | packets-wire-format |
| description | Reticulum's packet structure and wire format. Use when working with packet headers, MTU/MDU, packet types, header types (HEADER_1/HEADER_2), packet context flags, IFAC, or binary packet encoding. |
This skill provides detailed technical knowledge about Reticulum's binary packet structure and wire format, essential for understanding how data flows across the network at the byte level.
Every Reticulum packet follows a strict binary format:
[HEADER 2 bytes] [IFAC 0-64 bytes] [ADDRESSES 16/32 bytes] [CONTEXT 1 byte] [DATA 0-464 bytes]
HEADER (2 bytes)
IFAC Field (0-64 bytes, optional)
ADDRESSES Field (16 or 32 bytes)
CONTEXT Field (1 byte)
DATA Field (0-464 bytes)
The first header byte encodes six pieces of information using bit fields:
Bit Layout: [IFAC][Header Type][Context Flag][Propagation][Dest Type 2 bits][Packet Type 2 bits]
Bit 7: IFAC Flag (1 bit)
Bit 6: Header Type (1 bit)
Bit 5: Context Flag (1 bit)
Bit 4: Propagation Type (1 bit)
Bits 3-2: Destination Type (2 bits)
Bits 1-0: Packet Type (2 bits)
From a raw packet's first byte:
flags = raw_packet[0]
ifac_flag = (flags & 0b10000000) >> 7
header_type = (flags & 0b01000000) >> 6
context_flag = (flags & 0b00100000) >> 5
propagation_type = (flags & 0b00010000) >> 4
destination_type = (flags & 0b00001100) >> 2
packet_type = (flags & 0b00000011)
When constructing a packet:
packed_flags = (
(header_type << 6) |
(context_flag << 5) |
(transport_type << 4) |
(destination_type << 2) |
packet_type
)
Note: IFAC flag is typically set by the interface layer, not in application code.
Four fundamental packet types (2 bits, values 0-3):
| Type | Value | Purpose | Encrypted |
|---|---|---|---|
| DATA | 0x00 | Application data | Usually yes |
| ANNOUNCE | 0x01 | Identity/service announcement | No |
| LINKREQUEST | 0x02 | Establish link | No |
| PROOF | 0x03 | Delivery confirmation | Depends on context |
DATA (0x00)
ANNOUNCE (0x01)
LINKREQUEST (0x02)
PROOF (0x03)
Two header formats control address field structure:
HEADER_1 (0x00)
HEADER_2 (0x01)
Four destination types (2 bits):
| Type | Value | Bits | Purpose |
|---|---|---|---|
| SINGLE | 0 | 00 | One-to-one, ephemeral encryption |
| GROUP | 1 | 01 | One-to-many, shared key |
| PLAIN | 2 | 10 | Unencrypted broadcast |
| LINK | 3 | 11 | Over established link |
Two propagation modes (1 bit):
BROADCAST (0)
TRANSPORT (1)
The context byte indicates packet purpose within higher-level protocols:
NONE = 0x00 # Generic data packet
RESOURCE = 0x01 # Resource transfer data chunk
RESOURCE_ADV = 0x02 # Resource advertisement
RESOURCE_REQ = 0x03 # Resource part request
RESOURCE_HMU = 0x04 # Resource hashmap update
RESOURCE_PRF = 0x05 # Resource proof (not encrypted)
RESOURCE_ICL = 0x06 # Resource initiator cancel
RESOURCE_RCL = 0x07 # Resource receiver cancel
CACHE_REQUEST = 0x08 # Path/announce cache request
REQUEST = 0x09 # Request packet (request/response pattern)
RESPONSE = 0x0A # Response to request
PATH_RESPONSE = 0x0B # Path request response
COMMAND = 0x0C # Command packet
COMMAND_STATUS = 0x0D # Command execution status
CHANNEL = 0x0E # Link channel data
KEEPALIVE = 0xFA # Link keepalive (no data)
LINKIDENTIFY = 0xFB # Link peer identification proof
LINKCLOSE = 0xFC # Link close notification
LINKPROOF = 0xFD # Link packet proof
LRRTT = 0xFE # Link request RTT measurement
LRPROOF = 0xFF # Link request proof
The context flag (bit 5 in header byte 1) provides additional signaling:
Usage varies by packet context. For example, in resource transfers it may indicate last packet, or in links it may signal specific protocol states.
Understanding packet size limits is critical for protocol implementation:
MTU = 500 # Maximum Transmission Unit (bytes)
TRUNCATED_HASHLENGTH = 128 # Hash length in bits (16 bytes)
HEADER_MAXSIZE = 2 + 1 + (128//8)*2 # 35 bytes
IFAC_MIN_SIZE = 1 # Minimum IFAC overhead
The maximum payload size in a packet:
MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
= 500 - 35 - 1
= 464 bytes
The MDU is 464 bytes as calculated above.
When encryption is applied, overhead reduces available payload:
TOKEN_OVERHEAD = 48 # IV (16 bytes) + HMAC (32 bytes)
KEYSIZE = 512 # Identity keypair size in bits (64 bytes = KEYSIZE//8)
AES128_BLOCKSIZE = 16 # AES block size
# The calculation from Packet.py (KEYSIZE//16 = 32 bytes for ephemeral public key):
ENCRYPTED_MDU = floor((MDU - TOKEN_OVERHEAD - KEYSIZE//16) / AES128_BLOCKSIZE) * AES128_BLOCKSIZE - 1
= floor((464 - 48 - 32) / 16) * 16 - 1
= floor(384 / 16) * 16 - 1
= 24 * 16 - 1
= 384 - 1
= 383 bytes
The ENCRYPTED_MDU is 383 bytes. The KEYSIZE//16 term (32 bytes) accounts for the ephemeral X25519 public key prepended to encrypted tokens.
| Packet Type | Typical Size | Max Size |
|---|---|---|
| Path Request | 51 bytes | - |
| Announce | 167 bytes | - |
| Link Request | 83 bytes | - |
| Link Proof | 115 bytes | - |
| Link RTT | 99 bytes | - |
| Link Keepalive | 20 bytes | - |
| Data (encrypted to SINGLE) | Variable | 383 bytes payload |
| Data (unencrypted/GROUP) | Variable | 464 bytes payload |
| Data (over Link) | Variable | ~431 bytes payload |
IFAC provides interface-level authentication and access control:
Bit 7 of header byte 1:
When present, IFAC appears immediately after the 2-byte header:
[Header Byte 1][Header Byte 2][IFAC N bytes][Addresses...][Context][Data]
The IFAC content is interface-specific and opaque to higher protocol layers. Length is negotiated during interface configuration.
When unpacking a packet with IFAC set:
Most application code doesn't handle IFAC directly—it's managed by the interface layer.
Building a simple DATA packet to a SINGLE destination (broadcast):
import struct
# Parameters
destination_hash = b'\x01\x02\x03...' # 16 bytes
data_payload = b"Hello, Reticulum!"
hops = 0
# Header byte 1
header_type = 0 # HEADER_1
context_flag = 0 # FLAG_UNSET
transport_type = 0 # BROADCAST
destination_type = 0 # SINGLE
packet_type = 0 # DATA
flags = (
(header_type << 6) |
(context_flag << 5) |
(transport_type << 4) |
(destination_type << 2) |
packet_type
) # Result: 0b00000000 = 0x00
# Pack header
header = struct.pack("!B", flags) # Byte 1: 0x00
header += struct.pack("!B", hops) # Byte 2: 0x00
# Add destination
header += destination_hash # 16 bytes
# Add context
context = 0x00 # NONE
header += struct.pack("!B", context) # 1 byte
# Encrypt data (simplified, actual encryption is complex)
ciphertext = encrypt_for_destination(data_payload, destination_hash)
# Assemble packet
raw_packet = header + ciphertext
# Verify size
if len(raw_packet) > 500:
raise ValueError("Packet exceeds MTU")
Unpacking a received packet:
# Assume raw_packet is received bytes
flags = raw_packet[0]
hops = raw_packet[1]
# Extract header fields
ifac_flag = (flags & 0b10000000) >> 7
header_type = (flags & 0b01000000) >> 6
context_flag = (flags & 0b00100000) >> 5
transport_type = (flags & 0b00010000) >> 4
destination_type = (flags & 0b00001100) >> 2
packet_type = (flags & 0b00000011)
# Determine hash length
DST_LEN = 16 # TRUNCATED_HASHLENGTH // 8
# Parse based on header type
if header_type == 1: # HEADER_2
transport_id = raw_packet[2:DST_LEN+2]
destination_hash = raw_packet[DST_LEN+2:2*DST_LEN+2]
context = raw_packet[2*DST_LEN+2]
data = raw_packet[2*DST_LEN+3:]
else: # HEADER_1
transport_id = None
destination_hash = raw_packet[2:DST_LEN+2]
context = raw_packet[DST_LEN+2]
data = raw_packet[DST_LEN+3:]
# Process based on packet type
if packet_type == 0: # DATA
if destination_type == 0: # SINGLE
plaintext = decrypt_data(data, destination_hash)
# ... handle data
elif packet_type == 1: # ANNOUNCE
# ... process announce
HEADER FIELD DESTINATION FIELD CONTEXT FIELD DATA FIELD
_______|_______ _______|_______ ________|______ __|_
| | | | | | | |
00000000 00000111 [HASH1, 16 bytes] [CONTEXT, 1 byte] [DATA]
|| | | | |
|| | | | +-- Hops = 7
|| | | +------- Packet Type = DATA (00)
|| | +--------- Destination Type = SINGLE (00)
|| +----------- Propagation Type = BROADCAST (0)
|+------------- Header Type = HEADER_1 (0)
+-------------- Access Codes = DISABLED (0)
HEADER FIELD DESTINATION FIELDS CONTEXT FIELD DATA FIELD
_______|_______ ________________|________________ ________|______ __|_
| | | | | | | |
01010000 00000100 [HASH1, 16 bytes] [HASH2, 16 bytes] [CONTEXT, 1 byte] [DATA]
|| | | | |
|| | | | +-- Hops = 4
|| | | +------- Packet Type = DATA (00)
|| | +--------- Destination Type = SINGLE (00)
|| +----------- Propagation Type = TRANSPORT (1)
|+------------- Header Type = HEADER_2 (1)
+-------------- Access Codes = DISABLED (0)
HEADER FIELD IFAC FIELD DESTINATION FIELD CONTEXT FIELD DATA FIELD
_______|_______ ______|______ _______|_______ ________|______ __|_
| | | | | | | | | |
10000000 00000111 [IFAC, N bytes] [HASH1, 16 bytes] [CONTEXT, 1 byte] [DATA]
|| | | | |
|| | | | +-- Hops = 7
|| | | +------- Packet Type = DATA (00)
|| | +--------- Destination Type = SINGLE (00)
|| +----------- Propagation Type = BROADCAST (0)
|+------------- Header Type = HEADER_1 (0)
+-------------- Access Codes = ENABLED (1)
Byte Order: All multi-byte integers use network byte order (big-endian, ! format in struct)
Hash Truncation: Full SHA-256 hashes (256 bits) are truncated to 128 bits (16 bytes) for addresses
Hop Count: Starts at 0, incremented by each forwarding node, max 255
MTU Enforcement: Packets exceeding 500 bytes are rejected before transmission
Context Field Placement: Always the last byte before payload data, regardless of header type
Encryption Overhead: When encrypting to SINGLE destinations, expect ~81 bytes overhead (464 - 383)
Link Packets: Special handling with different encryption scheme, identified by destination_type = LINK
Proof Packets: Size varies; explicit proofs include full packet hash + signature
Announce Propagation: Controlled by hop count; decremented at each hop until reaching 0
Header Rewriting: Transport nodes may rewrite HEADER_1 to HEADER_2 when forwarding
When debugging packet issues:
See wire-examples.py for complete working examples of packet construction and parsing at the byte level.