Skip to content

Routing information: header vs routing block vs encrypted tail

This page answers: where does “the route” live? — for flood and strict source route traffic — under the current dynamic header (minimum 16-byte base, 20 bytes with HAS_DST_ID, 16-bit channelHash / messageId).

Stateless repeaters (no predictive tables)

Repeaters do not consult nextHop RAM tables or distance-vector databases for third-party frames. They:

InformationWhere it lives
Who sentsrcId in the base header
Who is addressedOptional dstId when HAS_DST_ID
How far it may travelttlRaw in the base header (policy-capped — see Routing)
Forward path / breadcrumbsRouting block in the plaintext tail before the AES-CCM inner region when ttlRaw & 0x80 (HAS_ROUTE_BLOCK)
Duplicate suppressionRAM cache keyed by (channelHash, srcId, sessionId, messageId, fragmentWord)

Omitting the routing block at origin (normative)

Do not require a routing block on every flood. That wastes bytes.

When hopControl bit 7 is clear (HAS_ROUTE_BLOCK == 0), no routing block exists on the wire — there is no pathCount field and no placeholder at that position. The application tail (ciphertext+MIC) immediately follows the last enabled prefix block (optional region/fragment if present, else the base header).

Originators MAY omit the routing block on flood frames when no path breadcrumbs are needed yet.

The first relay that forwards a flood frame with no routing block (ttlRaw & 0x80 == 0) MUST, during that forwarding operation:

  1. Insert a new routing block (pathCount = 1, local hashSize fingerprint) before the encrypted application tail (shift ciphertext+MIC right). Originators MAY omit the routing block entirely — there is no pathCount=0 placeholder.
  2. Set hopControl |= 0x80 (HAS_ROUTE_BLOCK).
  3. Decrement HOP_LIMIT per Routing.
  4. Verify the full Mesh PDU remains ≤ 255 bytes.

Any relay that chooses to forward a flood frame that lacks a routing block MUST insert the routing block as part of that forward (same steps). Repeaters MUST NOT mutate verFlags.

This is allowed because:

  • The routing block is outside the encrypted inner payload and excluded from CCM AAD.
  • hopControl is zero-masked in AAD at offset 0x04, so relays need not re-encrypt.
  • Repeaters MUST NOT mutate verFlags.
  • Repeaters MUST NOT exceed the 255-byte PHY payload limit.

Routing block (normative)

When hopControl bit 7 (HAS_ROUTE_BLOCK, wire ttlRaw & 0x80) is set, the routing block begins after the optional Region and optional Fragment blocks (see Packet layout).

FieldSizeDescription
pathCount1Number of path entries (0–63 typical; product caps MAY differ).
pathHashespathCount × hashSizeEach entry hashSize bytes: pathHash = SHA256("LowMesh/route-fingerprint/1" || uint32_le(nodeId32))[0..hashSize-1] — see Routing.

Wire bytes: 1 + pathCount × hashSize.

Flood append (normative sketch)

When FLOOD is set and the node rebroadcasts:

  1. Verify hop budget, duplicate cache, and PHY growth policy (≤ 255 bytes total).
  2. If (ttlRaw & 0x80) == 0: no routing block is present — the relay MUST insert one (pathCount = 1, local hashSize fingerprint) before the encrypted application tail, set ttlRaw |= 0x80, then decrement hops: ttlRaw = (ttlRaw & 0xC0) | ((hopLimit - 1) & 0x3F) (with hopLimit = ttlRaw & 0x3F before the decrement). verFlags MUST NOT change.
  3. If ttlRaw bit 7 is already set: append hashSize bytes to pathHashes, increment pathCount, then decrement hop count in ttlRaw the same way (upper bits preserved).
  4. Shift the encrypted inner tail right as needed without re-encrypting: the routing block is outside AES-CCM AAD, and ttlRaw is zero-masked in AAD — see Channels & security.

Strict source route (sketch)

Originators MAY pre-fill pathHashes with ordered fingerprints; relays verify their position in the path and forward toward the next hop per product rules (see firmware reference sourceRouteRelayRole).

Security (normative): The routing block is outside CCM AAD so repeaters can modify or grow flood breadcrumbs without re-encrypting. That is correct for flood path recording. Strict source-route instructions that affect security, authorization, or delivery guarantees MUST be authenticated inside the encrypted application body or by a separate routeAuth mechanism. Strict source routes carried only in the plaintext routing block are advisory unless authenticated by a higher-layer routeAuth field — MUST NOT be treated as trusted authorization by themselves. Do not change flood breadcrumb behavior: the routing block remains mutable for relay insertion and appending.

Crypto boundary note

On all channelHash values, only the application tail after the routing block is AES-256-CCM-4 protected (including 0x0000). The base header, region block, fragment block, and routing block are plaintext with respect to the channel PSK MIC, but the AAD policy authenticates an explicit prefix — see Channels & security.

See also

LowMeshOS — always open-source mesh protocol documentation