Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

UMSH is an experimental LoRa-oriented mesh protocol that grew out of a simple question: what would a cryptographically addressed LoRa mesh look like if designed from the ground up with strong security and clean architecture? Inspired by MeshCore, UMSH started as a thought experiment addressing what its author saw as critical shortcomings—shortcomings that would practically require backward-incompatible changes to fix. What began as a toy protocol has since been developed into this comprehensive specification.

The project repository, reference implementation, and supporting tooling are available on GitHub.

The ideas in UMSH are free for anyone to adopt, but was written with MeshCore V2 in mind. Meshtastic has discussed the possibility of a breaking v3 revision, and some of these ideas may be relevant there as well.

Point-by-point protocol comparisons with MeshCore, Meshtastic, and Reticulum are available.

Overview

In UMSH, endpoints are identified by public keys, and multicast communication is based on shared symmetric channel keys. At its core, UMSH defines a MAC layer with framing, addressing, encryption, authentication, and hop-by-hop forwarding. UMSH also defines application-layer protocols for text messaging, chat rooms, and node management that are built on top of this foundation. The MAC layer treats payloads opaquely and can equally carry UMSH-defined application protocols, third-party protocols such as CoAP, or any other higher-layer content.

UMSH is designed to support:

  • Public-key-addressed unicast
  • Symmetric-key multicast
  • Optional payload encryption
  • End-to-end authentication across multi-hop paths
  • Selective flooding and source-routed delivery
  • Operation in both encrypted and amateur-radio-compliant unencrypted modes
  • Ability to operate in a way that preserves perfect forward secrecy (PFS)
  • Timestamp-free at the MAC layer

Design Principles

The following principles guide UMSH’s design. When evaluating a design decision, prefer the option that best satisfies these principles. The order of these principles shouldn’t be interpreted as an order of importance.

Single-frame design. Every packet must fit in a single LoRa frame. Operations that require more data than one frame can carry belong at a higher layer.

Confidentiality. Encryption and authentication must be available for every kind of interaction. Where metadata concealment is also needed, the protocol should provide opt-in mechanisms rather than requiring it universally.

Robustness. Prefer constructions that fail gracefully over ones that fail catastrophically. A slightly less efficient design that degrades safely under adverse conditions is better than an efficient one that breaks badly.

Tolerance of loss and disorder. Assume packets will be dropped, duplicated, and delivered out of order. No operation should require synchronized state between two nodes that cannot recover from a missed message.

Brevity. Every byte costs airtime. Mandatory fields should be as small as correctness allows; optional fields should be absent when not needed.

Practicality. A protocol must be operable, not just correct. Prefer designs that make real networks easier to understand and debug — readable packet traces, attributable traffic, and identifiable nodes are operational requirements, not luxuries. Theoretical minimalism that makes a protocol difficult to deploy or troubleshoot is a real cost.

Layer separation. The MAC layer routes and delivers opaque payloads. It must not depend on payload content, and payload protocols must not depend on MAC-layer internals.

Minimal mandatory state. Basic operation should require only a node’s own keypair and its configured channel keys. Path tables, clock synchronization, and session state are optional enhancements, not prerequisites.

Graceful extensibility. The protocol must be able to evolve without requiring coordinated upgrades across a deployed network. New features should be deployable incrementally, with older nodes degrading gracefully rather than failing.

Use Cases

UMSH is designed for deployments where LoRa’s range and low power consumption are valuable and where the constraints of LoRa — low data rates, small frame sizes, shared channel — make protocol efficiency and cryptographic robustness important.

Intended use cases include:

  • Off-grid text communication — chat, direct messaging, and group channels between people in areas without cellular coverage: hiking, expeditions, disaster response, rural communities.
  • Emergency and disaster communications — resilient mesh networking that operates without any fixed infrastructure and degrades gracefully as nodes go offline.
  • IoT and sensor telemetry — authenticated sensor readings from battery-powered field devices, where per-packet overhead directly affects battery life and where tampered readings could have real consequences.
  • Amateur radio mesh networking — the protocol defines explicit amateur-radio-compliant modes with callsign fields and mandatory unencrypted operation, supporting legal use on amateur frequencies.
  • Privacy-sensitive communication — blind unicast and encrypted multicast allow metadata concealment (sender and recipient identity) for contexts where traffic analysis is a concern.
  • Embedded and constrained deployments — compact encoding (1-byte FCF, compact address hints, minimal per-packet overhead), single-frame design, and no mandatory runtime state (no path tables, no clock synchronization) make UMSH suitable for bare-metal microcontrollers with minimal RAM and no operating system.

UMSH is not designed for:

  • High-bandwidth applications — LoRa data rates (typically 0.3–27 kbps) make real-time voice, video, or large file transfer impractical.
  • Applications requiring low latency — multi-hop flood delivery adds variable latency that makes UMSH unsuitable for interactive or time-sensitive protocols.

Key Concepts

Nodes

A node is a logical endpoint on the network, identified by a 32-byte Ed25519 public key. That public key is the node’s long-term network identity — it serves as both its address and its cryptographic credential. A single physical device may host multiple nodes (e.g., a repeater node and a chat node), each with its own keypair.

A node’s public key must be known to communicate with it directly. Public keys can be learned through several mechanisms:

  • Beacons and advertisements — nodes periodically broadcast their presence, optionally including identity information (see Node Identity)
  • QR codes and URIs — public keys can be shared out-of-band via umsh:n: URIs (see URI Formats)
  • First-contact packets — a sender can set the S flag to include its full public key in any packet, allowing the receiver to learn it directly from the wire

Once a node’s public key is known, it can be cached and subsequent packets can use a compact source hint instead of the full key — saving 29 bytes per packet in unicast (3-byte hint vs 32-byte key).

Node Metadata

Nodes may also advertise additional metadata — such as a human-readable name, role, capabilities, and location — via the Node Identity payload. Metadata can also be contained in QR codes and URIs. This metadata is carried at the application layer and is not required by the MAC layer.

Unicast

Unicast packets are addressed to a destination node and may be authenticated or encrypted using per-destination cryptographic material derived from sender/recipient key agreement (see Frame Types and Security & Cryptography).

Channels

A channel is a shared symmetric key that serves two roles: multicast group communication and blind unicast metadata concealment. All nodes configured with a given channel key are members and can send and receive multicast packets addressed to it. Blind unicast uses the channel key to hide sender and destination addresses on the wire, while protecting the payload with combined keys that require both the channel key and the pairwise shared secret — only the intended recipient can read it. See Channels for channel types, membership models, and default channels.

Perfect Forward Secrecy

UMSH supports perfect forward secrecy, not as a core part of the underlying protocol but instead via ephemeral node addresses. Either node can initiate a PFS session, after which both parties communicate using ephemeral node addresses whose private keys are never stored durably and are erased at session end. Compromise of long-term keys cannot retroactively expose traffic protected by a completed PFS session.

Definitions

The following terms are used throughout this specification. Definitions are given in the context of UMSH; terms with broader meanings in other fields are defined here as they apply to this protocol.

Address
A node’s 32-byte Ed25519 public key, used as its stable network identifier. UMSH addresses are not numeric values used for routing. Short address hints derived from the address are used on the wire to save space.
Address Hint
A short prefix of a node’s public key used as a cheap prefilter before full cryptographic processing. Source and destination hints are 3 bytes; router and trace-route hints are 2 bytes. See Addressing.
AES (Advanced Encryption Standard)
A symmetric block cipher standardized by NIST. UMSH uses AES-128 in CTR mode for payload encryption and AES-CMAC for message authentication.
AES-SIV (Synthetic Initialization Vector)
A misuse-resistant authenticated encryption scheme (RFC 5297) in which the initialization vector is derived from an authentication tag computed over the plaintext. If the same plaintext is accidentally encrypted twice with the same key, the output reveals only that duplication — keys and other traffic remain uncompromised. UMSH uses a construction inspired by AES-SIV: AES-CMAC is used to compute the MIC, which then seeds AES-128-CTR for encryption.
ARNCE/HAM-64
A compact character encoding scheme for amateur radio callsigns, encoding up to 12 characters into 2, 4, 6, or 8 bytes. Used in UMSH’s Operator Callsign and Station Callsign packet options.
Beacon
A broadcast or multicast packet with an empty payload. Beacons advertise a node’s presence and are used for path discovery and route learning. See Beacons & Path Discovery.
Blind Unicast
A packet type that carries a unicast payload addressed to a specific destination while concealing both the sender and destination identities from observers who do not possess the channel key. The destination hint and source address are encrypted using the channel key; the payload is protected end-to-end using keys derived from both the channel key and the pairwise shared secret. See Frame Types.
Bridge
A node that relays UMSH packets between two different media or channels — for example, from a local LoRa radio to an internet backhaul and back to a distant LoRa radio. Bridges are protocol-transparent: they consume source-route hints and forward packets as repeaters do, but their onward transmission cannot be observed on the inbound medium.
Broadcast
A packet intended for all nodes in range. Broadcast packets carry no destination hint and are not encrypted or authenticated at the MAC layer. See Frame Types.
CAD (Channel Activity Detection)
A LoRa physical-layer feature that listens briefly for preamble energy on the channel with minimal power draw. UMSH uses CAD to implement listen-before-talk channel access, reducing collisions without requiring continuous reception. See Channel Access.
Channel
A logical communication group secured by a shared symmetric key. Channels serve two purposes: group communication (multicast) and metadata concealment (blind unicast). See Channels.
CoAP (Constrained Application Protocol)
A lightweight request/response protocol designed for constrained networks (RFC 7252). UMSH borrows CoAP’s delta-length option encoding for packet options and application-layer payloads.
Confidentiality
The property that payload content is accessible only to intended recipients. UMSH provides confidentiality via AES-128 encryption keyed with material derived from ECDH (unicast) or the channel key (multicast).
Duplicate Suppression
A mechanism by which repeaters track recently forwarded packets and decline to forward the same packet a second time. Each packet is identified by its MIC (for authenticated packets) or a locally computed hash (for unauthenticated packets). This prevents flood-routed packets from circulating indefinitely. See Repeater Operation.
ECDH (Elliptic Curve Diffie-Hellman)
A key agreement protocol that allows two parties to derive a shared secret using only their public keys and their own private keys. UMSH uses X25519 ECDH to derive pairwise shared secrets for unicast encryption and authentication.
Ed25519
An elliptic curve digital signature algorithm using the Edwards25519 curve. UMSH uses Ed25519 keypairs as node identities. The same keypair is converted to X25519 form for key agreement.
EdDSA (Edwards-curve Digital Signature Algorithm)
The family of signature algorithms that includes Ed25519. Used in UMSH for payload signatures, most notably for node identity broadcasts.
Ephemeral Key
A temporary Ed25519 keypair generated for a single PFS session. Unlike a long-term identity keypair, ephemeral keys are never written to persistent storage and are explicitly erased when the session ends, ensuring that compromise of long-term keys cannot retroactively decrypt traffic protected by them. See Security & Cryptography.
Flood Routing
A routing strategy where a packet is forwarded by every eligible repeater within the flood radius, subject to duplicate suppression. Requires no topology state at repeaters. Bounded by the flood hop count field (FHOPS). See Repeater Operation.
Frame
The unit of transmission at the LoRa PHY layer. A UMSH packet must fit within a single frame. The terms frame and packet are used interchangeably in this specification; frame emphasizes the physical transmission unit, packet emphasizes the logical protocol unit.
Frame Counter
A monotonically increasing 4-byte value included in every authenticated packet. The receiver tracks recently seen counter values and rejects packets with counters it has already processed, providing replay protection without requiring synchronized clocks. The counter must be persisted across reboots to prevent reuse. See Security & Cryptography.
Hop
One leg of a packet’s path through the network — the transmission from one node to an adjacent node within radio range. A packet that travels through two repeaters before reaching its destination has traversed three hops. The protocol differentiates between source-routed hops and flood-routed hops.
HKDF (HMAC-based Key Derivation Function)
A key derivation function standardized in RFC 5869, composed of two steps: Extract (combining a secret and optional salt into a pseudorandom key) and Expand (stretching that key to the required output length). UMSH uses HKDF-SHA256 with domain-separated labels to derive encryption keys, authentication keys, and channel identifiers from shared secrets and channel keys.
IoT (Internet of Things)
A broad term for networked embedded devices. UMSH is designed to be applicable to IoT use cases in addition to human communication, though it is optimized for the latter.
Latency
The time elapsed between a packet being transmitted and its receipt or acknowledgement. LoRa’s low data rate and mesh forwarding introduce significant latency compared to IP networks.
LoRa (Long Range)
A proprietary wireless modulation technology using chirp spread spectrum, designed for long range and low power consumption at the cost of low data rate. LoRa payloads are typically limited to 200–250 bytes, and transmitting a single packet may take hundreds of milliseconds depending on spreading factor and bandwidth. UMSH is designed around these constraints.
Long-Term Identity
A node’s stable Ed25519 keypair, used as its persistent network identity. Contrast with ephemeral keypairs used in PFS sessions, which are discarded after use.
MAC Layer (Medium Access Control)
The sublayer of the data link layer responsible for addressing, packet framing, and channel access. In UMSH, the MAC layer handles packet types, addressing, routing options, and cryptography. Application-layer protocols are carried in the payload and are defined separately.
MAC Ack
A packet type generated by the final destination of a unicast packet (UNAR or BUAR) to confirm receipt. The MAC Ack carries an ack tag — an 8-byte value derived from the original packet’s MIC and the pairwise encryption key — which allows the original sender to verify the acknowledgement. Repeaters do not generate MAC Acks; they forward them like any other packet. See Frame Types.
Mesh
A network topology where nodes can relay packets on behalf of other nodes, enabling communication beyond direct radio range. UMSH is designed for LoRa mesh networks where repeaters and bridges are used to extend coverage.
MIC (Message Integrity Code)
UMSH’s authentication tag, computed using AES-CMAC over the packet’s static fields and payload. Size is configurable from 4 to 16 bytes. The term MIC is used instead of the more common “MAC” (Message Authentication Code) to avoid confusion with Medium Access Control. See Security & Cryptography.
Multicast
A packet intended for all members of a channel, identified by a 2-byte channel identifier derived from the channel key. See Frame Types.
Node
A logical participant in a UMSH network, defined by a unique Ed25519 keypair. A single physical device may host multiple nodes. A node may act as an endpoint (sending and receiving application data), a repeater (forwarding packets), or both.
Packet
The logical unit of the UMSH protocol. Every packet must fit within a single LoRa frame. See Frame above.
Pairwise Key
A symmetric key derived from X25519 ECDH between a specific sender and recipient. Each pair of nodes shares a unique set of pairwise keys (one for encryption, one for authentication) derived deterministically from their long-term key material. Pairwise keys are stable across sessions unless a PFS session is used. See Security & Cryptography.
PFS (Perfect Forward Secrecy)
A property ensuring that compromise of long-term keys does not allow retroactive decryption of past traffic. UMSH provides optional PFS via ephemeral keypair sessions. See Security & Cryptography.
PHY (Physical Layer)
The lowest layer of a network stack, responsible for modulation and transmission over the physical medium. In UMSH deployments, this is typically LoRa. The PHY layer is below the MAC layer and is not defined by this specification.
Private Key
The secret half of an asymmetric keypair. In UMSH, a node’s Ed25519 private key is used to derive its X25519 private key for ECDH and to sign payloads when required. Must never be transmitted or disclosed.
Privacy
Broader than confidentiality: the protection of metadata and communication patterns in addition to payload content. UMSH provides confidentiality but does not fully protect against traffic analysis. See Security Considerations.
Public Key
The public half of an asymmetric keypair, which can be freely shared. In UMSH, a node’s Ed25519 public key is its address. Address hints are derived from it.
RSSI (Received Signal Strength Indicator)
A measurement of received radio signal power, expressed in dBm (negative values; higher is stronger).
Repeater
A node that forwards packets to extend the effective range of the mesh. Repeaters participate in flood routing and source routing but do not generate or consume application payloads for the packets they forward. See Repeater Operation.
SNR (Signal-to-Noise Ratio)
A measurement of the ratio between received signal power and background noise, expressed in dB. Unlike RSSI, SNR remains a reliable indicator of link quality even when the signal is below the noise floor, which is common in LoRa’s spread-spectrum operating regime.
Source Routing
A routing strategy where the sender specifies the explicit sequence of repeaters a packet must traverse. Requires the sender to have prior knowledge of a valid path. See Packet Options.
Trace Route
A packet option that instructs each forwarding repeater to prepend its router hint to the option value, building an ordered record of the path a packet has taken (most-recent repeater first). Used for route learning: a destination that receives a packet with a trace route has enough information to construct a source route for the reply. See Packet Options.
Unicast
A packet addressed to a single destination node, identified by a 3-byte destination hint. Unicast packets are always authenticated end-to-end; encryption is optional and controlled by the E flag. See Frame Types.
URI (Uniform Resource Identifier)
A compact string that identifies a resource or address. UMSH defines URI schemes for addressing nodes and channels. See URI Formats.
X25519
An elliptic curve Diffie-Hellman function over Curve25519. UMSH converts Ed25519 keypairs to X25519 form for key agreement. The conversion is deterministic and well-defined.

Common Patterns

UMSH reuses a small set of encoding patterns across both the MAC layer and application-layer protocols. This chapter collects them in one place so that individual protocol sections can reference them without repeating the details.

Byte Order

Multi-byte numeric fields are transmitted in big-endian (most-significant byte first), also known as network byte order. This is the standard convention for protocol specifications and is straightforward to interpret in packet diagrams. Modern hardware can convert between byte orders at effectively zero cost, so this choice imposes no practical performance penalty.

Non-numeric multi-byte data — such as SHA-256 hashes, Ed25519 public keys, and EdDSA signatures — is transmitted in its most common byte-wise representation, independent of any underlying endianness of the represented value.

CoAP-Style Option Encoding

UMSH uses the delta-length option encoding defined in CoAP (RFC 7252 §3.1) wherever a set of typed key-value fields needs to be carried compactly. This allows the protocols to be flexible and adapt to future needs while retaining backward compatability.

Each option is encoded as a delta from the previous option’s number, a length, and a value. The sequence is terminated by a 0xFF end-of-options marker if there is additional data present after the options section.

This encoding appears in:

  • MAC-layer packet options — routing, signal-quality thresholds, callsigns (see Packet Options)
  • Text message options — message type, sender handle, fragmentation, colors (see Text Messages)
  • Chat room payloads — room info responses, login parameters (see Chat Rooms)
  • Node identity metadata — location, battery, uptime (see Node Identity)

The full encoding rules — nibble interpretation, extended bytes, and the end marker — are defined in Packet Structure. Application-layer uses follow the same wire format.

ARNCE/HAM-64 Text Encoding

ARNCE (Amateur Radio Numeric Callsign Encoding), also known as HAM-64, is a compact encoding for short alphanumeric strings. It packs up to 12 characters into 2, 4, 6, or 8 bytes, making it well suited for identifiers that must fit in constrained fields.

UMSH uses ARNCE/HAM-64 for:

  • Operator callsign (packet option 4) — identifies the originating operator under amateur radio rules
  • Station callsign (packet option 7) — identifies the transmitting station, updated by repeaters during forwarding
  • Region codes (packet option 11) — IATA airport codes encoded as 2-byte ARNCE values (e.g. SJC → 0x7853)

UTF-8 Strings

All human-readable text in UMSH — message bodies, node names, sender handles, room descriptions — is encoded as UTF-8. String length is determined by context:

  • Inside a CoAP-style option, the option’s length field defines the string boundary.
  • As trailing data after a 0xFF marker, the string extends to the end of the payload (or to the start of a trailing signature).
  • In node identity payloads, the node name is NUL-terminated (0x00).

Base58 Encoding

Public keys and channel keys in human-facing contexts (URIs, QR codes) are encoded using Base58. This avoids visually ambiguous characters (0/O, l/1) and produces compact, copy-paste-friendly strings.

See URI Formats for the defined URI schemes.

Addressing

UMSH nodes are identified by their 32-byte Ed25519 public keys. Including a full 32-byte address in every packet would be expensive in the constrained LoRa frame budget, so UMSH defines several compact hint representations — short prefixes of a public key that allow receivers to quickly identify likely matches without the full key. Hints are not cryptographically authoritative; they serve only as cheap prefilters to avoid unnecessary work.

The sections below describe the three addressing forms used across the protocol: destination hints, router hints, and source addresses.

Destination Hint

A destination hint is defined as:

  • the first three bytes of the destination node’s 32-byte public key

This hint is not authoritative and is used only as a fast prefilter to avoid unnecessary cryptographic work.

A receiver that sees a matching destination hint must still confirm that it is the intended destination by successfully processing the packet cryptographically.

Router Hint

A router hint is defined as:

  • the first two bytes of the repeater’s 32-byte public key

Router hints are used in:

  • source-route options
  • trace-route options

Because router hints are only 2 bytes, collisions are possible in dense networks but are handled gracefully: the MIC-based duplicate suppression ensures that each repeater forwards a given packet at most once, so a router hint collision causes a spurious forward but not a loop or incorrect delivery.

Source Address

A source address in a packet is either:

  • a compact source hint (a prefix of the sender’s 32-byte public key), when the S flag in the FCF is clear, or
  • the full 32-byte public key, when the S flag is set.

The source hint is 3 bytes (the first three bytes of the public key) when S is clear.

The source hint is a compact reference used when the receiver is expected to already have the sender’s full public key cached (e.g., from a prior advertisement or first-contact exchange). When the full public key is present, the receiver can perform ECDH directly from the packet without any prior state.

In encrypted multicast and blind unicast packets, the source address is carried inside the ciphertext: a 3-byte hint when S is clear, or the full 32-byte public key when S is set.

Packet Structure

All UMSH packets begin with a one-byte Frame Control Field (FCF). Optional common fields then follow in a fixed order, followed by packet-type-specific fields.

Top-Level Packet Layout

+--------+-----------+--------+--------------+------------+-----------+---------+------+
|  FCF   |  OPTIONS  | FHOPS  | DST/CHANNEL  |    SRC     |  SECINFO  | PAYLOAD | MIC  |
+--------+-----------+--------+--------------+------------+-----------+---------+------+
   1 B      variable    0/1 B      0/2/3 B     0/3/32 B     0/5/7 B      var.   0-16 B

Where:

  • OPTIONS are present if the FCF options flag is set
  • FHOPS is present if the FCF flood hop count flag is set
  • DST is a 3-byte destination hint (2 bytes in MAC Ack packets)
  • CHANNEL is a 2-byte channel identifier
  • SRC is a compact 3-byte source hint (when S flag is clear) or 32-byte source public key (when S flag is set); in multicast and blind unicast packets with encryption enabled, SRC is encrypted inside the ciphertext rather than appearing as a separate field
  • SECINFO is present on authenticated/encrypted packet types
  • MIC is present on authenticated/encrypted packet types; MAC acks carry an ack tag instead

Frame Control Field

The Frame Control Field is one byte:

  7   6   5   4   3   2   1   0
+-------+-----------+---+---+---+
| VER   | PKT TYPE  | S | O | H |
+-------+-----------+---+---+---+
 2 bits    3 bits     1   1   1

Where:

  • VER = protocol version (this specification defines version 3, i.e., both bits set)
  • PKT TYPE = packet type
  • S = full 32-byte source address included (when clear, a compact source hint is used instead; see Source Address for hint size by packet type)
  • O = options present
  • H = flood hop count present

Packet Type Values

ValueName
0BCST: Broadcast
1UACK: MAC Ack
2UNIC: Unicast
3UNAR: Unicast, Ack-Requested
4MCST: Multicast
5RESERVED
6BUNI: Blind Unicast
7BUAR: Blind Unicast, Ack-Requested

Common Optional Fields

Options Field

Options use the same delta-length encoding as CoAP (RFC 7252 §3.1). Each option is encoded as a delta from the previous option’s number, a length, and a value. The sequence is terminated by a 0xFF byte.

Option Encoding

Each option begins with a single byte containing two 4-bit fields:

  7   6   5   4   3   2   1   0
+---------------+---------------+
| Option Delta  | Option Length |
+---------------+---------------+
     4 bits          4 bits

Followed by optional extended delta bytes, optional extended length bytes, and then the option value:

+---------------+---------------+
| Option Delta  | Option Length |  (1 byte)
+---------------+---------------+
| Extended Delta (0-2 bytes)    |
+-------------------------------+
| Extended Length (0-2 bytes)   |
+-------------------------------+
| Option Value (0 or more bytes)|
+-------------------------------+

Delta and length interpretation:

Nibble valueMeaning
0–12Literal value
13One extended byte follows; value = byte + 13
14Two extended bytes follow; value = uint16 (big-endian) + 269
15Reserved — used only in the delta field to indicate the 0xFF end-of-options marker

The option delta is the difference between this option’s number and the previous option’s number (or zero for the first option). Options must appear in order of increasing option number. Multiple options with the same number are permitted (delta = 0).

End-of-Options Marker

The byte 0xFF (delta nibble = 15, length nibble = 15) terminates the options field. It is always present when the O flag is set in the FCF.

Example

Two options — option 3 (1-byte value) followed by option 9 (2-byte value):

+------+-------+  +------+-------+-------+  +------+
| 0x31 |  val  |  | 0x62 |  val  |  val  |  | 0xFF |
+------+-------+  +------+-------+-------+  +------+
 delta=3 opt 3     delta=6 opt 9             marker
 len=1   val (1B)  len=2   val (2B)

Flood Hop Count

If present, FHOPS is a single byte containing two 4-bit fields:

  7   6   5   4   3   2   1   0
+---------------+---------------+
| FHOPS_REM     | FHOPS_ACC     |
+---------------+---------------+
     4 bits          4 bits

Where:

  • FHOPS_REM (high nibble) = hops remaining — the number of additional flood hops permitted. Decremented by each forwarding repeater. When zero, no further flood forwarding is allowed.
  • FHOPS_ACC (low nibble) = hops accumulated — the number of flood hops already traversed. Incremented by each forwarding repeater.

The sum FHOPS_REM + FHOPS_ACC is constant across forwarding hops and equals the original flood hop limit set by the sender. The maximum flood radius is 15 hops; longer paths can be achieved by combining source routing with flooding (see Routing Implications).

FHOPS_ACC enables the destination to determine how many flood hops the packet traversed, which is used for MAC ack routing when no trace route is available.

Frame Types

Broadcast Packet

Broadcast packets carry a source and payload, but no security info.

+-----+-----------+-------+-----+---------+
| FCF | [OPTIONS] |[FHOPS]| SRC | PAYLOAD |
+-----+-----------+-------+-----+---------+
  1 B    variable   0/1 B  3/32B   var.

A broadcast with an empty payload is a Beacon.

MAC Ack Packet

A MAC acknowledgement is generated by the final destination — the node that successfully processes and accepts the original packet. Repeaters do not generate MAC acks; they forward ack packets like any other packet type.

The ack identifies the original sender by destination hint and carries an ack tag — a cryptographically derived value that the sender can verify. See Ack Tag Construction for the derivation.

+-----+-----------+-------+-----+---------+
| FCF | [OPTIONS] |[FHOPS]| DST | ACK TAG |
+-----+-----------+-------+-----+---------+
  1 B    variable   0/1 B   3 B    8 B

Where:

  • DST is a 3-byte prefix of the original sender’s public key
  • ACK TAG is an 8-byte value derived from the original packet’s MIC and the pairwise encryption key (see Ack Tag Construction)

Because the ack tag requires knowledge of the pairwise K_enc, it cannot be forged by a passive observer — even one who received the original packet in its entirety.

The ack is routed back to the original sender using whatever routing state is available — a cached source route, a flood scoped by FHOPS_ACC, or both. See Route Learning for how nodes learn and cache routing information from incoming packets. For reliable ack delivery over long source-routed paths, the original sender should include a trace-route option.

Unicast Packet

Unicast packets are addressed by destination hint and carry the source address.

+-----+-----------+------+-----+-----+---------+---------+------+
| FCF | [OPTIONS] |[FHOPS]| DST | SRC | SECINFO | PAYLOAD | MIC  |
+-----+-----------+------+-----+-----+---------+---------+------+
  1 B    variable   0/1 B  3 B  3/32B    5/7 B     var.    4-16 B

DST is the first three bytes of the recipient’s public key.

Receivers first use DST as a cheap filter, then use the source public key (or its cached equivalent when only a hint is present) and their own key to derive the shared secret and authenticate/decrypt the packet.

Unicast Packet with Ack Requested

This is identical to unicast, but the packet-type value signals that a MAC acknowledgement is requested.

+-----+-----------+------+-----+------+---------+---------+------+
| FCF | [OPTIONS] |[FHOPS]| DST | SRC  | SECINFO | PAYLOAD | MIC  |
+-----+-----------+------+-----+------+---------+---------+------+
  1 B    variable   0/1 B  3 B   3/32B    5/7 B     var.    4-16 B

Semantics differ, wire layout does not.

Multicast Packet

Multicast packets carry a 2-byte channel identifier derived from the channel key.

Channel Identifier Derivation

channel_id = first_2_bytes( HKDF-SHA256(channel_key, salt="UMSH-CHAN-ID", info="", L=2) )

Encrypted Multicast (E = 1)

When encryption is enabled, the source address is encrypted together with the payload, concealing the sender’s identity from observers who do not possess the channel key.

+-----+-----------+------+---------+---------+----------------------+------+
| FCF | [OPTIONS] |[FHOPS]| CHANNEL | SECINFO | ENCRYPT(SRC+PAYLOAD) | MIC  |
+-----+-----------+------+---------+---------+----------------------+------+
  1 B    variable   0/1 B    2 B     5/7 B          3/32 + var.      4-16 B

The SRC inside the ciphertext follows the S flag convention: a 3-byte hint when S is clear, or the full 32-byte public key when S is set.

Only a node with the correct channel key can recover the source address and payload.

Unencrypted Multicast (E = 0)

When encryption is not enabled, the source address appears in cleartext, but in the same place that it appeared in encrypted multicast:

+-----+-----------+-------+---------+---------+------+---------+------+
| FCF | [OPTIONS] |[FHOPS]| CHANNEL | SECINFO | SRC  | PAYLOAD | MIC  |
+-----+-----------+-------+---------+---------+------+---------+------+
  1 B    variable   0/1 B     2 B      5/7 B   3/32 B    var.   4-16 B

Blind Unicast Packet

Blind unicast uses a multicast channel to conceal sender and destination metadata from observers without the channel key while still protecting the payload end-to-end for the actual destination.

Like other channel-addressed packets, blind unicast honors the E flag in SECINFO.

Encrypted Blind Unicast (E = 1)

+-----+-----------+-------+---------+---------+-------------+-------------+------+
| FCF | [OPTIONS] |[FHOPS]| CHANNEL | SECINFO | ENC_DST_SRC | ENC_PAYLOAD | MIC  |
+-----+-----------+-------+---------+---------+-------------+-------------+------+
  1 B    variable   0/1 B     2 B      5/7 B       6/35 B         var.     4-16 B

The MIC is computed over the payload using the blind unicast payload keys, which combine the pairwise shared secret with the channel key. ENC_DST_SRC is encrypted using the channel’s derived encryption key K_enc_channel (see Multicast Packet Keys) and the MIC as IV (see Security & Cryptography). Because ENC_DST_SRC decryption depends on the MIC, any tampering with the source address will produce an incorrect public key, causing pairwise key derivation to fail and payload authentication to reject.

Unencrypted Blind Unicast (E = 0)

When encryption is disabled, blind unicast still uses the channel identifier and the blind-unicast packet type, but the destination hint, source address, and payload appear in cleartext:

+-----+-----------+-------+---------+---------+-----+------+---------+------+
| FCF | [OPTIONS] |[FHOPS]| CHANNEL | SECINFO | DST | SRC  | PAYLOAD | MIC  |
+-----+-----------+-------+---------+---------+-----+------+---------+------+
  1 B    variable   0/1 B     2 B      5/7 B    3 B  3/32 B    var.   4-16 B

In this mode, the packet remains channel-associated and authenticated with the blind-unicast keys, but it does not conceal sender or destination metadata. This can still be useful when an implementation wants channel-associated unicast semantics without encryption.

Blind Unicast Processing

  1. Receiver uses CHANNEL to identify candidate channel keys.
  2. Receiver derives the channel’s candidate keys via HKDF.
  3. If E = 1, receiver reads the MIC and uses K_enc_channel plus MIC to decrypt ENC_DST_SRC, recovering the destination hint and sender address.
  4. If E = 0, receiver reads DST and SRC directly from the cleartext packet.
  5. Receiver converts the sender Ed25519 public key into an X25519 public key.
  6. Receiver converts its own Ed25519 private key into an X25519 private key.
  7. Receiver performs ECDH and derives the stable pairwise keys.
  8. Receiver computes the blind unicast payload keys by XORing the pairwise keys with the channel keys.
  9. Receiver authenticates the packet using the blind-unicast MIC.
  10. If E = 1, receiver decrypts ENC_PAYLOAD using the blind unicast payload keys.
  11. If authentication fails, the packet is rejected.

Some repeaters may decline to forward blind unicast packets for unknown channels.

Blind Unicast with Ack Requested

Same wire layout as blind unicast, but with ack-requested semantics.

+-----+-----------+-------+---------+---------+-------------+-------------+------+
| FCF | [OPTIONS] |[FHOPS]| CHANNEL | SECINFO | ENC_DST_SRC | ENC_PAYLOAD | MIC  |
+-----+-----------+-------+---------+---------+-------------+-------------+------+
  1 B    variable   0/1 B      2 B     5/7 B       6/35 B         var.     4-16 B

Packet Options

UMSH packet options use the delta-length encoding described in Packet Structure. Each option has a numeric option number whose two least significant bits encode two semantic attributes:

  • Bit 0: Critical (1) / Non-Critical (0)
  • Bit 1: Dynamic (1) / Static (0)

This means a node can determine an unrecognized option’s attributes by inspecting its option number without consulting a registry.

Attribute Encoding

The four attribute combinations and their option number patterns:

Low 2 bitsOption numbersClassification
0b000, 4, 8, 12, …Non-Critical, Static
0b011, 5, 9, 13, …Critical, Static
0b102, 6, 10, 14, …Non-Critical, Dynamic
0b113, 7, 11, 15, …Critical, Dynamic

Critical vs. Non-Critical

These determine behavior when a node encounters an unknown option:

  • Critical (bit 0 set): if unrecognized, the packet must be dropped
  • Non-Critical (bit 0 clear): if unrecognized, the option is ignored and the node continues processing

Dynamic vs. Static

These determine whether an option is covered by the MIC:

  • Dynamic (bit 1 set): not protected by the security MIC; may be modified in transit by repeaters
  • Static (bit 1 clear): protected by the security MIC; must not be modified in transit

This distinction allows forwarding-related metadata (source routes, trace routes, station callsigns) to be modified by repeaters without invalidating end-to-end authentication.

Defined Options

NumberNameClassificationValue
0RESERVEDNon-Critical, Static
1UNASSIGNEDCritical, Static
2Trace RouteNon-Critical, Dynamic0+ bytes
3Source RouteCritical, Dynamic0+ bytes
4Operator CallsignNon-Critical, StaticARNCE/HAM-64
5Minimum RSSICritical, Static0–1 bytes
6Route RetryNon-Critical, Dynamic0 bytes
7Station CallsignCritical, DynamicARNCE/HAM-64
8UNASSIGNEDNon-Critical, Static
9Minimum SNRCritical, Static0–1 bytes
11Region CodeCritical, Dynamic2 bytes

Region Code (option 11)

  • Type: 2-byte region identifier
  • Semantics: restricts flood-routing to repeaters configured for the specified region.
  • A repeater that does not recognize or is not configured for the region must not forward the packet when flooding.
  • This option is not enforced until the source route list is exhausted.
  • Multiple region-code options may appear on the same packet. In that case, a repeater may flood-forward the packet if any one of the listed regions matches local policy.
  • Because this option is dynamic, repeaters may insert it while flood-forwarding a packet that currently has no region code.
  • A repeater must never rewrite an existing region code and must never add a second region code to a packet that already has one or more region-code options.
  • Region insertion is a local policy decision. When no explicit local policy exists, a reasonable default is the IATA code of the closest regional commercial airport.
  • Region insertion applies only during flood forwarding. A source-routed packet without a region does not gain one until its source route is exhausted and it transitions to flooding.

Region Code Encoding

Region codes are 2-byte identifiers derived by one of two methods, depending on the type of region:

Airport-based regions. For regions defined by proximity to an airport, encode the airport’s 3-letter IATA code into a 16-bit value using ARNCE/HAM-64. Examples:

IATA CodeRegion Code
SJC0x7853
MFR0x5242

Named regions. For regions that are not associated with a single airport (super-regions, cities without a nearby airport, geographic areas, etc.), the region code is the first two bytes of the SHA-256 hash of the region name (UTF-8 encoded). Examples:

Region NameSHA-256 prefixRegion Code
Rogue Valley0xdf6f...0xdf6f
SF Bay Area0x31d9...0x31d9
Southern Oregon0x6af2...0x6af2

IATA-based region codes will never collide with each other. However, because region codes are only 2 bytes, named regions may happen to collide with IATA codes or other named regions. Approximately 30% of all hash-based identifiers will have a valid ARNCE decoding to three letters, and approximately 56% of those will colide with an actual assigned IATA code.

These collisions are rarely of practical concern. If a region code in one part of the world collides with a region code in a different part of the world, there is no actual ambiguity because flood repeating is an inherently local event. In the rare case of a collision within a geographic area, it can be resolved by adjusting the named region slightly (for example, making it more specific).

Note

If collisions between IATA-based codes and hash-based codes is a concern, we could redefine how hash-based codes are calculated to keep hashing the previous full hash value until it returns a result that is not a valid three-letter ARNCE encoding.

This would have the benefit of allowing IATA codes to be immediately renderable in user interfaces.

The assignment and scope of non-IATA-based region codes—and resolution of any collisions—are generally handled locally.

Trace Route (option 2)

  • Semantics: if present, repeaters prepend their own repeater hint before retransmitting.
  • If absent, no trace-route information is added automatically.
  • Value layout: see Trace Route Option Value.

Source Route (option 3)

  • Semantics: contains an ordered list of repeater hints designating the forwarding path.
  • Repeater behavior:
    • Only the repeater matching the first hint may forward the packet.
    • That repeater removes its own hint before retransmission.
    • If removing its own hint leaves zero remaining hints, the repeater still preserves the source-route option with an empty value.
      • This is important: the forwarded packet still carries the information that it was explicitly source-routed, even though the route is now exhausted.
    • Repeaters that do not match the first hint must not forward the packet.
  • Value layout: see Source Route Option Value.

Operator Callsign (option 4)

  • Encoding: ARNCE/HAM-64 (2, 4, 6, or 8 bytes; encodes callsigns up to 12 characters)
  • Semantics: identifies the original packet sender’s amateur radio callsign.
  • Use: required for locally originated packets in Licensed-Only amateur operation.
  • In Hybrid operation, its presence marks the packet as eligible for forwarding under amateur-radio authority; packets without it may still be forwarded under unlicensed authority if local rules allow.

Minimum RSSI (option 5)

  • Type: unsigned 1-byte integer, interpreted as a negative dBm value
  • Semantics: packet must be received with at least this RSSI to be flood-forwarded. This option does not apply to source-routed hops.
  • Example: value 130 means -130 dBm
  • If present with no value (length 0), default is -100 dBm (THIS VALUE IS SUBJECT TO CHANGE)
  • If a repeater has a locally configured minimum RSSI, it must use the higher of the packet’s minimum RSSI threshold and the repeater’s configured minimum RSSI threshold.

Route Retry (option 6)

  • Type: zero-length flag
  • Semantics: indicates that the originator is re-attempting forwarding of the same logical packet after a previously chosen source route was considered failed.
  • This option is intended for sender-originated route recovery, not for ordinary first transmission.
  • When present, repeaters treat the packet as a distinct forwarding attempt for duplicate-suppression purposes even though the MIC and frame counter are unchanged.
  • The destination does not treat this option as creating a new logical packet. Replay acceptance and duplicate application delivery remain governed by the packet’s normal security state, especially its frame counter.
  • A sender using this option for route recovery typically:
    • removes the stale source-route option
    • adds or refreshes flood hops
    • includes a trace-route option to learn a replacement route
    • preserves the same frame counter and payload
  • This option is non-critical and dynamic so that legacy repeaters may ignore it harmlessly, though they will also not provide the intended retry behavior.

Station Callsign (option 7)

  • Encoding: ARNCE/HAM-64 (2, 4, 6, or 8 bytes; encodes callsigns up to 12 characters)
  • Semantics: identifies the transmitting station’s amateur radio callsign.
  • If absent, the station callsign is assumed to equal the source callsign (if present)
  • This option is critical because repeaters must replace or remove it during forwarding.
  • Use:
    • in Licensed-Only mode, repeaters replace or insert it on every forwarded packet
    • in Hybrid mode, repeaters also replace or insert it on every forwarded packet
    • in Unlicensed mode, repeaters remove it if present and do not add their own

Minimum SNR (option 9)

  • Type: signed 1-byte integer, in dB
  • Semantics: packet must be received with at least this SNR to be flood-forwarded. This option does not apply to source-routed hops.
  • If present with no value (length 0), default is -3 dB. (THIS VALUE IS SUBJECT TO CHANGE)
  • If a repeater has a locally configured minimum SNR, it must use the higher of the packet’s minimum SNR and the repeater’s configured minimum SNR.

Routing Option Layouts

Source Route Option Value

A source-route option contains zero or more router hints:

+----------+----------+----------+-----+
|  RH[0]   |  RH[1]   |  RH[2]   | ... |
+----------+----------+----------+-----+
    2 B         2 B       2 B

Where each RH[i] is the first two bytes of a repeater’s public key.

Interpretation:

  • RH[0] is the next repeater that must forward the packet
  • when that repeater forwards, it removes RH[0]

An empty source-route option indicates that all explicit routing hints have been consumed.

  • For forwarding purposes, an empty source-route option behaves the same as an absent source-route option: there is no remaining explicit next hop.
  • However, it is still semantically useful and should be preserved when produced by forwarding, because it records that the packet did in fact traverse an explicit source-routed path before the hints were exhausted.

Trace Route Option Value

A trace-route option also contains zero or more router hints:

+----------+----------+----------+-----+
|  RH[0]   |  RH[1]   |  RH[2]   | ... |
+----------+----------+----------+-----+
    2 B         2 B       2 B

Repeaters prepend their 2-byte router hint:

new_trace = my_router_hint || old_trace

So the list is ordered most-recent repeater first.

Security & Cryptography

UMSH authenticates and optionally encrypts packets using a construction inspired by AES-SIV (RFC 5297). Unicast packets are secured with pairwise keys derived from X25519 ECDH between sender and recipient Ed25519 keys. Multicast packets are secured with keys derived from the shared channel key. In both cases, a monotonic frame counter provides replay protection without requiring synchronized clocks.

Each secured packet carries a Security Information (SECINFO) field containing a Security Control Field, a frame counter, and an optional salt. The sections below describe these fields, the key derivation process, and the cryptographic operations applied to each packet.

Security Information (SECINFO)

SECINFO Encoding

+--------+--------------------+----------------+
|  SCF   | FRAME COUNTER (4B) | [SALT (2B)]    |
+--------+--------------------+----------------+
   1 B            4 B              0/2 B

Security Control Field

  7   6   5   4   3   2   1   0
+---+-------+---+---------------+
| E |  MIC  | S |   RESERVED    |
+---+-------+---+---------------+
 1b   2 bits 1b      4 bits

Where:

  • E = encrypted payload flag
  • MIC = MIC size code
  • S = salt included
  • RESERVED = must all be set to zero

If the RESERVED bits read as anything other than zero, the packet MUST be dropped by the recipient.

MIC size encodings:

ValueMIC Length
04 bytes
18 bytes
212 bytes
316 bytes

The MIC is produced by computing the full 16-byte AES-CMAC and truncating to the specified length. Truncation of CMAC outputs is permitted by NIST SP 800-38B.

MIC Size Selection Guidance

Shorter MICs save bytes on the wire but reduce forgery resistance and increase the probability of duplicate-suppression collisions in repeater caches (see Duplicate Suppression). The following guidelines help choose an appropriate MIC size:

  • 16 bytes (default): Recommended for long-term stable identities where the same pairwise keys may be used for months or years. The cost of a successful forgery is high (attacker gains persistent access to impersonate a node), and the 2^-128 forgery probability makes brute-force infeasible regardless of how many packets an attacker can attempt.

  • 8 bytes: A reasonable middle ground for most communication. Provides 2^-64 forgery probability — well beyond practical brute-force for LoRa’s low packet rates — while saving 8 bytes per packet. Suitable for general unicast and multicast traffic.

  • 4 bytes: Appropriate for short-lived contexts where the keys will be discarded soon, such as PFS sessions or one-time exchanges using ephemeral node addresses. The 2^-32 forgery probability (~1 in 4 billion) is adequate when the window of exposure is brief. Also useful for latency-sensitive or payload-constrained scenarios where every byte matters, such as sensor telemetry on slow LoRa links.

  • 12 bytes: Available as an intermediate option when 8 bytes feels too tight but 16 bytes is more overhead than warranted. Provides 2^-96 forgery probability.

As a general principle: the longer the keys will be in use and the higher the value of the traffic they protect, the larger the MIC should be. For ephemeral keys that will be erased within minutes, a small MIC is sufficient. For a node’s long-term identity keys, prefer the full 16 bytes.

Frame Counter

The 4-byte frame counter must increase monotonically for a given shared secret and traffic direction. UMSH uses this monotonic counter — rather than timestamps — for replay protection, keeping the protocol free of any dependency on synchronized clocks or absolute time.

The exact mechanism for how the frame counter is handled is implementation specitic, assuming that it always increases. For example, the frame counter may be unique for each source+destination node pair, or it may be a single frame counter for the entire device. On constrained devices, it may make sense to use a combination of the two: have a fixed set of counters (say, 32) that are initialized with random starting values, and derive a pseudo-random number from 0-31 from the shared secret to pick which of those counters is being used.

Replay Detection

A receiver determines whether a frame counter is acceptable by computing:

delta = (received_counter - last_accepted_counter) mod 2^32

If delta is zero or exceeds the forward window, the packet is rejected. This modular comparison allows the counter to wrap around 2^32 without requiring special overflow handling. The suggested default forward window is 172800. Implementations MAY use a different value, but it should be large enough to accommodate gaps from packets sent to other destinations and small enough to limit the scope of replay attacks.

Implementations that need to tolerate out-of-order delivery may also define a backward window — a small range of counter values behind the highest accepted counter within which late-arriving packets are still considered. The suggested default backward window is 8. When a packet’s counter falls within the backward window, the receiver checks a small cache of recently accepted packet MICs (similar to the approach used for duplicate suppression in repeaters): if the MIC is already present, the packet is a replay and is rejected; if not, the packet is accepted and its MIC is added to the cache.

Regardless of window sizes, a packet must not be accepted if it is more than 5 minutes out of order — that is, if the highest accepted counter was last advanced more than 5 minutes ago and the received counter is behind it. MIC cache entries only need to be retained for the duration of this time bound. Additionally, the first packet accepted from a given node (or after a counter resynchronization) establishes that node’s counter baseline — packets with earlier counter values must be rejected, even if they arrive within the backward window.

Counter Persistence

How a node persists and recovers its frame counter across reboots is implementation-specific. Possible strategies include writing the counter to non-volatile storage periodically or advancing the counter by a large margin on startup to avoid replaying previously used values.

Caution

If the counter is written to non-volatile storage, care should be taken to avoid wearing out the underlying storage medium if it has a limited number of writes.

Counter Resynchronization

On first contact with a new peer, the received frame counter is accepted at face value and recorded as the baseline for future replay detection. If a known peer’s frame counter subsequently falls outside the forward window — for example, after the peer reboots and loses its persisted counter — the receiver MAY use the Echo Request MAC command (including a nonce, see MAC Commands) to determine the peer’s current counter value and re-establish a valid baseline.

Salt

The optional 2-byte salt is chosen randomly to reduce the liklihood of a nonce collision.

Cryptographic Processing

Unicast Key Agreement

For unicast and blind unicast:

  1. Start with sender Ed25519 keypair and recipient Ed25519 keypair.
  2. Convert both Ed25519 keys to X25519 form.
  3. Perform X25519 ECDH.
  4. Feed the resulting shared secret into HKDF-SHA256.
  5. Derive separate stable pairwise keys for encryption and MIC/authentication.

Ed25519 to X25519 Conversion

UMSH uses a single Ed25519 keypair per node as both its identity (for addressing) and the basis for key agreement. Standard cryptographic guidance recommends separate keys for signing and key agreement, so this choice warrants justification.

The Ed25519 and X25519 curves are birationally equivalent (both are defined over Curve25519), and the conversion between Edwards and Montgomery form is a well-understood, deterministic mapping. Using a single keypair for both purposes is not itself insecure — it is the approach taken by, among others, the Signal protocol’s X3DH key agreement and libsodium’s crypto_sign_ed25519_pk_to_curve25519 API.

The alternative — carrying separate Ed25519 (signing) and X25519 (key agreement) keys per node — would require a cryptographic binding between the two. Each node must distribute an additional 32-byte X25519 public key alongside its Ed25519 key, and the binding must be authenticated (e.g. by including the X25519 key in a signed advertisement). Every recipient must then verify that binding before trusting the key agreement key. On a LoRa link where the entire frame budget is ~255 bytes, even 32 extra bytes per identity exchange is a significant cost. By deriving X25519 keys from Ed25519 keys, UMSH eliminates this overhead entirely: the node address is the key agreement key, with no additional key distribution required.

UMSH assumes standard Edwards-to-Montgomery conversion:

  • sender Ed25519 private key → sender X25519 private key
  • sender Ed25519 public key → sender X25519 public key
  • recipient Ed25519 private key → recipient X25519 private key
  • recipient Ed25519 public key → recipient X25519 public key

Implementations should reject malformed public keys before conversion.

ECDH Shared Secret

The ECDH shared secret is:

ss = X25519(local_x25519_private, remote_x25519_public)

This shared secret is used as the input keying material for deriving the cryptographic keys to secure and authenticate messages.

HKDF Inputs for Unicast

For unicast packets, the encryption and MIC keys are derived from the X25519 ECDH shared secret and are stable for a given pair of nodes. These keys are not derived from packet-specific fields.

Let:

ss = X25519(local_x25519_private, remote_x25519_public)

The pairwise key material is then derived as:

ikm  = ss
salt = "UMSH-PAIRWISE-SALT"
info = "UMSH-UNICAST-V1"
okm  = HKDF-SHA256(ikm, salt, info, 32)

The output keying material is split as follows:

K_enc = okm[0..15]
K_mic = okm[16..31]

Where:

  • K_enc is the 16-byte encryption key
  • K_mic is the 16-byte message authentication key

These keys are stable for the sender/recipient pair and may be cached by the implementation. They do not change from packet to packet.

Because the key derivation depends only on the ECDH shared secret and fixed UMSH-specific HKDF parameters, it does not need to be recomputed for each transmitted packet.

Blind Unicast Payload Keys

Blind unicast payload encryption and authentication must require knowledge of both the pairwise shared secret and the channel key. This ensures that an attacker who compromises one of the two secrets — but not both — cannot decrypt blind unicast payloads.

The blind unicast payload keys are derived by XORing the pairwise unicast keys (see HKDF Inputs for Unicast) with the channel’s multicast keys (see Multicast Packet Keys):

K_enc_blind = K_enc_pairwise XOR K_enc_channel
K_mic_blind = K_mic_pairwise XOR K_mic_channel

Where:

  • K_enc_pairwise, K_mic_pairwise are the stable pairwise keys derived from the sender/recipient ECDH shared secret
  • K_enc_channel, K_mic_channel are the stable channel keys derived from the channel key

Both sets of input keys are independent HKDF outputs — pseudorandom and uncorrelated. XOR of two independent uniform random values is uniform random: an attacker who knows only one side sees the combined key as informationally equivalent to a one-time pad over the unknown side.

These combined keys are stable for a given (sender, recipient, channel) triple and may be cached. If the same two nodes use blind unicast over different channels, they get different payload keys — compromise of one channel key does not expose blind unicast traffic on another channel between the same pair.

Both the pairwise and channel keys can be cached independently by the implementation. Computing the blind unicast keys requires only a 16-byte XOR per key, with no additional HKDF calls.

Per-Packet Security Inputs

Although K_enc and K_mic are stable for a given node pair, each packet still carries per-packet security inputs in SECINFO.

These inputs are:

  • the 4-byte frame counter
  • the optional 2-byte salt

These values are not used to derive the pairwise keys. Instead, they are used as packet-specific inputs to encryption, authentication, and replay protection.

For encrypted packets using AES-SIV:

  • K_enc and K_mic are the stable pairwise keys
  • SECINFO and other immutable header fields are supplied as associated data
  • the frame counter and optional salt provide packet-specific variability and replay-detection context

For authenticated but unencrypted packets:

  • K_mic is the stable pairwise MIC key
  • the MIC is computed over the protected packet contents and relevant static fields

The frame counter must increase monotonically for a given traffic direction. Receivers should use it for replay detection even though AES-SIV is resistant to nonce misuse.

Multicast Packet Keys

For multicast, the configured channel key is the base secret. The encryption and authentication keys are derived once and are stable for a given channel.

ikm  = channel_key
salt = "UMSH-MCAST-SALT"
info = "UMSH-MCAST-V1" || channel_id
okm  = HKDF-SHA256(ikm, salt, info, 32)

K_enc = okm[0..15]
K_mic = okm[16..31]

These keys are stable for the channel and may be cached by the implementation. They do not change from packet to packet. Per-packet variability is provided by the frame counter and optional salt in SECINFO, which serve as inputs to encryption and replay detection (see Per-Packet Security Inputs).

Encrypted Packets

When encryption is enabled, UMSH uses a construction inspired by AES-SIV (RFC 5297), with the MIC and encryption steps separated to allow future support for different MIC lengths.

The processing is:

  1. Compute the full 16-byte AES-CMAC over the AAD and plaintext using K_mic.
  2. Truncate the CMAC to the MIC length specified by the SCF.
  3. Construct the CTR IV from the MIC (see CTR IV Construction).
  4. Encrypt the plaintext using AES-128-CTR with K_enc and the constructed IV.

The MIC is transmitted separately from the ciphertext (not prepended as in standard AES-SIV), allowing the MIC length to be controlled independently via the SCF MIC size field.

A key design goal is robustness against nonce reuse. Because the CTR IV is derived from the MIC (as in SIV-style constructions), accidental reuse of nonces or counters is not cryptographically catastrophic in the way it would be for CTR or GCM.

CTR IV Construction

The 16-byte CTR IV is constructed by appending the SECINFO field to the MIC, then zero-padding or truncating the result to exactly 16 bytes:

IV = truncate_or_pad_to_16( MIC || SECINFO )

For the 16-byte MIC, SECINFO is entirely truncated away and the IV equals the MIC — identical to standard AES-SIV. For shorter MICs, the IV incorporates the frame counter and optional salt from SECINFO, providing additional per-packet IV variability that compensates for the increased probability of truncated-MIC collisions.

MIC LengthSECINFO (5 B)SECINFO (7 B)SECINFO bytes in IV
16 Btruncate to 16truncate to 160 (IV = MIC)
12 Btruncate to 16truncate to 164 or 2
8 Bzero-pad to 16zero-pad to 165 or 7
4 Bzero-pad to 16zero-pad to 165 or 7

Unencrypted Packets

When encryption is disabled, the MIC is calculated using CMAC with K_mic.

Associated Data

The associated data (AAD) binds the immutable header fields to the MIC so that any modification is detected.

The AAD is constructed by concatenating the following fields in order:

  1. FCF (1 byte)
  2. Static options — re-encoded as type-length-value (see below)
  3. DST (2 bytes, unicast) or CHANNEL (2 bytes, multicast)
  4. SRC (2 or 32 bytes) — included only when the source field is outside the ciphertext
  5. SECINFO (5 or 7 bytes)

Dynamic options and the flood hop count are excluded from the AAD because they may be modified by repeaters during forwarding.

Static Option Encoding in AAD

Static options are not included in their wire delta-length form. Instead, each static option present in the packet is re-encoded using absolute type-length-value triples:

+----------+----------+-------+
|  number  |  length  | value |
+----------+----------+-------+
    2 B (BE)   2 B (BE)  var.

Where number is the option’s absolute option number (not a delta), encoded as a 2-byte big-endian unsigned integer, and length is the value length in bytes, also encoded as a 2-byte big-endian unsigned integer. Static options appear in the AAD in order of increasing option number. This avoids recomputing deltas after dynamic options have been removed.

Using 2-byte fields for both number and length ensures that option numbers above 255 (which are valid in the CoAP-style encoding used on the wire) and long option values are represented without truncation or ambiguity.

Ack Tag Construction

When a packet type requests an acknowledgement (UNAR or BUAR), both the sender and receiver independently compute an ack tag — an 8-byte value that the receiver includes in the MAC ack and the sender uses to match incoming acks to outstanding requests.

The ack tag is computed as follows:

  1. Compute the full 16-byte AES-CMAC over the AAD and plaintext using K_mic (this is the same computation used to produce the packet MIC, before any truncation).
  2. Encrypt the 16-byte CMAC with a single AES-128-ECB block encryption using the pairwise K_enc.
  3. Truncate the result to 8 bytes.
ack_tag = truncate_to_8( AES-128-ECB( key=K_enc, block=full_16B_CMAC ) )

Where:

  • K_enc is the encryption key used for the packet — the pairwise key for unicast (see HKDF Inputs for Unicast), or the combined blind unicast key for blind unicast (see Blind Unicast Payload Keys)
  • full_16B_CMAC is the full 16-byte AES-CMAC computed during packet processing, before truncation to the on-wire MIC length

The ack tag is never transmitted in the original packet — it appears only in the MAC Ack response. Because it requires knowledge of K_enc, a passive observer who intercepts the original packet cannot forge a valid ack, regardless of the MIC size used on the wire. The ack tag also bears no visible relationship to the on-wire MIC, preventing observers from correlating ack packets with the original packets by comparing values.

AES-ECB on a single 16-byte block is the raw AES block cipher — a pseudorandom permutation — and does not have the pattern-leakage weakness associated with multi-block ECB encryption.

Blind Unicast Address Encryption

Blind unicast packets encrypt both the destination hint and source address together, separately from the payload. The address block is encrypted with the channel key alone, so that any channel member can recover both the intended recipient and the sender’s identity. The payload is then encrypted with the combined blind unicast keys (see Blind Unicast Payload Keys), which require both the channel key and the pairwise shared secret.

The address block is encrypted using AES-128-CTR with the channel’s derived encryption key K_enc_channel (see Multicast Packet Keys), using the CTR IV constructed from the packet MIC and SECINFO (see CTR IV Construction).

Let:

  • K_enc_channel = channel encryption key derived from the channel key via HKDF
  • IV = CTR IV constructed from the packet MIC and SECINFO
  • DST = 3-byte destination hint
  • SRC = source address: 3-byte source hint when S=0, or 32-byte source public key when S=1

Then:

ENC_DST_SRC = AES-128-CTR( key=K_enc_channel, iv=IV, plaintext=DST || SRC )

This allows a receiver possessing the channel key to recover both the destination (to confirm the packet is addressed to them) and the source address (to derive the pairwise keys needed to authenticate and decrypt the payload).

Perfect Forward Secrecy Sessions

UMSH provides optional perfect forward secrecy (PFS) via ephemeral node addresses exchanged using the PFS Session MAC commands. Once a PFS session is established, traffic between the two nodes is encrypted and authenticated exactly as if the ephemeral addresses were any other long-term node identities. Compromise of either node’s long-term private key cannot retroactively expose traffic encrypted during a PFS session, because the private keys for the ephemeral addresses are erased when the session ends and the session’s ECDH shared secret is irrecoverable.

Handshake

A PFS session is established via a two-message exchange over the existing authenticated unicast channel:

  1. Initiator: Generates a fresh ephemeral node address. Sends a PFS Session Request carrying the new ephemeral address and a requested session duration. The request is authenticated with the initiator’s long-term keys.

  2. Responder: Generates its own fresh ephemeral node address. Sends a PFS Session Response carrying the responder’s ephemeral address and the accepted session duration. The response is authenticated with the responder’s long-term keys.

After this exchange, both sides hold each other’s ephemeral addresses and can independently derive the session keys. No further setup messages are required. The first data packet sent by the initiator using the ephemeral address hints serves as an implicit acknowledgement to the responder that the response was received and the session is active.

Session Key Derivation

A PFS session is cryptographically identical to a normal UMSH unicast session in every respect — the only difference is that the participating node addresses are ephemeral rather than long-term. Key derivation follows the exact same process as Unicast Key Agreement.

The PFS property arises not from any difference in how the keys are derived, but from the fact that the private keys for the ephemeral addresses are never stored durably and are securely erased when the session ends.

An ephemeral node address is a fully functional temporary UMSH node identity: it has an address hint, can be addressed directly, and its private key is converted to X25519 for ECDH the same way a long-term identity is.

Because a PFS session is indistinguishable from an ordinary unicast session at the MAC layer, it requires no changes to MAC-layer processing, no changes to any application-layer protocol, and adds zero per-packet overhead. Once the two-message handshake completes, every subsequent packet in the session is exactly the size it would have been without PFS.

Wire-Level Privacy

While a PFS session is active, packet hint fields are derived from the ephemeral node address rather than the long-term address. A passive observer sees packets flowing between two unfamiliar node IDs that appear only for the duration of the session. The only packets that expose the long-term node IDs are the two handshake messages (PFS Session Request and PFS Session Response), which are themselves protected by the long-term pairwise keys.

Because ephemeral node addresses are structurally identical to long-term node addresses, an observer cannot distinguish PFS session traffic from ordinary unicast traffic, nor associate the ephemeral addresses with the original nodes that created the session.

This identity separation is not unconditional. The PFS handshake messages are authenticated with the nodes’ long-term keys, so an attacker who later compromises a long-term private key can retroactively identify which long-term identities established the session — even though the session’s content remains protected by the erased ephemeral keys.

Additionally, implementations that use a single device-wide frame counter expose a correlation opportunity: an observer who can read the frame counter field across packets (e.g. by receiving a packet before and after the PFS handshake) may notice continuity in the counter value and link the ephemeral addresses to the originating nodes. Implementations that wish to preserve wire-level identity unlinkability should use independent frame counters for each node address — including ephemeral ones — so that session traffic is not correlated with long-term traffic through counter continuity.

From the application layer’s perspective, the implementation maps the ephemeral identity back to the originating long-term node ID throughout the session, so applications continue to see communication with the same peer they initiated the session with.

Session Lifetime

A PFS session ends when any of the following occur:

  • The agreed session duration expires.
  • Either party sends an End PFS Session command.
  • Either device reboots.

Upon session end, both sides must securely erase/zeroize the private keys for their ephemeral addresses. Without those private keys, the session’s ECDH shared secret cannot be reconstructed, and the session traffic cannot be decrypted even by an attacker who later obtains the long-term private keys. This erasure is the mechanism that provides forward secrecy.

Caution

Implementations must ensure that the private keys for ephemeral addresses are not swapped to disk, written to logs, or otherwise persisted in any form. On embedded platforms, this requires explicitly zeroing the key material in RAM before releasing it. Failure to securely erase these keys eliminates the PFS property entirely.

Routing Overview

UMSH packets can be delivered directly to nodes within radio range, flooded across the mesh, source-routed through a specific sequence of repeaters, or delivered using a hybrid of source routing and flooding. This chapter gives a high-level picture of how these mechanisms fit together; detailed procedures are covered in the sections linked below.

In general, it is the responsibility of the individual endpoints to properly route their traffic to their destination.

Direct (Single-Hop) Delivery

The simplest case: the sender transmits a packet with no source-route option and no flood hop count. Only nodes within direct radio range will receive it. No repeater forwarding occurs. This is appropriate when the destination is known to be a direct neighbor, or for local broadcasts and beacons that do not need multi-hop propagation.

Flood Routing

The sender sets a flood hop count in the packet header, and every repeater that receives the packet decrements the remaining count, increments the accumulated count, and retransmits. The packet radiates outward until the hop count is exhausted or all reachable repeaters have forwarded it.

Flood routing requires no prior knowledge of the network topology. It is used for broadcasts, multicast, and unicast when no source route is known. The cost is airtime: every repeater in range participates, so a high hop count can saturate a busy mesh.

See Packet Structure § Flood Hop Count for encoding details and Repeater Operation § Forwarding Procedure for the forwarding rules.

Region Scoping

The region code option restricts flood forwarding to repeaters configured for that specific geographic region. A repeater that does not recognize or is not configured for the region MUST NOT flood-forward the packet. If multiple region code options are present, matching any one of them is sufficient for flood forwarding. If a packet is being flood-forwarded without a region code, a repeater may add one according to local policy, but it must never rewrite an existing region code or add a second one. Region scoping is not enforced during the source-routed portion of a hybrid route — only after the source-route hints are exhausted and the packet transitions to flooding.

See Packet Options § Region Code.

Signal-Quality Filtering

Two packet options let the sender control which links are acceptable for flood forwarding:

  • Minimum RSSI — a repeater that received the packet below the specified signal strength must not flood-forward it.
  • Minimum SNR — a repeater that received the packet below the specified signal-to-noise ratio must not flood-forward it.

These thresholds prevent retransmission over weak links that are unlikely to deliver the packet reliably, saving airtime and transmit power. The repeater may also enforce its own local thresholds; the effective threshold is the higher of the two.

See Packet Options § Minimum RSSI and Packet Options § Minimum SNR.

Source Routing

When the sender knows a path to the destination, it can include a source-route option listing the sequence of repeater hints the packet should traverse. Each repeater checks whether it matches the next hint, removes its own hint, and forwards. Only the designated repeaters handle the packet, so source routing avoids the airtime cost of flooding.

Source routes are learned from the trace-route option: when a flooded packet carries a trace-route option, each forwarding repeater prepends its own hint. The recipient can reverse the accumulated trace and cache it as a source route for future replies. This means path discovery is not a separate operation — it falls out of normal packet exchange.

See Packet Options § Source Route, Packet Options § Trace Route, and Beacons & Path Discovery § Route Learning.

Hybrid Routing

A packet can carry both a source-route option and a flood hop count. The packet is source-routed through the listed repeaters first; once the source-route hints are exhausted, it transitions to flood routing bounded by the remaining flood hop count. This enables “deliver to a region, then flood locally” behavior — useful for reaching a node in a known area without flooding the entire mesh.

See Repeater Operation § Routing Implications.

Bridging

A bridge is a node that relays UMSH packets between two different media or RF channels — for example, from a local LoRa radio to an internet backhaul and back to a distant LoRa radio, or between two radio bands.

Bridges are not prohibited per-se, as that is not a protocol-level decision. Instead, this document provides some guidance on how bridges can be deployed while lowering the risk of hurting local mesh performance.

Bridges are largely protocol-transparent: they consume source-route hints and forward packets as repeaters do. Currently, a bridge also retransmits on the inbound medium — even for source-routed packets — to provide forwarding confirmation to the previous hop, though this may be optimized in the future.

Bridges participate in source routes and trace routes like any other repeater. A trace route that crosses a bridge will contain the bridge’s router hint, and source-routed packets will traverse the bridge transparently.

Flooding works across bridges, but the remaining flood hop count is clamped when a packet exits the bridge — by default, to a maximum of 1. This clamping applies even to hybrid-routed packets that transition from source routing to flooding after crossing the bridge. The effect is to keep individual meshes local and accountable while still enabling multi-segment routing.

Caution

Internet bridges have the potential to be destructive to the mesh and are generally discouraged because 1) they cannot be relied upon in an emergency, and 2) they can waste airtime with useless, non-local chatter. Moreso than other types of bridges, internet bridges MUST limit the flood hop count of packets which transit the bridge.

Forwarding Confirmation and Recovery

UMSH provides hop-by-hop forwarding confirmation for both source-routed and flood-originated packets. After transmitting, a node listens for the next hop to retransmit the same packet. If no retransmission is heard within a timeout, the node retries with exponential backoff (up to 3 retries). The original sender does not currently receive any notification of a forwarding failure when source routing.

If a cached source route fails entirely (noticed because of a timeout), the sender can fall back to flood routing for the same logical packet using the route retry option, which allows repeaters to forward it even if they already suppressed the original source-routed attempt.

See Repeater Operation § Forwarding Confirmation and Repeater Operation § Source-Route Failure Recovery.

Channel Access

Before any transmission — original, forwarded, or acknowledgment — a node performs Channel Activity Detection (CAD) and backs off if the channel is busy. Flood-forwarding repeaters additionally use a contention window based on received SNR, so that better-positioned repeaters transmit first and weaker ones can suppress their retransmission if they overhear an earlier forward.

See Channel Access.

Packet Processing

This chapter describes how a receiving node processes an incoming packet. This procedure applies to all nodes, not just repeaters. Repeater-specific forwarding logic is described separately in Repeater Operation.

Receive Procedure

  1. Well-formedness check

    • If the packet is malformed (invalid FCF, truncated fields, non-zero reserved bits in the SCF), drop.
  2. MAC Ack handling

    • If the packet is a MAC Ack:
      • If this node was not expecting the ack, stop.
      • Otherwise, handle the ack and stop.
  3. Address matching

    • If the packet is a broadcast, continue.
    • If the packet carries a destination hint that matches this node, continue.
    • If the packet carries a channel hint matching a configured channel, continue.
    • Otherwise, stop.

    A node always attempts to handle a packet that matches its destination hint, even if the packet has remaining source-route hops. This differs from systems like MeshCore and allows two nodes that are suddenly in direct range of each other to recover quickly without waiting for the packet to traverse the full source route. The packet may also be forwarded according to the normal forwarding procedure if the node is acting as a repeater.

  4. Channel processing (multicast and blind unicast)

    4.1. If the packet is a blind unicast:

    • Decrypt the source address using the channel’s derived encryption key K_enc.
    • If the source address is a hint (S=0), look up candidate public keys matching the hint. If no candidates exist, stop.

    4.2. Attempt decryption and MIC verification for each candidate channel key.

    • For blind unicast, this may require re-decrypting the source address for each candidate channel from step 4.1.
    • If no candidate channel succeeds, stop.
  5. Unicast processing

    5.1. If the source address is a hint (S=0), look up candidate public keys matching the hint. If no candidates exist, stop.

    5.2. Attempt MIC verification (and decryption if encrypted) for each candidate source address.

    • If no candidate succeeds, stop.

    5.3. If the source address is blacklisted, drop.

  6. Payload type validation

  7. Ack Processing

    • If the packet type requests an ACK, the receiving node (i.e., the final destination) computes the ack tag from the full 16-byte CMAC and pairwise K_enc, prepares a MAC Ack packet, and adds it to the outbound queue. Repeaters do not generate acks — see MAC Ack Packet.
  8. Application processing

    • Continue processing the application payload.

Channels

A channel is a shared symmetric key that enables group communication and metadata concealment. Channels serve two distinct roles in UMSH:

  • Multicast — any node that possesses the channel key can send and receive packets addressed to the channel, enabling group communication.
  • Blind unicast — the channel key conceals both sender and destination addresses on the wire, while the payload itself is protected end-to-end using combined keys that require both the channel key and the pairwise shared secret. The channel serves as a metadata-concealment layer; the payload is readable only by the intended recipient, not by all channel members. See Blind Unicast Packet and Blind Unicast Source Encryption for details.

In both cases, the channel key is the membership credential — possessing it is both necessary and sufficient to participate.

Channel Keys

A channel key is a 32-byte symmetric key. It serves as the root secret from which encryption, authentication, and identification keys are derived (see Multicast Packet Keys).

How a node obtains a channel key depends on the type of channel — see Joining a Channel below.

Channel Identifier

Each channel is identified on the wire by a 2-byte channel identifier derived from the channel key. This identifier is a compact hint that allows receivers to quickly identify candidate channels without attempting decryption with every configured key. Like destination hints, channel identifiers are not cryptographically authoritative — collisions are possible and must be resolved by attempting cryptographic verification.

Encrypted and Unencrypted Modes

Channel-addressed packets (multicast and blind unicast) may be sent with or without encryption, controlled by the E flag in the Security Control Field.

  • Encrypted (E=1): The source address is encrypted together with the payload, concealing the sender’s identity from observers who do not possess the channel key. Only channel members can recover the source address and payload. See Encrypted Multicast for the packet layout.

  • Unencrypted (E=0): The source address and payload appear in cleartext, but the packet is still authenticated with a MIC derived from the channel key. This mode is useful for amateur radio operation or other contexts where encryption is not permitted. See Unencrypted Multicast for the packet layout.

Multi-Hop Delivery

Channel-addressed packets are delivered via flood forwarding, bounded by the optional flood hop count field. Repeaters forward these packets according to the standard forwarding procedure, including duplicate suppression, signal-quality filtering, and region-scoped flooding.

Sender Authentication

Multicast authentication is based on the shared channel key, not on individual sender identity. The MIC proves that the sender possesses the channel key, but any channel member can construct a valid packet with any claimed source address. This is a fundamental property of symmetric-key multicast — see Multicast Sender Authentication for further discussion.

Blind unicast payloads are additionally authenticated using pairwise keys derived from the sender and recipient’s key agreement, so only the true sender can produce a valid payload and only the intended recipient can verify it.

Joining a Channel

UMSH supports three models for channel membership, from simplest to most capable.

Named Channels

Channel keys may be derived from human-readable channel names rather than distributed as raw keys. A named channel is identified by a umsh:cs: URI (see URI Formats):

umsh:cs:Public

Named channels are effectively public — anyone who knows the name can derive the key and participate. Long, high-entropy names may provide practical obscurity, but this should not be treated as strong secrecy.

The channel key is derived from the channel name using HKDF-Extract:

channel_key = HKDF-Extract-SHA256(salt = "UMSH-CHANNEL-V1", ikm = UTF-8(channel_name))

Where channel_name is the name portion of the umsh:cs: URI (everything after umsh:cs:), after percent-decoding, encoded as a UTF-8 byte string. For example, given umsh:cs:Public, the input is the UTF-8 encoding of Public. The output is a 32-byte pseudorandom key that serves as the channel key. This key then flows through the standard Multicast Packet Keys derivation to produce K_enc and K_mic.

HKDF-Extract is appropriate here because named channels are not secrets — the name is public input keying material, not a password. Password-based KDFs (PBKDF2, Argon2) would add computational cost without meaningful security benefit, since the channel name is assumed to be known to all participants.

Private Channels

For channels that require real secrecy, the channel key is distributed out-of-band — via QR codes, umsh:ck: URIs (see URI Formats), or any other secure channel (including in-band exchange over an existing authenticated unicast session). Anyone who possesses the key is a member; there is no central authority and no mechanism to revoke membership without changing the key for everyone.

Managed Channels

A managed channel is administered by a designated managing node that controls membership. Unlike named and private channels, a managed channel supports adding and removing individual members without requiring all remaining members to re-join manually.

Note: The specific wire formats and MAC commands for managed channel operations (join requests, key distribution, rotation signalling) are not yet defined. The MAC layer itself is unaffected — managed channels use the same multicast packet format and cryptographic processing as any other channel.

To join a managed channel, a node provides its public key to the managing node — either out-of-band or via an in-band join request that the manager can accept or deny. Once accepted, the new member receives the current channel key and channel metadata from the managing node.

The managing node periodically rotates the channel key. When a key rotation occurs, each current member receives the new key along with the time at which it becomes active, allowing a coordinated switchover. Because the channel identifier is derived from the channel key, a key rotation also changes the channel’s on-wire identifier; the application layer masks this from the user so the channel appears to be the same.

To remove a member, the managing node distributes a new key to all members except the excluded node. The excluded node still holds the old key but cannot decrypt traffic encrypted under the new one.

Members that are offline during a key rotation can request the current key from the managing node when they reconnect.

Default Channels

Implementations should recognize two well-known named channels with specific behavior requirements.

public

The public channel (derived from umsh:cs:public) is the default flooded group chat channel. It provides a shared communication space analogous to an open town square — any node that knows the name can participate.

  • Maximum flood hops: 5 without a region code, 7 with a region code.
  • Traffic may be encrypted (E=1).
  • Chat messages that do not include the full source key (S=1) must not be displayed in the user interface. This ensures that users can always verify sender identity on the public channel, even though the channel key itself is public knowledge.

EMERGENCY

The EMERGENCY channel (derived from umsh:cs:EMERGENCY, case-sensitive) is reserved for emergency communications. Repeaters should prioritize forwarding packets on this channel.

  • Maximum flood hops: 5 without a region code, 7 with a region code.
  • Chat messages must not be encrypted — all emergency traffic must be readable by any node in range, including nodes that have not explicitly joined the channel.
  • Chat messages must include the full source key (S=1).
  • Chat messages must include an EdDSA signature in the payload.
  • Messages that do not meet all three requirements (unencrypted, full source key, signed) must not be accepted or displayed by the user interface.

These requirements ensure that emergency traffic is universally readable, attributable to a specific node, and cryptographically authenticated against impersonation.

Payload Reuse

Application-layer channel communication reuses the same payload types as unicast. For example, group chat uses the same text message and chat room payload formats as direct messaging. However, not all application types are valid over multicast — see Payload Types for compatibility.

Channel Access

This chapter describes how UMSH nodes contend for channel access before transmitting. These procedures apply to all transmissions — original packets, forwarded packets, and acknowledgments — unless otherwise specified.

Frame Duration

T_frame is the maximum on-air duration of a LoRa frame at the configured channel settings (spreading factor, bandwidth, coding rate, and maximum payload size). T_frame is not a fixed protocol constant; implementations derive it from the channel configuration. All timing parameters in this chapter are expressed as multiples of T_frame.

For reference, typical T_frame values for a maximum-length (255-byte) packet using common MeshCore-style channel settings:

RegionSettingsT_frame
USA (915 MHz)BW 62.5 kHz, SF7, CR 4/5~0.8 s
Europe (868 MHz)BW 62.5 kHz, SF8, CR 4/8~2.2 s

Channel Sensing

Before transmitting any packet, a node MUST perform Channel Activity Detection (CAD). CAD is a LoRa hardware primitive that detects preamble energy on the channel with minimal power draw.

  • If CAD indicates the channel is idle, proceed to transmit.
  • If CAD indicates the channel is busy, enter the backoff procedure.

Backoff Procedure

When CAD indicates the channel is busy:

  1. Wait a random duration uniformly sampled from [0, T_frame].
  2. Perform CAD again.
  3. Repeat up to 4 more times (5 CAD attempts total).
  4. If the channel remains busy after all attempts, drop the packet silently.

Flood Forwarding Contention Window

When a repeater is eligible to flood-forward a packet, it SHOULD NOT transmit immediately. Instead, it waits a contention delay inversely proportional to the quality of the received signal. Nodes that heard the packet most clearly transmit first; nodes that barely met the signal threshold wait longer. When a well-positioned repeater transmits, others overhear it, recognize the packet via duplicate suppression, and usually defer or abandon their own pending forwarding.

Note

This guidance is still provisional and should be treated as a starting point until it is validated with real-world measurements.

Although the contention parameters below are configurable in principle, nodes in the same mesh SHOULD use the same values so that forwarding behavior remains predictable. Unless a deployment intentionally overrides them, implementations SHOULD use the defaults in this section.

For the first forwarding decision after reception, compute the contention window as:

quality = clamp((received_SNR − SNR_low) / (SNR_high − SNR_low), 0, 1)
W       = W_min + (W_max − W_min) × (1 − quality)
delay = uniform_random(0, W)

Where:

  • SNR_low and SNR_high define the clamp range used for the contention heuristic. The suggested defaults are −6 dB and +15 dB, respectively.
  • When flood-forwarding, the effective minimum SNR threshold is the higher of the Minimum SNR packet option (if present) and any locally configured minimum SNR. A repeater MUST NOT flood-forward if the received SNR is below that effective threshold. (Signal-quality thresholds do not apply to source-routed hops.)
  • W_min is the minimum contention window for strong receptions. The suggested default is 0.2 × T_frame.
  • W_max is the maximum intentional forwarding-delay window. The suggested default is 2 × T_frame.
  • received_SNR is the SNR measured during reception of the packet being forwarded.

If SNR is unavailable but RSSI is, the same formula MAY be applied with RSSI values substituted for SNR, using appropriate threshold and range parameters.

After computing the delay, the repeater waits.

If it overhears the same packet forwarded by another node (identified by MIC in the duplicate cache) before the delay expires, it SHOULD defer rather than transmit immediately. A safe default is to resample a delay using the same W_min/W_max limits and restart the waiting period. A repeater SHOULD NOT do this more than 3 times; after the third such deferral it SHOULD abandon the pending forward.

This deferral behavior is intended only for the first local forwarding decision after reception. Once a repeater has actually transmitted its own copy, any later retransmission behavior is governed by Repeater Operation.

Nodes waiting for implicit forwarding confirmation MUST size their confirmation timeout to include this full forwarding-delay window. A safe default is to allow:

  • up to W_max of intentional forwarding delay
  • up to T_frame for the forwarded transmission itself
  • an additional guard margin of up to T_frame

Immediate ACK Transmission

When a node is the final destination of an ack-requested packet (UNAR or BUAR) and the packet has no remaining source route hops, the node SHOULD transmit the ACK immediately — without performing CAD — provided the radio is available for transmission. This is warranted because the channel is known to have been clear at the moment the received packet ended.

If the radio is not immediately available for transmission, the node SHOULD perform normal CAD and backoff before transmitting the ACK.

Repeater Operation

Forwarding logic is intentionally conservative. A repeater should evaluate packets in the following order.

Routing Invariants

The routing model is governed by a few simple rules:

  • Every currently defined on-mesh packet type is routable.
    • In the current protocol this includes broadcast, MAC ack, unicast, multicast, and blind unicast packets.
    • Reserved or opaque packet types are not routable until the protocol defines their forwarding semantics (there is only one at the moment, type 5).
  • Repeaters MUST mutate specific dynamic routing metadata while forwarding (source route, trace route, hop count, etc)
    • Typical examples are flood hop counts, trace routes, source routes.
    • A repeater SHALL NOT simply repeat a packet verbatim under any circumstances.
    • The Route Retry flag MUST NOT be added to a packet by anyone other than the original sender.
    • These mutations do not create a new logical packet.
  • A packet’s logical delivery identity and its repeater forwarding identity are related but distinct.
    • The final destination decides whether a packet is new by its normal replay and destination-processing rules.
    • Repeaters suppress duplicates using a forwarding identity that remains stable across legal forwarding rewrites.
  • Forwarding confirmation uses the same identity as repeater duplicate suppression.
    • This ensures a sender or repeater recognizes “the same packet, forwarded onward” even if the next hop mutates dynamic routing metadata.

Duplicate Suppression

Each repeater maintains a fixed-size cache of recently seen cache keys used to detect duplicate packets.

Parameters:

  • cache size = implementation configurable (see sizing guidance below)
  • eviction policy = oldest entry removed when full

The cache key is derived from the packet as follows:

  • Authenticated packets (unicast, multicast, blind unicast): the cache key is normally the packet’s MIC. Because the MIC covers all static fields and is unaffected by repeater modifications to dynamic options or the flood hop count, it remains stable across forwarding hops.
    • If the packet carries the Route Retry option, the cache key must distinguish that retry attempt from the same packet without the option present. A simple and sufficient rule is to treat the cache key as (MIC, route_retry_present).
    • This gives a packet two bounded forwarding identities: the original forwarding attempt and one explicit reroute attempt.
  • MAC acks and broadcasts: these packet types do not carry a MIC. The cache key is a locally-computed hash of the packet content, excluding the flood hop count and dynamic options — the same fields that would be excluded from a MIC. The hash does not need to be cryptographic; CRC-32 is suggested, but any hash with comparable distribution is acceptable. The choice of hash algorithm is a local implementation detail.

Before forwarding a packet, the repeater checks the cache:

  • if the cache key is already present, do not forward
  • if the cache key is not present, continue processing
  • once the repeater decides the packet is eligible, insert the cache key into the cache

To avoid racy reforward behavior, the repeater should insert the cache key into the cache as soon as it accepts the packet for forwarding, not after transmission completes.

Shorter cache keys increase the probability of false-positive collisions. Deployments that use 4-byte or 8-byte MICs should account for this when sizing the duplicate cache.

Cache Sizing

Each cache entry is small (equal to the cache key size — typically 4 to 16 bytes), so generous sizing is inexpensive. The recommended minimum is 32 entries; the suggested default is 64 entries. High-traffic deployments or networks with large diameters may benefit from 128 or more entries.

Forwarding Procedure

  1. Duplicate suppression

    • If this packet was forwarded recently, do not forward.
  2. Locally-Handled Unicast

    • If this packet was a unicast (bind or direct) packet that was fully handled and processed according to Packet Processing, do not forward.
  3. Unknown critical options

    • If the packet contains any critical option the repeater does not understand, do not forward.
  4. Policy checks

    • If the packet does not satisfy local repeater policy, do not forward.
  5. Source-route match

    • If the packet contains a non-empty source-route option:
      • If this repeater does not match the next source-route hint, do not forward.
      • Otherwise, remove the repeater’s own hint from the source-route option.
    • If the repeater mutates a source-route option, it MUST preserve the option on the forwarded packet even when no hints remain.
      • In that case, the forwarded packet carries a source-route option with zero remaining hops.
      • This preserves provenance: downstream nodes can still determine that the packet arrived via explicit source routing rather than by pure flooding.
    • If the source-route option is still non-empty after removing this repeater’s hint, skip directly to step 9 (trace route processing). The remaining steps apply only to flood forwarding.
  6. Transition from source-routing to flooding

    • If the source-route option is now empty:
      • If the packet carries one or more region code options and none of them match this repeater’s configured regions, do not forward.
      • If the packet has no region code option, the repeater MAY insert one according to local policy before flood-forwarding.
      • If one or more region codes are already present, the repeater MUST preserve them unchanged.
      • A repeater MUST NOT add a second region code to a packet that already carries at least one region code.
      • If the packet has a flood hop count field with FHOPS_REM > 0, decrement FHOPS_REM and increment FHOPS_ACC.
      • Otherwise, do not forward.
  7. RSSI threshold check

    • If either the packet or repeater imposes a minimum RSSI, the effective threshold is the higher of the two. If the received RSSI is below the effective threshold, do not forward.
  8. SNR threshold check

    • If either the packet or repeater imposes a minimum SNR, the effective threshold is the higher of the two. If the received SNR is below the effective threshold, do not forward.
  9. Trace route processing

    • If the packet contains a trace-route option, prepend this repeater’s hint. If prepending the hint would cause the packet to exceed the maximum frame size, drop the packet.
  10. Retransmit

  • Forward the modified packet.

Bridges follow the same packet-rewrite rules as repeaters. A bridge that tunnels traffic to a physically different location generally should not forward flood packets that lack a region code.

Forwarding Confirmation

Repeaters do not generate MAC acks — acks are generated only by the final destination. Instead, a node can passively confirm that a transmitted or forwarded packet was received by listening for a subsequent retransmission of the same packet.

This applies to:

  • Source-routed packets: Each forwarding hop listens for the next hop — the node matching the next source-route hint — to retransmit.
  • Flood originators: The originating node listens for any node to retransmit.
  • Flood repeaters: Intermediate flood-forwarding nodes MUST NOT retry. Multiple nodes may forward the same flood packet, and a repeater has no designated next hop to listen for; retrying would increase congestion without improving reliability.

After transmitting, the node listens for the same packet — identified by its cache key — to be retransmitted. This confirmation timeout MUST be large enough to cover the worst-case forwarding delay allowed by Channel Access, plus the airtime of the forwarded frame itself, plus a guard margin. A safe default is:

confirm_timeout = 2 × T_frame + W_max

where W_max is the maximum intentional forwarding-delay window permitted for the path. With the suggested default W_max = 2 × T_frame, this yields confirm_timeout = 4 × T_frame.

If the packet is heard before confirm_timeout expires, forwarding is confirmed.

If confirm_timeout expires without a retransmission, the node SHOULD schedule a retry after a jittered exponential delay:

retry_delay_n = uniform_random(0, min(2^(n−1) × T_frame, 4 × T_frame))

where n is the 1-based retry number. After this delay expires, the retry is transmitted using normal CAD and backoff as described in Channel Access.

A node MUST NOT retry more than 3 times.

Source-Route Failure Recovery

When a node uses a cached source route for an ack-requested unicast or blind-unicast packet and that attempt fails, it needs a way to re-attempt delivery without causing duplicate application delivery at the final destination.

A practical recovery rule is:

  1. if the sender exhausts the retry budget for a packet sent using a cached source route, it SHOULD treat that cached route as failed
  2. the failed route SHOULD be discarded or marked unusable for immediate reuse
  3. if the sender wishes to re-attempt delivery of the same logical packet, it SHOULD:
    • preserve the same frame counter, payload, and MIC
    • remove the stale source-route option
    • add or refresh flood hops
    • include a trace-route option if route rediscovery is desired
    • set the Route Retry option

This recovery transmission is intentionally the same logical packet, not a new application message. The destination therefore still accepts it at most once according to the normal replay rules. The Route Retry option exists only to let repeaters forward the rerouted attempt even if they already suppressed the original source-routed attempt as a duplicate.

This preserves a useful separation of responsibilities:

  • routing recovery remains a MAC concern
  • duplicate application delivery remains prevented by the end-to-end replay rules
  • repeaters remain largely stateless and do not need to understand application semantics

For flood-forwarding repeaters that have accepted a packet for forwarding but have not yet transmitted it, overhearing another forwarding of the same packet SHOULD normally cause a bounded deferral rather than an immediate transmission. A safe default is:

  1. resample a forwarding delay using the contention-window procedure in Channel Access
  2. restart the waiting period
  3. after 3 such deferrals, abandon the pending forward

This behavior is still provisional and should be validated empirically. The intent is to reduce near-simultaneous forwarding while still allowing a second or third repeater to contribute if an earlier forward was not widely heard.

Routing Implications

This forwarding model allows hybrid routing behavior.

For example, a packet can be source-routed to a specific repeater and also carry a flood hop count. Once the source-route hints are consumed, the packet transitions to flood-based forwarding bounded by FHOPS_REM. This permits “delivery-to-region, then flood” behavior, which is useful when searching for a node in a known geographic area without flooding the entire mesh.

Beacons & Path Discovery

Beacons

A Beacon is defined as either:

  • a broadcast packet with no payload, or
  • a multicast packet with no payload

Beacons are used to announce the presence of a node on the network without carrying additional data.

A beacon with a trace-route option can inform listeners of both:

  • the node’s presence
  • a repeater path that may be usable to reach it

This is particularly useful when a receiver already knows the node’s identity information.

Path Discovery

UMSH does not define a dedicated path-discovery packet type. Instead, path discovery is performed using existing primitives:

  1. Outbound discovery: Node A sends a unicast packet to Node B with the trace-route option present and an appropriate flood hop count. The packet floods through the mesh; repeaters prepend their router hints to the trace-route option as they forward.

  2. Path learning: When Node B receives the packet, the trace-route option contains the sequence of repeater hints traversed, ordered most-recent first. Node B can use this list directly as a candidate source route back to Node A.

  3. Return path: Node B can now send unicast packets to Node A using the learned source route. If the packet was ack-requested, Node B’s MAC ack also traverses the mesh, allowing Node A to confirm reachability.

  4. Bidirectional establishment: If Node A also needs a source route to Node B, it can include the trace-route option on its initial packet. When Node B responds (e.g., with an ack, beacon, or identity payload) using its learned route and also including a trace-route option, Node A can learn its own source route to Node B.

Because router hints are only two bytes, different repeaters may share the same hint, which may result in redundant (but harmless) forwarding along a source route.

Route Learning

When a node successfully processes an incoming packet, it SHOULD update its routing state for the sender:

  • Trace route: if the packet contains a trace-route option, the node caches that trace route as a source route for future packets back to the sender. Because the trace route is accumulated most-recent first, it already describes the return path from the receiver back toward the original sender. This is the primary mechanism for learning precise multi-hop paths.
  • Flood hop count: if the packet contains a flood hop count, the node caches the sender’s FHOPS_ACC value as a distance estimate. When no source route is available, this value can be used as FHOPS_REM for flood responses — scoping the flood to approximately the right radius rather than flooding the entire network.

This routing state applies to all subsequent communication with the sender — replies, acknowledgments, and new messages alike. A node MAY replace a cached route when a newer packet provides a fresher trace route, and SHOULD discard cached routes that have proven unreachable.

In practice, “proven unreachable” usually means that an ack-requested packet sent using the cached source route exhausted its retry budget without end-to-end success. In that case, the sender should stop trusting the stale route and return to route-discovery behavior:

  • discard or demote the cached source route
  • send the same logical packet again using flood hops instead of the stale source route
  • include a trace-route option so that a fresh source route can be learned from the peer’s reply
  • set the Route Retry option so intermediate repeaters treat the rerouted attempt as a new forwarding opportunity even though the packet’s MIC and frame counter are unchanged

Once the peer replies and a fresher trace route is learned, the sender can resume normal source-routed transmission using the replacement route.

Potential Improvement: Proactive Route Refresh

The recovery behavior above is reactive: a node continues using a cached source route until that route appears to have failed. In mobile scenarios, this may mean the sender does not attempt to discover a fresher route until after packets have already stopped flowing end-to-end.

One possible future improvement would be to allow a sender to occasionally perform a low-rate exploratory route refresh even when there is no strong indication of failure. This behavior is not part of the current specified protocol behavior and has not been validated with real-world measurements. It is described here only as a possible future optimization.

A conservative version of this idea would look like:

  • only perform exploratory refresh when the sender is believed to be mobile or moving
  • use a normal cached source route, but also include a trace-route option
  • allow only a small flood budget, capped at no more than source_route_hops + 1
  • perform this no more than occasionally, for example no more than once every N successful transmissions and no more than once every T minutes, whichever is longer

The intent would be to probe for a slightly better or fresher route without incurring the cost of a full rediscovery flood. A small tail flood could help discover alternate final hops or nearby replacement repeaters when the old route is only partially stale.

This approach has important limitations:

  • if the cached source route breaks early, a small tail flood will not help, because forwarding remains constrained by the explicit source route until that route is exhausted
  • excessive probing would waste airtime and increase contention, especially on busy meshes
  • a newly observed route is not necessarily better and may require local policy before replacing the old route

If this idea is ever standardized, meshes should converge on the same probing policy and parameter values so that behavior remains predictable across implementations. Any such policy should be treated as provisional until it has been evaluated on real radios in mobile conditions.

Payload Format

The UMSH payload carries higher-layer content — either a network-layer protocol (e.g., 6LoWPAN), a third-party application protocol (e.g., CoAP), or one of the UMSH-defined application protocols (e.g., text messages, chat rooms). The MAC layer treats the payload opaquely; it does not interpret, fragment, or reassemble payload content (see Layer Separation).

Payloads are typically prefixed by a 1-byte payload type identifier. Values from 128-255 (all values with the most significant bit set) are currently RESERVED.

Payload Type Registry

ValueMeaning
0Unspecified
1Node Identity
2MAC Command
3Text Message
4RESERVED
5Chat-Room Message
6RESERVED
7CoAP-over-UMSH
8Node Management Command

Payload and Packet Type Compatibility

Not all payload types are valid with all packet types. A receiver should drop a packet whose payload type is not compatible with its packet type. For the purposes of this table, blind unicast follows the same rules as unicast.

Payload TypeUnicastMulticastBroadcast
Empty payloadYesYesYes
Node IdentityYesYesYes
MAC CommandYesNote 1No
Text MessageYesYesNo
Chat-Room MessageYesNoNo
CoAP-over-UMSHYesYesNo
Node Management CmdYesYesNo

Unless explicitly configured otherwise, the only payload types allowed for broadcast are empty payloads and node identities.

Note 1: Some MAC commands may be permitted on specific channels. For example, a private channel might allow echo requests to all members and receive echo responses from everyone. Whether a given MAC command is accepted over multicast is deployment-defined and not yet specified by the protocol.

In-Band Node Management

Nodes may optionally support remote management via Node Management Command payloads.

Support for in-band management is protocol-defined but implementation-optional.

Node Identity

The node identity payload is an application-layer structure carried inside the UMSH payload. Its contents — including the timestamp below — are not interpreted or required by the MAC layer. The MAC layer itself is timestamp-free (see Frame Counter).

A node’s identity may be expressed as the following structure:

  • 4 bytes: UNIX timestamp from when this information was last updated, truncated to 32 bits
  • 1 byte: Node primary role
  • 1 byte: Node feature/capability bitmap
  • N bytes, optional: zero-terminated node name
  • N bytes, optional: CoAP-style option list, terminated by 0xFF if EdDSA signature is present.
  • 64 bytes, optional: EdDSA signature over the preceding identity data

Node Primary Role

Defined values:

  • 0 — Unspecified
  • 1 — Repeater
  • 2 — Chat
  • 3 — Tracker
  • 4 — Sensor
  • 5 — Bridge
  • 6 — Chat Room
  • 7 — Temporary Session
  • all other values — Reserved

Capability Bitmap

Bit assignments:

  • bit 0 — Repeater
  • bit 1 — Mobile
  • bit 2 — Text Messages
  • bit 3 — Telemetry
  • bit 4 — Chat Room
  • bit 5 — CoAP
  • bit 6 — Node name included
  • bit 7 — Node options included

If the node-name-included bit is clear, the node name is simply not advertised in this identity payload; it does not imply the node lacks a name.

Node Identity Options

Possible options include:

  • Node Location (longitude/latitude)
  • Node Battery Percentage
  • Node Uptime (minutes)
  • Amateur Radio Callsign
  • Supported Regions (for repeaters)

Signature Usage

The optional 64-byte EdDSA signature is generally included only when the identity data must stand on its own, such as:

  • QR codes
  • broadcasts without a MIC

When the enclosing packet already carries a MIC, the EdDSA signature is generally omitted.

MAC Commands

A MAC command payload consists of:

  • 1 byte: command identifier
  • optional bytes: command-specific payload

Support for MAC commands is optional.

Command Registry

ValueCommandDirection
0Beacon RequestRequest
1Identity RequestRequest
2Signal Report RequestRequest
3Signal Report ResponseResponse
4Echo RequestRequest
5Echo ResponseResponse
6PFS Session RequestRequest
7PFS Session ResponseResponse
8End PFS SessionEither

Beacon Request (0)

Requests that the destination send back a beacon.

FieldSizeDescription
Nonce0 or 4 bytesIf present, must be copied into the response beacon

Beacon requests may be used for:

  • presence detection
  • frame-counter synchronization

Identity Request (1)

Requests that the destination respond with its node identity payload.

No command-specific payload.

Signal Report Request (2)

Requests that the destination respond with signal quality information about the link.

No command-specific payload.

Signal Report Response (3)

Reports signal quality measurements in response to a Signal Report Request.

FieldSizeDescription
RSSI1 byteReceived signal strength as an unsigned value representing negative dBm (e.g. 130 = -130 dBm)
SNR1 byteSignal-to-noise ratio as a signed value in dB

Echo Request (4)

Requests that the destination respond with an Echo Response.

FieldSizeDescription
Echo data0+ bytesArbitrary payload, copied verbatim into the Echo Response

Echo requests may be used for:

  • round-trip latency measurement
  • reachability testing
  • frame-counter synchronization (by observing the frame counter in the response’s SECINFO)

Echo Response (5)

Carries a response to a prior Echo Request, including any echo data from the request.

FieldSizeDescription
Echo data0+ bytesCopied verbatim from the Echo Request

PFS Session Request (6)

Initiates a PFS session. The sender generates a fresh ephemeral node address and transmits it along with a requested session duration. See Perfect Forward Secrecy Sessions for the session establishment mechanism, key derivation, and wire-level privacy properties.

FieldSizeDescription
Ephemeral node address32 bytesSender’s newly generated ephemeral node address (Ed25519 public key) for this session
Session duration2 bytesRequested session lifetime in minutes (0 = no expiration)

PFS Session Response (7)

Sent in response to a PFS Session Request. The responder generates its own ephemeral node address, returns it along with the accepted duration, and both sides derive session keys from the ephemeral addresses. See Perfect Forward Secrecy Sessions.

FieldSizeDescription
Ephemeral node address32 bytesResponder’s newly generated ephemeral node address (Ed25519 public key) for this session
Session duration2 bytesAccepted session lifetime in minutes

End PFS Session (8)

Terminates an active PFS session. May be sent by either party. Upon receipt, both sides securely erase the private keys for their ephemeral addresses and revert to using their long-term keys. See Session Lifetime for all conditions under which a session ends.

No command-specific payload. The sender and recipient are identified by the packet’s addressing fields.

Node Manament Protocol

TBD

Text Messages

The text message protocol carries human-readable text between nodes (unicast) or from a node to a channel (multicast).

The payload consists of a CoAP-style option list terminated by a 0xFF byte, followed by the message body. All options are non-critical — unrecognized options are ignored and the remainder of the message is displayed normally.

Message Options

NumberNameValue
0Message Type0 or 1 bytes
1Sender HandleUTF-8 string
2Message Sequence1 or 3 bytes (see below)
3Sequence Reset0 bytes (flag)
4Regarding1 or 4 bytes (see below)
5Editing1 byte
6Background Color3 bytes, RGB
7Text Color3 bytes, RGB

Message Type

ValueNameRendering
0Basic textDisplayed in a text bubble
1Status textDisplayed inline as “[HANDLE] [MESSAGE]” (similar to IRC /me)
2Message Resend RequestNot displayed, has no text, see below

If absent or empty, the message type defaults to 0 (basic text).

The presence of the Regarding option changes the semantics a bit: A reply is a type 0 message with a Regarding option specifying which message is being replied to. An emote is a type 1 message with a Regarding option specifying which message is being reacted to; the body is a single Unicode emoji or a short text token such as +1, -1, !, or ?. Implementations may differentiate emotes from plain status text by the presence of the Regarding option.

A message resend request it itself not a message but a request to re-send a message that was inferred to exist but was not received. Such a request SHALL only contain one “Message Sequence” option which contains the specific message or fragment that was missed. This MUST be received via unicast (for one-on-one messages) or blind-unicast (for channel messages), and SHALL be dropped if received via broadcast or multicast.

For requesting a message that was sent to a channel, there is a need to disambiguate between requesting a message missed from the channel chat vs requesting a message missed from a blind unicast 1:1 chat. To disambiguate, when requesting the message from a channel chat, the text body will contain a single ASCII “#” character.

Sender Handle

A UTF-8 string containing the name or pseudonym of the sender. If not supplied, a handle may be inferred from previously received node metadata for the sender’s address.

Message Sequence

Associates a packet with a per-sender monotonically increasing message identifier, and optionally carries fragmentation state. The option is encouraged on all messages but is not required. Messages without this option cannot be directly referenced in replies or emotes.

The option value is either 1 byte or 3 bytes:

1-byte form (message ID only):

ByteFieldDescription
0Message IDPer-sender message identifier (wraps at 255)

3-byte form (fragment):

ByteFieldDescription
0Message IDShared by all fragments of the same message
1Fragment IndexZero-based position of this fragment
2Fragment CountTotal number of fragments (must be 2 or greater)

Rules:

  • Message IDs are per-sender and monotonically increasing, wrapping at 255.
  • Messages smaller than MTU-32 bytes SHOULD NOT be fragmented.
  • Options from the first fragment (Fragment Index 0) apply to the entire reassembled message. Subsequent fragments MUST NOT include options that would override those of the first fragment, and any such options MUST be ignored by the receiver.
  • During reassembly, missing fragments SHOULD be rendered as [FRAGMENT MISSING], or an appropriately-localized equivalent.
  • Out-of-order reassembly SHOULD be supported for fragments received within a reasonable amount of time (thirty seconds to two minutes).
  • Edits (see Editing) carry their own message IDs and MUST NOT be referenced by subsequent Editing or Regarding options. The original message ID is the stable reference.

Sequence Reset

A 0-byte flag option that signals the sender has reset its message ID counter — for example, after a restart. Receivers SHOULD discard any cached message context for this sender, including pending fragment reassembly state.

The Sequence Reset option SHOULD accompany a Message Sequence option bearing the sender’s new starting ID. In the absence of a Message Sequence option, receivers SHOULD treat the next message from that sender as starting a fresh sequence.

Regarding

References a previously sent message for the purposes of replies and emotes.

The option length depends on context:

  • Unicast (MAC packet addressed to a single destination): 1 byte — the Message ID of the referenced message.
  • Multicast channel: 4 bytes — the 1-byte Message ID followed by the first 3 bytes of the source public key of the original sender.

The source prefix is necessary in multicast channels to disambiguate messages from different senders that may share the same Message ID. This means a message cannot be referenced if it is more than 255 messages old in that sender’s sequence, or if the user has since reset their sequence ID.

In chat rooms, the room assigns canonical Message IDs across all senders (see Chat Rooms), so the 1-byte form is used and no source prefix is needed.

Editing

Indicates that this message replaces a previously sent message from the same sender. The option value is 1 byte: the Message ID of the message being edited. Because only the original sender can issue an edit (enforced by MAC-layer authentication), no source prefix is needed.

An edit with a zero-length body signals deletion of the original message.

Edit messages carry their own Message IDs. References in subsequent Editing or Regarding options MUST use the original message’s ID, not the edit’s ID.

How edits are presented to users is implementation-defined. Implementations typically display only the most recent edit, with some indication that edits exist, and an optional mechanism to view edit history.

Background Color

Three bytes (red, green, blue) specifying a suggested background color for the text bubble. Receivers may ignore this option. If supported, implementations should ensure adequate contrast with the text color.

Text Color

Three bytes (red, green, blue) specifying a suggested text color. Receivers may ignore this option. If supported, implementations should ensure adequate contrast with the background color.

Message Body

The message body is a UTF-8 string.

Chat Rooms

A chat room is a special node that provides limited store-and-forward capability for text messages and potentially other types of data. Chat rooms may be polled or can push updates to joined members.

Action Types

The first byte of the payload identifies the action type.

ValueActionDirection
0Get Room InfoUser → Room
1Room InfoRoom → User
2LoginUser → Room
3LogoutUser → Room
5Fetch MessagesUser → Room
6Fetch UsersUser → Room
7Admin CommandsUser → Room
8Room UpdateRoom → User

Regular message exchange — including system events — does not use a dedicated action type. Users send messages to the room as plain text message payloads (unicast to the room node), and the room distributes them to members the same way. Action types are reserved for room management operations. Room Update (action 8) is used only for batch history delivery.

Get Room Info / Room Info

A user may send a Get Room Info action to a room node without being logged in. The room responds with a Room Info action containing CoAP-option-encoded metadata:

NumberNameNotes
0Room NameUTF-8 string
1Owner Information
2AdministratorUser ID; may appear more than once. May only be included for logged-in users
3Active User Count
4Max User Count
5Message Queue Depth
6Most Recent Message Timestamp
7Oldest Retrievable Message Timestamp

If the options are terminated with a 0xFF byte, the remainder of the response is a UTF-8 description of the room.

Login

The login payload is CoAP-option-encoded:

NumberNameNotes
0HandleIf omitted, the room uses the previous handle or assigns one
1Last Message TimestampIf present, the room sends up to 10 missed messages since this time
2Session TimeoutRequested inactivity timeout in minutes (1 byte)
3PasswordRequired only if the room is password-protected and the user’s public key is not already known

All options are optional. Behavior details:

  • If a last-message timestamp is provided and more than 10 messages have been received since then, only the 10 most recent are sent automatically. Older messages can be retrieved with Fetch Messages.
  • If the room is password-protected but already recognizes the user’s public key, the password is ignored. A room may forget a public key after prolonged inactivity, requiring a password on the next login.
  • First-time logins must include the full 32-byte public key (S flag set).

Logout

Logging out unsubscribes the user from push updates and removes them from the active user list. Previously sent messages remain stored and retrievable by other users up to the history limit.

If the user is currently logged in, the room sends a final text message to all members using the User Left message type (see System Events).

Send Message

To send a message to a chat room, a user sends a standard text message unicast to the room node. The Sender Handle option is ignored — the room fills it in from the sender’s registered handle when distributing the message to members.

The Message Sequence option SHOULD be included, using the sender’s own per-sender message ID counter. The room uses this to detect duplicate submissions and to order rapid messages from the same user. The sender’s per-sender ID is separate from the canonical room-assigned ID that the room assigns when distributing the message.

Fetch Messages

Retrieves previous messages posted to the room, which may include system messages.

FieldSizeDescription
Timestamp4 bytesFetch messages up to and including this time
Max Count1 byteMaximum number of messages to return

Fetch Users

Retrieves the currently active user list, possibly including their public keys.

Admin Commands

TBD.

Message Distribution

When the room receives a message from a user, it assigns a monotonically increasing canonical Message Sequence ID from a single room-wide counter and distributes the message to each logged-in member as a text message. System events (user join/leave, admin messages) are distributed the same way, using room-specific message types. This gives the room a single unified message ordering across all activity — a Regarding option referencing a room message ID is unambiguous without a source prefix (see Regarding).

All timestamps are managed by the room and are relative to its own clock — typically a UTC UNIX timestamp, though accuracy depends on whether the room’s clock is synchronized.

Sender Sequence

When the room echoes a message back to the original sender, it faces a correlation problem: the sender showed the message optimistically in their UI the moment they sent it, but the echoed copy arrives with a room-assigned ID the client has never seen. Without some way to link them, the client cannot reliably identify which pending outbound message the echo corresponds to — matching by content alone fails if the user sends identical messages in quick succession.

To solve this, the room includes a Sender Sequence option on the echo it sends back to the original sender. This option is not included in copies sent to other members.

NumberNameValue
12Timestamp Received4 bytes, UTC UNIX timestamp
13Sender Sequence1 byte — the sender’s original Message Sequence ID

The Sender Sequence value is the per-sender Message Sequence ID the user included in their outbound message. The client matches this against its pending outbound messages to identify the echo, then updates its local record to use the canonical room-assigned ID for future Regarding references.

System Events

The room delivers system notifications as text messages to all logged-in members, using message types reserved for room use:

ValueName
32User Joined
33User Left
34Admin Message

The Sender Handle option is automatically populated by the room for all distributed messages, including system events.

Room Update

Room Update is used exclusively for batch delivery: the history sent on login (via the Last Message Timestamp login option) and the response to Fetch Messages. It contains a list of length-prefixed text messages in chronological order, each carrying the room-injected options defined above (Timestamp Received, and Sender Sequence where applicable). This batching avoids the per-packet overhead of sending history as individual unicast messages on LoRa.

ValueActionDirection
8Room UpdateRoom → User

URI Formats

UMSH defines URI forms for nodes, channels, and CoAP resources.

Node URIs

Nodes are identified by their 32-byte public key encoded in Base58.

Example:

umsh:n:HJC9DJaaQEn88tAzbMM7BrYbsepNEB69RK1gZiKEYCPp

Node identity information may optionally be appended after a colon, encoded in a suitable representation of the identity structure and optional signature.

Example:

umsh:n:HJC9DJaaQEn88tAzbMM7BrYbsepNEB69RK1gZiKEYCPp:Rgx5U993cN52iHc9rPEFPpLTB66o2JLaDvSpCxmhPdReNd3QtrYcyrACdWV89L1xfZPJz4rZGeHX9BypGtDDYJXbDrWKJZixp9A8d3qcDNFq

This allows a node identity bundle to be embedded in a QR code.

Channel URIs

Internally, channels are identified by a 32-byte shared key.

Example direct-key URI:

umsh:ck:5BFn8YGKJ6pZR4qV3tW7mNhDrXsCxEaL9kUv2wAjT8bP

Additional metadata may be attached as URI parameters:

umsh:ck:5BFn8YGKJ6pZR4qV3tW7mNhDrXsCxEaL9kUv2wAjT8bP?n=MyPrivateChannel;mh=6;r=Eugine

Where, for example:

  • n = channel name
  • mh = recommended maximum flood hops
  • r = recommended region

A channel may also be identified by a string from which the channel key is derived:

umsh:cs:Public

CoAP-over-UMSH URIs

CoAP resources on a node use the coap-umsh scheme, with the node public key as the authority component.

Example:

coap-umsh://HJC9DJaaQEn88tAzbMM7BrYbsepNEB69RK1gZiKEYCPp/data/1

Companion Radios

Companion Radio

Note

This section remains partly exploratory, but it now describes the intended architecture more concretely.

A companion radio is a radio device that exposes UMSH capability to another device such as a phone, tablet, laptop, or small computer. The companion radio is not merely a dumb modem, but it is also not normally the primary home of the user’s long-term UMSH identity.

The intended model is:

  • the phone or computer owns the user’s long-term identities
  • the companion radio owns the physical LoRa transceiver and any always-on firmware services
  • the companion radio may also host one or more local radio-owned nodes for device management, maintenance, or shared-site infrastructure use

This differs from systems where the radio itself is the user’s primary mesh identity. In UMSH, the user-facing identity usually lives on the host device, not in the radio.

That separation has important consequences:

  • the companion radio does not normally hold the user’s long-term private key
  • the host device remains the authority for user identity, contacts, and high-level application behavior
  • the radio may still perform some limited actions while disconnected if the host has provisioned the necessary state in advance

Roles

It is useful to distinguish three logical roles that may coexist on one physical companion radio.

1. Radio-Owned Local Node

The companion radio may host a node that belongs to the radio itself. This node exists even when no phone is attached and can be used for:

  • in-band management
  • diagnostics
  • repeater or bridge behavior
  • announcing the presence or capabilities of the radio

By default, such a node need not advertise itself with ordinary beacons.

2. Tethered Host Identities

A phone or computer may attach directly to the companion radio and use it as its radio interface. In this mode, the host’s own UMSH identities remain on the host, but the radio forwards traffic for them and may cache some related state.

3. Bridged or Shared Service

A companion radio may also serve as a shared bridge for one or more nearby devices, much like a repeater or gateway. In this role it may forward traffic without being the primary owner of the identities using it.

These modes are not mutually exclusive. For example, a single radio might:

  • host its own hidden management node
  • act as a user’s tethered personal radio
  • also expose a shared bridged service to other nearby devices

Operating Modes

Tethered

In tethered mode, a host device uses the companion radio almost as though the radio were a local hardware peripheral. This is the most direct mode and is expected to be the common case for phones.

Tethered mode should support:

  • radio configuration
  • raw UMSH frame transmit and receive
  • receive filtering so the host is not woken for irrelevant traffic
  • optional offline assistance when the host disconnects

Bridged

In bridged mode, the companion radio behaves more like an infrastructure service. One or more host devices may submit traffic through it, or it may forward traffic on their behalf subject to local policy.

Bridged mode is useful for:

  • a fixed radio shared by multiple users in one location
  • a site gateway that extends range for nearby devices
  • deployments where the host device is intermittent but the radio remains on

Bridged mode should not be confused with the tethered companion-link protocol described later in this chapter. Tethering is one host talking to its own companion radio over a local control link. Bridging is a separate local access problem in which nearby devices are treated more like peers or clients of the radio itself.

Hybrid Use

A real device may use both modes at once. For example:

  • a phone is tethered for its user’s personal traffic
  • a second device is bridged through the same radio
  • the radio’s own local node remains available for management

The companion-radio protocol therefore must not assume exclusivity.

Security Boundary

The fundamental rule is:

A companion radio must not be provisioned with private keys owned by another device.

In particular, the host device keeps ownership of its own long-term and ephemeral private keys. This keeps the radio from becoming an alternate trust anchor for the user’s identity and reduces the impact of radio compromise, theft, or firmware bugs.

However, the radio may still be provisioned with some additional keying material, depending on what offline behavior is desired.

Material That May Be Provisioned

A host may choose to provision the companion radio with:

  • multicast channel keys
  • pairwise symmetric keys derived for specific peers
  • receive filters tied to specific identities, hints, or packet classes
  • queued outbound traffic awaiting transmission
  • queued inbound traffic awaiting host delivery

Material That Must Not Be Provisioned

The companion-radio protocol must not provide a mechanism for provisioning:

  • any private key owned by the host device

Material That Should Generally Be Avoided

Implementations should also avoid provisioning:

  • broad contact databases unrelated to radio operation

Why Provision Pairwise Keys At All?

If the radio does not have the host’s long-term private key, it cannot perform fresh ECDH on the host’s behalf. That means it cannot derive new pairwise state for previously unknown peers by itself.

Nevertheless, there are useful cases where the host may deliberately preload pairwise symmetric keys for specific already-known peers. Examples include:

  • allowing the radio to recognize and surface urgent messages from known peers
  • sending MAC ACKs on the host node’s behalf while the host is briefly asleep or disconnected
  • enabling simple keyword or alert matching for specific secure conversations

This does not grant the radio the full power of the host’s long-term identity. It only grants limited capability for the specific peers whose pairwise keys were provisioned.

Capabilities

The companion-radio interface should be thought of as four capability groups:

A. Radio Control

The host needs to configure the physical radio link, but this interface should not be LoRa-specific in shape where that can be avoided. Different radios may have different parameter sets.

At minimum, the host should be able to:

  • select the physical transport profile or channel plan
  • configure frequency, bandwidth, spreading factor, coding rate, power, and similar link parameters where applicable
  • query device capabilities and current active configuration
  • observe radio health and diagnostics

B. Frame Data Plane

The host should be able to use the companion radio as a transport for UMSH frames.

At minimum, the interface should provide:

  • transmit of raw complete UMSH frames
  • receive of raw complete UMSH frames
  • transmit result / queued / dropped indications
  • optional RSSI/SNR and similar receive metadata

This keeps the layering clean: the companion-radio link carries UMSH frames, not re-encoded UMSH semantics.

C. Receive Filtering and Wake Policy

A major value of the companion radio is letting the host sleep while the radio stays awake. For that to work, the radio needs filtering capability so it only wakes the host when a frame is relevant.

Useful filters include:

  • destination hint
  • destination full key, if present
  • channel identifier
  • packet type
  • ACK tag
  • “all packets”

It may also be useful to support higher-level policy such as:

  • wake only on packets matching known peers
  • wake only on packets for certain channels
  • wake only on packets that require host attention
  • enqueue packets for later delivery without waking the host immediately

D. Offline Assistance

The companion radio may be asked to do limited work while the host is disconnected.

Examples include:

  • buffering inbound frames until the host reconnects
  • storing outbound frames prepared by the host for later transmission
  • periodically transmitting configured beacons or advertisements
  • matching known-peer secure traffic against simple local rules
  • sending MAC ACKs for pre-provisioned identities and peers

These should remain tightly scoped. The radio is assisting the host, not fully impersonating it in the general case.

Suggested Capability Matrix

The table below summarizes which side should normally own which function.

CapabilityHostCompanion radio
Long-term private identity keyYesNormally no
Fresh pairwise derivation for arbitrary new peersYesNormally no
Raw frame transmit / receiveOptionalYes
Radio parameter controlYesYes
Receive filteringConfigureEnforce
Beacon schedulingConfigureExecute
Channel keysOptionalOptional
Preloaded pairwise keys for known peersOptionalOptional
MAC ACKs for preloaded secure peers while host disconnectedConfigure/policyPossible
Message queueing while host absentConsumePerform

State Synchronization

A companion radio and host will often need to synchronize state incrementally rather than all at once.

Important state classes include:

  • configured local host-owned identities
  • pinned peers
  • auto-learned peers, if the host wants visibility into them
  • channel keys
  • queued inbound/outbound frames
  • beacon schedules
  • alert/filter policy
  • frame-counter reservations, if the radio is allowed to send on behalf of a host-owned identity

This does not mean all such state must be mirrored perfectly at all times. Instead, the interface should let the host be explicit about what authority the radio has been granted.

Low-Power Expectations

A companion radio is especially useful when the host processor should remain asleep most of the time. The architecture should support:

  • the radio remaining awake while the host sleeps
  • filtering and queueing happening on the radio side
  • host wakeup only when a policy match occurs or buffered data crosses a threshold
  • reconnect and drain of queued events without losing radio continuity

This fits well with the broader UMSH design goal that devices should wait on real events rather than spin in polling loops.

This protocol is for the tethered companion-radio use case: one host device talking directly to one companion radio over a local link such as BLE, USB, or UART.

It is not the same thing as treating BLE itself as a local ad-hoc mesh or bridge medium. If a deployment wants nearby devices to discover one another and exchange UMSH frames over BLE as peers, that is a separate bearer problem and should not be conflated with the tethered companion-link protocol described here.

The companion-radio link itself is outside the core UMSH LoRa MAC. However, it should ideally be a single transport-independent protocol that can run over:

  • BLE
  • USB
  • UART / serial
  • TCP or other local transports, if desired

This avoids inventing one protocol for BLE, another for serial, and a third for USB. Instead, the system should define one companion-link framing and message protocol, then adapt that protocol to whatever local transport is available.

This protocol is not intended to solve the bridge or repeater access case for nearby devices. In that case, BLE is not just a cable replacement between a host and its own radio. BLE itself becomes a local bearer over which nearby devices discover the radio, submit frames, receive frames, or otherwise participate in a small local network. That requires a separate bearer design.

The following is a suggested direction, not yet a normative wire standard.

Use a unified framed message protocol in which every host-to-radio or radio-to-host interaction is carried inside one companion-link frame. The frame payload indicates what kind of message it contains, for example:

  • command request
  • command response
  • event notification
  • raw received UMSH frame
  • transmit request for a raw UMSH frame
  • buffered-frame delivery

This keeps the protocol consistent across transports and avoids designing separate “control channels” and “data channels” when the overall medium is already low-speed and latency-tolerant.

Why A Unified Framed Protocol Is Preferable

For companion-radio use, the important problem is not maximizing throughput through parallel logical channels. The more important goals are:

  • one protocol to implement and debug
  • one protocol that can be reused over BLE, USB, and serial
  • simple framing and resynchronization after transport disruption
  • clear sequencing of requests, events, and frame deliveries
  • transport independence

Given the low-speed, high-latency nature of the radio side of the system, a single orderly framed protocol is usually more valuable than splitting control and data into distinct lanes.

Spinel-Like Direction

A good starting point is a protocol that largely mirrors the low-level framing discipline of Spinel while defining a completely UMSH-specific command and object namespace.

The important ideas to preserve are:

  • lightweight binary framing
  • small transaction identifiers
  • support for multiple in-flight host commands
  • state changes communicated by publication of the new authoritative value
  • asynchronous indications using the same general message grammar as synchronous replies

The important idea not to cargo-cult is that everything must be forced into the property model. Properties are for simple state. Commands are verbs. Streams are for event-like or packet-like flows.

This section intentionally defines only the byte-level frame shape and the general semantic categories. It does not attempt to fully specify the final command set.

Inside whatever outer transport framing is used (GATT write/notify payload, L2CAP payload, SLIP/COBS-encoded serial frame, etc.), each logical companion-link frame should have the following structure:

+--------+-------------+-------------------+
| Header | Command/Key | Command arguments |
+--------+-------------+-------------------+
  1 byte   packed uint     zero or more bytes

The first octet is the link header:

  7 6   5 4 3   2 1 0
+-----+-------+-------+
|  P  |  IID  |  TID  |
+-----+-------+-------+

Where:

  • P is a 2-bit protocol-pattern / version field
    • the initial value should be fixed so receivers can quickly reject garbage or incompatible major revisions
  • IID is a 3-bit interface identifier
    • 0 should be the default companion-radio interface
    • other values may later identify additional logical services or vendor extensions
  • TID is a 3-bit transaction identifier
    • 0 is reserved for unsolicited indications and stream traffic
    • 1..7 are host-issued transactions

This preserves the useful “up to seven in-flight host commands” property.

Packed Integer Encoding

Command identifiers, object identifiers, lengths, and similar scalar values should use a compact packed-unsigned-integer encoding in the style of Spinel. This keeps common operations to one or two octets while allowing the namespace to grow later.

The exact packed integer encoding can be finalized later, but the intent is:

  • small numeric IDs occupy one octet
  • larger IDs may spill into subsequent octets
  • receivers can parse the stream incrementally without ambiguity

Fundamental Semantic Categories

The companion-link protocol should distinguish:

  • commands, which are verbs
  • properties, which are simple pieces of state
  • streams, which are event-like or packet-like flows

Commands are not objects. They are operations applied to properties or streams.

The namespace may still need to distinguish at least two kinds of named object:

  • property identifiers
  • stream identifiers

These may share one numeric registry or be separated later, but they must remain semantically distinct.

Property

A property is simple state that is naturally described as “this interface currently has this value.”

Examples:

  • repeater enabled/disabled
  • current RF profile
  • configured wake policy
  • current battery status
  • statistics counters

Properties are appropriate when:

  • the value is queryable
  • the value may change asynchronously
  • the authoritative confirmation of a change is publication of the new value

Properties are not appropriate for queued actions, packet ingress/egress, or multi-phase workflows.

Stream

A stream is an event-like or packet-like flow that is not well modeled as stable state.

Examples:

  • received UMSH frames
  • transmit status events
  • buffered frame delivery
  • diagnostic log records

Streams are generally one-way publications. They may optionally support flow-control or acknowledgement commands, but they are not properties.

Fundamental Command Vocabulary

The starting command vocabulary should be small and generic:

  • Noop
  • Reset
  • Get
  • Set
  • Insert
  • Remove
  • Send
  • Received
  • ValueIs
  • LastStatus

The intended roles are:

  • Get(key)
    • asks for the authoritative value of a property
  • Set(key, value)
    • requests that a property be changed
    • successful completion is normally reported by a matching ValueIs(key, value) indication rather than by inventing a separate “set succeeded” payload shape
  • Insert(key, value)
    • adds one member to a list- or table-like property
  • Remove(key, value-or-selector)
    • removes one member from a list- or table-like property
  • Send(stream, value)
    • sends one item into a stream
    • typical examples include host-to-radio frame submission or host acknowledgement/consumption of buffered stream items
  • Received(stream, value)
    • publishes one item received or emitted on a stream
    • typical examples include radio-to-host UMSH frame delivery, transmit status events, wake events, or log records
  • ValueIs(key, value)
    • publishes the authoritative current value of a property
    • used both for replies to Get/Set/Insert/Remove and for asynchronous change notification
  • LastStatus(code, ...)
    • reports completion status when there is no more specific authoritative publication to send, or when a command fails

If the protocol later needs additional verbs, they should be added explicitly rather than pretending a new class of action is really a property update.

Object Namespace

Properties and streams may share one numeric namespace if desired, but the specification must make their semantic category explicit.

In other words:

  • sharing one encoding space is acceptable
  • pretending every named thing in that space is a property is not

Every standardized object identifier should therefore be documented with:

  • its semantic category: property or stream
  • which verbs are valid for it
  • whether it may emit unsolicited ValueIs or Received indications

Publication Model

For properties, the authoritative rule should be:

  • the result of changing a property is publication of the new value

For example:

Host  -> Set(Prop::RepeaterEnabled, true)
Radio -> ValueIs(Prop::RepeaterEnabled, true)

If the value later changes for some other reason, the same ValueIs form is used again:

Radio -> ValueIs(Prop::RepeaterEnabled, false)

This makes state reconstruction from an observed packet trace straightforward.

Streams And Indications

Stream traffic uses explicit stream verbs rather than property publication.

For example:

Host  -> Send(Stream::UmshFrames, tx-envelope)
Radio -> Received(Stream::TransmitState, queued)
Radio -> Received(Stream::TransmitState, transmitted)
Radio -> Received(Stream::TransmitState, acked)

Or:

Radio -> Received(Stream::UmshFrames, rx-envelope)

Unsolicited indications use TID = 0.

Typical examples:

  • Stream::UmshFrames
  • Stream::TransmitState
  • Stream::BufferedFrameReady
  • Stream::LogRecord

These are not property publications even if they use the same packed integer encoding and frame grammar.

Transactions And Ordering

The host may have up to seven in-flight requests per interface because TID values 1..7 are available concurrently.

The radio should:

  • preserve the TID on direct replies
  • use TID = 0 for unsolicited indications
  • avoid requiring strict global serialization unless a specific command family needs it

This allows pipelining without abandoning observability.

Initial Object Families

A first draft of the UMSH companion-link namespace would likely include at least the following families:

  • protocol identity and capabilities
  • radio configuration and current RF state
  • repeater policy and wake/filter policy
  • buffered inbound/outbound queue state
  • transmit and queue-control streams
  • received-frame and transmit-status streams
  • companion health, battery, and diagnostics

The exact object numbers are intentionally left open for now.

Initial Candidate Properties And Streams

Using the Spinel core specification in /Users/darco/Projects/spinel-spec as a model, the most useful first pass is probably to separate candidate objects into:

  • constant single-value properties
  • mutable single-value properties
  • multi-value or table-like properties
  • stream properties

The table below is intentionally only a starting point. It is meant to make the object surface concrete enough to review, rename, split, or delete.

Candidate objectKindLikely verbsWhy it likely exists
PROP_PROTOCOL_VERSIONProperty, constantGet, ValueIsCompanion-link major/minor version so the host can reject incompatible radios early
PROP_RADIO_VERSIONProperty, constantGet, ValueIsHuman-readable firmware/build identifier for the companion radio
PROP_INTERFACE_TYPEProperty, constantGet, ValueIsIdentifies this as a UMSH companion-radio interface rather than some other service
PROP_CAPSProperty, multi-value constantGet, ValueIsAdvertises supported capabilities, optional features, and available object families
PROP_INTERFACE_COUNTProperty, constantGet, ValueIsNumber of logical interfaces or services exposed by the companion
PROP_LAST_STATUSProperty, read-onlyGet, ValueIsLast command status or reset reason; useful for failures and post-reset synchronization
PROP_POWER_STATEProperty, mutableGet, Set, ValueIsCompanion-radio power mode such as offline, standby, low-power, online
PROP_HOST_ATTACH_STATEProperty, mutable or read-onlyGet, Set?, ValueIsWhether a host session is attached, suspended, draining, or detached
PROP_BATTERY_STATEProperty, read-onlyGet, ValueIsBattery percentage, voltage, charging state, or external-power presence
PROP_DEVICE_HEALTHProperty, read-onlyGet, ValueIsCompact overall health summary for quick status display
PROP_RF_PROFILEProperty, mutableGet, Set, ValueIsSelected RF profile or channel plan name/ID
PROP_RF_REGIONProperty, mutableGet, Set, ValueIsCurrent regulatory region or UMSH region profile
PROP_RF_FREQUENCYProperty, mutableGet, Set, ValueIsActual center frequency when direct tuning is exposed
PROP_RF_BANDWIDTHProperty, mutableGet, Set, ValueIsRadio bandwidth
PROP_RF_SPREADING_FACTORProperty, mutableGet, Set, ValueIsLoRa spreading factor
PROP_RF_CODING_RATEProperty, mutableGet, Set, ValueIsLoRa coding rate
PROP_RF_TX_POWERProperty, mutableGet, Set, ValueIsRadio TX power
PROP_RF_RSSIProperty, read-onlyGet, ValueIsLatest RSSI snapshot if the host wants direct radio diagnostics
PROP_RF_SNRProperty, read-onlyGet, ValueIsLatest SNR snapshot if the host wants direct radio diagnostics
PROP_REPEATER_ENABLEDProperty, mutableGet, Set, ValueIsTurns repeater forwarding behavior on or off
PROP_REPEATER_POLICYProperty, mutableGet, Set, ValueIsEncodes repeater thresholds and policy such as min RSSI/SNR and region restrictions
PROP_STATION_CALLSIGNProperty, mutableGet, Set, ValueIsCallsign used by the radio’s own repeater behavior where required
PROP_WAKE_POLICYProperty, mutableGet, Set, ValueIsHigh-level wake behavior while the host sleeps
PROP_WAKE_REASONProperty, read-only asyncGet, ValueIsMost recent wake cause, with optional unsolicited publication
PROP_RECEIVE_FILTERSProperty, multi-value mutableGet, Set, Insert, Remove, ValueIs, Inserted, RemovedFilter table controlling what wakes the host or gets buffered
PROP_BUFFER_LIMITSProperty, mutableGet, Set, ValueIsQueue capacities, thresholds, or retention policy
PROP_BUFFERED_RX_COUNTProperty, read-onlyGet, ValueIsNumber of buffered inbound items waiting for the host
PROP_BUFFERED_TX_COUNTProperty, read-onlyGet, ValueIsNumber of queued outbound items awaiting transmission
PROP_BUFFERED_RX_POLICYProperty, mutableGet, Set, ValueIsPolicy for retaining and aging buffered inbound items
PROP_INSTALLED_IDENTITIESProperty, multi-value mutableGet, Set, Insert, Remove, ValueIs, Inserted, RemovedHost-provided identity contexts the radio is allowed to assist
PROP_INSTALLED_CHANNEL_KEYSProperty, multi-value mutableGet, Set, Insert, Remove, ValueIs, Inserted, RemovedShared channel keys provisioned to the companion
PROP_INSTALLED_PEER_KEYSProperty, multi-value mutableGet, Set, Insert, Remove, ValueIs, Inserted, RemovedPairwise symmetric peer material provisioned for limited offline assistance
PROP_BEACON_JOBSProperty, multi-value mutableGet, Set, Insert, Remove, ValueIs, Inserted, RemovedPeriodic beacon/advertisement jobs owned by the companion
PROP_STATS_COUNTERSProperty, read-onlyGet, ValueIsPacket/queue/retry counters suitable for UI and diagnostics
PROP_UNSOL_UPDATE_FILTERProperty, multi-value mutableGet, Set, Insert, Remove, ValueIs, Inserted, RemovedFilters which properties are allowed to generate unsolicited ValueIs updates
PROP_UNSOL_UPDATE_LISTProperty, multi-value constantGet, ValueIsLists properties capable of unsolicited publication
STREAM_DEBUG_LOGStream, output-onlyReceivedHuman-readable debug/log output from the companion
STREAM_UMSH_FRAMESStream, input/outputSend, ReceivedCarries raw UMSH frames across the host/radio boundary, with direction-specific envelopes for transmit and receive metadata
STREAM_TRANSMIT_STATUSStream, output-onlyReceivedReports queued, transmitted, forwarded, acked, timed-out, or dropped outcomes
STREAM_BUFFERED_RXStream, output-onlyReceivedDelivers previously buffered inbound frames when the host drains them
STREAM_WAKE_EVENTStream, output-onlyReceivedWake-trigger events such as matching frame, timer, queue threshold, or button press
STREAM_DIAGNOSTIC_EVENTStream, output-onlyReceivedStructured diagnostic/fault events that are not well modeled as properties

UMSH Frame Stream

The most important stream is the raw UMSH frame stream across the host/radio boundary.

This stream is best modeled as a single bidirectional stream rather than as separate “transmit” and “receive” streams.

The stream carries raw UMSH frames together with associated local metadata:

  • Send(STREAM_UMSH_FRAMES, tx-envelope)
    • host to radio
    • requests transmission of one raw UMSH frame
  • Received(STREAM_UMSH_FRAMES, rx-envelope)
    • radio to host
    • reports reception of one raw UMSH frame

The envelope contents are direction-specific:

  • a TX envelope would normally contain:
    • raw UMSH frame bytes
    • any companion-link-local transmit metadata or policy hints
  • an RX envelope would normally contain:
    • raw UMSH frame bytes
    • receive metadata such as RSSI, SNR, timestamp, queue origin, or buffering information

This stream is fundamentally about moving raw UMSH traffic across the host/radio boundary. It is not a separate application protocol.

One practical consequence is that the host can also communicate with the companion radio’s own local UMSH node using ordinary UMSH frames sent over this stream, rather than requiring a separate bespoke message path for such traffic.

Additional Command Candidates

The objects above imply a few likely verbs or verb families beyond the very basic ones already listed:

Candidate commandWhy it may be needed
SendNatural fit for input or bidirectional streams such as STREAM_UMSH_FRAMES
ReceivedNatural fit for output or bidirectional streams such as STREAM_UMSH_FRAMES or STREAM_TRANSMIT_STATUS
Acknowledge or AdvanceLikely useful if buffered stream delivery needs explicit host acknowledgement without overloading Send
ClearMay be clearer than Set(empty) for some queues, logs, or statistics
DescribeMay be useful if the host wants schema-like detail for complex properties or stream item formats

These are only candidates. A stricter design may decide that some of these are unnecessary and can be replaced by better property or stream definitions.

BLE As A Local Bearer

If BLE is used for more than tethering, it should be treated as a separate local bearer concept rather than an extension of the companion-link protocol.

Two broad BLE directions are relevant:

  • connection-oriented tethering, where one host talks directly to one radio over a local link
  • connectionless or mesh-style local participation, where multiple nearby devices can observe, relay, or respond

The first case is what the companion-link protocol in this chapter is about. The second case is a different design problem.

For clarity:

  • tethered companion-link means “my host talks to my radio”
  • BLE local bearer means “nearby devices can discover and use this radio or exchange nearby UMSH-related traffic over BLE”

The first is point-to-point control and framing. The second is local network access.

Plausible BLE Building Blocks

BLE does have modes that are closer to local ad-hoc participation than ordinary GATT tethering:

  • ordinary LE advertising for one-to-many broadcast
  • periodic advertising for scheduled connectionless broadcast
  • Periodic Advertising with Responses (PAwR) for scheduled broadcast with slotted responses
  • Bluetooth Mesh, which defines an advertising bearer and a GATT bearer

These are the main reasons it is reasonable to think BLE could support a small local access or bridge protocol. In particular:

  • ordinary advertising can announce the presence, capabilities, and service class of a nearby radio
  • periodic advertising can provide a more structured broadcast schedule for status or downlink announcements
  • PAwR is notable because it adds scheduled responses, making it one of the clearer BLE building blocks for a low-rate shared local uplink/downlink model
  • Bluetooth Mesh is relevant less as a complete stack to adopt wholesale and more as proof that the Bluetooth ecosystem already recognizes both advertising-bearer and GATT-bearer styles of participation

Practical Payload Size Considerations

Not all BLE bearers are equally suitable for carrying complete UMSH frames.

For the tethered companion-link case, GATT is attractive partly because its payload sizes are large enough to be practical for whole-frame carriage. In BLE, an attribute value may be up to 512 octets, which in practice corresponds to the familiar “ATT MTU up to 517 bytes” figure once ATT overhead is included. That is comfortably in the range needed for a unified framed companion-link protocol.

Advertising-oriented bearers are different. Their payloads are much smaller, and they should therefore be treated as:

  • discovery bearers
  • short-message bearers
  • or fragmented local bearers

rather than assumed to be “GATT, but connectionless.”

As a practical rule of thumb:

BLE modeTypical role for UMSHPayload-size implications
GATTTethered host-to-radio companion linkLarge enough for full companion-link frames and often full UMSH frames without special contortions
L2CAP CoCTethered host-to-radio companion link where availableSimilar role to GATT, often a cleaner framing substrate
LE advertising / scan responseDiscovery, announcements, tiny local messagesSmall; should not be treated as a full-frame bearer without fragmentation
Periodic advertisingScheduled broadcast / downlink-style announcementsStill advertising-scale payloads; better for scheduled broadcast than general frame transport
PAwRScheduled low-rate local access with responsesMore interesting for shared local access, but still a constrained bearer compared with GATT
Bluetooth Mesh bearersSeparate larger design spacePotentially relevant architecturally, but implies adopting a much larger stack and message model

This suggests a clean split:

  • if the goal is host-to-radio tethering, prefer GATT first and L2CAP CoC where available
  • if the goal is nearby-device participation over BLE, assume the bearer is constrained and design for small messages or fragmentation from the outset

These suggest that BLE can support a local bearer for discovery and limited frame exchange. However, this should be specified separately from the tethered companion-radio protocol.

Likely Design Guidance

If UMSH eventually wants BLE-based local participation, the cleaner approach is probably:

  • keep the companion-link protocol for tethered host-to-radio control and frame exchange
  • define a separate BLE local bearer for nearby-device participation
  • ensure both can coexist on the same physical device without sharing message semantics unnecessarily

That BLE local bearer would likely need its own answers for questions such as:

  • how nearby devices discover an available bridge or repeater
  • how access is authorized
  • whether traffic is connectionless, connection-oriented, or mixed
  • whether the bearer only tunnels complete UMSH frames or also exposes local service messages
  • how buffering, fairness, and airtime limits are handled when several nearby clients share one radio

Bluetooth Mesh is particularly notable because the Bluetooth SIG already defines an advertising bearer and a GATT bearer, with Proxy nodes bridging between them. That architecture is conceptually similar to what a UMSH device may eventually want: one mode for direct tethered interaction and another for local many-to-many participation. At the same time, adopting Bluetooth Mesh itself would mean adopting a substantial stack, not just borrowing the bearer idea.

BLE Adaptation Suggestion

If BLE is used, BLE should carry the unified companion-link protocol rather than defining a BLE-specific control protocol.

Why GATT Is Still A Good Baseline

For phones, GATT is the most widely deployable BLE interface today. It works on Android and iOS without requiring unusual privileges or assuming support for less common BLE features.

The simplest BLE mapping is therefore:

  • one custom service
  • one write characteristic from host to radio
  • one notify characteristic from radio to host

Each write or notification carries one or more companion-link frames, subject to the MTU and fragmentation rules of the transport.

Optional L2CAP CoC

Where platform support is available, BLE L2CAP Credit-Based Channels may be a better transport for the same companion-link frames because they reduce GATT overhead and simplify fragmentation. But the protocol riding above should remain the same.

Serial / USB Adaptation Suggestion

For UART or USB CDC serial, the same companion-link frames can be carried over a byte stream using an ordinary framing scheme such as:

  • length-prefixed frames with CRC
  • SLIP-style framing
  • COBS framing

The important part is that the message protocol above remains unchanged. The serial transport should not require a second command language.

Raw Frame Carriage

Messages carrying raw UMSH frames should include:

  • direction (tx request vs rx indication)
  • frame length
  • frame bytes
  • optional metadata for received frames such as RSSI, SNR, and local timestamp

Large frames may need fragmentation at the companion-link transport layer. That fragmentation belongs to the companion-radio link, not to UMSH itself.

Reliability Model

For any transport, a good default is:

  • host-originated requests use TID = 1..7
  • direct replies preserve the request TID
  • unsolicited indications and stream publications use TID = 0
  • buffered stream delivery remains queued until the host explicitly advances or acknowledges it

This keeps the protocol lightweight while still allowing pipelining and post-facto reconstruction of companion-link state.

Whatever transport is used, the companion-radio link should provide:

  • authenticated pairing between host and radio
  • authorization for which host may use which identities
  • replay protection on companion-link control messages
  • explicit policy for whether bridged clients may provision keys or only submit frames

If BLE is used, link-layer encryption and bonding are helpful but should not be treated as the entire security story. The application protocol should still assume that authorization decisions matter.

Open Questions

The following items remain intentionally open:

  • how much queued state the radio should persist durably
  • whether the host should mirror all auto-learned peers or only pinned ones
  • how MAC ACK delegation should be authorized per identity
  • how much application-layer filtering is appropriate before violating layer separation
  • whether bridged clients should be allowed to provision keys or only use pre-provisioned shared services

Summary

A companion radio should be understood as a UMSH radio service with optional delegated capabilities, not as the default owner of the user’s identity. The host keeps authority over long-term identity, while the radio contributes:

  • always-on physical connectivity
  • receive filtering and low-power wake support
  • queued buffering
  • optional narrowly scoped offline assistance

That split preserves UMSH’s cryptographic model while still making small, low-power, phone-connected radios practical.

Security Considerations

This chapter consolidates the security properties, limitations, and implementation guidance that are distributed throughout the specification. It is intended as a reference for implementers and reviewers evaluating UMSH’s security posture.

Threat Model

UMSH is designed for a shared radio medium where any device in range can observe and inject packets. The threat model assumes:

  • Passive eavesdroppers can observe all traffic on the channel, including packet timing, size, hint values, and frame counters.
  • Active attackers can inject, replay, modify, or selectively drop packets.
  • Compromised nodes may leak their long-term private keys, channel keys, or both.

UMSH does not assume a trusted infrastructure, a reliable transport, or a synchronized clock.

What UMSH Protects Against

Eavesdropping. When encryption is enabled, payload content is protected by AES-128-CTR keyed with material derived from ECDH (unicast) or the channel key (multicast). An observer without the relevant key cannot recover plaintext.

Forgery. All authenticated packets carry a MIC computed with AES-CMAC. An attacker who does not possess the encryption and authentication keys cannot produce a valid MIC. The MIC size determines the forgery resistance — from 2^-32 (4-byte MIC) to 2^-128 (16-byte MIC).

Replay attacks. Monotonically increasing frame counters allow receivers to detect and reject replayed packets. The backward window and MIC cache provide tolerance for out-of-order delivery without weakening replay protection.

Nonce misuse. The AES-SIV-inspired construction derives the CTR IV from the MIC, so accidental nonce reuse (e.g., due to a buggy counter implementation) does not produce the catastrophic plaintext leakage that would occur with AES-GCM or raw AES-CTR. In the worst case, an attacker can detect when two packets carry identical plaintext — the keys and other traffic remain uncompromised.

Long-term key compromise (with PFS). If a PFS session was active and the ephemeral keys were properly erased, traffic from that session cannot be retroactively decrypted even if the long-term private keys are later compromised.

What UMSH Does Not Protect Against

Traffic analysis. A passive observer can see packet timing, frequency, size, hint values, frame counters, and flood hop counts — all in the clear. This reveals communication patterns (who is active, how often, rough network topology) even when payloads are encrypted. Hint values are stable for a given identity, enabling long-term tracking of a node’s activity.

Multicast sender impersonation. Multicast authentication is based on the shared channel key. Any node possessing the key can construct a valid packet with any claimed source address. Other channel members cannot cryptographically distinguish the true sender from an impersonator. See Multicast Sender Authentication.

Selective packet dropping. A compromised or malicious repeater can selectively drop packets without detection. UMSH provides no mechanism to verify that a repeater faithfully forwarded a packet. The flood routing model provides redundancy (multiple paths), but a strategically positioned adversary can still disrupt delivery.

Denial of service. An attacker can flood the radio channel with valid-looking packets, forcing receivers to expend computation on cryptographic verification. The 3-byte destination hint reduces this cost (only ~1 in 16,777,216 unicast packets will trigger verification for any given node), but the shared medium provides no isolation. The EMERGENCY channel’s priority forwarding could be abused to amplify DoS traffic, though the signature requirement limits this to attackers who possess a valid Ed25519 keypair.

Bounded extra forwarding via route recovery. The Route Retry option intentionally allows one extra forwarding wave for an already-seen authenticated packet when the sender is recovering from a stale source route. Because the option is dynamic and not MIC-protected, an observer who can copy a packet can also add the option and potentially trigger that extra forwarding attempt. This is a real amplification tradeoff, but it is tightly bounded: the cache key distinguishes only the original packet and the route-retry form, not an unbounded sequence of retries. Implementations should preserve that bound and must not treat arbitrary dynamic-option changes as creating new forwarding identities.

Peer-registry exhaustion by first-contact senders. If an implementation automatically learns peers from inbound full-key packets, an attacker can generate many distinct keypairs and send valid first-contact traffic in an attempt to fill the peer table. If successful, this can crowd out legitimate peers or prevent future first contact. Implementations should distinguish between explicitly configured peers and opportunistically learned peers. Explicit peers should be pinned and must not be displaced by auto-learning. Opportunistically learned peers should be bounded separately or recycled with an eviction policy such as least-recently-seen replacement. Multicast traffic should not require persistent peer registration merely to deliver application traffic in large group-chat scenarios; where sender identity is not already known, implementations may need to fall back to best-effort duplicate suppression rather than strict per-peer replay tracking.

Traffic amplification via broadcast or multicast requests. A broadcast packet is unauthenticated by design, and a multicast packet may be attributable only to a shared channel key or an ephemeral source identity. An attacker can exploit this by sending a request that appears to warrant a response or some other follow-on action from every receiving node. If the request does not include a trace-route option, recipients do not learn a specific return path. Any per-node reply may therefore fall back to flood routing, using the inbound FHOPS_ACC as a distance estimate or flooding more broadly if no better routing state exists. The result is an amplification attack: one injected request can trigger many independent flood-routed responses, consuming airtime and effectively causing a distributed denial of service. Implementations and application protocols must therefore treat broadcast and multicast requests as fan-out hazards. They should not automatically generate per-node responses unless those responses are explicitly designed to avoid amplification through mechanisms such as route learning, strict rate limits, randomized suppression, aggregation, or making the request one-way only.

Non-repudiation. UMSH’s MIC is computed with symmetric pairwise keys that both sender and recipient possess, so a recipient cannot cryptographically prove to a third party who authored a given packet — either party could have constructed it. However, UMSH does not claim to provide deniability. Real-world deniability depends on the entire system: usage patterns, device forensics, metadata, and interactions with other systems. The symmetric MIC is a narrow property, not a deniability guarantee. When the application layer includes an EdDSA signature in the payload (as required by the EMERGENCY channel), even this narrow property is lost — a signature can only be produced by the private key holder.

Forward secrecy without PFS sessions. Normal unicast traffic uses stable pairwise keys derived from long-term ECDH. If a node’s long-term private key is compromised, all past and future unicast traffic with that node can be decrypted. Forward secrecy requires explicit use of PFS sessions.

Anonymous channel membership. Possessing a channel key is both necessary and sufficient for channel membership. There is no mechanism to verify who holds a key, revoke access to a specific node without re-keying the entire channel (except via managed channels), or detect how many members a channel has.

Implementation Requirements

The following requirements are critical for security. Failure to implement any of them correctly can compromise the properties described above.

Frame Counter Monotonicity

The frame counter must strictly increase for each packet sent in a given traffic direction. Reusing a counter value with the same key undermines replay protection and, in the worst case, can leak information about plaintext differences (though the AES-SIV construction limits the damage). See Frame Counters.

Frame Counter Persistence

A node must not reuse frame counter values across reboots. Implementations must either persist the counter to non-volatile storage or advance it by a large margin on startup. If writing to non-volatile storage, care must be taken to avoid wearing out the storage medium. See Counter Persistence and Counter Resynchronization.

Ephemeral Key Erasure

PFS sessions derive their security from the guarantee that ephemeral private keys are erased when the session ends. Implementations must ensure that ephemeral keys are:

  • Never written to persistent storage, swap files, or logs
  • Explicitly zeroed in memory upon session termination (not just freed — freed memory may not be overwritten promptly)
  • Not retained in core dumps or crash reports

Failure to erase ephemeral keys eliminates the forward secrecy property entirely. See Key Erasure.

Constant-Time MIC Verification

MIC comparison must use constant-time comparison (e.g., a fixed-iteration XOR-and-OR loop) rather than memcmp or similar short-circuiting functions. A timing side channel in MIC verification allows an attacker to incrementally guess MIC bytes by measuring response time.

Public Key Validation

Implementations must reject malformed Ed25519 public keys before converting them to X25519 form. Accepting a malformed key can produce a low-order X25519 point, resulting in a shared secret of zero — which would cause all pairwise keys to be identical across different peers. See Ed25519 to X25519 Conversion.

Reserved Bits

Packets with non-zero reserved bits in the Security Control Field must be dropped. Accepting unknown bit patterns could indicate a protocol version mismatch or a malformed packet; processing them risks undefined behavior.

Metadata Exposure

Even with encryption enabled, the following information is visible to a passive observer. Which fields are present depends on the packet type:

FieldPacket typesWhat it reveals
Packet timing and frequencyAllCommunication patterns — when a node is active, how often it transmits
Destination hint (3 bytes)UnicastStable per-identity; enables tracking a node’s correspondents over time
Source hint (3 bytes)Unicast, unencrypted multicast, broadcastStable per-identity; enables tracking a node’s activity over time
Channel identifier (2 bytes)Multicast, blind unicastStable per-channel; reveals which channel a packet belongs to
Frame counterAll authenticatedMonotonically increasing; reveals total packet count and transmission rate
Flood hop countAll with FHOPSReveals approximate distance from the original sender
Packet sizeAllMay correlate with payload type or content length
MICAll authenticatedUnique per-packet; usable as a packet fingerprint for correlation across hops

In encrypted multicast, the source address is encrypted inside the ciphertext. In blind unicast, both the source and destination addresses are encrypted using the channel key — only the channel identifier remains in the clear. Normal unicast exposes both the destination hint and source hint (or full source key) to passive observers.

Frame Counter Correlation and PFS

If a device uses a single monotonic frame counter across all traffic (including PFS sessions), an observer can correlate PFS session traffic with the device’s long-term identity by observing counter continuity. Implementations concerned with PFS unlinkability should consider using independent frame counters for PFS sessions. See Wire-Level Privacy.

Hint Stability and Tracking

Because hints are derived deterministically from public keys, they remain stable for the lifetime of a node identity. An observer who associates a hint with a physical location or person can track that identity across sessions, power cycles, and network changes. The only countermeasure is generating a new identity (a new Ed25519 keypair), which requires all peers to re-learn the new public key.

Cryptographic Design Rationale

AES-SIV over AES-GCM

UMSH uses an AES-SIV-inspired construction rather than AES-GCM. AES-GCM is catastrophically vulnerable to nonce reuse: a single repeated nonce leaks the authentication key and allows forgery of arbitrary messages. On a mesh network where counter management is distributed across many independent nodes and persistence across reboots is not guaranteed, nonce reuse is a realistic failure mode. The AES-SIV construction degrades gracefully — nonce reuse reveals only whether two plaintexts are identical, without compromising keys or enabling forgery. See the FAQ.

Stable Keys over Ratcheting

UMSH uses stable pairwise keys rather than a ratcheting protocol. Ratcheting provides forward secrecy per-message but requires synchronized state between sender and receiver. On a lossy, high-latency mesh where packets are routinely dropped, duplicated, or delivered out of order, ratchet state can desynchronize — potentially requiring expensive resynchronization exchanges over a slow radio link. UMSH’s stable keys combined with per-packet counter and salt inputs provide per-packet IV uniqueness without requiring synchronized state. Optional PFS sessions provide forward secrecy when needed, without imposing ratcheting’s fragility on all traffic. See the FAQ.

Single Keypair for Signing and Key Agreement

UMSH uses a single Ed25519 keypair per node for both identity (signing) and key agreement (via X25519 conversion). Standard guidance recommends separate keys, but the alternative would require distributing an additional 32-byte X25519 public key per identity and cryptographically binding it to the Ed25519 key. On a ~255-byte LoRa frame, this overhead is significant. The Ed25519/X25519 conversion is a well-understood, deterministic mapping over birationally equivalent curves, used by Signal’s X3DH and libsodium. See Ed25519 to X25519 Conversion.

Channel-Specific Considerations

Named Channel Security

Named channels derive their key from a human-readable name via HKDF-Extract. Anyone who knows (or guesses) the name can derive the key. Named channels should be treated as public — they provide a shared namespace, not confidentiality. Long, high-entropy names offer practical obscurity but should not be relied upon for security.

Emergency Channel Integrity

The EMERGENCY channel requires unencrypted transmission, full source key (S=1), and an EdDSA payload signature. These requirements ensure that emergency traffic is universally readable and cryptographically attributable. However, an attacker with a valid Ed25519 keypair can still send fraudulent emergency messages — the signature proves only that the sender possesses the key, not that the emergency is real. Social and operational controls (e.g., reputation, identity verification) are needed to complement the cryptographic guarantees.

Blind Unicast Key Binding

Blind unicast payload keys are derived by XORing the pairwise unicast keys with the channel’s multicast keys. This ensures that decrypting a blind unicast payload requires both the pairwise shared secret and the channel key. Compromise of one without the other is insufficient.

Amateur Radio Operation

UMSH supports three distinct operating modes for devices or repeaters deployed on spectrum where amateur operation and unlicensed operation may coexist.

Operating Modes

Unlicensed

In Unlicensed mode, the node operates only under non-amateur rules.

  • Locally originated packets are treated as unlicensed traffic.
  • Encryption and blind unicast are allowed.
  • A repeater may forward any packet it lawfully may retransmit under unlicensed rules.
  • Maximum transmit power and duty cycle are determined by local rules for unlicensed operation.
  • If a forwarded packet carries a station callsign, the repeater removes it rather than replacing it.
  • The repeater must not add its own station callsign.

The specific requirements for unlicensed transmission vary by jurisdiction and frequency, but may include restrictions on transmit power, antenna gain, and/or duty cycle.

Licensed-Only

In Licensed-Only mode, all locally originated and forwarded traffic is treated as amateur-radio traffic.

  • Encryption is forbidden. All encrypted packets encountered must be immediately dropped.
  • Locally originated packets must include an operator callsign.
  • Restrictions on transmit power and duty cycle are generally more relaxed.
  • A repeater forwards only packets that already carry an operator callsign.
  • A repeater replaces or inserts the station callsign option with its own callsign on every forwarded packet.

Note

Blind unicast is not categorically forbidden by this mode, but the expected utility of using it without encryption is limited.

Hybrid

In Hybrid mode, the node may operate under either authority depending on the packet.

  • A repeater always adds or replaces the station callsign option on forwarded packets.
  • Packets carrying an operator callsign may be forwarded under amateur-radio authority.
  • Packets lacking an operator callsign may still be forwarded, but only when the retransmission can lawfully occur under unlicensed rules.
  • If encryption is enabled, the transmission must be treated as unlicensed traffic, including using power and any other regulatory limits appropriate for unlicensed operation.

Hybrid mode is useful where amateur stations may use higher power for qualifying amateur traffic, while still allowing encrypted or otherwise unlicensed-only traffic to transit the same repeater at unlicensed settings.

Locally Originated Packets

The MAC layer should apply the following transmit rules:

  • Unlicensed: no amateur-specific restriction is implied, but restrictions on tx power and duty cycle may apply.
  • Licensed-Only: encrypted packets must be rejected, and an operator callsign is required. Max transmit power may increase.
  • Hybrid: encrypted packets are allowed, but they must be transmitted under unlicensed constraints rather than amateur-only ones.

Limitations & Open Items

Known Limitations

No MAC-Layer Fragmentation

UMSH intentionally does not define a fragmentation mechanism at the MAC layer. The MAC layer delegates fragmentation to higher-layer protocols carried in the payload (see Layer Separation). LoRa payloads are typically limited to approximately 200–250 bytes, and UMSH header overhead (FCF, addresses, SECINFO, MIC) consumes a significant portion of this budget. Higher-layer protocols that require payloads larger than a single frame must provide their own segmentation — for example, CoAP block-wise transfer or 6LoWPAN fragmentation.

Multicast Sender Authentication

Multicast channels use a shared symmetric key. Any node possessing the channel key can send packets with any claimed source address, and other channel members cannot cryptographically verify that the claimed sender actually produced the packet. When the S flag is set, the source public key is carried in the packet and can be used for application-level trust decisions, but the protocol-level MIC authenticates only channel membership, not individual sender identity.

This is a fundamental property of symmetric-key multicast and is shared by other protocols with similar designs, including MeshCore.

Known Hint Collision Properties

MeshCore originally used 1-byte hints for source, destination, and source-routing addresses, placing the birthday bound at just 16 nodes — far too low for practical networks. UMSH uses 3-byte hints for node addresses and 2-byte hints for router and trace-route addresses.

As a concrete example, consider a regional network of approximately 600 active nodes (roughly the scale of the Oregon MeshCore network, concentrated in the Portland area). The probability of at least one collision among all nodes for a given hint size:

Hint sizeCollision probability (600 nodes)
1 byte (256 values)~100%
2 bytes (65,536 values)~94%
3 bytes (16,777,216 values)~1%

Node hints (3 bytes)

The destination hint is a prefilter: a match causes the receiver to attempt full cryptographic verification. A false positive wastes computation on every packet exchanged between the two colliding nodes, for the lifetime of both identities. The cost is persistent and proportional to traffic volume. The source hint is used for source identification, traffic attribution, and diagnostics.

With 3-byte hints the collision probability drops to ~1% even in a 600-node regional network. The only remedy for a collision is for one node to generate a new identity (a new Ed25519 keypair), which for a chat node means all peers must re-learn the new public key. The 3-byte size makes this scenario rare.

Router hints (2 bytes)

Router hints are used in source-route and trace-route options. A router hint collision causes an unintended repeater to forward the packet; MIC-based duplicate suppression ensures each repeater forwards a given packet at most once, so collisions add traffic but not loops or incorrect delivery.

Source routing is an inherently local operation — only repeaters within radio range of the transmitting node can act on the hint. For a local population of ~50 repeaters:

  • 1-byte hints: ~46% collision probability
  • 2-byte hints: ~1.9% collision probability

2-byte router hints reduce the collision probability by roughly 24× relative to 1-byte hints for typical deployments, at a cost of 1 extra byte per hop in source-route and trace-route options.

Open Issues

Bridge Hop Confirmation

A bridge is a node that relays UMSH packets over a different medium or channel than the one it received them on — for example, an internet backhaul, a wired link, or a different radio band connecting two geographically distant segments. Bridges are transparent to the protocol at the MAC layer: they consume source-route hints and forward packets exactly as repeaters do.

The simplest approach to bridge confirmation is to have the bridge retransmit the packet on the same inbound medium in addition to forwarding it to the other medium. This fully preserves the existing implicit confirmation mechanism with no protocol changes — the previous-hop sender hears the retransmission and confirms delivery exactly as it would with a normal repeater. The cost is doubled on-air time for every bridged packet on the inbound segment.

Retransmitting the entire packet solely to signal receipt is wasteful. However, if the bridge does not retransmit, the previous-hop node cannot observe the bridge’s onward transmission and will assume delivery failed — triggering retries that are even more wasteful, since the bridge did receive the packet successfully.

To be honest, it isn’t entirely clear that this is a problem worth optimizing. Bridges aren’t expected to exactly be common. But it is worth thinking about, so here is a possible solution:

Possibility: Hop Signal for non-retransmitting bridges

A Hop Signal is a local-only BCST (no FHOPS field, so it is never forwarded) emitted by the bridge on its inbound medium immediately after handling a packet. The BCST carries a MIC reference to the original packet for correlation, a signal type (Hop Ack or Hop Nak), and the bridge’s own 3-byte SRC hint for identification. It is smaller than a full retransmission and can also convey failure (Hop Nak) rather than just presence.

Because only one packet type slot (value 5) remains reserved, a Hop Signal would be defined as a MAC option on BCST rather than a dedicated packet type, preserving the reserved slot for a future use case with stronger architectural justification.

Hop signals would be informational only. A forged Hop Ack is equivalent to silent dropping — already in the threat model — so senders must still fall back to full MAC ack timeout if no Hop Ack arrives. The format of the Hop Signal option and the complete emission rules have not yet been defined.

Intermediate Node Error Feedback

Problem

When a packet cannot be delivered — for example, because a bridge’s backhaul link is down, or because a source-routed path is broken — intermediate nodes have no reliable way to inform the original sender. The sender can only detect failure by waiting for a MAC ack that never arrives.

This timeout-based detection is slow and provides no diagnostic information: the sender cannot distinguish a slow destination from a broken path.

Two independent gaps make this hard to address:

  • Routing: an intermediate node needs a return path to send anything back. The sender’s 3-byte SRC hint provides a destination address, but that alone is not enough — the error packet needs to know how to get there. Flood routing is not an option: flooding an error response across the mesh in response to a delivery failure would be prohibitively expensive. A return path is only available if the original packet carried a trace route option, whose accumulated hops already describe the return path from the receiver back toward the original sender.

  • Authentication: an intermediate node cannot send an authenticated reply without the sender’s full public key. Any error reply sent without it is unencrypted and unauthenticated. Only the final destination — which has the full source key and performs ECDH — can send a fully authenticated reply.

Without a trace route, there is no viable return path and no error feedback is possible.

Possible Approach: Trace-Route Return Path

If the original packet carries a trace route option, an intermediate node can use the accumulated hops directly as a source route back toward the original sender and emit an error packet along that path, addressed to the sender’s 3-byte SRC hint.

This is opt-in by the sender: include a trace route to signal willingness to receive error feedback; omit it to suppress errors. No special flag or option is needed. If no trace route is present, the intermediate node has no viable return path and should remain silent.

The on-wire format for such an error packet would likely be similar or identical to the Hop Signal mechanism described above — a compact notification carrying a signal type and a MIC reference — differing only in that it carries a source route and travels end-to-end rather than remaining local. Defining a single format that covers both cases would reduce protocol surface area.

Any such error is unencrypted and unauthenticated. Senders MUST treat it as untrusted diagnostic information only — a forged error is equivalent in effect to a dropped packet, which is already in the threat model.

This remains an open design question. No mechanism is specified in the current version of this protocol. The format and semantics of error reports — error codes, triggering conditions, encoding — have not yet been defined.

FAQ

Can an attacker spoof a MAC Ack to make the sender believe a packet was delivered?

No. A MAC Ack contains an ack tag — an 8-byte value derived by encrypting the full 16-byte CMAC with K_enc. Computing a valid ack tag requires knowledge of the encryption key (pairwise for unicast, or the combined blind unicast key for blind unicast). A passive observer who intercepts the original packet can read the on-wire MIC, but cannot derive the ack tag from it without K_enc. Ack forgery is therefore as hard as breaking the underlying key agreement.

Doesn’t blind unicast have a circular dependency between the MIC and address decryption?

No. The MIC field is located at the end of the packet and can be read directly from the wire. It is computed using the blind unicast payload keys, which combine the pairwise shared secret with the channel key. The receiver reads the MIC, uses it (together with the channel’s K_enc_channel) as the IV to decrypt ENC_DST_SRC, and then derives the pairwise keys from the recovered source address. The pairwise keys are XORed with the channel keys to produce the blind unicast payload keys, which are used to authenticate and decrypt ENC_PAYLOAD. If either address has been tampered with, the derived pairwise keys will be wrong and payload authentication will fail. There is no circular dependency — only a specific processing order (see Blind Unicast).

Can source-routed packets loop if router hints collide?

No, for two reasons. First, the forwarding path is bounded by the number of router hints in the source route plus the flood hop count — a packet cannot be forwarded more times than the sum of these values. Second, duplicate suppression (see Duplicate Suppression) ensures that each repeater forwards a given packet at most once (identified by MIC). Even if a router hint collision causes an unintended repeater to forward the packet, the probability of subsequent hints also colliding with nearby repeaters drops dramatically at each hop, making extended misrouting extremely unlikely.

What happens when a cached source route goes stale?

If an ack-requested packet sent on a cached source route exhausts its retry budget, the sender should treat that route as failed and return temporarily to route-discovery mode. The recommended recovery is:

  • discard or demote the stale route
  • re-attempt the same logical packet
  • remove the stale source route
  • add or refresh flood hops
  • include a trace-route option so a fresh path can be learned
  • set the Route Retry option

The key point is that this is still the same logical packet, not a new application message. The destination therefore accepts it at most once according to the normal replay rules, while repeaters treat the Route Retry form as a distinct forwarding opportunity for duplicate-suppression purposes.

Why doesn’t UMSH define a dedicated path-discovery packet type?

The existing primitives are sufficient. A node can discover a path by sending a flooded packet (broadcast, unicast, or beacon) with the trace-route option present. Repeaters prepend their router hints as they forward. The recipient can use the accumulated trace directly as a candidate source route. This avoids adding protocol complexity for a function that composes naturally from existing features. See Path Discovery for the full procedure.

How does UMSH handle frame counter overflow?

The 4-byte frame counter wraps naturally at 2^32. Replay detection uses modular arithmetic: delta = (received - last_accepted) mod 2^32. A positive delta within a reasonable forward window is accepted; zero or excessively large deltas are rejected. This means overflow is not a special case — it is handled identically to any other counter increment. See Replay Detection.

Can a multicast channel member impersonate another member?

Yes. Multicast authentication is based on the shared channel key, not on individual sender identity. Any node with the channel key can construct a valid packet with any claimed source address. This is an inherent property of symmetric-key multicast and is shared by other protocols with similar designs. See Multicast Sender Authentication.

This does not apply to blind unicast. Blind unicast payloads are authenticated using combined keys that require both the pairwise shared secret and the channel key, so only the true sender can produce a valid payload and only the intended recipient can read it.

When should the S flag (full source address) be set?

The S flag controls whether the full 32-byte source public key or a compact source hint is included in the packet. Set S when:

  • This is a first-contact transmission and the receiver has never seen the sender’s public key before.
  • The sender wants to allow any receiver to perform ECDH and authenticate the packet without prior state.
  • The sender is using an ephemeral keypair (anonymous request pattern).

Leave S clear when the receiver is known to have the sender’s full public key cached — for example, after a prior advertisement, identity exchange, or any earlier S=1 packet. Using the compact hint saves 29 bytes per packet in unicast (3-byte hint vs 32-byte key), which is significant on LoRa.

Receivers that see an unknown source hint on an authenticated packet should treat it as an authentication failure (the cached key lookup fails, so decryption or CMAC verification will fail). The sender can retransmit with S=1 to provide the full key.

How does a MAC Ack get routed back to the original sender?

MAC acks are end-to-end: the final destination generates the ack, not any intermediate repeater. The ack is routed back to the original sender using whatever routing state the destination has learned — typically a source route derived from the inbound packet’s trace route, or a flood scoped by FHOPS_ACC. This is the same route learning mechanism used for all communication, not an ack-specific feature.

Repeaters do not generate acks themselves. Instead, a repeater can confirm successful forwarding by overhearing the next hop’s retransmission of the same packet (see Forwarding Confirmation).

Why does UMSH use stable pairwise keys instead of a ratcheting scheme like the Signal Protocol?

LoRa mesh networks have high latency, low bandwidth, and unreliable delivery — properties that are hostile to ratcheting protocols. Ratcheting requires reliable in-order message delivery to keep both sides synchronized; a single lost message can desynchronize the ratchet and require an expensive recovery handshake. In a mesh where packets may be lost, duplicated, or arrive out of order, this would lead to frequent resynchronization storms. Stable pairwise keys derived from a single ECDH are simple, stateless, and robust to packet loss. The frame counter and optional salt still provide per-packet uniqueness, and the AES-SIV-inspired construction provides nonce-misuse resistance as an additional safety margin.

When forward secrecy is needed, UMSH provides PFS sessions — a two-message handshake where both nodes exchange ephemeral node addresses and communicate using session-specific keys for an agreed duration. PFS sessions add no per-packet overhead once established, and the private keys for the ephemeral addresses are erased when the session ends. This provides perfect forward secrecy without the fragility of continuous ratcheting.

What happens if a 2-byte channel identifier collides across different channel keys?

The 2-byte channel identifier is a hint, not a unique identifier. If two different channel keys happen to produce the same 2-byte channel ID, a receiver configured with both keys will attempt to process the packet with each candidate key. Only the correct key will produce a valid MIC, so the wrong candidate will be rejected during authentication. The cost is wasted computation, not incorrect behavior. With 2 bytes the collision probability is 1 in 65536, which is higher than a 4-byte hint but still negligible for deployments with a small number of configured channels.

Why use an AES-SIV-inspired construction instead of AES-GCM?

AES-GCM is catastrophically vulnerable to nonce reuse — repeating a nonce with the same key completely breaks both confidentiality and authenticity. In a mesh network, nonce management is difficult: nodes may reboot and lose counter state, clocks may not be synchronized, and packets may be retransmitted. The SIV-style construction used by UMSH is nonce-misuse-resistant: even if a nonce is accidentally reused, the only consequence is that an observer can detect that two plaintexts are identical. Confidentiality and authenticity are otherwise preserved. This robustness is worth the minor overhead of computing the MIC before encryption.

How does “deliver to a region, then flood” work?

A sender can include both a source-route option and a flood hop count in the same packet. The source-route directs the packet through specific repeaters, and as each repeater forwards, it removes its own hint. Once all source-route hints are consumed, the packet transitions to flood-based forwarding bounded by FHOPS_REM. This allows targeted delivery to a specific area of the mesh followed by a local flood — useful when searching for a node in a known geographic region without flooding the entire network. See Routing Implications.

Can UMSH support anonymous requests, similar to MeshCore’s ANON_REQ mechanism?

Yes. A node can generate an ephemeral Ed25519 keypair, set the S flag, and use the ephemeral public key as the source address for a single request, then discard the private key immediately afterward. The recipient performs ECDH with the ephemeral public key as normal, encrypts a response to it, and sends it back. The requester’s long-term identity is never revealed. This pattern also provides forward secrecy for the exchange: once the ephemeral private key is discarded, the session cannot be decrypted even if the requester’s long-term key is later compromised. No dedicated packet type is required.

Does UMSH support automatic route learning?

Yes. A node that wants to learn a source route to a peer sends any flooded packet (unicast, broadcast, or beacon) with the trace-route option present. Repeaters prepend their router hint as they forward. When the peer receives the packet, the trace-route option contains the accumulated path, ordered nearest-repeater-first, and can be used directly as a source-route option on reply packets. Both sides can learn routes simultaneously by including the trace-route option on their outbound packets and caching the results. See Path Discovery for the full path-discovery procedure.

Comparison with MeshCore

This section compares UMSH with MeshCore, a LoRa mesh protocol with similar goals. The comparison is based on MeshCore firmware v1.12.0 and its primary source code and documentation.

Note

This comparison aims to be as fair and accurate as possible, not promotional material. If you spot any unfair comparisons, factual errors, or other mistakes, please file an issue!

Identity and Addressing

Both protocols use Ed25519 public keys as node identities and perform X25519 ECDH for pairwise key agreement.

AspectUMSHMeshCore
Identity key32-byte Ed25519 public key32-byte Ed25519 public key
Source address in packets3-byte hint (S=0), or full 32-byte key (S=1)1-byte hash (first byte of public key)
Destination address3-byte hint1-byte hash
Channel identifier2-byte derived hint1-byte hash of SHA-256 of channel key

UMSH uses 3-byte hints for node addresses and 2-byte hints for router and trace-route addresses, giving 1-in-16,777,216 collision resistance on node identifiers. An explicit S flag includes the full 32-byte source key when needed (first contact, ephemeral keys). MeshCore uses 1-byte hashes for all regular addressing, with a dedicated ANON_REQ packet type that carries the full 32-byte sender public key for first-contact or anonymous exchanges. The tradeoff is that MeshCore saves bytes per address field in the common case, but requires a special packet type for any situation where the full key must be transmitted.

Packet Structure

AspectUMSHMeshCore
Header1-byte FCF with version, type, flags1-byte header with version, type, route mode
Packet types8 (via 3-bit field in FCF)16 payload types (via 4-bit field)
Routing infoCoAP-style options (source route, trace route, region, RSSI/SNR thresholds)Path field (up to 64 bytes), transport codes
Flood hop countSplit 4-bit FHOPS field (max 15)Implicit via path length
Region supportOptional region code optionTransport codes (2 × 16-bit)

UMSH separates routing metadata into composable options, allowing packets to carry source routes, trace routes, signal-quality thresholds, and region codes independently. MeshCore uses a simpler flat structure with a path field and route-type bits.

Cryptography

AspectUMSHMeshCore
Encryption algorithmAES-128-CTR (SIV-style: MIC used as CTR IV)AES-128-ECB
AuthenticationAES-CMAC (4/8/12/16-byte MIC)HMAC-SHA256 (truncated to 2-byte MAC)
Key derivationHKDF-SHA256 with domain-separated keys (K_enc, K_mic)Raw ECDH shared secret used directly
Key separationSeparate 16-byte encryption and 16-byte MIC keysSame shared secret for both AES key (first 16 bytes) and HMAC key (full 32 bytes)
Nonce misuse resistanceYes (SIV construction)N/A (ECB mode is deterministic)
Replay protection4-byte monotonic frame counter (timestamp-free)Hash-based duplicate cache (128 entries); timestamps at application layer

The cryptographic gap is substantial:

  • AES-128-ECB is a textbook-insecure mode: it uses no IV or nonce, and identical plaintext blocks produce identical ciphertext blocks, leaking structural information about the payload. AES-128-CTR with a synthetic IV (as used by UMSH) does not have this weakness.

  • 2-byte MAC truncation in MeshCore means an attacker has a 1-in-65536 chance of forging a valid MAC per attempt, which is marginal for a protocol where an attacker can observe and replay packets at will. UMSH’s 16-byte MIC provides a forgery probability of 2^-128.

  • No key separation in MeshCore means the same bytes of the ECDH shared secret serve as both the AES key and the beginning of the HMAC key. UMSH derives independent keys via HKDF with domain-specific labels, which is the standard practice for preventing cross-protocol or cross-purpose key reuse.

  • MAC verification timing: MeshCore’s MACThenDecrypt function uses memcmp to compare HMAC values, which is not constant-time and introduces a timing side channel. This is primarily a concern in contexts where an attacker can measure verification timing with sufficient precision.

Routing

AspectUMSHMeshCore
Flood routingYes, bounded by flood hop countYes (ROUTE_TYPE_FLOOD)
Direct/source routingYes, via source-route optionYes (ROUTE_TYPE_DIRECT)
Hybrid routingSource route + flood hop count in same packetNot supported
Path discoveryTrace-route option on any flooded packetDedicated PATH payload type
Route learningTrace-route option accumulates hints during flooding; reversed into source route by recipientExplicit returned-path messages
Forwarding confirmationYes (retries with backoff)Not defined
Channel accessCAD with random backoff; SNR-based contention windowsListen-before-talk with random backoff; SNR-based flood retransmit delay
Signal-quality filteringMin RSSI and min SNR optionsSNR-based retransmit prioritization (implicit, no explicit thresholds)
Region-scoped floodingRegion code optionTransport codes

UMSH’s hybrid routing model allows a single packet to be source-routed to a specific area and then flood locally, which is useful for reaching a node in a known geographic region without flooding the entire mesh. MeshCore treats flood and direct routing as mutually exclusive modes selected by route-type bits.

Both protocols support automatic route learning, but through different mechanisms. UMSH uses a trace-route option that accumulates router hints as a packet floods; the recipient reverses the accumulated trace and caches it as a source route for all subsequent communication with the sender — replies, acknowledgments, and new messages alike (see Route Learning). MeshCore uses a dedicated returned-path message type.

Both protocols define channel access mechanisms. MeshCore checks for preamble or signal detection before transmitting and defers with a randomized backoff (120–360 ms) if the channel is busy, with a forced-transmit safety valve after 4 seconds. Flood retransmissions use a random delay proportional to airtime and a score-based priority derived from received SNR. UMSH uses CAD with random backoff and SNR-based contention windows for collision avoidance. UMSH additionally defines hop-by-hop forwarding confirmation with retries, providing reliability across the forwarding chain that MeshCore does not offer.

Privacy and Blind Modes

AspectUMSHMeshCore
Multicast source concealmentYes (source encrypted inside ciphertext when encryption enabled)No
Blind unicastYes (source encrypted with channel key, payload with pairwise key)No
Anonymous requestsEphemeral Ed25519 key with S=1 flagDedicated ANON_REQ packet type
Metadata concealmentChannel-key-based, hides sender and/or destination from non-membersNot supported

UMSH provides protocol-level privacy features that conceal sender and destination information from observers who do not possess the relevant channel key. Encrypted multicast conceals the source address, and blind unicast conceals both sender and destination. MeshCore does not define equivalent privacy modes.

Both protocols support anonymous first-contact requests, but through different mechanisms. UMSH uses an ephemeral keypair as the source address with the S flag set — no dedicated packet type is needed. MeshCore defines a specific ANON_REQ payload type that carries the full 32-byte sender public key.

Multicast

AspectUMSHMeshCore
Channel key size32 bytesVariable (shared secret)
Channel identifier2-byte derived hint1-byte hash of SHA-256 of key
Group message authChannel-key-based CMACChannel-key-based HMAC (2-byte MAC)
Sender authenticationNot cryptographically verified (symmetric key limitation)Not cryptographically verified (same limitation)
Source privacySource encrypted when encryption enabledNo

Both protocols share the fundamental limitation that symmetric-key multicast cannot authenticate individual senders — any channel member can forge a packet with any claimed source address.

Application Layer

AspectUMSHMeshCore
Payload typing1-byte payload type prefix4-bit payload type in header
Structured dataCoAP-over-UMSH (block-wise transfer)Multipart packets
Node identityIdentity payload with role, capabilities, name, options, optional EdDSA signatureAdvertisement payload with public key, timestamp, EdDSA signature, appdata
URI schemeumsh:n:, umsh:ck:, umsh:cs:, coap-umsh://meshcore:// (contacts and channels)
Amateur radioOperator/station callsign options, explicit unencrypted modeNot defined

UMSH’s payload types identify which higher-layer protocol is carried inside the payload — whether UMSH-defined (text messages, chat rooms, node identity) or third-party (CoAP, 6LoWPAN). The MAC layer treats all payloads identically. MeshCore’s payload types define application-level semantics directly at the protocol level, without a clean separation between MAC and application concerns. UMSH defines a CoAP-over-UMSH transport (payload type 7) that inherits CoAP’s block-wise transfer for payloads larger than a single LoRa frame. MeshCore defines a multipart packet type for segmented transfers at the protocol level.

Layer Separation

AspectUMSHMeshCore
Protocol scopeMAC layer with cleanly separated application protocolsCombined MAC, network, and application layer
Payload interpretationOpaque at MAC layer — application protocols defined separatelyProtocol defines payload types with application semantics (text messages, advertisements, login, etc.)
FragmentationDelegated to higher-layer protocols in the payloadMultipart packet type defined at protocol level
Node identity / advertisementsApplication-layer payload (see Node Identity)Protocol-level advertisement packet with mandatory fields
Time dependencyTimestamp-free — monotonic frame counters for replay protection (see Frame Counter)Hash-based duplicate cache at MAC layer; relies on UNIX timestamps for advertisement freshness and login sequencing

UMSH maintains a clean boundary between the MAC layer and higher-layer protocols. The MAC layer defines framing, addressing, encryption, authentication, and forwarding, and treats payload content as opaque. UMSH also defines its own application-layer protocols (text messaging, chat rooms, node identity, node management), but these are architecturally separate from the MAC layer and carried in the payload alongside any other higher-layer protocol.

MeshCore takes a more vertically integrated approach: the protocol directly defines payload types for text messages, node advertisements, login sequences, and multipart transfers without a clear separation between MAC and application concerns.

Timestamps and Time Dependency

MeshCore relies on UNIX timestamps in several protocol-critical roles:

  • Replay protection: MeshCore uses a fixed-size circular buffer of packet hashes (128 entries) for short-term duplicate detection. Once the buffer wraps, previously seen packets can no longer be detected as duplicates. Application-layer timestamps provide additional protection for some message types, but there is no MAC-layer replay protection counter.
  • Advertisement freshness: Node advertisements carry a timestamp used to determine which advertisement is most recent.
  • Login sequencing: The login handshake incorporates timestamps.

UMSH is entirely timestamp-free at the MAC layer. Replay protection is based on monotonic 4-byte frame counters (see Frame Counter), which require no clock synchronization and no access to absolute time. Higher-layer payloads (such as the node identity payload in Node Identity) may optionally carry timestamps for application-level purposes, but the MAC layer neither requires nor interprets them.

UMSH’s monotonic frame counter provides cryptographic replay protection that does not depend on clock accuracy and does not degrade as traffic volume increases. MeshCore’s hash-based duplicate cache provides short-term deduplication but has a fixed capacity — in a busy mesh, the 128-entry buffer can wrap quickly, allowing replayed packets to be accepted after the original entry is evicted. MeshCore’s reliance on timestamps for advertisement freshness and login sequencing additionally requires nodes to maintain reasonably accurate clocks.

Packet Overhead Comparison

Minimum overhead for a typical encrypted unicast message (no options, no flood hop count):

FieldUMSH (S=0, 16B MIC)UMSH (S=0, 4B MIC)UMSH (S=1)MeshCore
Header/FCF1111
Path length1
Destination3331
Source33321
Security info555
MAC/MIC1644–162
ECB block padding0–15 (avg ~8)
Total overhead281645–57~14

UMSH supports MIC sizes of 4, 8, 12, and 16 bytes (see Security & Cryptography). With a 4-byte MIC and S=0, UMSH’s 16 bytes of overhead is 2 bytes more than MeshCore’s effective ~14 bytes — the additional cost of 3-byte source and destination hints compared to MeshCore’s 1-byte addresses, in exchange for uniform 1-in-16,777,216 collision resistance on both source and destination.

MeshCore’s use of AES-128-ECB requires the plaintext to be padded to a multiple of 16 bytes. This wastes 0–15 bytes per packet depending on the payload size, averaging roughly 8 bytes of dead space. When this padding overhead is included, MeshCore’s effective overhead rises from 6 bytes to approximately 14 bytes.

MeshCore achieves low per-packet overhead by using 1-byte addresses, a 2-byte MAC, and no frame counter or security control field. However, this compactness comes at a significant cost to security (ECB mode, 2-byte MAC, no replay protection counter, no key separation) and to flexibility (no first-contact without ANON_REQ, no blind unicast, no composable options).

UMSH with S=0 and a 16-byte MIC provides the strongest security configuration at 28 bytes of overhead. With shorter MICs, UMSH can trade integrity margin for payload capacity — a 4-byte MIC still provides a 1-in-2^32 forgery resistance (compared to MeshCore’s 1-in-2^16 with its 2-byte MAC) while matching MeshCore’s effective overhead.

Power Consumption

Address hint width has a direct effect on power consumption in battery-constrained LoRa nodes.

When a node receives a packet, it checks the destination hint against its own address before committing to cryptographic verification. If the hint matches, the node must attempt full packet verification to confirm whether the packet is genuinely addressed to it. Pairwise keys are cached after first contact, so no ECDH is needed for known senders — but verification still requires decrypting the payload with AES-CTR (using the transmitted MIC as the CTR IV) and then computing CMAC over the decrypted plaintext to confirm the MIC matches. Only a collision from a completely unknown sender transmitting with a full 32-byte source key (S=1) would additionally require ECDH and HKDF derivation. If the hint does not match, the packet can be discarded immediately with minimal CPU cost.

The problem is collisions. In a network of many nodes, some fraction of packets addressed to other nodes will collide with your own hint and trigger unnecessary cryptographic work. The collision rate depends on the hint width:

ProtocolDestination hint widthFalse-positive rate per unicast packet
MeshCore8 bits (1 byte)~1 in 256
UMSH24 bits (3 bytes)~1 in 16,777,216

UMSH’s 3-byte node hints reduce spurious cryptographic wake-ups by a factor of ~65,536 compared to MeshCore, at a combined address overhead of 6 bytes per unicast packet versus MeshCore’s 2 bytes. In a busy mesh where a node receives hundreds of packets per hour intended for others, fewer wasted verifications means less CPU time, fewer memory accesses, and a faster return to sleep.

The same logic applies to multicast channel identifiers. MeshCore uses a 1-byte hash of the channel key, giving a 1-in-256 chance that any packet addressed to an unknown channel matches a channel you are not a member of. UMSH’s 2-byte channel identifier reduces this to 1-in-65536.

Repeater Power

Both protocols use flood routing, so nodes configured as repeaters must receive and retransmit packets intended for other nodes. Transmit is the most power-intensive radio operation, so minimizing unnecessary retransmissions matters. In practice, repeating is enabled only on dedicated infrastructure nodes; end-user devices are typically configured as non-repeating nodes and incur no forwarding transmit cost.

For dedicated repeater nodes, UMSH does not require decrypting or verifying the payload MIC before forwarding — the MAC layer treats payloads opaquely, and forwarding decisions are based solely on the flood hop count and duplicate suppression cache. UMSH’s channel access mechanisms (CAD with random backoff, SNR-based contention windows) reduce collisions, and forwarding confirmation with retries provides reliable hop-by-hop delivery. The signal-quality filtering options (minimum RSSI and SNR) allow senders to prevent retransmission over weak links, avoiding wasted transmit power on paths unlikely to deliver the packet successfully.

MeshCore’s SNR-based retransmit delay implicitly prioritizes better-positioned repeaters — nodes with stronger reception retransmit sooner, which can suppress weaker nodes via duplicate detection. However, no packet is ever dropped due to poor signal quality; every repeater in range of a flooded packet will eventually retransmit it (subject to hop count), regardless of link quality. UMSH’s explicit signal-quality thresholds allow the sender to prevent retransmission over weak links entirely, avoiding wasted transmit power on paths unlikely to deliver the packet successfully.

What This Means in Practice

The protocol differences described above translate into concrete user-visible behaviors:

  • Multi-hop delivery is more reliable. UMSH defines hop-by-hop forwarding confirmation with retries, so each repeater along the path confirms receipt before the previous hop moves on. Versions of this are present for both source-routed paths and flooded packets in UMSH. MeshCore’s forwarding is fire-and-forget in both flood and direct modes — if a transmission is lost at any hop, there is no recovery mechanism at the forwarding layer. This makes multi-hop forwarding much less reliable over long distances.

  • Nodes do not need accurate clocks. MeshCore uses UNIX timestamps for advertisement freshness and login sequencing, so nodes with drifted or reset clocks may reject valid advertisements or fail login handshakes. UMSH is timestamp-free at the MAC layer — no clock synchronization is required for any protocol operation.

  • Fewer false wake-ups on busy networks. MeshCore’s 1-byte address hints mean that roughly 1 in 256 packets addressed to other nodes will appear to match yours, triggering unnecessary cryptographic verification before the packet can be discarded. UMSH’s 3-byte hints reduce this to roughly 1 in 16 million, which matters for battery-powered nodes that need to return to sleep quickly.

  • Routes can combine source routing and flooding. A UMSH packet can be source-routed to a known region and then flood locally from there, reaching a specific area without flooding the entire mesh. MeshCore treats flood and direct routing as mutually exclusive.

  • Amateur radio operation is a first-class concern. UMSH defines packet options for operator and station callsigns and an explicit unencrypted mode, allowing compliant operation on amateur radio frequencies where encryption is prohibited and station identification is required. MeshCore does not define equivalent mechanisms.

  • Easier to extend without breaking existing deployments. UMSH’s composable options and opaque payload model let developers add new routing behaviors, packet options, or application protocols without changing the MAC layer — existing nodes simply ignore options and payload types they do not recognize. MeshCore’s vertically integrated design, where application-layer semantics are defined at the protocol level, means that new features are more likely to require coordinated firmware updates across the network.

  • Stronger security from a coherent cryptographic design. MeshCore’s cryptographic choices — AES-128-ECB encryption, 2-byte MACs, a 128-entry duplicate cache for replay protection, and no key separation — individually and collectively weaken the security guarantees the protocol can offer. Identical messages produce identical ciphertext, MAC forgery is feasible to brute-force, replayed packets are accepted once the duplicate cache wraps, and the same key material is reused across cryptographic operations. UMSH addresses all of these with AES-CTR encryption using a synthetic IV, configurable MIC sizes up to 16 bytes, monotonic frame counters for replay protection, HKDF-derived domain-separated keys, and optional perfect forward secrecy sessions that protect past traffic if a long-term key is later compromised. Something like this cannot be easily bolted onto MeshCore’s current design.

Summary of Design Differences

MeshCore optimizes aggressively for minimal packet overhead in the common case, accepting significant cryptographic and flexibility tradeoffs to maximize payload capacity within LoRa frame constraints. It takes a vertically integrated approach, defining application-layer payload types and relying on a fixed-size duplicate cache for deduplication and UNIX timestamps for advertisement freshness.

UMSH prioritizes cryptographic robustness, composable routing, privacy features, and strict layer separation, accepting higher overhead in exchange for stronger security guarantees and a more extensible protocol structure. By restricting itself to the MAC layer and using monotonic frame counters instead of timestamps, UMSH avoids coupling to specific application assumptions or clock synchronization requirements. The S flag allows the overhead to scale based on whether the receiver already knows the sender’s public key, bridging the gap for established communication pairs while still supporting zero-prior-state first contact.

Comparison with Meshtastic

This section compares UMSH with Meshtastic, a popular open-source LoRa mesh project. The comparison is based on Meshtastic firmware v2.5+ and its documentation and protobuf definitions.

Note

This comparison aims to be as fair and accurate as possible, not promotional material. If you spot any unfair comparisons, factual errors, or other mistakes, please file an issue!

Meshtastic and UMSH occupy different positions in the design space. Meshtastic is a mature, widely deployed application-focused system optimized for ease of use and broad hardware support. UMSH prioritizes cryptographic rigor, compact encoding, and clean layer separation. The comparison below highlights the technical differences without implying that one set of tradeoffs is universally better than the other.

Identity and Addressing

AspectUMSHMeshtastic
Identity basis32-byte Ed25519 public key32-bit node number derived from Bluetooth MAC address
Cryptographic identityPublic key is the addressOptional Curve25519 keypair (PKC, v2.5+), not used for addressing
Source address in packetscompact 3-byte hint (S=0) or 32-byte key (S=1)4-byte node number (cleartext)
Destination address3-byte hint4-byte node number (cleartext)
Channel identifier2-byte derived hint1-byte DJB2 hash of channel name
Address spoofing resistanceCryptographic — pairwise keys are derived from public keysNone — node numbers are hardware-derived and trivially spoofable

UMSH identifies nodes by their Ed25519 public keys, which serve as both the address and the cryptographic credential. A node’s identity is inseparable from its ability to authenticate and decrypt. Meshtastic identifies nodes by a 32-bit number derived from the device’s Bluetooth MAC address. This number is not cryptographically bound to any key — any device can claim any node number.

Meshtastic added optional Curve25519 keypairs in v2.5 for direct message encryption, but these are not used for addressing. The node number remains the primary identifier, and channel-encrypted traffic has no per-node authentication regardless of whether PKC keys are configured.

Packet Structure

AspectUMSHMeshtastic
Header1-byte FCF with version, type, flags16-byte fixed header (always cleartext)
Payload encodingRaw bytes with 1-byte payload type prefixProtobuf-encoded Data message
Packet types8 (via 3-bit field in FCF)Implicit in protobuf portnum field (~30+ application types)
Routing infoCoAP-style composable optionsFixed fields: hop limit (3-bit), next hop (1 byte), relay node (1 byte)
Flood hop countSplit 4-bit FHOPS field (max 15)Mandatory 3-bit field (max 7 hops)
Max LoRa payload~255 bytes255 bytes (233 bytes application payload after header and encoding overhead)
Typical unicast overhead14–28 bytes (depending on MIC size and source hint vs full key)16 bytes header + 28 bytes crypto = 44 bytes minimum

UMSH uses a compact 1-byte Frame Control Field with optional expansion — fields are present only when needed for the packet type. Meshtastic uses a fixed 16-byte header on every packet, with source and destination node numbers, packet ID, flags, channel hash, and routing fields always present.

Meshtastic’s header is always transmitted in cleartext, exposing sender and recipient node numbers, packet IDs, and channel hashes to any passive observer. UMSH’s addressing fields are compact hints that do not directly reveal node identity, and in blind unicast or encrypted multicast modes, the source address is encrypted.

Meshtastic encodes application payloads using Protocol Buffers (protobuf), which adds encoding overhead but provides a flexible, self-describing serialization format. UMSH uses raw byte payloads with a 1-byte type prefix, minimizing encoding overhead at the cost of less built-in structure.

Cryptography

AspectUMSHMeshtastic (channel)Meshtastic (PKC DM)
EncryptionAES-128-CTR (SIV-style)AES-256-CTRAES-CCM
AuthenticationAES-CMAC (4/8/12/16-byte MIC)NoneCCM auth tag
Key exchangeX25519 ECDHPre-shared keyCurve25519 ECDH
Key derivationHKDF-SHA256 with domain separationPSK used directlySHA-256 of ECDH shared secret
Nonce constructionFrame counter + optional salt in SECINFOPacket ID + sender node number8-byte random nonce
Replay protection4-byte monotonic frame counter32-bit random packet ID (duplicate cache)Not defined
Forward secrecyOptional PFS sessionsNoNo

Channel Encryption

The most significant cryptographic difference is that Meshtastic’s channel-encrypted packets have no authentication. AES-CTR provides confidentiality but no integrity protection. This means:

  • An attacker who knows the channel key can modify ciphertext in transit (CTR mode bit-flipping), and the recipient has no way to detect the tampering.
  • Any node with the channel key can forge packets claiming to be from any other node, since there is no per-node authentication and the sender’s node number in the cleartext header is not cryptographically bound to anything.

UMSH authenticates every secured packet with an AES-CMAC MIC (4–16 bytes, see MIC Size Selection Guidance). Even with a 4-byte MIC, UMSH provides 2^-32 forgery resistance — qualitatively different from Meshtastic’s complete absence of authentication on channel traffic.

PKC Direct Messages

Meshtastic v2.5+ added Curve25519 ECDH with AES-CCM for direct messages, providing both confidentiality and authentication. This is a substantial improvement over channel-only encryption, but applies only to direct messages — all broadcast traffic (position, telemetry, channel text) remains unauthenticated.

UMSH authenticates all traffic uniformly — unicast, multicast, and broadcast — using the same CMAC-based construction. There is no distinction between “authenticated” and “unauthenticated” packet classes.

Key Derivation

Meshtastic uses the channel PSK directly as the AES key for channel encryption, with no key derivation step. For PKC, the ECDH shared secret is hashed with SHA-256 to produce the AES key.

UMSH uses HKDF-SHA256 with domain-separated labels to derive independent encryption and authentication keys from each shared secret. This prevents cross-purpose key reuse and is the standard practice recommended by cryptographic literature.

Routing

AspectUMSHMeshtastic
Flood routingYes, bounded by flood hop countYes (managed flood with SNR-based priority)
Source routingYes, via source-route optionNo
Hybrid routingSource route + flood hop count in same packetNo
Next-hop routingN/AYes (learned from ACK paths, v2.6+)
Max hops15 flood + “many” source-routed7 (3-bit hop limit)
Duplicate detectionMIC cachePacket ID cache (32-bit random IDs)
Forwarding confirmationYes (hop-by-hop retries with backoff when source routing)Implicit ACK for broadcasts (sender listens for neighbor rebroadcast, up to 3 retries); not hop-by-hop
Channel accessCAD with random backoff; SNR-based contention windowsSNR-based contention windows
Signal-quality filteringMin RSSI and min SNR optionsSNR-based rebroadcast priority (implicit)
Region-scoped floodingRegion code optionNot defined
TracerouteTrace-route option on any packetDedicated TRACEROUTE_APP port

Both protocols use flood-based routing as their primary delivery mechanism. Meshtastic’s managed flood uses SNR-based contention windows to prioritize better-positioned relays, which is an effective heuristic for reducing redundant rebroadcasts. UMSH provides explicit signal-quality thresholds (minimum RSSI and SNR options) that allow the sender to control relay eligibility per packet.

Meshtastic’s 3-bit hop limit caps multi-hop delivery at 7 hops. UMSH’s 4-bit flood hop count allows up to 15 flood hops, and source routing allows packets to traverse specific paths without flooding (with no hop limit).

Meshtastic v2.6+ added next-hop routing for direct messages: after a successful ACK exchange, the firmware learns which relay carried the response and uses it as a designated next hop for subsequent packets. UMSH achieves similar directed delivery through source-route options learned via trace routes — the recipient caches the accumulated trace directly as a source route for all subsequent communication with the sender, because the trace is already built most-recent hop first (see Route Learning).

Both protocols define channel access mechanisms. Meshtastic uses SNR-based contention windows to prioritize better-positioned relays. UMSH uses CAD (Channel Activity Detection) with random backoff and SNR-based contention windows for collision avoidance.

Both protocols provide forwarding confirmation, but with different scope. Meshtastic’s sender listens for any neighbor to rebroadcast a flooded packet; if no rebroadcast is overheard, the sender retransmits up to 3 times (with the final retry falling back to flooding if next-hop routing was in use). This provides 0-hop reliability — the originator can confirm that at least one neighbor forwarded the packet — but intermediate relays do not confirm onward delivery. UMSH defines hop-by-hop forwarding confirmation: each forwarding node (whether source-route hop or flood originator) listens for retransmission by the next hop and retries with backoff if none is heard, providing reliability across the full forwarding chain.

Privacy

AspectUMSHMeshtastic
Header confidentialityAddressing fields are compact hints; blind modes encrypt source/destinationHeader always cleartext — sender, recipient, packet ID, channel hash exposed
Source concealmentEncrypted multicast, blind unicastNot supported
Destination concealmentBlind unicastNot supported
Node ID linkabilityPublic key (can use ephemeral keys)Hardware MAC-derived (persistent identifier)
Anonymous first contactEphemeral Ed25519 key with S=1 flagNot supported

Meshtastic’s 16-byte cleartext header exposes the full sender and recipient node numbers on every packet. A passive observer with a LoRa receiver can identify who is communicating with whom, build traffic graphs, and track individual devices over time — even without the channel key. Node numbers are derived from hardware MAC addresses, making them persistent identifiers tied to physical devices.

UMSH’s compact hints reveal far less information to passive observers, and blind unicast and encrypted multicast modes encrypt the source and/or destination entirely. Nodes can also use ephemeral keypairs for anonymous communication.

Multicast and Group Communication

AspectUMSHMeshtastic
Channel key size32 bytes1, 16, or 32 bytes (PSK)
Channel identifier2-byte derived hint1-byte DJB2 hash of channel name
Channels per nodeUnlimited (implementation-defined)Up to 8
Multi-hop multicastYes (flood with flood hop count)Yes (managed flood with hop limit)
Group message authChannel-key-based CMACNone (AES-CTR only)
Source privacySource encrypted when encryption enabledNo (source in cleartext header)
Named channelsYes (key derived from name)Yes (name + PSK configured together)

Both protocols support multiple channels with independent keys. Meshtastic limits nodes to 8 simultaneous channels. Meshtastic’s 1-byte channel hash has a high collision probability (1 in 256), requiring trial decryption when collisions occur. UMSH’s 2-byte channel identifier reduces this to 1 in 65536.

Application Layer

AspectUMSHMeshtastic
Payload typing1-byte payload type prefixProtobuf portnum field (~30+ types)
Payload encodingRaw bytesProtocol Buffers
Structured dataCoAP-over-UMSH (block-wise transfer)Protobuf with defined message schemas
Text messagingUMSH text message payloadTEXT_MESSAGE_APP (portnum 1)
Position/telemetryNot defined (delegated to higher-layer protocols)Built-in POSITION_APP, TELEMETRY_APP
Node identityIdentity payload with role, capabilities, nameNODEINFO_APP with User protobuf
Remote administrationNode management MAC commandsADMIN_APP (portnum 6)
AudioNot definedAUDIO_APP (codec2, 2.4 GHz only)
Store and forwardNot definedSTORE_FORWARD_APP
Amateur radioOperator/station callsign options, explicit unencrypted modeis_licensed flag (lifts power limits, callsign via long name, manual PSK removal)
ImplementationProtocol spec (language-agnostic)C++ firmware + protobuf definitions

Meshtastic defines a rich application layer with built-in support for position sharing, telemetry, waypoints, audio, store-and-forward, and TAK integration. These are tightly integrated into the firmware and protobuf schema.

UMSH defines a smaller set of application protocols (text messaging, chat rooms, node identity, node management) and delegates richer application functionality to higher-layer protocols carried in the payload, such as CoAP. This approach is less feature-complete out of the box but allows UMSH to carry arbitrary higher-layer content without protocol changes.

Both protocols address amateur radio operation, but at different levels. Meshtastic provides an is_licensed configuration flag that lifts firmware power limits and expects the operator to manually set their callsign as the node’s long name and clear the channel PSK to disable encryption. The callsign is carried in the existing user info field rather than a dedicated protocol field. UMSH defines amateur radio support at the protocol level: dedicated packet options carry operator and station callsigns as structured fields, and the Frame Control Field explicitly indicates whether a packet is encrypted. Both protocols require the operator to configure the device appropriately, but UMSH’s approach makes compliance structurally visible in the packets themselves — a monitoring station can verify callsign presence and unencrypted transmission by inspecting the packet, without needing to know the device’s configuration state.

Layer Separation

AspectUMSHMeshtastic
Protocol scopeMAC layer with separate application protocolsMonolithic — radio, routing, and application layers interleaved
Payload interpretationOpaque at MAC layerProtobuf Data message decoded at every layer
FragmentationDelegated to higher-layer protocolsNot defined (single-frame limit)
Application couplingApplication protocols are architecturally separate~30+ application types defined in core protobuf schema

UMSH maintains a clean boundary between the MAC layer and application protocols. The MAC layer treats payloads opaquely and can carry any higher-layer protocol. Meshtastic’s protobuf-defined Data message structure spans from radio-level fields to application payloads in a single schema, with no clean separation between layers.

Timestamps and Time Dependency

AspectUMSHMeshtastic
Replay protection4-byte monotonic frame counter32-bit random packet ID (duplicate cache)
Timestamps in packetsNone at MAC layerrx_time metadata (not used for protocol decisions)
Clock synchronization requiredNoNo

Neither protocol requires clock synchronization for core operation. Meshtastic includes reception timestamps as metadata but does not use them for routing or replay protection. Both protocols detect duplicates without relying on wall-clock time — UMSH via monotonic frame counters, Meshtastic via random packet ID caching.

Packet Overhead Comparison

Minimum overhead for a typical encrypted unicast message:

FieldUMSH (S=0, 16B MIC)UMSH (S=0, 4B MIC)Meshtastic (channel)Meshtastic (PKC DM)
Header/FCF111616
Destination33(in header)(in header)
Source33(in header)(in header)
SECINFO55
MIC / auth tag164~12
Nonce / IV(derived, not transmitted)(8 in payload)
Protobuf overhead~6~6
Total overhead2816~22~42

Meshtastic’s nonce is derived from header fields (packet ID + sender node number) rather than transmitted, saving bytes compared to protocols that transmit the IV. However, the fixed 16-byte cleartext header and protobuf encoding overhead partially offset this advantage.

UMSH with a 16-byte MIC has slightly more overhead than Meshtastic channel encryption (28 vs ~22 bytes), but UMSH’s overhead includes full authentication that Meshtastic’s channel mode lacks entirely. With a 4-byte MIC, UMSH achieves 16 bytes of overhead — lower than Meshtastic’s ~22 bytes — while still providing authentication that Meshtastic channel traffic does not have.

Meshtastic PKC direct messages add approximately 20 bytes of overhead beyond channel encryption (ECDH-derived key, CCM nonce, and authentication tag), bringing total overhead to roughly 42 bytes for authenticated direct messages.

Power Consumption

Power consumption on a battery-constrained LoRa node is driven by two factors: how long the radio is active (airtime), and how much CPU work is required after each received packet.

Channel Filtering and False Positives

In a LoRa mesh, broadcast and multicast traffic (position reports, telemetry, channel messages) outnumber unicast packets. For this traffic, the only pre-crypto filter available is the channel identifier. When a packet’s channel identifier matches a channel the node does not belong to, the node must attempt decryption to confirm the mismatch — a false positive.

ProtocolChannel identifier widthFalse-positive rate per broadcast packet
Meshtastic8 bits (1-byte DJB2 hash)~1 in 256
UMSH16 bits (2-byte derived hint)~1 in 65536

Meshtastic’s 1-byte channel hash produces ~256× more false positives than UMSH’s 2-byte channel identifier. Each false positive requires an AES-256-CTR decryption attempt (cheap relative to ECDH, but still unnecessary CPU work and a delay before the MCU can return to sleep). In a busy mesh with many active channels, this adds up.

Unicast Filtering

For unicast packets, Meshtastic’s 4-byte cleartext node number provides near-zero false-positive filtering with no cryptographic work — the destination can be checked by simple integer comparison before any decryption is attempted. UMSH’s 3-byte destination hint has a ~1-in-16,777,216 false-positive rate; when a collision occurs, verification requires decrypting the payload with AES-CTR and computing CMAC over the result — pairwise keys are cached after first contact so no ECDH is needed for known senders, but the decrypt-then-MAC work still applies.

This is a genuine power tradeoff: Meshtastic achieves cheaper unicast filtering by including the full destination identifier in the cleartext header, while UMSH accepts a small false-positive rate in exchange for transmitting fewer bytes and not fully exposing node identity to passive observers.

Packet Length and Airtime

Meshtastic’s fixed 16-byte header is transmitted on every packet regardless of content. UMSH’s header includes only the fields needed for the packet type. On a LoRa network, longer packets mean longer airtime, which means nearby nodes must keep their radios active longer to receive each packet — a cost that compounds across all nodes in range, not just the sender.

Repeater Power

Both protocols use flood routing as their primary delivery mechanism, so nodes configured as repeaters must receive and retransmit packets. Transmit is the most power-intensive radio operation on a LoRa node. In practice, repeating is enabled only on dedicated infrastructure nodes; end-user devices are typically configured as non-repeating and incur no forwarding transmit cost.

Meshtastic’s managed flood uses SNR-based contention windows: after receiving a packet, each potential relay waits a random delay inversely proportional to its received SNR before retransmitting. If it hears a better-positioned node retransmit first, it suppresses its own retransmission. This heuristic reduces the number of redundant rebroadcasts compared to simple flooding and saves transmit power across the network.

UMSH’s signal-quality filtering options (minimum RSSI and minimum SNR) allow the original sender to set explicit thresholds: a repeater that received the packet below the threshold must not retransmit it. This gives the sender direct control over which links are used for forwarding, avoiding transmit power wasted on paths unlikely to deliver the packet. Meshtastic’s SNR-based approach is automatic but implicit; UMSH’s approach is explicit but requires the sender to configure appropriate thresholds.

UMSH repeaters do not need to decrypt or verify the payload before forwarding — the MAC layer treats payloads opaquely. Meshtastic repeaters also forward without decryption for channel traffic.

Summary of Design Differences

Meshtastic is a full-featured, batteries-included mesh communication system with a large and active user community. It provides a rich application layer (position sharing, telemetry, store-and-forward, TAK integration), broad hardware support, and an easy on-ramp for non-technical users. Its channel-based encryption model is simple to configure and deploy.

UMSH prioritizes cryptographic robustness, compact encoding, and architectural cleanliness. It authenticates all traffic, provides privacy modes for metadata concealment, and maintains strict layer separation that allows it to carry arbitrary higher-layer protocols.

Key tradeoffs:

  • Authentication: UMSH authenticates every packet. Meshtastic’s channel traffic has no authentication — only PKC direct messages (v2.5+) are authenticated.
  • Privacy: UMSH provides compact addressing hints and opt-in blind modes. Meshtastic exposes full sender and recipient identifiers in cleartext headers on every packet.
  • Identity model: UMSH uses cryptographic public keys as addresses. Meshtastic uses hardware-derived node numbers that are not cryptographically bound to any key.
  • Overhead: Comparable in the common case (~14–26 bytes for UMSH vs ~22 bytes for Meshtastic channel), but UMSH’s overhead includes authentication.
  • Application richness: Meshtastic provides a far richer built-in application layer. UMSH delegates richer functionality to higher-layer protocols.
  • Layer separation: UMSH cleanly separates MAC and application concerns. Meshtastic is a monolithic system where protocol and application are interleaved.
  • Implementation: Meshtastic is a mature C++ firmware with broad device support. UMSH is not tied to any implementation language or runtime, and its compact design can target bare-metal microcontrollers.
  • Ease of deployment: Meshtastic is designed for immediate use with consumer hardware. UMSH requires implementation effort and explicit key configuration.

Comparison with Reticulum

This section compares UMSH with Reticulum, a cryptography-based networking stack designed for operation over a wide range of mediums, including LoRa. The comparison is based on Reticulum v1.1.4 (tag 1.1.4) and its manual and source code.

Note

This comparison aims to be as fair and accurate as possible, not promotional material. If you spot any unfair comparisons, factual errors, or other mistakes, please file an issue!

The Reticulum claims in this document can be independently verified against the following source files:

FileRelevant claims
RNS/Reticulum.pyMTU, header sizes, announce bandwidth cap, IFAC derivation
RNS/Packet.pyPacket types, header layout, context values
RNS/Identity.pyKey sizes, ECDH, HKDF derivation, ephemeral keys, ratchet system, announce format
RNS/Destination.pyDestination types, destination hash construction, GROUP limitations, ratchet interval
RNS/Transport.pyRouting, replay protection via packet hash cache, max hop cap, IFAC generation
RNS/Cryptography/Token.pyAES-256-CBC, PKCS7, HMAC-SHA256, IV handling, timestamp removal
RNS/Link.pyLINK session ECDH, symmetric key persistence, MTU signalling, link modes
RNS/Interfaces/Interface.pyLink MTU auto-configuration (optimise_mtu)
RNS/Discovery.pyOn-network interface discovery, network identity system

Protocol Scope

The most fundamental difference between UMSH and Reticulum is their scope.

UMSH defines a MAC layer with cleanly separated application protocols. The MAC layer handles framing, addressing, encryption, authentication, and forwarding, and treats payloads opaquely. Application protocols (text messaging, chat rooms, node management) are architecturally separate and carried in the payload alongside any other higher-layer content such as CoAP or 6LoWPAN.

Reticulum is a complete network stack that replaces the IP layer entirely. It provides addressing, routing, link establishment, encryption, reliable delivery (via its Resources API), request/response patterns, and bidirectional channels. Reticulum does not separate MAC-layer concerns from application-layer concerns; these are interwoven throughout the stack.

This difference has practical implications: UMSH’s simpler MAC-layer model has lower minimum state requirements, making it easier to implement on constrained microcontrollers. Reticulum’s richer protocol machinery (path tables, link establishment, announce propagation) demands more from an implementation regardless of language. UMSH’s MAC layer can carry arbitrary higher-layer protocols, while Reticulum applications must use Reticulum’s own APIs for structured communication.

Identity and Addressing

AspectUMSHReticulum
Identity key32-byte Ed25519 public key64-byte keyset: 32-byte X25519 + 32-byte Ed25519 (Identity.py:58, KEYSIZE = 256*2)
Address in packetscompact 3-byte hint (S=0) or full 32-byte key (S=1)16-byte truncated SHA-256 hash (Reticulum.py:146, TRUNCATED_HASHLENGTH = 128)
Source address3-byte hint (S=0) or full 32-byte key (S=1)Not included (no source address in packets)
Destination address3-byte destination hint16-byte destination hash
Channel identifier2-byte derived hint16-byte destination hash

UMSH identifies nodes directly by their Ed25519 public keys and uses compact 3-byte hints as prefilters for efficient matching. The S flag allows including the full 32-byte key when needed (first contact, ephemeral keys). Reticulum derives 16-byte destination hashes via a two-step construction (Destination.py:118): (1) the aspect name (a dotted string like app.sensor.temperature) is hashed with SHA-256 and truncated to 10 bytes (Identity.py:80, NAME_HASH_LENGTH = 80); (2) the final address is SHA-256(name_hash || identity_hash)[:16], where identity_hash = SHA-256(public_key)[:16]. These hashes are larger than UMSH hints but serve a different purpose — they are meant to be globally unique identifiers rather than prefilters.

Reticulum does not include a source address in any packet. This provides initiator anonymity by default but means that the recipient must already have context (via an established link or a prior announce) to know who sent a given packet. UMSH includes the source address (as a compact hint or full key) in every packet, which allows stateless first-contact and simplifies protocol logic at the cost of revealing the sender’s identity to observers. UMSH offers two opt-in mechanisms that reduce identity exposure. Blind unicast encrypts the source address with the channel key so that only channel members can identify the sender. PFS sessions use ephemeral node addresses for the duration of the session, so an observer sees only hints derived from short-lived keys rather than the nodes’ long-term identities — the long-term identity hints never appear on the wire during the session. This identity obscuration is not unconditional: because the PFS handshake is authenticated with the nodes’ long-term keys, an attacker who later compromises a long-term private key can retroactively attribute the session to those identities, even though the session’s content remains protected.

Packet Structure

AspectUMSHReticulum
Header1-byte FCF with version, type, flags2-byte header (flags + hop count)
Packet types8 (via 3-bit field in FCF)4: DATA, ANNOUNCE, LINKREQUEST, PROOF (Packet.py:60–63)
Destination typesImplicit in packet type (unicast, multicast, broadcast, blind)4: SINGLE, GROUP, PLAIN, LINK (Destination.py:63–66)
Routing infoCoAP-style composable optionsTransport ID field (16 bytes) in HEADER_2
Flood hop countSplit 4-bit FHOPS field (max 15)Mandatory 1-byte field
MTULoRa frame size (typically 255 bytes)500-byte network MTU (Reticulum.py:91, MTU = 500); per-link MTU discovery (since v0.9.3) allows upward negotiation on capable links
Typical unicast overhead (total)14–28 bytes (depending on MIC size and source hint vs full key)~91 bytes LINK / ~108 bytes SINGLE (19–35 byte header + 56–88 bytes crypto; see Packet Overhead Comparison)

UMSH uses compact fields that are present only when needed for the packet type. Reticulum’s 16-byte destination hashes and optional 16-byte transport IDs result in larger headers (19–35 bytes before crypto overhead), and the total per-packet overhead — header plus cryptographic fields — ranges from roughly 91 to 108 bytes depending on destination type. On a 255-byte LoRa frame, this leaves 147–164 bytes for payload compared to UMSH’s 227–239 bytes.

Reticulum’s 500-byte network MTU exceeds what most LoRa configurations can carry in a single frame. Reticulum introduced link MTU discovery in v0.9.3, which allows adjacent nodes to negotiate a higher effective MTU than 500 bytes when the underlying interface can support it — but this only applies to high-bandwidth interfaces. The Interface.optimise_mtu() method (Interface.py:115–138) maps link speed to hardware MTU, and sets HW_MTU = None for any interface running at or below 62,500 bps — which encompasses every LoRa configuration. When HW_MTU is None, the link request falls back to signalling the base 500-byte MTU (Link.py:273–278), and link MTU discovery is never entered. For LoRa interfaces, Reticulum relies on the RNode firmware to reassemble sub-255-byte air frames into 500-byte packets before presenting them to the stack via KISS. UMSH is designed to fit within a single LoRa frame, avoiding fragmentation entirely.

UMSH uses composable CoAP-style options for routing metadata (source routes, trace routes, signal-quality thresholds, region codes), allowing packets to carry exactly the routing information they need. Reticulum uses a fixed two-header-type system: HEADER_1 for direct packets and HEADER_2 for transport-routed packets, with no equivalent to UMSH’s composable options.

Cryptography

AspectUMSHReticulum
EncryptionAES-128-CTR (SIV-style: MIC used as CTR IV)AES-256-CBC with PKCS7 padding (Token.py:91); AES-128 support removed in v1.0.0
AuthenticationAES-CMAC (16-byte MIC)HMAC-SHA256 (32-byte tag, Token.py:50, TOKEN_OVERHEAD = 48)
Key exchangeX25519 ECDHX25519 ECDH (Identity.py:581)
Key derivationHKDF-SHA256, domain-separated (K_enc, K_mic)HKDF-SHA256, 64-byte output split into HMAC key + AES key (Identity.py:86, DERIVED_KEY_LENGTH = 512//8)
Nonce handlingSIV construction (MIC as CTR IV)Random 16-byte IV per packet (Token.py:89, os.urandom(16))
Replay protection4-byte monotonic frame counterDuplicate packet hash detection (Transport.py:59, packet_hashlist)
Per-packet overhead (crypto)5–7 bytes (SECINFO) + 16 bytes (MIC) = 21–23 bytes16 bytes (IV) + 32 bytes (HMAC) = 48 bytes minimum (LINK); +32 bytes ephemeral pubkey for SINGLE
Forward secrecyOptional PFS sessions via MAC commands (per-session ephemeral keys)Per-packet ephemeral key for SINGLE (Identity.py:574); optional ratchets for LINK (default min 30 min rotation, Destination.py:90, up to 512 ratchet keys stored per destination, 30-day expiry)
Future modesAES-256-GCM defined (link mode 0x02) but reserved; OTP/post-quantum modes reserved

Encryption Mode

UMSH uses an AES-SIV-inspired construction where the MIC doubles as the CTR IV, providing nonce-misuse resistance. Reticulum uses AES-256-CBC with a random 16-byte IV. Both are sound constructions — the primary difference in practice is overhead: CBC requires transmitting a 16-byte IV and adds 1–16 bytes of PKCS7 padding, while UMSH’s SIV construction derives the IV from the MIC (which is already transmitted) and uses CTR mode which requires no padding.

Authentication and Integrity

UMSH’s AES-CMAC MIC is configurable at 4, 8, 12, or 16 bytes (see MIC Size Selection Guidance), providing 32-bit to 128-bit integrity protection. Reticulum’s 32-byte HMAC-SHA256 tag provides 256-bit integrity. Both are sound choices; UMSH’s configurable size allows deployments to trade integrity margin for payload capacity within the constrained LoRa frame budget.

Key Management

For unicast, UMSH derives stable pairwise keys from the ECDH shared secret via HKDF with domain-separated labels. These keys are reused across packets, with per-packet variability provided by the frame counter and optional salt in SECINFO. This is efficient: no per-packet key exchange overhead. For forward secrecy, UMSH defines PFS sessions in which both nodes exchange ephemeral node addresses via a two-message handshake and communicate using session-specific keys for an agreed duration. Compromise of long-term keys does not expose traffic encrypted under PFS session keys. PFS sessions add no per-packet overhead once established.

Reticulum uses two approaches. For SINGLE (one-off) destinations, each packet includes a fresh ephemeral X25519 public key (32 bytes), providing per-packet forward secrecy at substantial overhead cost — 32 extra bytes on every packet (Identity.py:574, ephemeral_key = X25519PrivateKey.generate()). For LINK (session) destinations, a single ECDH exchange establishes symmetric keys that persist for the link’s lifetime — similar to UMSH’s stable pairwise keys (Link.py:340, self.shared_key = self.prv.exchange(self.peer_pub)). Reticulum also offers a ratchet mechanism that rotates keys at a configurable minimum interval (default 30 minutes, adjustable per-destination via Destination.set_ratchet_interval() (Destination.py:514)), providing periodic forward secrecy within a link (Destination.py:90, RATCHET_INTERVAL = 30*60). Up to 512 ratchet keys are stored per destination, each expiring after 30 days. Ratchet key presence is signalled via a context flag in announce packets, allowing senders to use the most recent ratchet key in place of the static identity key, providing forward secrecy for single-packet communication without the full 32-byte ephemeral pubkey overhead.

Both protocols offer forward secrecy, but with different granularity and overhead tradeoffs. Reticulum’s SINGLE mode provides per-packet forward secrecy at 32 bytes per packet; UMSH’s PFS sessions provide per-session forward secrecy at zero per-packet overhead after setup.

Replay Protection

UMSH uses explicit 4-byte monotonic frame counters, which provide deterministic, stateless replay detection with a well-defined forward window. A receiver can immediately reject a replayed packet by comparing the counter to its stored state.

Reticulum detects duplicates by caching packet hashes (Transport.py:59, packet_hashlist = set()). This approach works but has different tradeoffs: it requires maintaining a hash cache, and once the cache fills it is evicted in bulk via a two-generation rolling scheme — when the active set exceeds 500,000 entries it is moved into a packet_hashlist_prev set (Transport.py:60) and a fresh set starts accumulating (Transport.py:565–567, cap: Transport.py:115, hashlist_maxsize = 1000000). A replayed packet that was seen in neither the current nor the previous generation would not be detected. The reference implementation’s 500,000-entry threshold assumes ample memory; on constrained hardware where the cache must be significantly smaller, the window for undetected replay narrows accordingly.

Cryptographic Overhead

For an encrypted unicast message, the total cryptographic overhead differs significantly:

ComponentUMSH (16B MIC)UMSH (4B MIC)Reticulum (SINGLE)Reticulum (LINK)
SECINFO5 B5 B
MIC / HMAC16 B4 B32 B32 B
IV16 B16 B
Ephemeral pubkey32 B
CBC padding1–16 B (avg ~8)1–16 B (avg ~8)
Subtotal (crypto)21 B9 B~88 B~56 B

UMSH supports MIC sizes of 4, 8, 12, and 16 bytes (see Security & Cryptography), allowing deployments to trade integrity margin for payload capacity. Even with a 16-byte MIC, UMSH’s 21 bytes of crypto overhead is far less than Reticulum’s 56–88 bytes.

Routing

AspectUMSHReticulum
Flood routingYes, bounded by flood hop countYes (broadcast propagation)
Source routingYes, via source-route optionNo
Hybrid routingSource route + flood hop count in same packetNo
Transport/directed routingN/ATransport nodes with next-hop forwarding
Path discoveryTrace-route option on any flooded packetAnnounce flooding + path request/response
Max hops15 flood + unlimited source-routed128 (hard-coded announce propagation cap, Transport.py:41, PATHFINDER_M)
Forwarding confirmationYes (retries with backoff)No — forwarding is fire-and-forget; reliability is end-to-end via cryptographic proofs
Channel accessCAD with random backoff; SNR-based contention windowsNot defined at protocol level; RNode firmware implements CSMA with persistence probability for LoRa interfaces
Signal-quality filteringMin RSSI and min SNR optionsNot defined at protocol level
Region-scoped floodingRegion code optionNot defined
Announce bandwidth capNot defined (implementation policy)Default 2% of interface bandwidth (Reticulum.py:115, ANNOUNCE_CAP = 2), configurable per-interface via announce_cap key
Interface discoveryNot definedOn-network auto-discovery via rnstransport.discovery.interface destination (since v1.1.0)

UMSH and Reticulum take fundamentally different approaches to routing.

UMSH provides source routing — the sender can specify the exact sequence of repeaters a packet should traverse, using 2-byte router hints. This can be combined with flood routing: a packet can be source-routed to a specific area and then flood locally. Path discovery is built into the MAC layer via the trace-route option, which accumulates router hints as a packet floods — the recipient reverses the accumulated trace and caches it as a source route for all subsequent communication with the sender (see Route Learning).

UMSH defines channel access mechanisms (CAD with random backoff, SNR-based contention windows) and forwarding confirmation with retries, providing reliable hop-by-hop delivery and collision avoidance. Reticulum does not define equivalent mechanisms at the protocol level, though RNode firmware provides CSMA with persistence probability for LoRa interfaces independently of Reticulum.

Reticulum uses next-hop routing via Transport Nodes — dedicated forwarding nodes that maintain path tables learned from announces. Regular nodes do not forward packets. When no path is known, a path request is flooded (51 bytes in non-transport mode: 19-byte HEADER_1 + 16-byte destination hash + 16-byte request tag); transport nodes with cached paths respond. This approach is more automatic but requires designated infrastructure nodes and does not support sender-specified routing.

Reticulum’s maximum announce propagation is 128 hops (Transport.py:41, PATHFINDER_M). This constant is hard-coded; the hop count field is one byte and could technically carry values up to 255, but transport logic enforces the 128-hop limit.

Reticulum v1.1.0 introduced on-network interface discovery: nodes can broadcast structured discovery announces (containing interface type, LoRa parameters, IFAC credentials, and GPS coordinates) to the rnstransport.discovery.interface destination. Other nodes can receive these announces and automatically connect to trusted remote interfaces. This capability requires the LXMF module and uses proof-of-work stamps to prevent spam. UMSH does not define an equivalent mechanism.

UMSH’s signal-quality filtering (minimum RSSI and SNR options) allows packets to avoid weak links, which is valuable in LoRa networks where marginal links waste airtime on packets that are unlikely to be received reliably. Reticulum does not define equivalent mechanisms at the protocol level.

RNode and LoRa Access

Reticulum does not define radio-level concerns such as channel access or fragmentation at the protocol level. Instead, it relies on RNode, an open-source firmware for commodity ESP32-based LoRa boards, to bridge between the protocol stack and the LoRa physical layer. RNode communicates with the host via KISS framing over serial, Bluetooth LE, or TCP, and handles radio configuration, CSMA/CA channel access, and airtime regulation in firmware.

Critically for LoRa use, RNode also handles fragmentation: since Reticulum’s 500-byte network MTU exceeds the ~255-byte LoRa frame limit, the firmware transparently splits oversized packets across two LoRa frames and reassembles them on receive. This keeps the Reticulum stack simple — it sees a 500-byte pipe — but means that large packets require two air frames transmitted back-to-back, doubling airtime and introducing a window where interference or a collision on either frame loses the entire packet. Because fragmentation and channel access are handled in firmware, the protocol stack has no visibility into these concerns and cannot factor them into routing or scheduling decisions.

UMSH takes the opposite approach: each packet fits within a single LoRa frame, and channel access (CAD with random backoff, SNR-based contention windows) is defined at the protocol level. This allows any radio interface to be used without requiring firmware-level fragmentation or channel access logic, at the cost of bounding per-packet payload to what a single frame can carry.

Privacy and Anonymity

AspectUMSHReticulum
Source address in packetsYes (compact hint or 32-byte key)No (default initiator anonymity)
Blind unicastYes (source encrypted with channel key)N/A (no source to conceal)
Multicast source concealmentYes (source encrypted inside ciphertext)N/A
Anonymous first contactEphemeral Ed25519 key with S=1 flagPer-packet ephemeral key for SINGLE destinations
Destination concealmentNot definedNot defined
Interface access controlNot definedIFAC (truncated Ed25519 signature per packet)
Network trust domainsNot definedNetwork Identity system (since v1.1.0)

The two protocols achieve privacy through different structural choices.

Reticulum omits the source address from all packets, providing initiator anonymity as a default property of the protocol. The tradeoff is that recipients must establish context through other means (announces, link establishment) before they can identify who is communicating with them.

UMSH includes source addresses by default but provides explicit privacy modes. Blind unicast encrypts the source address with a channel key so that only channel members can identify the sender. Encrypted multicast conceals the source inside the ciphertext. These are opt-in features that allow nodes to choose their privacy posture per packet.

Reticulum’s IFAC (Interface Access Code) mechanism provides network-level access control: a shared 64-byte keypair (X25519 + Ed25519) is derived from the network name and/or passphrase via HKDF-SHA256(SHA-256(network_name) || SHA-256(passphrase)). Each packet is signed with the Ed25519 key, and a configurable-length tail of that signature (1–64 bytes) is appended to the packet as the IFAC code (Transport.py:1485–1490). Interfaces reject packets with invalid IFAC codes. UMSH does not define an equivalent mechanism.

Reticulum v1.1.0 introduced a Network Identity system: a standard Reticulum identity keypair can be designated as a network’s signing authority. Network Identity keys sign interface discovery announces, allowing receiving nodes to verify that a discovered interface belongs to a trusted administrative domain. This enables optional encrypted discovery and provides a foundation for inter-network trust and future distributed name resolution. UMSH does not define an equivalent network identity layer.

Reticulum v1.1.0 also introduced a distributed blackhole list: specific identities can be blacklisted, causing their announces to be dropped by participating nodes. The blackhole list can be published and updated across the network. UMSH has no equivalent mechanism.

Multicast and Group Communication

AspectUMSHReticulum
Channel key size32 bytes32 bytes (AES-256)
Channel identifier2-byte derived hint16-byte destination hash
Multi-hop multicastYes (flood with flood hop count)No (single-hop broadcast only)
Group message authChannel-key-based CMAC (16-byte MIC)Channel-key-based HMAC-SHA256 (32-byte tag)
Source privacySource encrypted when encryption enabledNo source address to conceal
Named channelsYes (key derived from name)Not defined

UMSH supports multi-hop multicast via flood forwarding with flood hop count limits. Reticulum’s GROUP destinations are currently limited to single-hop broadcast — the manual states:

Packets to this type of destination are not currently transported over multiple hops, although a planned upgrade to Reticulum will allow globally reachable group destinations.

For LoRa mesh networks that rely on multi-hop coverage, this is a notable difference.

Application Layer

AspectUMSHReticulum
Payload typing1-byte payload type prefix1-byte context field (21 defined values; Packet.py:72–92)
Structured dataCoAP-over-UMSH (block-wise transfer)Resources API (multi-packet reliable transfer)
Node identityIdentity payload with role, capabilities, name, optionsAnnounce packets with public key, name hash, app data, Ed25519 signature (Identity.py:355, validate_announce())
Service discoveryBeacon broadcastsAspect-based naming + announce propagation
Interface discoveryNot definedOn-network auto-discovery with trust verification (since v1.1.0)
Network identityNot definedSigning authority keypair for administrative domains (since v1.1.0)
Amateur radioOperator/station callsign options, explicit unencrypted modeNot defined
ImplementationsProtocol spec (language-agnostic); experimental Rust reference implementationPython 3 reference; C++ for microcontrollers; Rust

Reticulum’s protocol is documented in its manual. In addition to the Python reference implementation, Reticulum has community C++ and Rust ports targeting embedded platforms. UMSH’s Rust reference implementation is experimental and early in development.

UMSH delegates reliable multi-packet transfer to CoAP’s block-wise transfer mechanism, reusing a well-established standard. Reticulum provides its own Resources API for the same purpose, including compression, sequencing, and checksumming — capable but specific to the Reticulum stack.

Reticulum v1.1.0 introduced structured interface discovery at the application layer: nodes can publish and consume typed discovery records that include interface parameters, GPS coordinates, IFAC credentials, and network identity signatures. This enables a form of self-organizing network management that has no counterpart in UMSH, which relies on out-of-band coordination for infrastructure configuration.

Timestamps and Time Dependency

Both protocols are designed to operate without clock synchronization.

AspectUMSHReticulum
Replay protection4-byte monotonic frame counterDuplicate packet hash cache
Timestamps in headersNoneNone (explicitly removed from Fernet-derived token format; Token.py:41–49)
Clock synchronization requiredNoNo

Both protocols avoid timestamp dependencies at the protocol level. UMSH uses monotonic frame counters for replay protection. Reticulum uses packet hash caching for duplicate detection. Neither requires nodes to agree on wall-clock time.

Reticulum’s ratchet mechanism uses local time for 30-day key expiry and minimum rotation intervals, but this is a local policy decision rather than a protocol requirement — no timestamp is transmitted on the wire.

Packet Overhead Comparison

Minimum overhead for a typical encrypted unicast message with no routing options (no source route, no flood hops, no trace route). In practice, multi-hop packets will carry additional routing metadata — UMSH adds 1 byte for flood hops and 2 bytes per source-route hop; Reticulum adds 16 bytes for the Transport ID when routed through a transport node:

FieldUMSH (S=0, 16B MIC)UMSH (S=0, 4B MIC)Reticulum (SINGLE)Reticulum (LINK)
Header/FCF1122
Destination331616
Transport ID16 (if routed)
Source33
Context byte11
SECINFO55
Ephemeral pubkey32
IV1616
MIC / HMAC1643232
CBC padding1–161–16
Total overhead2816~108~91

On a 255-byte LoRa frame:

UMSH (S=0, 16B MIC)UMSH (S=0, 4B MIC)Reticulum (SINGLE)Reticulum (LINK)
Available payload227 B239 B~147 B~164 B

With a 16-byte MIC, UMSH provides roughly 45–55% more payload capacity than Reticulum. With a 4-byte MIC, UMSH’s 16 bytes of total overhead leaves 239 bytes for payload — over 45% more than Reticulum on a typical LoRa frame. At LoRa data rates where every byte costs airtime, these differences affect how much payload capacity remains for application data.

Reticulum’s 500-byte network MTU exceeds what most LoRa configurations can transmit in a single frame, so Reticulum requires link-layer fragmentation at the LoRa interface that further reduces effective throughput. Link MTU discovery (added in v0.9.3) allows Reticulum to negotiate larger MTUs on capable links, but provides no relief for LoRa interfaces with sub-500-byte physical limits.

Power Consumption

The power profiles of UMSH and Reticulum differ across every dimension: platform, per-packet overhead, and filtering behavior.

Minimum Hardware Floor

Reticulum’s protocol machinery — path tables for Transport Node operation, 500-byte packet buffers, announce propagation state, and link establishment sessions — requires more RAM and processing than UMSH’s simpler model, raising the minimum hardware floor regardless of implementation language. A higher hardware floor generally means a higher baseline power draw, since more capable hardware tends to consume more power even when idle.

UMSH also requires per-node state — own keypair, configured channel keys, per-peer cached keys and frame counters, a duplicate cache, and optionally cached source routes — but the single-frame design avoids the need for large packet buffers, and the simpler protocol machinery fits on lower-power microcontrollers.

False-Positive Filtering

Reticulum’s 16-byte (128-bit) destination addresses have an essentially zero collision probability — a node receiving a packet addressed to someone else will never mistake it for its own. There is no wasted cryptographic work from address false positives. UMSH’s 3-byte destination hints have a ~1-in-16,777,216 false-positive rate; when a collision occurs, the node must attempt full packet verification before discarding it. Pairwise keys are cached after first contact, so no ECDH is needed for known senders — but verification still requires decrypting the payload with AES-CTR (using the transmitted MIC as the CTR IV) and then computing CMAC over the decrypted plaintext to confirm the MIC matches. ECDH and HKDF would additionally be required for a false positive from an unknown sender transmitting with a full 32-byte source key (S=1), which is rare in normal operation. In practice, on a LoRa network with modest traffic, spurious collisions are rare enough that this cost is negligible.

Packet Length and Airtime

Reticulum’s total per-packet overhead is roughly 91 bytes (LINK) or 108 bytes (SINGLE), combining header and cryptographic fields. UMSH’s total overhead is 14–28 bytes for a typical authenticated unicast. Shorter packets mean less airtime per message, which translates directly to less receive power for every node in range — a cost the sender imposes on the whole network.

Fragmentation

Reticulum’s 500-byte network MTU exceeds the ~255-byte LoRa frame limit, requiring link-layer fragmentation for larger messages. A node receiving a fragmented message must keep its radio and MCU active across multiple frames until reassembly completes. UMSH is designed to fit each packet into a single LoRa frame, so the radio can return to sleep as soon as one frame is processed.

Announce Traffic and Repeater Power

Reticulum relies on periodic announce flooding to build and maintain path tables. Transport Nodes re-broadcast announces on all interfaces (subject to a default 2% bandwidth cap); regular nodes receive announces but do not re-broadcast them. This creates a continuous background of traffic that all nodes must receive and that Transport Nodes must retransmit. UMSH does not define an equivalent mechanism — path discovery is on-demand via the trace-route option and imposes no standing overhead.

For data packet forwarding, Reticulum divides nodes into two classes at the protocol level: regular nodes, which do not forward unicast packets, and Transport Nodes, which maintain path tables and forward on behalf of others. This means most nodes in a Reticulum network incur zero transmit cost for forwarding unicast traffic. UMSH makes the same distinction at the configuration level — repeating is enabled only on dedicated infrastructure nodes, and end-user devices are typically configured as non-repeating. The practical power implication for non-repeating nodes is the same in both protocols; the difference is that Reticulum enforces the separation in the protocol itself rather than leaving it to deployment configuration.

The infrastructure dependency is the key tradeoff: Reticulum’s routing model requires Transport Nodes to be present and reachable, and these nodes need reliable power to maintain path tables. UMSH’s flood-based model works without any fixed infrastructure, with repeater nodes sharing the forwarding load.

Summary of Design Differences

Reticulum is a comprehensive, general-purpose network stack designed to operate across a wide range of mediums — from gigabit Ethernet to sub-kilobit LoRa. It prioritizes medium independence, automatic path discovery, initiator anonymity by default, and a rich application API. Recent versions (v1.1.0+) have added on-network interface discovery and a network identity system that enable more sophisticated network management and trust hierarchies.

UMSH is purpose-built for constrained LoRa networks. It prioritizes compact packet encoding, minimal overhead, composable routing options, and strict layer separation. Its small per-packet overhead, single-frame design, and lower protocol state requirements (no path tables, no mandatory announce propagation, no clock synchronization, no global packet hash cache) are designed with constrained hardware in mind.

Key tradeoffs:

  • Overhead: UMSH achieves 60–85% lower per-packet overhead than Reticulum (depending on MIC size), maximizing payload capacity within tight LoRa frame budgets.
  • Cryptographic overhead: UMSH’s SIV construction avoids transmitting a separate IV and requires no padding; Reticulum’s CBC mode (AES-256 only since v1.0.0) adds 17–32 bytes of IV and padding overhead per packet.
  • Routing flexibility: UMSH offers composable source routing, hybrid routing, and signal-quality filtering. Reticulum offers automatic next-hop routing via transport nodes, and on-network interface auto-discovery since v1.1.0.
  • Privacy model: Reticulum provides initiator anonymity by default (no source address), plus a network identity system for administrative trust domains. UMSH provides source addresses by default with opt-in privacy modes.
  • Multicast: UMSH supports multi-hop multicast. Reticulum’s group communication is currently single-hop only (multi-hop planned).
  • Replay protection: UMSH uses per-peer monotonic frame counters, which require a small amount of per-peer state but provide deterministic replay detection regardless of traffic volume. Reticulum uses a global packet hash cache, which requires no per-peer state but must be large enough to cover the replay window — a tradeoff that favors hosts with ample memory.
  • Scope: Reticulum is a complete network stack with reliable delivery, sessions, and application APIs. UMSH is a MAC layer with defined-but-separate application protocols, designed to carry arbitrary higher-layer content.
  • Implementation complexity: Reticulum’s richer protocol machinery (path tables, link establishment, announce propagation) raises the minimum implementation complexity. UMSH’s simpler MAC-layer model is more amenable to constrained implementations.

Test Vectors

This appendix contains byte-level packet examples. All values are hexadecimal, and multi-byte numeric fields are big-endian.

Conventions

The generated examples use fixed Ed25519 private keys so the appendix covers the full path from private key to public key to X25519 ECDH to packet bytes.

  • Node A private key: 1112 1314 1516 1718 191A 1B1C 1D1E 1F20 2122 2324 2526 2728 292A 2B2C 2D2E 2F30
  • Node A public key: ED54 A59F B1AC 3A51 2393 5136 2941 B868 E85A 60E3 D7B2 485D 8288 21DC 7A69 C279
    • Source hint: ED 54 A5
  • Node B private key: 3132 3334 3536 3738 393A 3B3C 3D3E 3F40 4142 4344 4546 4748 494A 4B4C 4D4E 4F50
  • Node B public key: 6C28 FD05 8C18 C88C 6CCE 2AF9 81D2 D11C 851B 123E D5B6 9B78 7677 3ED0 99EA 3F83
    • Destination hint: 6C 28 FD
  • Pairwise shared secret: 5ADD 834F C109 FAD5 2F04 1C5A F84A 7966 526D 364D 1895 AFFC D794 E044 F3A9 DB14
    • Derived from the two private keys via the implementation’s Ed25519-to-X25519 conversion and X25519 ECDH.
  • Channel key: 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A 5A5A
  • Derived channel identifier: B0 8D

FCF Bit Layout Reference

  7   6   5   4   3   2   1   0
+-------+-----------+---+---+---+
| VER   | PKT TYPE  | S | O | H |
+-------+-----------+---+---+---+

SCF Bit Layout Reference

  7   6   5   4   3   2   1   0
+---+-------+---+---------------+
| E |  MIC  | S |   RESERVED    |
+---+-------+---+---------------+

Example 1: Broadcast Beacon (S=0)

A minimal beacon with a 3-byte source hint and no payload.

FieldValueHex
FCFVER=3, TYPE=0 (broadcast), S=0, O=0, H=0C0
SRCNode A hintED 54 A5
C0 ED 54 A5

Total: 4 bytes.

Example 2: Broadcast Beacon (S=1)

A first-contact beacon carrying the sender’s full 32-byte public key.

FieldValueHex
FCFVER=3, TYPE=0 (broadcast), S=1, O=0, H=0C4
SRCNode A full keyED 54 A5 9F B1 AC 3A 51 23 93 51 36 29 41 B8 68 E8 5A 60 E3 D7 B2 48 5D 82 88 21 DC 7A 69 C2 79
C4 ED 54 A5 9F B1 AC 3A 51 23 93 51 36 29 41 B8
68 E8 5A 60 E3 D7 B2 48 5D 82 88 21 DC 7A 69 C2
79

Total: 33 bytes.

Example 3: Encrypted Unicast (S=0)

An encrypted unicast from Node A to Node B using source hints and frame counter 42.

FieldValueHex
FCFVER=3, TYPE=2 (unicast), S=0, O=0, H=0D0
DSTNode B hint6C 28 FD
SRCNode A hintED 54 A5
SCFE=1, MIC=3 (16-byte), S=0E0
Frame Counter4200 00 00 2A
PayloadEncrypted 48 65 6C 6C 6F ("Hello")4F A0 84 B2 92
MIC16 bytesEA 32 F4 91 09 E8 D4 E6 01 16 73 C1 5B 31 84 F0
D0 6C 28 FD ED 54 A5 E0 00 00 00 2A 4F A0 84 B2
92 EA 32 F4 91 09 E8 D4 E6 01 16 73 C1 5B 31 84
F0

Total: 33 bytes.

Example 4: Encrypted Unicast with Ack Requested (S=1)

A first-contact encrypted unicast from Node A to Node B requesting a MAC acknowledgement. The full 32-byte source key is included.

FieldValueHex
FCFVER=3, TYPE=3 (unicast ack-req), S=1, O=0, H=0DC
DSTNode B hint6C 28 FD
SRCNode A full keyED 54 A5 9F B1 AC 3A 51 23 93 51 36 29 41 B8 68 E8 5A 60 E3 D7 B2 48 5D 82 88 21 DC 7A 69 C2 79
SCFE=1, MIC=3 (16-byte), S=0E0
Frame Counter100 00 00 01
PayloadEncrypted 68 65 79 ("hey")68 CF 7B
MIC16 bytes96 3F CE BA 86 8C 92 96 DD E2 E5 0F 5B 54 42 3F
DC 6C 28 FD ED 54 A5 9F B1 AC 3A 51 23 93 51 36
29 41 B8 68 E8 5A 60 E3 D7 B2 48 5D 82 88 21 DC
7A 69 C2 79 E0 00 00 00 01 68 CF 7B 96 3F CE BA
86 8C 92 96 DD E2 E5 0F 5B 54 42 3F

Total: 60 bytes.

Example 5: Encrypted Multicast (E=1)

An encrypted multicast from Node A on channel B08D. The encrypted body contains the source hint followed by the plaintext payload.

FieldValueHex
FCFVER=3, TYPE=4 (multicast), S=0, O=0, H=0E0
CHANNELDerived channel identifierB0 8D
SCFE=1, MIC=3 (16-byte), S=0E0
Frame Counter500 00 00 05
Encrypted dataENCRYPT(`SRC
MIC16 bytes30 35 87 B0 01 F2 17 98 7A 08 1C F5 6E DC 85 36
E0 B0 8D E0 00 00 00 05 9B B6 F2 5E C7 DA 95 D2
30 35 87 B0 01 F2 17 98 7A 08 1C F5 6E DC 85 36

Total: 32 bytes.

Example 6: Authenticated Multicast (E=0)

An authenticated but unencrypted multicast from Node A carrying payload type 03 followed by "Hello".

FieldValueHex
FCFVER=3, TYPE=4 (multicast), S=0, O=0, H=0E0
CHANNELDerived channel identifierB0 8D
SCFE=0, MIC=3 (16-byte), S=060
Frame Counter300 00 00 03
SRCNode A hintED 54 A5
Payload`03
MIC16 bytes7C 9A 9C 4B C0 DD B4 96 65 6A 9D F1 5F 5B 9C C4
E0 B0 8D 60 00 00 00 03 ED 54 A5 03 48 65 6C 6C
6F 7C 9A 9C 4B C0 DD B4 96 65 6A 9D F1 5F 5B 9C
C4

Total: 33 bytes.

Example 7: Encrypted Unicast with Options and Flood Hops

An encrypted unicast with a region code option, an empty trace-route option, and flood hop limit 4.

Options encoding:

OptionNumberDeltaLengthEncoding
Trace Route22020
Region Code119292 then value 78 53
End markerFF
FieldValueHex
FCFVER=3, TYPE=2 (unicast), S=0, O=1, H=1D3
OptionsTrace route + region code + end marker20 92 78 53 FF
FHOPSFHOPS_REM=4, FHOPS_ACC=040
DSTNode B hint6C 28 FD
SRCNode A hintED 54 A5
SCFE=1, MIC=3 (16-byte), S=0E0
Frame Counter1000 00 00 0A
PayloadEncrypted 68 65 79 ("hey")AB 87 DC
MIC16 bytes83 07 00 18 AA 22 DB FC 93 86 B8 D1 F0 74 85 39
D3 20 92 78 53 FF 40 6C 28 FD ED 54 A5 E0 00 00
00 0A AB 87 DC 83 07 00 18 AA 22 DB FC 93 86 B8
D1 F0 74 85 39

Total: 37 bytes.

Example 8: Blind Unicast (S=0)

A blind unicast on channel B08D. The destination hint and source hint are encrypted together in ENC_DST_SRC, while the payload is encrypted with the blind-unicast payload keys.

FieldValueHex
FCFVER=3, TYPE=6 (blind unicast), S=0, O=0, H=0F0
CHANNELDerived channel identifierB0 8D
SCFE=1, MIC=3 (16-byte), S=0E0
Frame Counter700 00 00 07
ENC_DST_SRCENCRYPT(`DST
ENC_PAYLOADENCRYPT("Hello")1A 3B 73 CD 1B
MIC16 bytes42 9D E6 DD 47 AD 3A 6B E5 FF 89 BB 16 15 E8 7A
F0 B0 8D E0 00 00 00 07 9C A3 DF 8D F8 A6 1A 3B
73 CD 1B 42 9D E6 DD 47 AD 3A 6B E5 FF 89 BB 16
15 E8 7A

Total: 35 bytes.