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

Comparison with MeshCore

This section compares UMSH with MeshCore, a LoRa mesh protocol with similar goals. The comparison is based on MeshCore firmware v1.17.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 source and destination hashes in regular encrypted unicast payloads, while routing paths support configurable 1-, 2-, or 3-byte node hashes. A dedicated ANON_REQ packet type 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-type code points (13 assigned; via 4-bit field)
Routing infoCoAP-style options (source route, trace route, region, RSSI/SNR thresholds)Path field (up to 64 bytes; 1–3-byte hashes), 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-256-CTR (AES-SIV, RFC 5297)AES-128-ECB
AuthenticationS2V (AES-CMAC), 4/8/12/16-byte MICHMAC-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 32-byte encryption and 32-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 (160 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-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.

Region-Scoped Flooding

Although both protocols carry a 16-bit value to scope flood forwarding, those values are derived and evaluated very differently.

An UMSH region code is a stable two-byte identifier for a region. It is derived from the configured region name according to the Region Code Encoding, independently of any particular packet. A sender places one or more region-code options in the routing metadata, and a repeater decides whether to forward by comparing those values directly with its configured region codes. The payload remains opaque: changing the payload does not change the region code or require the repeater to perform any payload-dependent calculation.

A MeshCore transport code is packet-specific rather than a stable identifier for a region. For a public region, MeshCore first derives a 16-byte transport key from the region name: the first 16 bytes of SHA-256 over the #-prefixed name. Despite its name, this is not an encryption key; anyone who knows the public region name can derive it. For each packet, the transport code is the first 16 bits of:

HMAC-SHA256(transport_key, payload_type || payload)

MeshCore remaps the reserved results 0x0000 and 0xFFFF to 0x0001 and 0xFFFE, respectively. The routing path and transport-code fields are not included in the HMAC input, so repeaters can extend the path without changing the code. Changing either the payload type or payload bytes does change the code.

When a MeshCore repeater receives a transport-scoped packet, it iterates through the region entries allowed for that routing mode, obtains up to four candidate transport keys for each entry, recomputes the HMAC for each candidate, and compares the result with the packet’s first transport code. It forwards only after finding a match. Thus, MeshCore does not decrypt the payload to make this decision, but its forwarding layer does cryptographically process the payload once per candidate key. The work grows with both the number of candidate keys and the payload length. UMSH instead performs fixed two-byte comparisons against routing metadata.

This payload-dependent transport-code mechanism was introduced in MeshCore commit 03fc9490.

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)Yes (no cleartext source; claimed sender name is encrypted)
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-membersGroup sender and content concealed; no blind-unicast equivalent

Both protocols conceal the claimed sender of encrypted group traffic from observers who do not possess the channel key. UMSH encrypts the source address inside the multicast ciphertext. MeshCore group packets have no cleartext source field and place the self-asserted sender name inside the ciphertext. MeshCore does not cryptographically authenticate that group sender name and does not define an equivalent of UMSH blind unicast, which conceals both unicast endpoints from non-members.

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 S2V MICChannel-key-based HMAC (2-byte MAC)
Sender authenticationNot cryptographically verified (symmetric key limitation)Not cryptographically verified (same limitation)
Source privacySource encrypted when encryption enabledNo cleartext source; claimed sender name encrypted

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

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; uses non-regressing UNIX timestamp values 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 uses UNIX timestamp values in several protocol-critical roles:

  • Replay protection: MeshCore uses a fixed-size circular buffer of packet hashes (160 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. For an already-known contact, the receiver accepts an advertisement only if its timestamp is greater than the last accepted value from that contact.
  • Login sequencing: Login handling compares the sender’s timestamp with the last accepted value from that sender.

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 a clock 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 160-entry buffer can wrap quickly, allowing replayed packets to be accepted after the original entry is evicted. MeshCore’s advertisement and login checks require a sender’s timestamp values not to regress relative to previously accepted state. Clock reset or rollback can therefore cause valid traffic to be rejected, but these checks do not require nodes’ clocks to be accurate or synchronized with one another.

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 a CTR IV derived from the transmitted MIC) and then computing S2V 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 a packet sent to a different channel collides with one of the receiver’s configured channel identifiers and triggers an unnecessary verification attempt. 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 use routing metadata, duplicate suppression, and configured forwarding policy. In particular, region filtering consists of comparing the packet’s fixed two-byte region-code options with pre-derived local codes; it does not require an HMAC over the payload for every configured region. 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. MeshCore does not drop a packet merely because its received signal quality is poor, but that does not mean every repeater forwards every flood. Forwarding remains subject to path and duplicate limits, configured region policy, and transport-code matching. For a transport-scoped packet, a repeater performs the payload HMAC described above for each candidate region key and drops the packet if none match. Eligible repeaters still lack UMSH’s explicit sender-selected signal-quality thresholds, which can prevent retransmission over weak links entirely.

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, leaving application-level retries as the only recovery mechanism on MeshCore.

  • Replay protection does not depend on clocks. MeshCore uses non-regressing UNIX timestamp values for advertisement freshness and login sequencing, so a clock reset or rollback can cause valid advertisements or login attempts to be rejected until the timestamp advances beyond the previously accepted value. The clocks do not need to be accurate or synchronized. UMSH is timestamp-free at the MAC layer—its replay protection instead uses monotonic frame counters.

  • 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 160-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.