<?xml version="1.0" encoding="UTF-8"?>
<?rfc toc="yes"?>
<?rfc sortrefs="yes"?>
<?rfc symrefs="yes"?>
<?rfc compact="yes"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     category="exp"
     docName="draft-sharma-oepb-00"
     ipr="trust200902"
     submissionType="IETF"
     version="3">
<front>
  <title abbrev="OEPB">Offline Emergency Peer-to-Peer Broadcast Protocol</title>
  <seriesInfo name="Internet-Draft" value="draft-sharma-oepb-00"/>
  <author fullname="Karan Sharma" initials="K" surname="Sharma">
    <organization>Independent</organization>
    <address>
      <postal><country>India</country></postal>
      <email>karansharmaresearch@gmail.com</email>
    </address>
  </author>
  <date year="2026" month="June" day="9"/>
  <keyword>emergency</keyword>
  <keyword>disaster</keyword>
  <keyword>offline</keyword>
  <keyword>peer-to-peer</keyword>
  <keyword>mesh</keyword>
  <keyword>bluetooth</keyword>
  <keyword>wifi-direct</keyword>
  <keyword>trickle</keyword>
  <abstract>
    <t>This document specifies the Offline Emergency Peer-to-Peer Broadcast Protocol (OEPB). OEPB is a transport-agnostic overlay protocol for distributing authenticated emergency alerts over short-range peer-to-peer radios in infrastructure-absent environments. Its principal contributions are: (1) a Transport Abstraction Layer (TAL) that presents heterogeneous radio technologies (BLE, Wi-Fi Direct, LoRa, IEEE 802.15.4) as a uniform 256-byte datagram interface to upper layers; (2) application of the Trickle algorithm (RFC 6206) to content-dissemination suppression in a multi-class broadcast context, distinct from its original routing-consistency application in RPL/6LoWPAN; (3) an emergency-semantic five-class Weighted Fair Queuing taxonomy calibrated to disaster-triage urgency; and (4) a trust architecture that deliberately separates relay forwarding from signature verification, preserving life-safety reachability for unauthenticated SOS messages. To the authors' knowledge, no prior open specification addresses authenticated, amplification-resistant emergency broadcast in a transport-agnostic manner across heterogeneous short-range radios; Section 1.1 surveys prior systems and standards. A companion document defines the Transport Binding Profile for Bluetooth Low Energy.</t>
  </abstract>
</front>
<middle>
  <section anchor="introduction" title="Introduction" numbered="true">
    <t>Severe emergencies frequently disable centralized communication infrastructure. Disseminating evacuation orders or distress signals becomes unreliable when cellular networks, public-safety answering points, or internet backbones fail.</t>
    <t>Modern personal devices possess short-range, peer-to-peer radio capabilities (Bluetooth Low Energy, Wi-Fi Direct, LoRa, IEEE 802.15.4). Prior systems have demonstrated the viability of smartphone mesh networking for emergency communication <xref target="SERVAL"/>, but no open, transport-agnostic standard has been defined that addresses amplification-resistant authenticated broadcast across heterogeneous short-range radios.</t>
    <t>This document introduces OEPB: a Best-Effort Delivery overlay protocol for offline and infrastructure-degraded environments. OEPB defines:</t>
    <ul>
      <li><t>A canonical 256-byte wire format with cryptographic integrity binding, sized to fit within a single BLE 5.x extended advertisement or Wi-Fi Direct frame; on BLE 4.x (31-byte advertisement payload) the TAL provides transparent L2 fragmentation and reassembly.</t></li>
      <li><t>A Transport Abstraction Layer (TAL) that unifies BLE, Wi-Fi Direct, LoRa, and IEEE 802.15.4 under a single datagram interface, enabling the same upper-layer logic to operate without modification across radio technologies.</t></li>
      <li><t>Probabilistic forwarding suppression via the Trickle algorithm <xref target="RFC6206"/>, applied to content dissemination rather than routing consistency, with constants characterized through discrete-event simulation across 10-200-node topologies under both lossless and lossy link conditions (Section 6.1).</t></li>
      <li><t>A five-class message taxonomy with Weighted Fair Queuing calibrated to emergency-triage semantics (Section 4).</t></li>
      <li><t>A trust architecture that separates relay forwarding from signature verification: relay nodes forward without cryptographic verification, preserving life-safety reachability while allowing terminals to authenticate messages (Section 9).</t></li>
      <li><t>A strict deduplication cache with time-based and capacity-based eviction preventing replay and routing loops (Section 8).</t></li>
    </ul>
    <t>While prior research exists in Delay-Tolerant Networking <xref target="RFC5050"/> and the Bundle Protocol <xref target="RFC9171"/>, OEPB focuses specifically on real-time emergency broadcasts. It prioritizes extreme payload compactness and deterministic Trickle suppression over the store-carry-forward semantics of DTN. Section 1.1 discusses the relationship to prior implementations and standards in depth.</t>
    <section anchor="related-work" title="Related Work" numbered="true">
      <section anchor="delay-tolerant-networking-dtn" title="Delay-Tolerant Networking (DTN)" numbered="true">
        <t>The Bundle Protocol <xref target="RFC5050"/><xref target="RFC9171"/> provides a store-carry-forward architecture for networks with intermittent connectivity and long propagation delays. OEPB differs fundamentally in its delivery model: OEPB targets real-time broadcast (sub-100ms delivery in urban topologies per Section 6.1) rather than asynchronous delivery across custody-transfer chains. DTN's per-bundle overhead and custody negotiation are incompatible with the 256-byte MTU constraint and sub-100ms latency targets of OEPB.</t>
      </section>
      <section anchor="serval-mesh" title="Serval Mesh" numbered="true">
        <t>The Serval Project <xref target="SERVAL"/> demonstrated fully functional smartphone mesh networking for emergency communication using a custom protocol (Serval DNA) over Wi-Fi ad-hoc networks. Serval established the foundational viability of the peer-to-peer emergency mesh model and was deployed in real disaster-response contexts. OEPB differs in three respects: (1) Serval targets a single radio technology (Wi-Fi ad-hoc), while OEPB defines a TAL that abstracts BLE, Wi-Fi Direct, LoRa, and IEEE 802.15.4 under one interface; (2) Serval does not define a Trickle-equivalent amplification-suppression mechanism; and (3) the Serval DNA protocol is not an open IETF specification, which limits interoperability across independent implementations. OEPB provides the open-standard complement to the proof-of-concept demonstrated by Serval.</t>
      </section>
      <section anchor="bluetooth-mesh-profile" title="Bluetooth Mesh Profile" numbered="true">
        <t>The Bluetooth Mesh Profile Specification <xref target="BT-MESH"/> defines a managed-flooding mesh over Bluetooth Low Energy, including relay behavior, network keys, application keys, and publication/subscription addressing. OEPB differs in four key respects: (1) Bluetooth Mesh is BLE-only; OEPB's TAL supports heterogeneous radio technologies; (2) Bluetooth Mesh uses a fixed relay TTL mechanism without an adaptive suppression algorithm equivalent to Trickle; (3) Bluetooth Mesh requires prior provisioning of devices into a managed network, which is incompatible with the spontaneous, uncoordinated participation model required for disaster response; and (4) Bluetooth Mesh is a Bluetooth SIG specification, not an open IETF standard. Bluetooth Mesh is a suitable choice for pre-provisioned IoT sensor networks; OEPB targets ad-hoc participation by arbitrary devices with no prior coordination.</t>
      </section>
      <section anchor="firechat-and-bridgefy" title="FireChat and Bridgefy" numbered="true">
        <t>Commercial applications including FireChat (Open Garden, 2014) and Bridgefy demonstrated peer-to-peer messaging over BLE and Wi-Fi Direct without infrastructure, with documented real-world use in disaster and civil-emergency scenarios. Both applications use proprietary, undisclosed protocols; neither provides cryptographic authority authentication; and neither defines formal priority queuing or adaptive suppression mechanisms. OEPB provides an open, implementable specification addressing all three gaps.</t>
      </section>
      <section anchor="meshtastic" title="Meshtastic" numbered="true">
        <t>The Meshtastic project <xref target="MESHTASTIC"/> provides an open-source mesh communication platform over LoRa radios, implementing hop-limited flooding with basic MsgID deduplication. OEPB differs in that it defines a radio-agnostic TAL (not LoRa-specific), specifies Trickle-based amplification suppression rather than time-based rebroadcast, defines a formal five-class priority taxonomy, and provides a cryptographic authority trust model supporting pre-distributed root anchors.</t>
      </section>
      <section anchor="aprs-automatic-packet-reporting-system" title="APRS (Automatic Packet Reporting System)" numbered="true">
        <t>APRS <xref target="APRS"/> is a long-established amateur radio protocol for distributing real-time geographic and status information across an uncoordinated mesh of digipeaters operating on 144.390 MHz (North America) and regional equivalents. APRS has been operationally deployed in exactly the disaster scenarios OEPB targets, including hurricane response and search-and-rescue coordination. OEPB differs from APRS in three respects: (1) APRS requires licensed amateur radio hardware and operator licensing, while OEPB targets consumer smartphones with BLE and Wi-Fi Direct; (2) APRS uses unencrypted, unauthenticated AX.25 frames with no cryptographic trust model or authority hierarchy; and (3) APRS implements a simple digipeater rebroadcast mechanism with no priority queuing or Trickle-equivalent amplification suppression. OEPB may be considered the smartphone-native successor to the APRS model, extending its emergency communication concept to unlicensed consumer hardware with cryptographic authentication and amplification resistance.</t>
      </section>
      <section anchor="disaster-radio" title="Disaster Radio" numbered="true">
        <t>The Disaster Radio project <xref target="DISASTER-RADIO"/> provides an open-source mesh communication platform over LoRa radios specifically targeting infrastructure-absent emergency communication scenarios. Like Meshtastic, Disaster Radio implements hop-limited flooding but does not define Trickle-equivalent amplification suppression, a formal priority taxonomy, or a cryptographic authority trust model. OEPB extends this class of work by adding the TAL abstraction for multi-radio support and the trust architecture required for authenticated emergency directives at authority level.</t>
      </section>
      <section anchor="epidemic-routing" title="Epidemic Routing" numbered="true">
        <t>Epidemic routing <xref target="EPIDEMIC"/> and related gossip protocols achieve probabilistic delivery in highly partitioned networks through pairwise message exchange. OEPB targets broadcast rather than unicast delivery, and uses Trickle suppression to guarantee a bounded retransmission rate -- a property epidemic routing does not provide without additional mechanisms. Epidemic routing also does not define a priority taxonomy or authority trust model.</t>
      </section>
      <section anchor="ieee-802-11s-wi-fi-mesh" title="IEEE 802.11s (Wi-Fi Mesh)" numbered="true">
        <t>IEEE 802.11s <xref target="IEEE80211S"/> defines a Layer 2 mesh standard over Wi-Fi using the Hybrid Wireless Mesh Protocol (HWMP) for path selection between mesh portals. IEEE 802.11s is an infrastructure mesh protocol: it establishes state-bearing paths and requires association and path-establishment overhead. OEPB operates as a stateless broadcast overlay with no path state and no association requirement, enabling immediate participation by any device within radio range with no prior network membership.</t>
      </section>
    </section>
  </section>
  <section anchor="terminology" title="Terminology" numbered="true">
    <t>The key words &quot;MUST&quot;, &quot;MUST NOT&quot;, &quot;REQUIRED&quot;, &quot;SHALL&quot;, &quot;SHALL NOT&quot;, &quot;SHOULD&quot;, &quot;SHOULD NOT&quot;, &quot;RECOMMENDED&quot;, &quot;NOT RECOMMENDED&quot;, &quot;MAY&quot;, and &quot;OPTIONAL&quot; in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
    <t>The following terms are used in this document:</t>
    <ul>
      <li><t><strong>Node</strong>: A device implementing the OEPB protocol stack.</t></li>
      <li><t><strong>Broadcaster</strong>: A node that originates OEPB messages.</t></li>
      <li><t><strong>Relay</strong>: A node that forwards OEPB messages it did not originate.</t></li>
      <li><t><strong>TAL</strong>: Transport Abstraction Layer.</t></li>
      <li><t><strong>MIL</strong>: Mesh Intelligence Layer.</t></li>
      <li><t><strong>MsgID</strong>: 16-byte Message ID field, used as the primary deduplication key.</t></li>
      <li><t><strong>Trickle Interval</strong>: The time window during which a node counts received copies of a message before deciding whether to suppress its own transmission.</t></li>
    </ul>
  </section>
  <section anchor="architecture" title="Architecture" numbered="true">
    <t>OEPB restricts routing logic to an overlay abstraction, offloading physical transmission to defined Transport Bindings.</t>
    <section anchor="transport-abstraction-layer-tal" title="Transport Abstraction Layer (TAL)" numbered="true">
      <t>The TAL manages physical-layer state transitions and exposes a uniform datagram interface to the Mesh Intelligence Layer. To support OEPB, the TAL MUST expose a minimum datagram MTU of 256 bytes to the MIL. Transports that cannot natively deliver a 256-byte MTU (e.g., standard BLE 4.0 with a 20-byte ATT payload) MUST implement fragmentation and reassembly at Layer 2. Transport-specific framing is defined in separate Transport Binding Profile documents. A companion document <xref target="OEPB-BLE"/> defines the Bluetooth Low Energy binding, including the advertising mode, the L2 fragmentation and reassembly scheme required to meet the 256-byte MTU over BLE 4.x legacy advertising, and the optimized single-frame path for BLE 5.x with Data Length Extension. Binding profiles for Wi-Fi Direct, LoRa, and IEEE 802.15.4 are future work; Section 11.3 discusses the platform constraints any Wi-Fi Direct binding must address.</t>
      <t>TAL implementations that perform L2 fragment reassembly MUST apply a reassembly timeout: any partially-received fragment set for which the complete packet has not been received within <tt>MAX_FRAG_TIMEOUT = 30 seconds</tt> of the first fragment's arrival MUST be discarded and all associated reassembly buffers released. This prevents memory exhaustion attacks where an attacker sends only the first fragment of a large packet and withholds subsequent fragments indefinitely. Implementations on LoRa or other low-data-rate transports with duty-cycle constraints SHOULD increase <tt>MAX_FRAG_TIMEOUT</tt> to at least 60 seconds to accommodate the transport's time-on-air budget.</t>
    </section>
    <section anchor="mesh-intelligence-layer-mil" title="Mesh Intelligence Layer (MIL)" numbered="true">
      <t>The MIL executes all core overlay routing policy:</t>
      <ul>
        <li><t>Trickle algorithm <xref target="RFC6206"/> for probabilistic suppression.</t></li>
        <li><t>Weighted Fair Queuing (WFQ) across five message classes.</t></li>
        <li><t>MsgID-keyed deduplication cache with LRU eviction.</t></li>
        <li><t>Multi-radio bridging for heterogeneous-radio nodes.</t></li>
        <li><t>Rate limiting: The MIL applies per-transport-source-address rate limiting (absolute intake budget) for all packets. Per-public-key-fingerprint rate limiting for authenticated packets is an Application Layer responsibility, because the sender's public key is not present in the fixed header and can only be resolved by the Application Layer trust store (see Section 8.2).</t></li>
      </ul>
      <t>The MIL operates a single logical deduplication namespace spanning all transport bindings. A packet accepted as novel by the MIL is broadcast on all active Transport Bindings.</t>
    </section>
    <section anchor="application-layer" title="Application Layer" numbered="true">
      <t>The Application Layer parses CBOR <xref target="RFC8949"/> payload blocks and maps data structures to end-user interfaces. It is responsible for:</t>
      <ul>
        <li><t>Constructing outbound OEPB packets including the Ed25519 signature.</t></li>
        <li><t>Setting the initial TTL value.</t></li>
        <li><t>Presenting received messages with appropriate trust indicators.</t></li>
      </ul>
    </section>
    <section anchor="geographic-scope-design" title="Geographic Scope Design" numbered="true">
      <t>Geographic scope information is intentionally absent from the OEPB v1 fixed header. Geographic scope filtering is an Application Layer function: terminal nodes SHOULD filter displayed messages by geographic relevance using coordinate fields present in ALERT, EVAC, and SOS message payloads. Relay nodes in the MIL MUST NOT drop packets based on geographic scope -- relay nodes may lack location awareness entirely, and encoding a geographic field in the 40-byte header would consume MTU budget required for cryptographic material.</t>
      <t>This design mirrors the trust architecture: just as relay nodes forward without signature verification (preserving life-safety reachability for unauthenticated SOS), relay nodes also forward without geographic verification (preserving mesh coverage across heterogeneous deployments). Geographic relevance is a presentation-layer concern, not a forwarding concern.</t>
      <t>Implementations MAY add a geo_scope field to the header in a future protocol extension to enable relay-level geographic suppression in high-density homogeneous deployments. Such an extension is out of scope for OEPB v1.</t>
    </section>
  </section>
  <section anchor="routing-queue-and-fairness" title="Routing Queue and Fairness" numbered="true">
    <t>OEPB restricts propagation to five message classes managed via Weighted Fair Queuing (WFQ). Strict priority queuing would cause absolute starvation of lower-priority classes under heavy high-priority load. WFQ allocates transmission scheduling ratios proportionately:</t>
    <table><thead><tr>
      <th>Priority</th>
      <th>Type</th>
      <th>Value</th>
      <th>WFQ Ratio</th>
      <th>Rationale</th>
    </tr></thead><tbody>
    <tr>
      <td>1 (Highest)</td>
      <td>SOS</td>
      <td>0x01</td>
      <td>50%</td>
      <td>Immediate individual life threat; latency is critical</td>
    </tr>
    <tr>
      <td>2</td>
      <td>EVAC</td>
      <td>0x03</td>
      <td>30%</td>
      <td>Authority-issued mass evacuation; broad impact</td>
    </tr>
    <tr>
      <td>3</td>
      <td>ALERT</td>
      <td>0x02</td>
      <td>15%</td>
      <td>Verified hazard warning; important but less urgent than EVAC</td>
    </tr>
    <tr>
      <td>4</td>
      <td>AUTH</td>
      <td>0x05</td>
      <td>3%</td>
      <td>Trust infrastructure; system overhead</td>
    </tr>
    <tr>
      <td>5 (Lowest)</td>
      <td>INFO</td>
      <td>0x04</td>
      <td>2%</td>
      <td>Situational awareness; best-effort only</td>
    </tr>
    </tbody></table>
    <t>Note: SOS holds the highest scheduling ratio because individual life-threatening distress requires the lowest possible delivery latency. EVAC, while higher in authority-level, covers populations that can tolerate seconds of additional latency and is typically issued by signed authority nodes with more reliable transmission resources.</t>
    <t>These ratios represent the general-case deployment where individual SOS events and authority-issued EVAC are not simultaneously overloaded. Implementations operating in mass-casualty scenarios -- where hundreds of simultaneous SOS signals risk delaying EVAC packets that reach larger populations -- MAY locally override the WFQ weights. Any such override MUST NOT reduce SOS below 20% or reduce EVAC below 20% of total scheduling bandwidth. The default weights MUST be restored when the overload condition clears.</t>
    <t>Message class definitions:</t>
    <ul>
      <li><t><strong>SOS (0x01)</strong>: Immediate life-threatening emergency from an individual. Contains geographic coordinates. MAY be unauthenticated.</t></li>
      <li><t><strong>EVAC (0x03)</strong>: Evacuation directive from a verified authority. SHOULD be signed.</t></li>
      <li><t><strong>ALERT (0x02)</strong>: Hazard warning from a verified authority. SHOULD be signed.</t></li>
      <li><t><strong>AUTH (0x05)</strong>: Trust infrastructure. Carries authority key announcements and Certificate Revocation Lists (CRLs). MUST be signed.</t></li>
      <li><t><strong>INFO (0x04)</strong>: Situational awareness data. MAY be unsigned. Assigned lowest scheduling priority.</t></li>
    </ul>
  </section>
  <section anchor="packet-structure" title="Packet Structure" numbered="true">
    <t>OEPB mandates Network Byte Order (Big-Endian) for all multi-byte numeric fields.</t>
    <artwork><![CDATA[
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Version    |   Msg Type    |     TTL       |   Hop Count   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Timestamp (High 32 bits)                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Timestamp (Low 32 bits)                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Nonce (High 32 bits)                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Nonce (Low 32 bits)                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                    Message ID (16 bytes)                      |
|                                                               |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Payload Length (16)   |           Flags (16)          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
~                  Variable Payload (CBOR-encoded)              ~
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                  Ed25519 Signature (64 bytes)                 |
|                      (present if SIGNED flag set)             |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork>
    <section anchor="sizing-constraints" title="Sizing Constraints" numbered="true">
      <artwork><![CDATA[
Fixed Header = 4 + 8 + 8 + 16 + 4 = 40 bytes
Ed25519 Signature                  = 64 bytes
Total Overhead (signed packet)     = 104 bytes

Given minimum Transport MTU of 256 bytes:
MAX_PAYLOAD_SIZE = 256 - 104 = 152 bytes
]]></artwork>
      <t>Unsigned packets have a maximum payload of 216 bytes (256 - 40). However, implementations SHOULD use the signed-packet budget of 152 bytes as the safe default to allow signatures to be added without restructuring.</t>
      <t>Payload sizes exceeding <tt>MAX_PAYLOAD_SIZE</tt> for the applicable packet type MUST cause the parser to silently discard the packet.</t>
    </section>
    <section anchor="field-definitions" title="Field Definitions" numbered="true">
      <t><strong>Version</strong> (1 byte): Assigned 0x01. Nodes receiving an unknown version value MUST silently discard the packet. Version 1 establishes no backward compatibility obligations with future versions.</t>
      <t><strong>Msg Type</strong> (1 byte): Identifies the message class. Valid values are 0x01-0x05. Packets carrying unknown or reserved Msg Type values MUST be silently discarded and MUST NOT be forwarded.</t>
      <t><strong>TTL</strong> (1 byte): Hop limit. Decremented by 1 on each forward. The recommended initial value is <tt>DEFAULT_TTL = 10</tt>. Nodes MAY set initial values up to <tt>MAX_TTL = 15</tt>. Nodes MUST silently discard packets received with TTL = 0 (before decrement). Nodes MUST silently discard packets received with TTL &gt; MAX_TTL (15) on ingress; such values indicate a malformed or maliciously crafted packet. TTL is mutable and MUST NOT be included in the signature input (see Section 5.3).</t>
      <t><strong>Hop Count</strong> (1 byte): Incremented by 1 on each forward. Retained to supply Application Layer heuristics such as spatial proximity estimation. Nodes MUST silently discard packets received with Hop Count &gt;= MAX_HOPCOUNT = 15. Hop Count is mutable and MUST NOT be included in the signature input.</t>
      <t><strong>Timestamp</strong> (8 bytes): 64-bit unsigned integer, UNIX epoch seconds. Nodes MUST tolerate highly unsynchronized clocks; the Timestamp field is used for cache eviction velocity relative to the receiving node's local clock, not for absolute event ordering. See Section 8 for expiration semantics.</t>
      <t><strong>Nonce</strong> (8 bytes): 64-bit pseudo-random value generated fresh for each new message. Combined with the Timestamp, the Nonce provides a cryptographically unique sequence number, allowing identical payloads originating simultaneously to produce distinct Message IDs.</t>
      <t><strong>Message ID</strong> (16 bytes): Primary deduplication key. Computed deterministically from immutable packet fields prior to signature generation. See Section 5.3 for the canonical construction.</t>
      <t><strong>Payload Length</strong> (2 bytes): Length in bytes of the Variable Payload field. A value of 0 is valid for message types that carry no payload data.</t>
      <t><strong>Flags</strong> (2 bytes): Bit field controlling packet interpretation and forwarding behavior. See Section 5.5 for bit assignments. Bits not assigned in this specification are Reserved. Reserved bits MUST be set to zero on transmission. Reserved bits MUST be ignored on reception.</t>
      <t><strong>Variable Payload</strong> (variable): CBOR-encoded <xref target="RFC8949"/> message-type-specific data. Payload schemas are defined per message type in Section 5.4.</t>
      <t><strong>Ed25519 Signature</strong> (64 bytes, conditional): Present if and only if the SIGNED flag bit (bit 0 of Flags) is set. Covers the canonical signature input defined in Section 5.3. Absent for unsigned messages.</t>
    </section>
    <section anchor="cryptographic-construction" title="Cryptographic Construction" numbered="true">
      <section anchor="message-id-computation" title="Message ID Computation" numbered="true">
        <t>The Message ID is computed prior to and independently of signature generation, binding all immutable packet fields:</t>
        <artwork><![CDATA[
MsgID = Truncate_128( SHA-256(
    Version        ||
    Msg_Type       ||
    Timestamp      ||
    Nonce          ||
    Payload_Length ||
    Flags          ||
    Payload
))
]]></artwork>
        <t>The Truncate_128 function retains the first 16 bytes of the SHA-256 output. TTL and Hop Count are excluded because they are mutable relay fields. The signature is excluded to avoid a circular dependency (MsgID must be finalized before signing).</t>
        <t>Implementations MUST compute the MsgID over the same byte encoding used in the wire format (network byte order).</t>
      </section>
      <section anchor="cbor-payload-canonicalization" title="CBOR Payload Canonicalization" numbered="true">
        <t>Originators MUST serialize CBOR payloads using Deterministic Encoding as specified in RFC 8949 Section 4.2.1 (also called Core Deterministic Encoding). This ensures a unique byte-string representation for any given semantic payload value, which in turn ensures a unique MsgID for each distinct logical message. A non-deterministic originator that emits two differently-encoded CBOR representations of the same payload would produce two different MsgIDs, causing both to propagate through the mesh as novel messages rather than deduplicating.</t>
      </section>
      <section anchor="signature-input" title="Signature Input" numbered="true">
        <t>The Ed25519 algorithm <xref target="RFC8032"/> signs the following exact byte concatenation:</t>
        <artwork><![CDATA[
Signature_Input = Version   ||
                  Msg_Type  ||
                  Timestamp ||
                  Nonce     ||
                  MsgID     ||
                  Payload_Length ||
                  Flags     ||
                  Payload
]]></artwork>
        <t>TTL and Hop Count are excluded. This construction ensures that the signature remains valid as the packet traverses relay nodes that decrement TTL and increment Hop Count.</t>
      </section>
      <section anchor="strict-ed25519-scalar-verification" title="Strict Ed25519 Scalar Verification" numbered="true">
        <t>Implementations MUST perform strict scalar verification per RFC 8032, Section 5.1.7: the scalar component S of any received Ed25519 signature MUST satisfy S &lt; L, where L is the curve group order (L = 2^252 + 27742317777372353535851937790883648493). Signatures where S &gt;= L MUST be silently rejected.</t>
        <t>Without this check, an adversary can produce a non-canonical but mathematically equivalent variant of a legitimate signature by computing S' = S + L. The S' variant has different bytes than S but verifies successfully against the same public key and message. Because the two variants produce different raw packet bytes, a node that keys its deduplication state on the full packet bytes rather than the MsgID would treat the variant as a novel packet, re-entering the Trickle scheduling path and enabling indefinite re-circulation of the same logical message as distinct wire-level packets. See Section 7 for the normative requirement that the deduplication cache keys exclusively on MsgID.</t>
        <t>Relay nodes that do not perform signature verification are not affected by this requirement; they forward without inspecting the signature bytes. The strict scalar check is an Application Layer responsibility performed at final trust presentation.</t>
      </section>
    </section>
    <section anchor="cbor-payload-schemas-cddl" title="CBOR Payload Schemas (CDDL)" numbered="true">
      <t>All coordinate fields MUST use Signed 32-bit integers encoding WGS84 microdegrees. The valid range for latitude microdegrees is [-90,000,000, 90,000,000] and for longitude microdegrees is [-180,000,000, 180,000,000].</t>
      <t>Note on CDDL coordinate constraints: the <tt>.size 4</tt> operator constrains the byte length of the serialized CBOR integer but does NOT constrain the numeric value. A value such as 2,000,000,000 is byte-length-valid but geographically impossible. The schemas below use the CDDL range operator <tt>..</tt> to enforce value bounds directly. Implementations MUST reject payloads where latitude or longitude values fall outside the stated geographic range.</t>
      <sourcecode type="cddl"><![CDATA[
; SOS: Individual distress signal with geographic location
SOS_Payload = {
    1: -90000000..90000000,    ; latitude (WGS84, microdeg)
    2: -180000000..180000000,  ; longitude (WGS84, microdeg)
    ? 3: uint .size 4,         ; accuracy_meters (uint32)
    ? 4: uint .size 1,         ; emergency_code (uint8)
    ? 5: tstr .size (0..40),   ; short_text (UTF-8, <= 40 B)
}

; ALERT: Hazard warning from verified authority
ALERT_Payload = {
    1: uint .size 2,           ; alert_code (uint16)
    2: tstr .size (0..60),     ; short_text (UTF-8, <= 60 B)
    ? 3: uint .size 4,         ; expires_at (uint32, Unix epoch)
    ? 4: -90000000..90000000,  ; ref_latitude (WGS84, microdeg)
    ? 5: -180000000..180000000, ; ref_longitude (WGS84, microdeg)
}

; EVAC: Evacuation directive from verified authority
EVAC_Payload = {
    1: uint .size 2,           ; evac_code (uint16)
    2: tstr .size (0..60),     ; short_text (UTF-8, <= 60 B)
    ? 3: bstr .size (0..16),   ; route_hint (opaque, <= 16 B)
    ? 4: uint .size 4,         ; expires_at (uint32, Unix epoch)
}

; INFO: Supplementary situational information
INFO_Payload = {
    1: uint .size 2,           ; info_code (uint16)
    2: tstr .size (0..60),     ; short_text (UTF-8, <= 60 B)
    ? 3: bstr .size (0..16),   ; reference (opaque, <= 16 B)
}

; AUTH: Trust management (key announcements and revocations)
; subject_id = Truncate_128(SHA-256(key_material)):
;   first 16 bytes of SHA-256 over raw 32-byte Ed25519 key.
;   128-bit fingerprint provides second-preimage resistance at 2^128.
;   MUST be consistent so revocations match announced keys.
;
; "/" (type choice) enforces conditional key_material:
;   announcement (0x01) requires key_material + validity;
;   revocation (0x02) requires only subject_id.
AUTH_Payload =
    {                          ; Key Announcement
        1: 0x01,               ; auth_action = announce
        2: bstr .size 16,      ; subject_id (Truncate_128)
        3: uint .size 4,       ; validity (seconds); REQUIRED
        4: bstr .size 32,      ; key_material (Ed25519); REQUIRED
    } /
    {                          ; Key Revocation
        1: 0x02,               ; auth_action = revoke
        2: bstr .size 16,      ; subject_id of revoked key
    }

; CANCEL: cancels a prior alert. MUST be signed.
; Replaces the normal payload when CANCEL flag is set.
CANCEL_Payload = {
    1: bstr .size 16,        ; target_msg_id (exactly 16 bytes)
    ? 2: uint .size 1,       ; reason: 0x01=expired 0x02=false_alarm
                             ;         0x03=superseded
    ? 3: tstr .size (0..40), ; short_text (UTF-8, <= 40 B)
}
]]></sourcecode>
      <t>The <tt>route_hint</tt> field (EVAC_Payload key 3) and <tt>reference</tt> field (INFO_Payload key 3) are opaque binary identifiers whose interpretation is deployment-specific and outside the scope of this specification. Implementations MUST NOT assume any particular structure or meaning for these fields. Interoperating deployments that require structured route hints or references MUST define the encoding in an out-of-band agreement or companion specification. Implementations that do not understand the content of these fields MUST ignore them and MUST NOT discard the packet solely because these fields are present.</t>
      <t>A CANCEL packet MUST carry the same Msg Type as the message being cancelled, so that WFQ priority matches the urgency of the retraction. If the original message type is unknown to the sender, Msg Type EVAC (0x03) MUST be used as a conservative default, ensuring the retraction receives adequate scheduling bandwidth.</t>
      <t>A packet with the CANCEL flag set MUST NOT be counted toward type-specific operational statistics or presentation heuristics (including the Mesh Consensus heuristic of Section 9.4), regardless of the Msg Type field value. The Msg Type field in a CANCEL packet conveys only WFQ priority for the retraction, not semantic message content.</t>
      <t>CANCEL processing is split across two protocol layers. Relay nodes (MIL-layer only) and Application Layer nodes have different responsibilities:</t>
      <t><strong>Relay node behavior</strong> (MIL layer, no trust store):</t>
      <ol>
        <li><t>Verify the SIGNED flag is set. If not, silently discard -- unsigned CANCEL packets MUST NOT be forwarded.</t></li>
        <li><t>Forward the packet normally per Trickle and WFQ rules if the SIGNED flag is set. Relay nodes do not perform signing key verification; they cannot -- they do not cache public keys from previously forwarded messages.</t></li>
      </ol>
      <t><strong>Application Layer node behavior</strong> (nodes maintaining a trust store and presenting alerts to users):</t>
      <ol>
        <li><t>Verify the packet is signed (SIGNED flag set). If not, silently discard.</t></li>
        <li><t>Verify the Ed25519 signature is cryptographically valid.</t></li>
        <li><t>Verify that the signing public key satisfies at least one of the following conditions. If neither condition is met, silently discard -- do not suppress the original message:</t></li>
      </ol>
      <t>   a. The signing public key matches the public key that signed the original message identified by <tt>target_msg_id</tt> (as cached from when the original was received and verified), OR    b. The signing public key is the immediate (1-hop) rotation successor of the original signing key: a valid AUTH announcement (auth_action=0x01) signed by the original key, announcing the current signing key, was previously received and validated, and that AUTH message is still within its declared <tt>validity</tt> window. Rotation chain traversal MUST NOT exceed 1 hop: a key may cancel only messages signed by itself or its immediate cryptographic predecessor. Multi-hop chains (e.g., original -&gt; key1 -&gt; current key) are NOT valid for CANCEL authorization. This depth limit bounds the blast radius of a compromised historical key.    Condition (b) accommodates the operational pattern where an authority issues an EVAC, subsequently rotates keys per the rotation policy of Section 9.1, and then discovers the EVAC was a false alarm after rotation.</t>
      <ol>
        <li><t>Mark the <tt>target_msg_id</tt> as cancelled in the local cache and suppress its display to the user. If <tt>target_msg_id</tt> is not present in the local cache (the node never received the original message), the node MUST create a tombstone cache entry for that MsgID, permanently marked as cancelled, to preemptively suppress any future out-of-order arrival of the original message. Tombstone entries MUST persist for the full <tt>MAX_EXPIRATION_WINDOW</tt>. The tombstone cache MUST be bounded to at most <tt>MAX_TOMBSTONE_SIZE = 512</tt> entries. When the tombstone cache is full, the oldest-received tombstone entry MUST be evicted (LRU) to create space for the new one. This may evict a tombstone that is still within its <tt>MAX_EXPIRATION_WINDOW</tt>, creating a residual window where the corresponding cancelled message could be accepted if the original arrives after eviction; this is an accepted trade-off of bounded memory operation.</t></li>
      </ol>
      <t>Implementations receiving a CANCEL packet where field 2 (reason) carries a value not in {0x01, 0x02, 0x03} MUST process the cancellation normally as if the reason field were absent. An unknown reason code MUST NOT cause the CANCEL packet itself to be discarded.</t>
    </section>
    <section anchor="flags-bit-assignments" title="Flags Bit Assignments" numbered="true">
      <table><thead><tr>
        <th>Bit</th>
        <th>Name</th>
        <th>Description</th>
      </tr></thead><tbody>
      <tr>
        <td>0</td>
        <td>SIGNED</td>
        <td>Packet carries an Ed25519 signature in the trailing 64 bytes</td>
      </tr>
      <tr>
        <td>1</td>
        <td>CANCEL</td>
        <td>Message cancels a previously issued alert. The payload MUST include the MsgID of the message being cancelled.</td>
      </tr>
      <tr>
        <td>2</td>
        <td>AUTHORITY_HINT</td>
        <td>Sender asserts authority status. MUST be verified against the appended signature and a locally trusted public key.</td>
      </tr>
      <tr>
        <td>3</td>
        <td>HIGH_PRIORITY</td>
        <td>Advisory flag requesting expedited processing; does not override WFQ scheduling.</td>
      </tr>
      <tr>
        <td>4-15</td>
        <td>Reserved</td>
        <td>MUST be zero on transmission; MUST be ignored on reception.</td>
      </tr>
      </tbody></table>
      <t>Nodes receiving a packet with the CANCEL flag set MUST verify the signature before acting on the cancellation. Unsigned CANCEL packets MUST be silently discarded.</t>
    </section>
  </section>
  <section anchor="trickle-forwarding-behavior" title="Trickle Forwarding Behavior" numbered="true">
    <t>Radio spectrum collapse is caused by amplification storms, in which every node immediately rebroadcasts every received packet. OEPB suppresses this using the Trickle algorithm <xref target="RFC6206"/> with the following constants:</t>
    <table><thead><tr>
      <th>Parameter</th>
      <th>Value</th>
      <th>Description</th>
    </tr></thead><tbody>
    <tr>
      <td>Imin</td>
      <td>50 ms</td>
      <td>Minimum interval</td>
    </tr>
    <tr>
      <td>Imax</td>
      <td>1000 ms</td>
      <td>Maximum interval (= Imin * 2^4)</td>
    </tr>
    <tr>
      <td>k</td>
      <td>3</td>
      <td>Redundancy constant</td>
    </tr>
    </tbody></table>
    <t>An &quot;identical packet&quot; is defined as a packet whose 16-byte MsgID matches a MsgID currently resident in the MIL deduplication cache.</t>
    <t>If the MIL observes <tt>c &gt;= k</tt> (3 identical MsgIDs during the active Trickle interval), it executes suppression and does not retransmit the packet during that interval.</t>
    <section anchor="simulation-based-characterization-of-trickle-constants" title="Simulation-Based Characterization of Trickle Constants" numbered="true">
      <t>The Trickle constants specified above were characterized using a discrete-event simulation across a range of node densities. Simulation parameters: 200m x 200m arena, 50m radio range, 5000ms simulation window, 30 Monte Carlo runs per configuration. The per-MsgID instance termination bounds of Section 6.3 (<tt>MAX_TRICKLE_INTERVALS = 8</tt>, <tt>MAX_TRICKLE_TX = 3</tt>) were active in all simulations.</t>
      <t>Key results (Imin=50ms, k=3, Imax=1000ms):</t>
      <table><thead><tr>
        <th>Nodes</th>
        <th>Delivery</th>
        <th>Median Latency</th>
        <th>p95 Latency</th>
        <th>Suppression</th>
      </tr></thead><tbody>
      <tr>
        <td>10</td>
        <td>100.0%</td>
        <td>23 ms</td>
        <td>43 ms</td>
        <td>9.5%</td>
      </tr>
      <tr>
        <td>25</td>
        <td>100.0%</td>
        <td>63 ms</td>
        <td>143 ms</td>
        <td>27.1%</td>
      </tr>
      <tr>
        <td>50</td>
        <td>100.0%</td>
        <td>77 ms</td>
        <td>151 ms</td>
        <td>51.0%</td>
      </tr>
      <tr>
        <td>100</td>
        <td>100.0%</td>
        <td>63 ms</td>
        <td>103 ms</td>
        <td>70.3%</td>
      </tr>
      <tr>
        <td>200</td>
        <td>100.0%</td>
        <td>52 ms</td>
        <td>76 ms</td>
        <td>83.2%</td>
      </tr>
      </tbody></table>
      <t>Key observations:</t>
      <ul>
        <li><t>At all tested densities (10-200 nodes), delivery ratio is 100% with Imin=50ms, k=3, including with the instance termination bounds in force -- bounding instance lifetime to ~4.55 seconds costs no delivery.</t></li>
        <li><t>Suppression rate scales with density (9.5% at 10 nodes -&gt; 83.2% at 200 nodes), demonstrating Trickle's self-scaling suppression behaviour: the algorithm eliminates more redundant transmissions precisely where the mesh is most redundant.</t></li>
        <li><t>p95 latency peaks at intermediate densities (~150 ms at 25-50 nodes, where multi-hop path lengths are longest relative to available path redundancy) and falls to 76 ms at 200 nodes, where more parallel relay paths accelerate convergence.</t></li>
        <li><t>Reducing Imin to 50ms (versus 100ms or 200ms) provides the lowest median latency with no delivery penalty. This is critical for SOS delivery where seconds matter.</t></li>
        <li><t>k=3 provides full delivery with balanced suppression. A lower threshold of k=2 suppresses more aggressively (e.g., 63.3% vs 51.0% at 50 nodes) but exhibits delivery instability in sparse, slow configurations (99.9% at 25 nodes with Imin=200ms). A higher threshold of k=5 forfeits a large fraction of suppression (32.9% vs 51.0% at 50 nodes) -- and the redundant airtime and energy that suppression saves -- for marginal latency improvement.</t></li>
      </ul>
      <t><strong>Lossy-link results</strong>: A lossless radio model trivially yields 100% delivery for any flooding protocol; the lossless table above therefore characterizes latency and suppression behaviour, not delivery robustness. To characterize delivery under loss, the same sweep was repeated with independent per-link, per-transmission Bernoulli loss applied to every delivery attempt (Imin=50ms, k=3):</t>
      <table><thead><tr>
        <th>Nodes</th>
        <th>Delivery (10% loss)</th>
        <th>Delivery (30% loss)</th>
        <th>Suppression (0% -&gt; 30% loss)</th>
      </tr></thead><tbody>
      <tr>
        <td>10</td>
        <td>100.0%</td>
        <td>96.6%</td>
        <td>9.5% -&gt; 6.9%</td>
      </tr>
      <tr>
        <td>25</td>
        <td>100.0%</td>
        <td>98.1%</td>
        <td>27.1% -&gt; 18.2%</td>
      </tr>
      <tr>
        <td>50</td>
        <td>100.0%</td>
        <td>100.0%</td>
        <td>51.0% -&gt; 39.8%</td>
      </tr>
      <tr>
        <td>100</td>
        <td>100.0%</td>
        <td>100.0%</td>
        <td>70.3% -&gt; 61.1%</td>
      </tr>
      <tr>
        <td>200</td>
        <td>100.0%</td>
        <td>100.0%</td>
        <td>83.2% -&gt; 76.9%</td>
      </tr>
      </tbody></table>
      <t>Observations under loss:</t>
      <ul>
        <li><t>10% per-link loss is fully absorbed at every tested density and every tested k: the redundant transmissions that Trickle deliberately permits (up to k copies per interval) function as forward error correction at the topology level.</t></li>
        <li><t>At 30% per-link loss, residual delivery failure concentrates in sparse topologies (10-25 nodes), where some nodes are reachable only through one or two relay paths; dense meshes (&gt;= 50 nodes) retain 100% delivery. Delivery differences between k=2, k=3, and k=5 at 30% loss are within Monte Carlo variance at 30 runs per configuration and should not be interpreted as a ranking.</t></li>
        <li><t>Suppression rate falls as loss rises (51.0% to 39.8% at 50 nodes from 0% to 30% loss) without any parameter change: lost copies do not increment the redundancy counter c, so Trickle automatically substitutes retransmissions for suppression exactly when the channel degrades. This self-tuning property is the principal argument for counter-based suppression over fixed-probability gossip in emergency deployments.</t></li>
        <li><t>The loss model is a simplification: independent Bernoulli loss does not capture bursty interference, MAC-layer collision correlation between neighboring links, or capture effects. The results bound protocol-layer behaviour, not radio-layer behaviour.</t></li>
      </ul>
      <t><strong>Comparison with a flooding baseline</strong>: To quantify what Trickle adds over the simplest viable alternative, the same simulator was run in a flooding-with-deduplication mode -- on first receipt of a novel MsgID, a node schedules exactly one rebroadcast after a random 0-50ms jitter; duplicates are dropped and never retransmitted. This is the dissemination mechanism of the Meshtastic/Disaster Radio class of systems surveyed in Section 1.1. Topologies, seeds, and the loss model are paired with the Trickle runs (Imin=50ms, k=3):</t>
      <table><thead><tr>
        <th>Nodes</th>
        <th>Delivery at 30% loss (Flooding / Trickle)</th>
        <th>Tx per reached node, lossless (Flooding / Trickle)</th>
      </tr></thead><tbody>
      <tr>
        <td>10</td>
        <td>84.2% / 96.6%</td>
        <td>1.0 / 3.0</td>
      </tr>
      <tr>
        <td>25</td>
        <td>81.9% / 98.1%</td>
        <td>1.0 / 3.0</td>
      </tr>
      <tr>
        <td>50</td>
        <td>97.2% / 100.0%</td>
        <td>1.0 / 2.8</td>
      </tr>
      <tr>
        <td>100</td>
        <td>100.0% / 100.0%</td>
        <td>1.0 / 2.0</td>
      </tr>
      <tr>
        <td>200</td>
        <td>100.0% / 100.0%</td>
        <td>1.0 / 1.3</td>
      </tr>
      </tbody></table>
      <t>The comparison yields three honest conclusions:</t>
      <ol>
        <li><t><strong>Trickle is not a transmission-count optimization over single-shot flooding.</strong> On lossless links both achieve 100% delivery, flooding transmits less (exactly once per node, by construction), and flooding's median latency is marginally lower (no Imin scheduling delay). Claims that suppression &quot;saves airtime versus flooding&quot; hold only against naive flooding *without* deduplication; OEPB does not make that comparison.</t></li>
        <li><t><strong>What Trickle purchases is loss robustness.</strong> Single-shot flooding has no recovery path: one lost transmission can permanently strand a node, and at 30% per-link loss sparse-mesh delivery collapses to 81.9-84.2%. Trickle re-arms across intervals and retransmits up to <tt>MAX_TRICKLE_TX</tt> times, holding 96.6-98.1% delivery in the same topologies -- a 12-16 percentage-point improvement exactly in the sparse, degraded conditions that characterize disaster scenarios.</t></li>
        <li><t><strong>The retransmission budget is self-allocating.</strong> Per-node transmissions fall from 3.0 (the full <tt>MAX_TRICKLE_TX</tt> budget) in sparse meshes, where redundancy must be manufactured, to 1.3 in dense meshes, where suppression recognizes that ambient redundancy already exists -- approaching flooding's 1.0 floor without giving up the retransmission reserve. OEPB Trickle is best understood as flooding plus a bounded, self-tuning retransmission reserve.</t></li>
      </ol>
      <t>Two caveats apply: the jittered, deduplicated flooding baseline is itself a polite idealization (the simulator models no MAC collisions, so dense unsuppressed flooding suffers no broadcast-storm penalty here -- in real radio environments it would); and the transmission-count comparison inherits the lossless-model limitations noted above.</t>
      <t>The chosen constants <tt>Imin=50ms, k=3, Imax=1000ms</tt> represent the optimal tradeoff across the full density range. Implementations MAY tune these values for specific deployment contexts (e.g., increasing <tt>Imin</tt> on duty-cycled LoRa radios to respect regulatory transmission limits).</t>
      <t><strong>Minimum viable topology for suppression</strong>: With k=3, meaningful Trickle suppression requires a fully-connected mesh of at least 4 nodes. In a 3-node fully-connected triangle, the maximum counter value any node can reach is c=2 (it hears the other two nodes), which is less than k=3 -- suppression never fires with k=3. In a 2-node mesh, each node hears at most c=1 copy. Implementations SHOULD reduce k proportionally: k=2 enables suppression in a 3-node mesh (c=2 &gt;= k=2); k=1 enables suppression in a 2-node mesh (c=1 &gt;= k=1). The delivery ratio remains 100% in small meshes regardless of suppression; reduced k only prevents unnecessary retransmissions in micro-deployments.</t>
      <t><strong>Simulation Scope and Limitations</strong>: The results above were produced by a discrete-event Python simulator (<tt>simulator/python/trickle_sim.py</tt>) that models protocol-layer logic with position-aware topology. The simulator does not model BLE connection setup latency (~100-600ms per peer), Wi-Fi Direct group formation overhead (~2-8 seconds), MAC-layer collision behavior at high density, or radio duty-cycle constraints. Link loss is modeled only as independent per-link Bernoulli loss (see the lossy-link results above), not as correlated or bursty interference. Consequently, the median latency figures above represent a lower bound; real-hardware delivery latency on BLE or Wi-Fi Direct transports will exceed these values by the connection setup overhead of the underlying transport. The simulator validates protocol-layer correctness properties (delivery ratio, suppression behavior under varying density) rather than absolute latency. Implementations deploying on specific transports MUST measure end-to-end latency empirically on target hardware and adjust <tt>Imin</tt> to a value achievable by the transport's connection setup pipeline.</t>
      <t>Simulation source: <tt>simulator/python/trickle_sim.py</tt>; full results in <tt>simulator/python/trickle_results.json</tt>.</t>
    </section>
    <section anchor="per-transport-trickle-instances" title="Per-Transport Trickle Instances" numbered="true">
      <t>Nodes possessing heterogeneous radios (e.g., BLE + Wi-Fi Direct) operate an independent Trickle instance per Transport Binding. The MIL deduplication cache is shared across all bindings. When a packet is received on one Transport Binding and cleared as novel by the deduplication cache, the MIL schedules independent transmissions on all other active Transport Bindings, each governed by their own Trickle state.</t>
      <t>This prevents cross-radio amplification: a packet suppressed on BLE (due to <tt>c &gt;= k</tt>) is independently evaluated on Wi-Fi Direct before being forwarded on that medium.</t>
    </section>
    <section anchor="trickle-state-granularity-and-reset" title="Trickle State Granularity and Reset" numbered="true">
      <t>Each MsgID maintains its own independent Trickle state tuple <tt>(interval, c, timer_fires_at)</tt>. Trickle state is per-MsgID, not per-WFQ-class. Sharing one Trickle instance across a WFQ class would allow a flood of novel packets in that class to continuously reset the interval to Imin, preventing suppression from ever engaging -- the precise attack Trickle is intended to defeat.</t>
      <t>In the OEPB context, a Trickle &quot;inconsistency&quot; per RFC 6206, Section 4.2 is defined as the receipt of a packet bearing a novel MsgID not present in the local deduplication cache. Upon detecting this inconsistency, the node MUST initialize a new per-MsgID Trickle instance with interval=Imin and c=0.</t>
      <t>When a node receives a packet with a MsgID not present in its deduplication cache (a novel message), it MUST create a new per-MsgID Trickle state entry, set the interval to Imin, set c=0, and schedule the first transmission timer at a random offset in [0, Imin], consistent with RFC 6206 Section 4.2.</t>
      <t>When a node receives a packet with a MsgID already present in its deduplication cache (a redundant copy), it MUST increment the counter c for that MsgID's Trickle state. If c reaches k, the scheduled transmission for that MsgID is suppressed for the current interval.</t>
      <t><strong>Trickle instance termination</strong>: The Trickle algorithm as specified in RFC 6206 maintains ongoing routing consistency and therefore runs indefinitely. Applied unmodified to one-shot message dissemination, an unsuppressed per-MsgID instance (c &lt; k, as occurs in sparse topologies) would retransmit the same packet once per Imax interval until the MsgID is evicted from the deduplication cache -- up to <tt>MAX_EXPIRATION_WINDOW</tt> (24 hours), or approximately 86,000 redundant transmissions of a single message. OEPB therefore bounds the lifetime of every per-MsgID Trickle instance. An instance MUST be terminated when the first of the following conditions is met:</t>
      <ol>
        <li><t>The instance has completed <tt>MAX_TRICKLE_INTERVALS = 8</tt> Trickle intervals since creation. With the constants of Section 6, this is the doubling ladder of 50, 100, 200, 400, and 800 ms followed by three intervals at Imax = 1000 ms, giving a maximum instance lifetime of approximately 4.55 seconds.</t></li>
        <li><t>The node has transmitted the packet <tt>MAX_TRICKLE_TX = 3</tt> times on the associated Transport Binding.</t></li>
      </ol>
      <t>Upon termination, the instance's Trickle state tuple and pending timer MUST be discarded, freeing the instance's slot against the <tt>MAX_ACTIVE_TRICKLE_INSTANCES</tt> bound. The MsgID itself remains in the deduplication cache for the full <tt>MAX_EXPIRATION_WINDOW</tt> per Section 8.1. A redundant copy received after instance termination MUST be discarded as a duplicate per Section 7 and MUST NOT cause a new Trickle instance to be created for that MsgID; only a MsgID absent from the deduplication cache constitutes a Trickle inconsistency.</t>
      <t>Both termination bounds were active in the simulations of Section 6.1: delivery ratio remains 100% across all tested densities (10-200 nodes) with the bounds in force, confirming that bounding instance lifetime costs no delivery. Implementations on duty-cycle-constrained transports that increase Imin or Imax MUST retain the interval-count and transmission-count bounds (the absolute lifetime scales with the configured intervals).</t>
      <t><strong>Originator self-suppression prohibition</strong>: A node MUST transmit the first broadcast of any locally-originated message regardless of Trickle counter state. Trickle suppression (c &gt;= k) applies exclusively to relay forwarding of packets received from peer nodes. A locally-generated message MUST be dispatched directly to all active Transport Bindings without entering the Trickle suppression evaluation path. Failure to enforce this rule risks a victim's SOS never leaving their device in a dense RF environment where the suppression threshold is met by ambient mesh traffic before the originating node schedules its first transmission.</t>
      <t>Memory note: implementations maintaining per-MsgID Trickle state MUST bound the number of simultaneously active Trickle timer instances to <tt>MAX_ACTIVE_TRICKLE_INSTANCES = 512</tt>. This bound is intentionally lower than <tt>MAX_CACHE_SIZE = 2048</tt> because each Trickle instance requires an active timer in addition to cache memory, and constrained hardware (MCU-class devices) may have far fewer available timer resources than cache entries. When <tt>MAX_ACTIVE_TRICKLE_INSTANCES</tt> is reached, new novel MsgIDs MUST be forwarded immediately on first receipt (without Trickle scheduling) and added to the deduplication cache without a Trickle instance. Timer slots are freed by instance termination (the lifetime and transmission-count bounds above); additionally, if a MsgID is evicted from the deduplication cache while its Trickle instance is still active, that Trickle state MUST also be discarded. Because instance lifetime (~4.55 s) is far shorter than cache residency (24 h), termination is the dominant slot-recycling path, and the 512-instance bound is reached only under sustained novel-packet arrival rates exceeding ~112 packets/second.</t>
    </section>
  </section>
  <section anchor="error-handling-and-duplicate-resolution" title="Error Handling and Duplicate Resolution" numbered="true">
    <t>OEPB uses a Silent Drop error model. Nodes MUST discard malformed, invalid, or duplicate packets without transmitting NACK responses. This prevents negative acknowledgment amplification in dense topologies.</t>
    <t>Conditions for silent drop include:</t>
    <ul>
      <li><t>Unknown Version field value.</t></li>
      <li><t>Unknown Msg Type value.</t></li>
      <li><t>TTL equal to 0 on ingress (before decrement).</t></li>
      <li><t>TTL greater than MAX_TTL (15) on ingress.</t></li>
      <li><t>Hop Count greater than or equal to MAX_HOPCOUNT (15) on ingress.</t></li>
      <li><t>Payload Length field value that, when combined with the 40-byte header and (if SIGNED=1) 64-byte signature, exceeds the total received L2 frame length. This check MUST be performed before any CBOR decoding is attempted, to prevent buffer over-read on maliciously crafted Payload Length values.</t></li>
      <li><t>Payload Length exceeding MAX_PAYLOAD_SIZE for the applicable signing status (signed: 152 bytes; unsigned: 216 bytes).</t></li>
      <li><t>MsgID already present in the deduplication cache.</t></li>
      <li><t>SIGNED flag set but packet length insufficient to contain a 64-byte trailing signature.</t></li>
      <li><t>CANCEL flag set but packet is unsigned.</t></li>
    </ul>
    <t>The deduplication cache MUST key exclusively on the 16-byte MsgID field. Implementations MUST NOT include the signature bytes, TTL, Hop Count, or any other mutable field in the cache key. This ensures that Ed25519 signature variants of the same logical packet (which share the same MsgID) are correctly identified as duplicates. Relay nodes MUST forward packets with the SIGNED flag set regardless of signature validity -- signature verification is an Application Layer responsibility and MUST NOT gate forwarding decisions.</t>
    <t>Relay nodes MUST treat the Variable Payload field as an opaque byte string. Relay nodes MUST NOT decode, re-encode, or otherwise transform the CBOR payload. Any modification to the Payload bytes would change the MsgID (since Payload is an input to the MsgID hash) and would invalidate the Ed25519 signature. Bitwise identity of the Payload field from ingress to egress is a protocol requirement for correct deduplication and signature verification.</t>
    <section anchor="message-id-collision-handling" title="Message ID Collision Handling" numbered="true">
      <t>A SHA-256 truncation collision producing a matching MsgID for a different packet is cryptographically negligible. However, implementations MAY perform secondary disambiguation if a collision is suspected (the MsgID matches a cached entry but the payload length differs). Disambiguation rules by packet type:</t>
      <ul>
        <li><t>If both the cached and incoming packets have SIGNED flag set: compare the 64-byte Ed25519 signatures. If they differ, treat the incoming packet as a distinct message with a new cache entry.</t></li>
        <li><t>If either packet is unsigned: the collision MUST be resolved by discarding the incoming packet. Without a signature to distinguish the two, no safe disambiguation is possible. The probability of a legitimate collision between two unsigned packets is negligible (2^{-128}) and does not justify the complexity of accepting both.</t></li>
      </ul>
    </section>
  </section>
  <section anchor="rate-limiting-and-deduplication-cache" title="Rate Limiting and Deduplication Cache" numbered="true">
    <section anchor="deduplication-cache" title="Deduplication Cache" numbered="true">
      <t>The MIL maintains a bounded cache of observed MsgIDs. Eviction is driven by two policies, applied in order:</t>
      <ul>
        <li><t><strong>Time-Based Eviction</strong>: For each cached entry, compute <tt>delta = |LocalClock - Timestamp|</tt>. Entries where <tt>delta &gt; MAX_EXPIRATION_WINDOW</tt> (default: 24 hours) MUST be evicted on each cache sweep. Implementations on critically memory-constrained hardware MAY reduce <tt>MAX_EXPIRATION_WINDOW</tt> to as low as 4 hours under high-load conditions.</t></li>
        <li><t><strong>Capacity Eviction</strong>: When the cache exceeds <tt>MAX_CACHE_SIZE = 2048</tt> entries after time-based eviction, the MIL evicts the entry whose wire-packet Timestamp is furthest in the past (oldest originating packet first) until the entry count is within bounds.</t></li>
      </ul>
      <t>Note on CANCEL persistence: When a CANCEL is processed for a given <tt>target_msg_id</tt>, the cache entry for that MsgID MUST be retained for the full <tt>MAX_EXPIRATION_WINDOW</tt> even if it would otherwise be evicted by capacity pressure. This prevents a cancel-then-replay attack in which the cancelled MsgID is evicted from cache and a replayed copy of the original message is subsequently accepted as novel. Implementations MUST maintain a separate &quot;cancelled&quot; flag on cache entries independently of the capacity eviction policy.</t>
    </section>
    <section anchor="rate-limiting" title="Rate Limiting" numbered="true">
      <t>A token bucket rate limiter applies per originating public-key fingerprint (derived from authenticated packets), allocating a sustained rate of 1 packet per 5 seconds with a burst capacity of 3 packets. Because the sender's public key is not present in the OEPB fixed header, the MIL cannot independently determine a packet's key fingerprint; per-key rate limiting MUST be implemented at the Application Layer, which has access to the trust store and can resolve the signing key from verified packets. The MIL applies only per-transport-source-address rate limiting (see below). Rate-limiting applies to packet acceptance, not to forwarding of packets already in the relay queue.</t>
      <t>Nodes MUST apply a general absolute per-transport-source intake budget: no more than <tt>MAX_PKT_RATE = 30</tt> packets per <tt>MAX_PKT_WINDOW = 60</tt> seconds MUST be accepted from any single transport-layer source address (e.g., BLE MAC address, Wi-Fi Direct peer ID), regardless of packet type or authentication status. This baseline MIL-level budget is the primary defense against authenticated flooding attacks where an attacker uses a self-generated keypair to flood signed packets with unique Nonces (bypassing Trickle suppression and the unauthenticated-SOS-specific limit). When this budget is exhausted, additional packets from that source MUST be silently discarded until the window resets.</t>
      <t>For unauthenticated SOS packets where no public-key fingerprint is available, an additional stricter limit applies: no more than <tt>MAX_UNAUTH_SOS_RATE</tt> (default: 10) unauthenticated SOS packets per <tt>MAX_UNAUTH_SOS_WINDOW</tt> (default: 60 seconds) MUST be accepted from any single transport-layer source address. This tighter budget applies within the general <tt>MAX_PKT_RATE</tt> budget. Both limits are intentionally per transport-layer source, not global, to prevent a single flooding attacker from exhausting budget for geographically distinct genuine SOS signals.</t>
      <section anchor="auth-revocation-for-unknown-keys" title="AUTH Revocation for Unknown Keys" numbered="true">
        <t>If a node receives an AUTH revocation packet (auth_action=0x02) for a subject_id fingerprint that has no corresponding announced key in the local trust store, the node MUST persistently cache the subject_id in a local cryptographic deny-list. Any subsequent auth_action=0x01 key announcement whose computed subject_id (Truncate_128(SHA-256(key_material))) matches a deny-list entry MUST be immediately rejected and MUST NOT be added to the trust store. This handles out-of-order delivery scenarios where the revocation message propagates faster than, or without, the corresponding announcement.</t>
        <t>Deny-list entries MUST be retained for at least <tt>MAX_EXPIRATION_WINDOW</tt> (24 hours) from the time of receipt. The deny-list MUST be bounded to at most <tt>MAX_DENY_LIST_SIZE = 1024</tt> entries. When full, LRU eviction MUST be applied: the oldest-received subject_id entry is removed to make room for the new one. Implementations SHOULD log LRU eviction events, as they represent a potential memory-exhaustion attack vector (an attacker flooding unique subject_ids to cycle legitimate revocations out of the deny-list).</t>
      </section>
    </section>
    <section anchor="global-intake-limiting" title="Global Intake Limiting" numbered="true">
      <t>Under global network saturation conditions where completely unique packets overwhelm Trickle suppression, nodes MUST apply a Global Intake Limit. When the MIL's inbound queue depth exceeds <tt>DEFAULT_QUEUE_DEPTH = 64</tt> packets (RECOMMENDED default; implementations MAY configure a different value), new packets are accepted in WFQ priority order and INFO packets are Tail-Dropped until the queue depth returns to a safe level. Implementations MUST document their configured queue depth threshold.</t>
    </section>
  </section>
  <section anchor="trust-model-and-sybil-defense" title="Trust Model and Sybil Defense" numbered="true">
    <section anchor="identity-and-key-rotation" title="Identity and Key Rotation" numbered="true">
      <t>Authority nodes -- nodes that issue signed ALERT, EVAC, or AUTH messages -- SHOULD rotate their Ed25519 signing keypair periodically. The rotation period depends on the operational profile:</t>
      <ul>
        <li><t><strong>Fixed-installation authorities</strong> (emergency operations centers, fire stations, municipal alert systems): RECOMMENDED maximum rotation period of 7 days. The physical location of such installations is typically public knowledge, so frequent rotation purchases no tracking resistance; the residual value of rotation is bounding the blast radius of an undetected key compromise.</t></li>
        <li><t><strong>Mobile or field-operated authority keys</strong> (keys carried on personal devices by responders or officials): SHOULD rotate at least every 24 hours. A stable public-key fingerprint broadcast from a moving device allows a passive adversary to track the operator's movements (Section 10.6).</t></li>
      </ul>
      <t>Rotation is deliberately SHOULD rather than MUST. Every mechanism in this specification that exists to survive rotation -- the <tt>KEY_OVERLAP_WINDOW</tt> below, the 1-hop CANCEL rotation chain of Section 5.4, and the validity-window management of Section 11.2 -- is exercised only when a rotation actually occurs. Deployments that rotate less frequently encounter proportionally fewer rotation-induced failure modes; a mandatory aggressive rotation schedule would maximize exposure to exactly the operational hazards those mechanisms mitigate, while delivering tracking resistance that fixed installations do not need.</t>
      <t>Non-authority nodes (civilian SOS senders, relay-only nodes) are not required to maintain a keypair; key rotation requirements do not apply to unsigned operation. The new public key SHOULD be announced via an AUTH message signed by the previous key during the rotation window.</t>
      <t>To prevent loss of CANCEL authority after key rotation, nodes MUST retain the previous private key for a <tt>KEY_OVERLAP_WINDOW</tt> of at least 10 minutes following the rotation AUTH announcement. During this overlap window, the node MAY sign CANCEL packets using the previous key to retract messages issued under that key. After <tt>KEY_OVERLAP_WINDOW</tt> expires, CANCEL authority for messages signed with the previous key is delegated to the current key via the rotation chain: a CANCEL signed with the current key is accepted for prior-key messages if a verified rotation AUTH from the previous key to the current key is in the receiving node's trust cache and remains within its <tt>validity</tt> window. See Section 5.4 for CANCEL verification rules that implement this chain.</t>
    </section>
    <section anchor="authority-trust-levels" title="Authority Trust Levels" numbered="true">
      <t>Nodes classify received packets into one of four trust levels for presentation and forwarding policy:</t>
      <table><thead><tr>
        <th>Level</th>
        <th>Name</th>
        <th>Basis</th>
      </tr></thead><tbody>
      <tr>
        <td>0</td>
        <td>Unverified</td>
        <td>No valid signature or unknown sender</td>
      </tr>
      <tr>
        <td>1</td>
        <td>Locally Known</td>
        <td>Sender recognized by local node policy</td>
      </tr>
      <tr>
        <td>2</td>
        <td>Community</td>
        <td>Sender trusted within a local group</td>
      </tr>
      <tr>
        <td>3</td>
        <td>Authority</td>
        <td>Sender verified against a preloaded root anchor</td>
      </tr>
      </tbody></table>
      <t>Trust level assignment is implementation-defined. Nodes MUST NOT refuse to forward packets solely on the basis of trust level. Trust level influences presentation (e.g., visual indicators) and MAY influence storage duration.</t>
    </section>
    <section anchor="authority-root-anchors" title="Authority Root Anchors" numbered="true">
      <t>Authority-issued EVAC and ALERT messages are verified against Monolithic Root Anchor public keys distributed out-of-band (e.g., pre-installed in emergency management applications, broadcast by national alert systems prior to disaster events). Nodes without a matching root anchor for a given signing key MUST treat the message as Trust Level 0 and SHOULD indicate the unverified status to the user.</t>
    </section>
    <section anchor="sybil-defense-for-sos" title="Sybil Defense for SOS" numbered="true">
      <t>Unauthenticated SOS broadcasts do not admit exhaustive Sybil defenses without contradicting the emergency use case (a person in immediate danger cannot be required to solve a computational puzzle). The following lightweight mitigations apply:</t>
      <ul>
        <li><t><strong>MsgID-based Geographic Convergence</strong>: A node receiving 3 or more distinct SOS packets (distinct MsgIDs) whose payload coordinates fall within a proximity threshold (implementation-defined, e.g., 500 meters) within a rolling time window of <tt>MAX_EXPIRATION_WINDOW</tt> MAY elevate the effective trust presentation of those messages to indicate corroborated geographic activity. This heuristic is advisory and SHOULD be labeled clearly as &quot;multiple independent reports&quot; rather than &quot;verified.&quot; Note that a single attacker with a single device can still trigger this heuristic by originating 3 distinct SOS packets with different Nonces (producing 3 unique MsgIDs); it provides weak social evidence, not cryptographic assurance.</t></li>
      </ul>
      <t>  Implementations MUST NOT use Layer 2 source addresses (BLE MAC address, Wi-Fi Direct peer ID) as a metric for source diversity. On modern Android and iOS, MAC addresses are randomized per connection; a single device can rotate its L2 address to appear as arbitrarily many distinct sources, making MAC-based diversity counting trivially exploitable.</t>
      <ul>
        <li><t><strong>Rate Limiting</strong>: Per-sender rate limiting (Section 8.2) limits the throughput of any single attacker.</t></li>
        <li><t><strong>Forwarding Caps</strong>: SOS packets exceeding the Trickle redundancy threshold <tt>k</tt> are suppressed, limiting amplification from any single fabricated SOS flood.</t></li>
      </ul>
      <t>Geographic evaluation is delegated to emergency responder analysis; the protocol does not attempt algorithmic verification of SOS legitimacy.</t>
    </section>
  </section>
  <section anchor="security-considerations" title="Security Considerations" numbered="true">
    <t>OEPB operates under the Dolev-Yao adversary model, assuming adversaries can intercept, replay, block, synthesize, and selectively forward arbitrary packets.</t>
    <section anchor="replay-attacks" title="Replay Attacks" numbered="true">
      <t>The combined (Timestamp, Nonce, MsgID) triple provides replay resistance. The 64-bit Nonce ensures that even identical payloads originating at the same timestamp produce distinct MsgIDs. Time-based cache eviction (Section 8.1) bounds the replay window to <tt>MAX_EXPIRATION_WINDOW</tt>. Implementations MUST treat clock uncertainty conservatively: a packet timestamped significantly in the past may be legitimate (originating node had a wrong clock) or a replay attempt.</t>
    </section>
    <section anchor="amplification-attacks" title="Amplification Attacks" numbered="true">
      <t>Trickle suppression (Section 6) is the primary amplification defense against retransmission storms for a given MsgID. An adversary that floods the network with unique-Nonce packets bypasses Trickle's MsgID-based suppression since each packet has a distinct MsgID. Three layered backstops bound this attack: (1) for authenticated sources, the per-key token bucket (Section 8.2) limits throughput to 1 pkt/5s sustained; (2) for unauthenticated sources, the per-transport-source absolute intake budget (Section 8.2) limits acceptance to <tt>MAX_UNAUTH_SOS_RATE</tt> packets per window; (3) the Global Intake Limit (Section 8.3) applies WFQ-ordered tail drop when queue depth is exceeded. Implementations SHOULD additionally monitor total forwarding rate and apply backpressure when it exceeds a locally configured threshold. Note that BLE MAC address randomization on modern smartphones limits the effectiveness of the per-transport-source budget against an attacker that rotates their L2 address; this residual risk is acknowledged in Section 3.8 of the threat model.</t>
    </section>
    <section anchor="forged-authority-alerts" title="Forged Authority Alerts" numbered="true">
      <t>An adversary may transmit EVAC or ALERT messages with the AUTHORITY_HINT flag set but without a valid signature, or with a signature from a key not in the receiving node's trust anchor set. Nodes MUST NOT present such messages as authenticated authority alerts. The AUTHORITY_HINT flag is advisory; trust is established solely through successful signature verification against a trusted root anchor.</t>
      <t>At the Application Layer, packets bearing AUTHORITY_HINT=1 that fail signature verification or trust chain resolution MUST have the AUTHORITY_HINT flag treated as unset for all presentation and heuristic purposes. The flag MUST NOT be re-propagated with authority weight by relay nodes performing application-layer processing; any presentation to the user MUST reflect Trust Level 0 (Unverified) for such packets. Pure relay nodes (MIL-only forwarding without application-layer involvement) MAY forward the flag bytes unchanged, as they do not perform trust evaluation.</t>
    </section>
    <section anchor="ttl-inflation-by-malicious-relay" title="TTL Inflation by Malicious Relay" numbered="true">
      <t>The TTL field is mutable and intentionally excluded from the signature, allowing relay nodes to decrement it without invalidating cryptographic integrity. A consequence is that a malicious relay node may inflate the TTL field (e.g., resetting a TTL=1 packet to MAX_TTL=15) before retransmitting, extending a packet's intended propagation range beyond what the originator specified.</t>
      <t>The MsgID deduplication cache is the primary defense against TTL-inflation routing loops: a node that has already forwarded a MsgID will reject any subsequent copy bearing the same MsgID regardless of TTL value, preventing indefinite circulation of inflated packets within the mesh. However, the dedup cache does not prevent geographic range extension: nodes that have not yet seen the packet will accept and forward the TTL-inflated copy, propagating it further than the original TTL would allow.</t>
      <t>Relay nodes MUST NOT increase TTL values on any packet they forward. This requirement cannot be cryptographically enforced, so implementations in security-sensitive deployments SHOULD log and flag packets whose hop count appears inconsistent with their TTL (e.g., TTL=15 but Hop Count=8 suggesting prior decrements that should have reduced TTL further).</t>
    </section>
    <section anchor="cancel-abuse" title="CANCEL Abuse" numbered="true">
      <t>The CANCEL flag allows a valid authority to retract a previously issued alert. An adversary might transmit forged CANCEL messages to suppress legitimate alerts. Section 5.5 mandates that unsigned CANCEL packets MUST be silently discarded. Nodes MUST verify that the CANCEL signing key is authorized per the rotation chain rules in Section 5.4: either it is the exact key that signed the original message, or it is the immediate (1-hop) rotation successor of that key within its validity window. A CANCEL signed by an unrelated key or by a key more than 1 rotation step removed from the original MUST be silently discarded.</t>
    </section>
    <section anchor="privacy-and-tracking" title="Privacy and Tracking" numbered="true">
      <t>Key rotation (Section 9.1) limits long-term geographic tracking via static public-key fingerprints. However, within any single rotation window, a passive adversary observing broadcast traffic can correlate a node's movements with its current key fingerprint. This is why Section 9.1 differentiates by operational profile: fixed installations with public locations gain nothing from frequent rotation, while mobile signers SHOULD rotate at least every 24 hours. Mobile operators in high-sensitivity contexts SHOULD apply additional rotation (e.g., every 6 hours) and avoid including precise coordinates in INFO packets.</t>
    </section>
    <section anchor="energy-exhaustion" title="Energy Exhaustion" numbered="true">
      <t>Adversaries may attempt to exhaust node battery resources by flooding novel packets that pass Trickle suppression. The mandatory <tt>Imax = 1000ms</tt> bound limits active radio transmit cycles. Rate limiting and Global Intake Limiting (Section 8) provide additional protection. Implementations SHOULD implement radio duty-cycling at the TAL for low-power deployments.</t>
    </section>
    <section anchor="signature-verification-cost" title="Signature Verification Cost" numbered="true">
      <t>Ed25519 verification on constrained hardware requires approximately 0.5-2 ms and 1-3 mA depending on hardware. Because OEPB mandates that signature verification MUST NOT be required for forwarding decisions, relay nodes can forward without verification, deferring verification cost to the application presentation layer. This asymmetry is intentional: it preserves relay throughput while allowing full verification at terminals.</t>
    </section>
    <section anchor="root-anchor-key-compromise" title="Root Anchor Key Compromise" numbered="true">
      <t>Root anchor keys distributed out-of-band (Section 9.3) cannot be revoked in-band. The AUTH revocation mechanism (Section 5.4) applies to sub-authority keys only; there is no OEPB-level message that can revoke a pre-installed root anchor. If a root anchor private key is compromised after deployment, all messages signed under that root anchor (or any sub-authority chain rooted there) must be treated as potentially adversarial, and there is no in-band mechanism to push a replacement root. Remediation requires an out-of-band channel (e.g., an application update). Deployments MUST treat root anchor key compromise as a critical incident requiring immediate out-of-band remediation. To limit blast radius, deployments SHOULD use root anchors only to certify short-lived sub-authority keys (via AUTH announcements) rather than signing operational messages directly with root keys.</t>
    </section>
    <section anchor="crl-withholding" title="CRL Withholding" numbered="true">
      <t>An adversary that selectively drops AUTH (CRL) packets can prevent nodes from learning about compromised authority keys. This is a fundamental limitation of any offline system. Implementations SHOULD apply conservative key validity windows (AUTH packet <tt>validity</tt> field) and require periodic re-announcement of authority keys to bound the impact of CRL suppression.</t>
    </section>
  </section>
  <section anchor="deployment-considerations" title="Deployment Considerations" numbered="true">
    <t>Deployments on unlicensed ISM bands (e.g., 868 MHz Sub-GHz in the EU, 915 MHz in the US) MUST comply with applicable regulatory duty-cycle limitations. For example, EU ETSI EN 300 220 limits duty cycles to 1% or 10% depending on sub-band. These duty-cycle constraints directly limit achievable retransmission rates and may require implementations to increase <tt>Imax</tt> or decrease burst capacity relative to the defaults specified in Section 6.</t>
    <t>Transport-specific parameters (MTU, fragmentation strategy, channel access rules) MUST be defined in Transport Binding Profile documents corresponding to each physical layer.</t>
    <t>Implementors deploying on IEEE 802.15.4 networks (e.g., Thread) SHOULD note that the maximum physical-layer frame is 127 bytes. The OEPB signed packet overhead of 104 bytes leaves only 23 bytes for payload, necessitating L2 fragmentation for any non-trivial message. The TAL MUST handle reassembly transparently below the MIL.</t>
    <section anchor="clock-bootstrap-in-infrastructure-absent-environments" title="Clock Bootstrap in Infrastructure-Absent Environments" numbered="true">
      <t>OEPB uses the 64-bit Timestamp field for cache eviction relative to local clock. A node whose real-time clock is wrong by more than <tt>MAX_EXPIRATION_WINDOW</tt> (24 hours) will reject all received packets as expired or from the distant future, isolating itself from the mesh.</t>
      <t>In an infrastructure-absent disaster scenario, a freshly powered-on or battery-reset device may have an incorrect RTC (e.g., reset to UNIX epoch 0). Implementations SHOULD apply the following clock bootstrap heuristic:</t>
      <ol>
        <li><t>On startup, before accepting or rejecting packets on timestamp grounds, a node SHOULD listen passively for a short window (RECOMMENDED: 30 seconds) and collect the Timestamp field values of received packets.</t></li>
        <li><t>If the node observes 3 or more packets with SIGNED=1 and AUTHORITY_HINT=1 whose Timestamps agree within a 5-minute window and diverge from the local clock by more than 1 hour, the node MAY advance its local time estimate to the median of those Timestamps. Note: AUTHORITY_HINT is an unverified advisory flag -- any device can set it. An attacker could transmit multiple SIGNED+AUTHORITY_HINT packets with false future timestamps to force a victim node's clock forward. The monotonic-only constraint (step 3) limits damage by preventing the attacker from pushing the clock backward (which would expand the replay acceptance window); a forward push causes the node to reject past-legitimate packets as &quot;too old&quot; until real traffic arrives. Implementations SHOULD cap single-step clock advancement at 48 hours regardless of observed Timestamps to limit attacker leverage. Implementations MUST additionally apply a cumulative multi-cycle cap: the total cumulative forward clock advancement applied via this heuristic from node startup MUST NOT exceed 72 hours. This prevents an attacker from repeatedly triggering the bootstrap condition across multiple cycles (each time staying just below the 48-hour per-step cap) to advance the node's clock by an arbitrarily large amount.</t></li>
        <li><t>Clock adjustment MUST be strictly monotonic: a node MUST NOT move its local clock backward under any circumstance, to prevent replay window expansion.</t></li>
        <li><t>If no Authority-signed packets are available for bootstrap, the node SHOULD accept packets whose Timestamp values fall within a liberal initial window (RECOMMENDED: +/-7 days of local clock time) for the first 10 minutes of operation, then revert to the standard +/-<tt>MAX_EXPIRATION_WINDOW</tt> check once the clock is likely synchronized.</t></li>
      </ol>
      <t>This heuristic does not provide cryptographically secure time synchronization and should not be confused with NTP or PTP. Its purpose is to prevent a node with a dead RTC from being permanently excluded from the mesh.</t>
    </section>
    <section anchor="cancel-authority-window-for-long-duration-events" title="CANCEL Authority Window for Long-Duration Events" numbered="true">
      <t>The 1-hop rotation chain limit (Section 5.4) combined with periodic key rotation (Section 9.1) creates a bounded CANCEL authority window. A message signed under key K0 can be cancelled by: (a) K0 directly during the KEY_OVERLAP_WINDOW, or (b) K1 (immediate successor of K0) while the K0-&gt;K1 rotation AUTH remains within its <tt>validity</tt> window. If an event spans more than the K0-&gt;K1 AUTH validity period, messages signed under K0 can no longer be cancelled cryptographically. Authorities operating multi-day deployments MUST set the <tt>validity</tt> field of rotation AUTH messages to cover the expected event duration, and MUST issue CANCEL messages for false alarms promptly following key rotation rather than deferring them. Note that this window exists only across rotation events: the 7-day RECOMMENDED rotation period for fixed installations (Section 9.1) means most events of ordinary duration complete under a single signing key, never exercising this machinery.</t>
    </section>
    <section anchor="mobile-platform-execution-constraints" title="Mobile Platform Execution Constraints" numbered="true">
      <t>The protocol-layer properties specified in this document assume that participating nodes can transmit, receive, and relay continuously. On consumer smartphone platforms -- the primary deployment target -- this assumption is constrained by the operating system, not by the protocol, and deployments MUST plan for the following realities:</t>
      <t><strong>Wi-Fi Direct topology constraints</strong>: Wi-Fi Direct requires Group Owner (GO) negotiation before any data transfer. Group formation takes approximately 2-8 seconds, produces a star topology centered on the GO rather than a true many-to-many mesh, and Android devices can be a member of only one P2P group at a time. A relay node bridging two groups must time-division multiplex between them, adding multi-second latency per bridge hop. Consequently, Wi-Fi Direct SHOULD be treated as a high-throughput secondary transport between already-associated peers (e.g., for AUTH/CRL transfer), not as the primary spontaneous-mesh transport. BLE advertising, which requires no association, group formation, or negotiation, SHOULD be the primary discovery and dissemination transport on smartphone deployments. The BLE Transport Binding Profile <xref target="OEPB-BLE"/> specifies this binding.</t>
      <t><strong>Background execution limits</strong>: Mobile operating systems aggressively restrict background radio activity. On iOS, an application cannot broadcast manufacturer-specific BLE advertising data while backgrounded, and background scanning is heavily throttled; on Android, Doze mode and App Standby throttle scanning, and continuous BLE operation requires a user-visible foreground service. Mesh applications relying on background participation have historically seen effective node density collapse once users switch away from the app -- a primary operational failure mode of the FireChat-class systems surveyed in Section 1.1. Smartphone deployments SHOULD therefore run as a foreground service with persistent user-visible notification (Android) and SHOULD document the foreground-only limitation to users (iOS). Reliable always-on relay participation ultimately requires OS-level or firmware-level integration (e.g., inclusion in a platform emergency framework); this is a deployment prerequisite that no overlay protocol can engineer around, and OEPB does not claim otherwise.</t>
      <t>These constraints reinforce the scope statement of Section 6.1: protocol-layer simulation results are lower bounds, and end-to-end behaviour on smartphone platforms is dominated by transport and OS factors that MUST be measured on target hardware.</t>
    </section>
    <section anchor="iana-codepoint-stability" title="IANA Codepoint Stability" numbered="true">
      <t>This document defines specific numeric codepoints (Message Types 0x01-0x05, Flags bits 0-3) as informational values for Experimental use. Concurrent independent implementations SHOULD use these exact codepoint values to maintain interoperability. If this specification is advanced to the Standards Track, IANA will be requested to create formal registries (see Section 12).</t>
      <t>In the interim, implementors extending the protocol with private codepoints SHOULD use values in the Reserved ranges. For Msg Type, the RECOMMENDED private-use range is 0xF0-0xFF (following the private-use range convention of <xref target="RFC8126"/>). For Flags bits, the RECOMMENDED private-use range is bits 8-15. Implementors SHOULD document their private codepoints in a manner that avoids collision with other deployments.</t>
    </section>
  </section>
  <section anchor="iana-considerations" title="IANA Considerations" numbered="true">
    <t>This document is published as an Experimental specification. Experimental documents do not create normative IANA registries; the codepoints defined below are for use by implementations of this specification and are not formally registered.</t>
    <t>If this specification is advanced to the IETF Standards Track, IANA would be requested to create and maintain the following registries under the &quot;OEPB Protocol Parameters&quot; heading. Until that time, implementors SHOULD use the codepoint values defined in this document and SHOULD NOT assume these values are reserved in any IANA namespace.</t>
    <t><strong>OEPB Message Types</strong> (informational, 8-bit namespace):</t>
    <table><thead><tr>
      <th>Value</th>
      <th>Name</th>
      <th>Reference</th>
    </tr></thead><tbody>
    <tr>
      <td>0x01</td>
      <td>SOS</td>
      <td>This document</td>
    </tr>
    <tr>
      <td>0x02</td>
      <td>ALERT</td>
      <td>This document</td>
    </tr>
    <tr>
      <td>0x03</td>
      <td>EVAC</td>
      <td>This document</td>
    </tr>
    <tr>
      <td>0x04</td>
      <td>INFO</td>
      <td>This document</td>
    </tr>
    <tr>
      <td>0x05</td>
      <td>AUTH</td>
      <td>This document</td>
    </tr>
    <tr>
      <td>0x06-0xFF</td>
      <td>Reserved for future use</td>
      <td>--</td>
    </tr>
    </tbody></table>
    <t><strong>OEPB Version Numbers</strong> (informational, 8-bit namespace):</t>
    <table><thead><tr>
      <th>Value</th>
      <th>Description</th>
      <th>Reference</th>
    </tr></thead><tbody>
    <tr>
      <td>0x01</td>
      <td>Version 1</td>
      <td>This document</td>
    </tr>
    <tr>
      <td>0x02-0xFF</td>
      <td>Reserved for future use</td>
      <td>--</td>
    </tr>
    </tbody></table>
    <t><strong>OEPB Flags Bits</strong> (informational, 16-bit namespace): Assignments per Section 5.5. Bits 4-15 are reserved and MUST be zero on transmission.</t>
  </section>
  <section anchor="references" title="References" numbered="true">
    <section anchor="normative-references" title="Normative References" numbered="true">
      <ul>
        <li><t><strong><xref target="RFC2119"/></strong> Bradner, S., &quot;Key words for use in RFCs to Indicate Requirement Levels&quot;, BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997.</t></li>
        <li><t><strong><xref target="RFC8174"/></strong> Leiba, B., &quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&quot;, BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017.</t></li>
        <li><t><strong><xref target="RFC6206"/></strong> Levis, P., Clausen, T., Hui, J., Gnawali, O., and J. Ko, &quot;The Trickle Algorithm&quot;, RFC 6206, DOI 10.17487/RFC6206, March 2011.</t></li>
        <li><t><strong><xref target="RFC8032"/></strong> Josefsson, S. and I. Liusvaara, &quot;Edwards-Curve Digital Signature Algorithm (EdDSA)&quot;, RFC 8032, DOI 10.17487/RFC8032, January 2017.</t></li>
        <li><t><strong><xref target="RFC8949"/></strong> Bormann, C. and P. Hoffman, &quot;Concise Binary Object Representation (CBOR)&quot;, RFC 8949, DOI 10.17487/RFC8949, December 2020.</t></li>
        <li><t><strong><xref target="RFC8610"/></strong> Birkholz, H., Vigano, C., and C. Bormann, &quot;Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures&quot;, RFC 8610, DOI 10.17487/RFC8610, June 2019.</t></li>
      </ul>
    </section>
    <section anchor="informative-references" title="Informative References" numbered="true">
      <ul>
        <li><t><strong><xref target="RFC5050"/></strong> Scott, K. and S. Burleigh, &quot;Bundle Protocol Specification&quot;, RFC 5050, DOI 10.17487/RFC5050, November 2007.</t></li>
        <li><t><strong><xref target="RFC8126"/></strong> Cotton, M., Leiba, B., and T. Narten, &quot;Guidelines for Writing an IANA Considerations Section in RFCs&quot;, BCP 26, RFC 8126, DOI 10.17487/RFC8126, June 2017.</t></li>
        <li><t><strong><xref target="RFC9171"/></strong> Burleigh, S. et al., &quot;Bundle Protocol Version 7&quot;, RFC 9171, DOI 10.17487/RFC9171, January 2022.</t></li>
        <li><t><strong><xref target="SERVAL"/></strong> Gardner-Stephen, P. and Arns, J., &quot;The Serval Project: Practical Wireless Ad Hoc Mobile Telecommunications&quot;, Technical Report, Flinders University, Australia, December 2011.</t></li>
        <li><t><strong><xref target="BT-MESH"/></strong> Bluetooth Special Interest Group, &quot;Mesh Profile Specification&quot;, Version 1.0.1, March 2019, &lt;https://www.bluetooth.com/specifications/specs/mesh-profile/&gt;.</t></li>
        <li><t><strong><xref target="EPIDEMIC"/></strong> Vahdat, A. and Becker, D., &quot;Epidemic Routing for Partially Connected Ad Hoc Networks&quot;, Technical Report CS-2000-06, Duke University, April 2000.</t></li>
        <li><t><strong><xref target="IEEE80211S"/></strong> IEEE, &quot;IEEE Standard for Information Technology -- Local and Metropolitan Area Networks -- Part 11: Wireless LAN MAC and PHY Specifications Amendment 10: Mesh Networking&quot;, IEEE Std 802.11s-2011, September 2011.</t></li>
        <li><t><strong><xref target="MESHTASTIC"/></strong> Meshtastic Project, &quot;Meshtastic Open Source Mesh Communication&quot;, 2020, &lt;https://meshtastic.org&gt;.</t></li>
        <li><t><strong><xref target="APRS"/></strong> Bruninga, B., &quot;Automatic Packet Reporting System -- Protocol Reference 1.0.1&quot;, US Naval Academy, 2000, &lt;http://www.aprs.org/doc/APRS101.PDF&gt;.</t></li>
        <li><t><strong><xref target="DISASTER-RADIO"/></strong> Disaster Radio Project, &quot;Disaster Radio: Open Source LoRa Mesh Communication&quot;, 2019, &lt;https://disaster.radio&gt;.</t></li>
        <li><t><strong><xref target="OEPB-BLE"/></strong> Sharma, K., &quot;OEPB Transport Binding: Bluetooth Low Energy&quot;, Internet-Draft draft-sharma-oepb-binding-ble-00, June 2026.</t></li>
      </ul>
      <t>---</t>
    </section>
    <section anchor="test-vectors-and-routing-example" title=": Test Vectors and Routing Example" numbered="true">
      <section anchor="a-1-end-to-end-broadcast-flow" title="A.1 End-to-End Broadcast Flow" numbered="true">
        <ol>
          <li><t><strong>Generation</strong>: Node A constructs an SOS CBOR payload containing WGS84 latitude and longitude in microdegrees. It assembles the OEPB fixed header with a fresh 64-bit Nonce and current Timestamp, computes the 16-byte MsgID per Section 5.3, signs the canonical signature input with its Ed25519 private key, and sets the SIGNED flag in the Flags field.</t></li>
        </ol>
        <ol>
          <li><t><strong>Relay at Node B</strong>: Node B receives the frame via BLE. The MIL checks the 16-byte MsgID against its deduplication cache -- cache miss, so the packet is novel. The MIL verifies basic header validity (Version, Msg Type, TTL &gt; 0, Payload Length within bounds). The packet is enqueued in the SOS WFQ class. The MIL schedules a Trickle transmission after a random delay in [0, Imin]. If <tt>c &lt; k</tt> copies are observed before the interval fires, Node B transmits on all active Transport Bindings (BLE + Wi-Fi Direct), decrementing TTL by 1 and incrementing Hop Count by 1.</t></li>
        </ol>
        <ol>
          <li><t><strong>Application Layer</strong>: Nodes at or beyond Node B that receive the packet present it to the user with trust level 0 (unauthenticated SOS) unless they can verify the signature against a locally trusted key.</t></li>
        </ol>
      </section>
      <section anchor="a-2-complete-verifiable-test-vector" title="A.2 Complete Verifiable Test Vector" numbered="true">
        <t>The following is a fully verifiable OEPB v1 SOS packet. All field values, the Message ID, and the Ed25519 signature are cryptographically correct and independently reproducible from the key material below.</t>
        <t><strong>Key Material</strong></t>
        <artwork><![CDATA[
Private Key Seed (Ed25519, 32 bytes):
  9D61B19DEFFD5A60BA844AF492EC2CC4
  4449C5697B326919703BAC031CAE3D55

Public Key (Ed25519, 32 bytes):
  700E2CE7C4B674427EAB27BA820BCF6F
  0FAEBE68E09FE8564292114E41DC6A41
]]></artwork>
        <t><strong>Packet Field Values</strong></t>
        <artwork><![CDATA[
Version     : 0x01
Msg Type    : 0x01 (SOS)
TTL         : 0x0A (10)
Hop Count   : 0x00
Timestamp   : 0x000000006787A340 = 1736942400 = 2025-01-15 12:00:00 UTC
Nonce       : 0x4F4550425F563100 (ASCII "OEPBV1\x00\x00")
Flags       : 0x0001 (SIGNED)
Payload Len : 0x0010 (16 bytes)
]]></artwork>
        <t><strong>CBOR Payload (16 bytes) -- SOS {latitude, longitude, accuracy}</strong></t>
        <artwork><![CDATA[
A3                      CBOR map(3)
  01 1A 01 B4 9D 70  key=1, lat  = 28614000 (~28.614 N, New Delhi)
  02 1A 04 9A 03 7C  key=2, lon  = 77202300 (~77.202 E)
  03 18 1E              key=3, accuracy  = 30 meters

Payload hex: A3 01 1A 01 B4 9D 70 02 1A 04 9A 03 7C 03 18 1E
]]></artwork>
        <t><strong>Message ID (SHA-256 truncated, 16 bytes)</strong></t>
        <t>Input to SHA-256 (38 bytes):</t>
        <artwork><![CDATA[
01 01                            Version || MsgType
00 00 00 00 67 87 A3 40          Timestamp (BE)
4F 45 50 42 5F 56 31 00          Nonce (BE)
00 10                            PayloadLength (BE)
00 01                            Flags (BE)
A3 01 1A 01 B4 9D 70 02
1A 04 9A 03 7C 03 18 1E          Payload
]]></artwork>
        <artwork><![CDATA[
MsgID: 11 84 78 44 E6 41 C2 8C 0F 40 48 24 08 8B 09 6B
]]></artwork>
        <t>SHA-256 input (38 bytes, strictly packed, network byte order -- no padding): <tt>01 01 00 00 00 00 67 87 A3 40 4F 45 50 42 5F 56 31 00 00 10 00 01 A3 01 1A 01 B4 9D 70 02 1A 04 9A 03 7C 03 18 1E</tt></t>
        <t><strong>Signature Input (72 bytes)</strong></t>
        <artwork><![CDATA[
01 01                            Version || MsgType
00 00 00 00 67 87 A3 40          Timestamp (BE)
4F 45 50 42 5F 56 31 00          Nonce (BE)
11 84 78 44 E6 41 C2 8C          MsgID (first 8 bytes)
0F 40 48 24 08 8B 09 6B          MsgID (last 8 bytes)
00 10                            PayloadLength (BE)
00 01                            Flags (BE)
A3 01 1A 01 B4 9D 70 02
1A 04 9A 03 7C 03 18 1E          Payload
]]></artwork>
        <t><strong>Ed25519 Signature (64 bytes)</strong></t>
        <artwork><![CDATA[
B9 81 45 84 5F DD D9 6F  0F 49 FE 2F 95 23 16 EE
0A DE 69 53 66 E2 85 92  E3 3C 91 28 B1 59 B8 98
A8 51 E4 66 11 E6 2F F5  CE C8 36 D1 E9 15 2D 06
A9 99 C1 4C 28 E4 37 A7  25 07 6B 97 58 16 FA 08
]]></artwork>
        <t><strong>Complete Wire Packet (120 bytes)</strong></t>
        <artwork><![CDATA[
01 01 0A 00 00 00 00 00  67 87 A3 40 4F 45 50 42
5F 56 31 00 11 84 78 44  E6 41 C2 8C 0F 40 48 24
08 8B 09 6B 00 10 00 01  A3 01 1A 01 B4 9D 70 02
1A 04 9A 03 7C 03 18 1E  B9 81 45 84 5F DD D9 6F
0F 49 FE 2F 95 23 16 EE  0A DE 69 53 66 E2 85 92
E3 3C 91 28 B1 59 B8 98  A8 51 E4 66 11 E6 2F F5
CE C8 36 D1 E9 15 2D 06  A9 99 C1 4C 28 E4 37 A7
25 07 6B 97 58 16 FA 08
]]></artwork>
        <t>Wire size: 40 (header) + 16 (payload) + 64 (signature) = <strong>120 bytes</strong>. Well within the 256-byte MTU.</t>
        <t>Implementations can verify this vector by:</t>
        <ol>
          <li><t>Loading the 32-byte private seed to reconstruct the Ed25519 keypair.</t></li>
          <li><t>Computing MsgID per Section 5.3 over the immutable fields shown above.</t></li>
          <li><t>Constructing the Signature Input as shown.</t></li>
          <li><t>Verifying the 64-byte signature against the Signature Input using the public key.</t></li>
        </ol>
        <t>Reference implementation for generating and verifying this vector: <tt>simulator/python/gen_test_vectors.py</tt></t>
      </section>
    </section>
  </section>
  <section anchor="reference-implementation-notes" title="Reference Implementation Notes" numbered="true">
    <t>The Android reference implementation (BroadcasterApp / ReceiverApp) uses a 48-byte fixed header that differs from the canonical 40-byte wire format defined in Section 5.1. The implementation header layout is:</t>
    <artwork><![CDATA[
Version(1) | Type(1) | Flags(1) | TTL(1) | MsgID(16) |
CreatedTime(4) | Nonce(8) | GeoScope(8) | SenderID(8)
]]></artwork>
    <t>The canonical format uses an 8-byte Timestamp, a 2-byte PayloadLength, and 2-byte Flags field in place of the 1-byte Flags, 4-byte CreatedTime, and 8-byte Nonce. The MsgID computation in the reference implementation is functionally equivalent to Section 5.3 but operates over the implementation header fields rather than the canonical layout.</t>
    <t>This divergence exists because the reference implementation predates the finalisation of the canonical wire format. Interoperability with conformant implementations requires alignment to the Section 5.1 format.</t>
    <t>The signature verification in the reference implementation is a flag-check mock (SIGNED and AUTHORITY_HINT flags present) rather than actual Ed25519 verification. Real deployments MUST verify signatures per Section 5.3.</t>
  </section>
</middle>
<back>
  <references title="Normative References">
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.6206.xml"/>
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8032.xml"/>
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8949.xml"/>
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8610.xml"/>
  </references>
  <references title="Informative References">
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5050.xml"/>
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.9171.xml"/>
    <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8126.xml"/>
    <reference anchor="SERVAL">
      <front>
        <title>The Serval Project: Practical Wireless Ad Hoc Mobile Telecommunications</title>
        <author fullname="Paul Gardner-Stephen"/>
        <date year="2011"/>
      </front>
      <seriesInfo name="Technical Report" value="Flinders University, Australia"/>
    </reference>
    <reference anchor="BT-MESH" target="https://www.bluetooth.com/specifications/specs/mesh-profile/">
      <front>
        <title>Mesh Profile Specification</title>
        <author fullname="BT-MESH"/>
        <date year="2019"/>
      </front>
      <seriesInfo name="Version" value="1.0.1"/>
    </reference>
    <reference anchor="EPIDEMIC">
      <front>
        <title>Epidemic Routing for Partially Connected Ad Hoc Networks</title>
        <author fullname="Amin Vahdat"/>
        <date year="2000"/>
      </front>
      <seriesInfo name="Technical Report" value="CS-2000-06, Duke University"/>
    </reference>
    <reference anchor="IEEE80211S">
      <front>
        <title>IEEE Standard for Information Technology -- Local and Metropolitan Area Networks -- Part 11: Wireless LAN MAC and PHY Specifications Amendment 10: Mesh Networking</title>
        <author fullname="IEEE80211S"/>
        <date year="2011"/>
      </front>
      <seriesInfo name="IEEE Std" value="802.11s-2011"/>
    </reference>
    <reference anchor="MESHTASTIC" target="https://meshtastic.org">
      <front>
        <title>Meshtastic Open Source Mesh Communication</title>
        <author fullname="MESHTASTIC"/>
        <date year="2020"/>
      </front>
    </reference>
    <reference anchor="APRS" target="http://www.aprs.org/doc/APRS101.PDF">
      <front>
        <title>Automatic Packet Reporting System -- Protocol Specification</title>
        <author fullname="Bob Bruninga"/>
        <date year="2000"/>
      </front>
      <seriesInfo name="APRS101" value="APRS Protocol Reference 1.0.1"/>
    </reference>
    <reference anchor="DISASTER-RADIO" target="https://disaster.radio">
      <front>
        <title>Disaster Radio: Open Source LoRa Mesh Communication</title>
        <author fullname="DISASTER-RADIO"/>
        <date year="2019"/>
      </front>
    </reference>
    <reference anchor="OEPB-BLE">
      <front>
        <title>OEPB Transport Binding: Bluetooth Low Energy</title>
        <author fullname="Karan Sharma"/>
        <date year="2026"/>
      </front>
      <seriesInfo name="Internet-Draft" value="draft-sharma-oepb-binding-ble-00"/>
    </reference>
  </references>
</back>
</rfc>
