<?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-01"
     ipr="trust200902"
     submissionType="independent"
     version="3">
<front>
  <title abbrev="OEPB">Offline Emergency Peer-to-Peer Broadcast Protocol</title>
  <seriesInfo name="Internet-Draft" value="draft-sharma-oepb-01"/>
  <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="September" day="30"/>
  <workgroup>Independent Submission</workgroup>
  <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), an experimental protocol for disseminating authenticated emergency alerts among unprovisioned devices over short-range peer-to-peer radios when network infrastructure is unavailable. OEPB defines a compact 256-byte packet format with Ed25519 signatures; a transport abstraction over radios such as Bluetooth Low Energy, Wi-Fi Direct, and LoRa; per-message Trickle dissemination with a bounded number of retransmissions; a five-class weighted fair queuing scheme reflecting emergency triage priorities; and a trust model in which relays forward without verifying signatures, so that unauthenticated distress messages still propagate while receivers authenticate authority alerts. A companion document defines the Bluetooth Low Energy transport binding.</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. A maximum-size packet fits in a single Wi-Fi Direct frame or a single BLE 5.x extended advertising event (which, because the packet plus advertising framing exceeds the 254-byte AUX_ADV_IND payload, requires AUX_CHAIN_IND chaining); on BLE 4.x legacy advertising (31-byte AdvData) the TAL provides transparent L2 fragmentation and reassembly <xref target="OEPB-BLE"/>.</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>Per-message Trickle <xref target="RFC6206"/> dissemination with a bounded number of interval expirations, as in MPL <xref target="RFC7731"/>, adopted here for multi-class non-IP broadcast; constants are 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>Section 1.1 discusses the relationship to prior implementations and standards, Section 1.2 the relationship to IETF work, and Section 1.3 the scope of the experiment this document proposes.</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, and BPSec <xref target="RFC9172"/> secures bundles end to end. OEPB differs in three practical respects. First, bundles are addressed to endpoints, whereas OEPB is broadcast-by-default to every reachable device. Second, the Bundle Protocol primary block plus a BPSec integrity block consumes a substantial fraction of the 256-byte MTU that OEPB targets, leaving little room for payload and signature on BLE-class links. Third, there is no standardized Bundle Protocol convergence layer for connectionless BLE advertising, the primary transport OEPB targets on smartphones (Section 11.3). OEPB could in principle be carried as a bundle payload where a Bundle Protocol deployment exists; this document does not define such a mapping.</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 protocols are open source but have not been published as an IETF specification, which limits independent interoperable implementation. OEPB aims to provide a published, implementable specification for the class of system Serval demonstrated.</t>
      </section>
      <section anchor="bluetooth-mesh" title="Bluetooth Mesh" numbered="true">
        <t>Bluetooth Mesh (originally the Mesh Profile, now the Mesh Protocol specification, version 1.1 <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 three substantive respects: (1) Bluetooth Mesh is BLE-only, whereas OEPB's TAL supports heterogeneous radio technologies; (2) Bluetooth Mesh relaying relies on TTL, a network message cache, and configured relay retransmission counts rather than a density-adaptive suppression mechanism equivalent to Trickle; and (3) Bluetooth Mesh requires prior provisioning of devices into a managed network with shared network keys, which is incompatible with the spontaneous, uncoordinated participation model required for disaster response. Bluetooth Mesh is well suited to pre-provisioned sensor and building-control 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. Neither protocol is published as an open specification. An independent security analysis of Bridgefy <xref target="BRIDGEFY-BREAK"/> found that, as analyzed, it provided no message authenticity, permitted tracking of users, and could be disrupted network-wide by a single crafted message; later versions of the application revised its cryptography, but its protocol remains unpublished. Neither system publishes an authority-authentication model, a priority-queuing discipline, or a suppression mechanism that independent implementations could interoperate with. OEPB aims to provide an open, implementable specification covering these aspects.</t>
      </section>
      <section anchor="briar" title="Briar" numbered="true">
        <t>Briar is an open-source peer-to-peer messenger whose Bramble transport, synchronisation, and rendezvous protocols are openly documented <xref target="BRIAR"/> and which can operate over Bluetooth and Wi-Fi without Internet access. Briar targets confidential messaging between contacts who have established a relationship (for example, by exchanging QR codes in person) and forums among such contacts. It does not target broadcast of authority alerts to arbitrary, previously unknown devices, and it does not define a priority taxonomy for emergency traffic. OEPB is complementary: it provides public, authenticated broadcast rather than confidential contact-to-contact messaging.</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 using hop-limited &quot;managed flooding&quot; with packet-ID deduplication. Before rebroadcasting a packet, a node waits for a contention window whose size depends on the received signal-to-noise ratio (so that more distant receivers tend to rebroadcast first), and it cancels its own pending rebroadcast if it overhears another node rebroadcast the same packet. This is counter-based suppression with a threshold of k=1 and a single transmission opportunity. OEPB differs in that it defines a radio-agnostic TAL (not LoRa-specific); uses Trickle with k=3 and a bounded number of retransmissions across several intervals, which provides the loss recovery quantified in Section 6.1 that a single transmission opportunity cannot; defines a formal five-class priority taxonomy; and provides a cryptographic authority trust model based on 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.</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 anchor="relationship-to-ietf-work" title="Relationship to IETF Work" numbered="true">
      <t>OEPB is not an IP protocol and does not modify, extend, or depend on any IETF-specified protocol. It operates directly over link-layer broadcast primitives (e.g., BLE advertising) among devices that share no network configuration, addressing, or prior provisioning, and it defines no IP, transport, or IANA-registered codepoints. It does not conflict with active IETF work and is not intended as a substitute for it.</t>
      <t>The IETF has standardized related mechanisms for IP networks. Simplified Multicast Forwarding <xref target="RFC6621"/> provides duplicate-suppressed flooding within MANETs. The Multicast Protocol for Low-Power and Lossy Networks <xref target="RFC7731"/> disseminates data using per-message Trickle <xref target="RFC6206"/> timers with a bounded number of expirations, an approach OEPB adopts (Section 6.3). RPL <xref target="RFC6550"/> provides routing for LLNs. The Bundle Protocol <xref target="RFC9171"/> with BPSec <xref target="RFC9172"/> provides secured store-carry-forward delivery. Each assumes an IP (or bundle) addressing context, configured nodes, or endpoint-addressed delivery. OEPB instead targets unprovisioned consumer devices that must exchange short, authenticated, priority-classed broadcasts with no shared configuration at all.</t>
      <t>The Authority-to-Citizen Alert (ATOCA) working group, now concluded, was chartered to deliver alerts to IP endpoints only, building on existing message-delivery protocols; infrastructure-less peer-to-peer dissemination was outside its scope. OEPB addresses only that case. Should the IETF take up infrastructure-less emergency dissemination, this document is offered as input to that work, and its experimental codepoints impose no constraint on it.</t>
    </section>
    <section anchor="experiment-scope" title="Experiment Scope" numbered="true">
      <t>This document is published with Experimental status because several of its design choices have been characterized only in simulation and require field evidence before they could be recommended for broad deployment. The experiment is intended to answer the following questions:</t>
      <ol>
        <li><t><strong>Trickle termination constants</strong>: Do <tt>MAX_TRICKLE_INTERVALS = 8</tt> and <tt>MAX_TRICKLE_TX = 3</tt> (Section 6.3), with Imin = 50 ms and k = 3, deliver messages reliably on real BLE hardware with realistic loss, collisions, and scan duty cycles, or must they be scaled to the transport's timing?</t></li>
        <li><t><strong>Forwarding without verification</strong>: Does separating forwarding from signature verification (Sections 7 and 9) preserve reachability for unauthenticated SOS traffic without enabling unacceptable abuse in practice, including the signature-substitution race of Section 10.11?</t></li>
        <li><t><strong>WFQ weights under load</strong>: Do the default weights of Section 4 keep EVAC and ALERT latency acceptable during mass-casualty SOS load, and is the permitted local override range adequate?</t></li>
        <li><t><strong>BLE fragment trains</strong>: Does the BLE 4.x fragment train of the companion binding <xref target="OEPB-BLE"/> reassemble reliably on real controller stacks, including under address randomization and scan throttling?</t></li>
      </ol>
      <t>Results that would change this specification include: delivery or latency on hardware materially worse than the simulated lower bounds of Section 6.1, which would require different Trickle constants or per-transport scaling rules; evidence that signature substitution or unauthenticated flooding defeats the mitigations of Sections 8 and 10, which would require changing the forwarding or re-admission rules; and fragment-train failure rates that make the BLE 4.x path impractical, which would restrict the binding to BLE 5.x extended advertising. Results will be reported in the project repository and on the mailing lists where this document is discussed, and will inform subsequent revisions.</t>
    </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 BLE 5.x paths (extended advertising with AUX_CHAIN_IND chaining, and GATT connections with ATT_MTU negotiation). 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 signing status 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 ingress freshness checks (Section 7) and cache eviction 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; a malleated variant that reaches a relay is handled by the bounded signature-variant re-admission rule of Section 7.2 and cannot circulate indefinitely.</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>The payload schemas below are expressed in CDDL <xref target="RFC8610"/>. 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>AUTH payloads are processed as specified in Section 9.5: an announcement is accepted only if its signer is authorized to certify or rotate the announced key, and a revocation (auth_action=0x02) only if it verifies under a root anchor, under the revoked key itself, or under the key that certified the revoked key. The subject_id of an announcement MUST equal Truncate_128(SHA-256(key_material)); an announcement where it does not MUST be discarded.</t>
      <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>Record <tt>target_msg_id</tt> in the tombstone set and suppress display of the target message to the user. The tombstone set is the single structure that holds cancellation state, whether or not the original message was ever received: recording a MsgID that was never received preemptively suppresses any later out-of-order arrival of the original. A MsgID in the tombstone set MUST be treated as a duplicate by Section 7 even if it has been evicted from the deduplication cache. Tombstone entries MUST persist for <tt>MAX_EXPIRATION_WINDOW</tt> unless evicted for capacity. The tombstone set MUST be bounded to at most <tt>MAX_TOMBSTONE_SIZE = 512</tt> entries; when it is full, the least recently inserted entry MUST be evicted (LRU) to make room. Capacity eviction may remove a tombstone that is still within its <tt>MAX_EXPIRATION_WINDOW</tt>, creating a residual window in which the cancelled message could be accepted again if the original is replayed 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. Advisory only; relays do not evaluate it. At the Application Layer it is honored only if the signature verifies under a Trust Level 3 key (Sections 9.5 and 10.3).</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"/>, which originated as a suppression mechanism for code propagation in sensor networks <xref target="TRICKLE-2004"/> and is used per message for data dissemination by MPL <xref target="RFC7731"/>. OEPB uses 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>Cap on interval doubling</td>
    </tr>
    <tr>
      <td>k</td>
      <td>3</td>
      <td>Redundancy constant</td>
    </tr>
    </tbody></table>
    <t>RFC 6206 expresses Imax as a number of doublings of Imin. OEPB instead specifies Imax directly as a 1000 ms cap: the interval doubles from Imin through 50, 100, 200, 400, and 800 ms, and the next doubling (1600 ms) is clamped to 1000 ms. Because 1000 ms is not a power-of-two multiple of Imin, implementations that represent Imax as a doubling count MUST clamp the interval at 1000 ms rather than round to 800 ms or 1600 ms.</t>
    <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. Nodes are placed uniformly at random, so sparse topologies are frequently disconnected. Delivery is therefore defined as the fraction of nodes in the source's connected component (the nodes that are reachable at all, including the source) that receive the message; it is not the fraction of all nodes. The mean size of that component is reported alongside each density. 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>Mean Component Size</th>
        <th>Delivery</th>
        <th>Median Latency</th>
        <th>p95 Latency</th>
        <th>Suppression</th>
      </tr></thead><tbody>
      <tr>
        <td>10</td>
        <td>3.8</td>
        <td>100.0%</td>
        <td>23 ms</td>
        <td>43 ms</td>
        <td>9.5%</td>
      </tr>
      <tr>
        <td>25</td>
        <td>14.9</td>
        <td>100.0%</td>
        <td>63 ms</td>
        <td>143 ms</td>
        <td>27.1%</td>
      </tr>
      <tr>
        <td>50</td>
        <td>49.3</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>100.0%</td>
        <td>63 ms</td>
        <td>103 ms</td>
        <td>70.3%</td>
      </tr>
      <tr>
        <td>200</td>
        <td>200.0</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 within the source's connected component 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. At 10 nodes the component averages only 3.8 nodes, so the sparsest results describe small connected clusters rather than a 10-node mesh; the 100- and 200-node topologies are fully connected in every run.</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 approximates the single-transmission-opportunity mechanism of the Meshtastic/Disaster Radio class of systems surveyed in Section 1.1 (Meshtastic additionally cancels a pending rebroadcast on overhearing one, which reduces transmissions further but adds no retransmission). 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> performed best among the values tested (Imin in {50, 100, 200} ms and k in {2, 3, 5}); no broader optimization was performed. 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 need to 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>: As used for maintaining routing state or code consistency, Trickle 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, following the precedent of MPL <xref target="RFC7731"/>, in which a node stops transmitting a data message after DATA_MESSAGE_TIMER_EXPIRATIONS (default 3) Trickle timer expirations. 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>Timestamp stale or future-dated relative to the local clock: <tt>LocalClock - Timestamp &gt; MAX_EXPIRATION_WINDOW</tt>, or <tt>Timestamp - LocalClock &gt; MAX_FUTURE_SKEW</tt> (<tt>MAX_FUTURE_SKEW = 1 hour</tt>). This check is subject only to the clock-bootstrap exception of Section 11.1.</t></li>
      <li><t>MsgID already present in the deduplication cache or, on nodes that maintain one, the tombstone set (Section 5.4), except for the bounded signature-variant re-admission of Section 7.2.</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>
      <li><t>Msg Type AUTH (0x05) with the SIGNED flag not set. Like the CANCEL check, this requires only the fixed header and is applied by relays.</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. Copies of the same logical packet that carry different signature bytes share one cache entry; their handling is bounded by Section 7.2. 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 (2^-128 for any given pair). Implementations MUST NOT create a second cache entry for a MsgID. A packet whose MsgID matches a cached entry is a duplicate, subject only to the signature-variant rule of Section 7.2 when both copies are signed; an unsigned packet whose MsgID matches a cached entry MUST be discarded.</t>
    </section>
    <section anchor="signature-variant-re-admission" title="Signature-Variant Re-admission" numbered="true">
      <t>Because the signature is excluded from the MsgID and relays do not verify signatures, an adversary that overhears a genuine signed packet can rebroadcast it with different (invalid) signature bytes. Nodes that receive the altered copy first would cache the MsgID and discard the genuine copy as a duplicate, so terminals behind them would see only an unverifiable copy (Section 10.11). To bound this, nodes apply the following rule:</t>
      <ol>
        <li><t>Each deduplication cache entry for a signed packet MUST store a short hash of every distinct signature seen for that MsgID (the first 8 bytes of SHA-256 over the 64-byte signature suffice), up to <tt>1 + MAX_SIG_VARIANTS</tt> hashes, where <tt>MAX_SIG_VARIANTS = 2</tt>.</t></li>
        <li><t>When a packet with the SIGNED flag set arrives whose MsgID is cached, and whose signature hash differs from every stored hash for that MsgID, and fewer than <tt>MAX_SIG_VARIANTS</tt> variants have been accepted for that MsgID, the node MUST accept it as a signature variant: it MUST store the hash, pass the packet to the Application Layer, and forward it.</t></li>
        <li><t>An accepted variant is forwarded once on each active Transport Binding after a random delay in [0, Imin], subject to the intake budgets of Section 8.2. It MUST NOT create a new Trickle instance and MUST NOT increment the counter c of the existing instance for that MsgID.</t></li>
        <li><t>Copies whose signature hash matches a stored hash, and variants beyond <tt>MAX_SIG_VARIANTS</tt>, are duplicates and MUST be silently discarded.</t></li>
        <li><t>A node whose Application Layer has already verified a valid signature on an earlier copy of the same MsgID MAY decline to forward a variant whose signature fails verification. This does not gate forwarding of any message, only of a redundant copy known to be invalid.</t></li>
      </ol>
      <t>The rule applies only to signed packets; since the Flags field (including SIGNED) is an input to the MsgID, a signed and an unsigned packet cannot share a MsgID.</t>
    </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 entries in order of local arrival, least recently inserted first (LRU), until the entry count is within bounds. Eviction MUST NOT be ordered by the packet's Timestamp field: an attacker-chosen Timestamp would otherwise let future-dated packets pin themselves in the cache and push out legitimate entries. The ingress check of Section 7 bounds how far in the future an accepted Timestamp can be (<tt>MAX_FUTURE_SKEW</tt>).</t></li>
      </ul>
      <t>Note on CANCEL persistence: cancellation state is held in the bounded tombstone set of Section 5.4, not in the deduplication cache, so that capacity eviction of the deduplication cache does not re-admit a cancelled message. A MsgID in the tombstone set is treated as a duplicate (Section 7) even after its deduplication cache entry is evicted. The tombstone set has its own bound and LRU eviction rule (Section 5.4); there is no other unbounded cancellation state.</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 authorized 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. Because the revoked key and its certifier are unknown to the node, such a revocation is authorized only if it verifies under a root anchor (Section 9.5); a revocation that does not verify under an authorized key MUST NOT modify the 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. Because only root-anchor-signed revocations enter the deny-list, an attacker without a root anchor key cannot cycle legitimate revocations out of it.</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 should 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>Signature verifies under a root anchor or a key certified under one (Section 9.5)</td>
      </tr>
      </tbody></table>
      <t>Assignment of Levels 1 and 2 is implementation-defined; Level 3 is assigned only as specified in Section 9.5. 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). Keys certified by a root anchor through AUTH announcements are also Trust Level 3 (Section 9.5). Nodes that cannot resolve a message's signing key to Trust Level 3 MUST treat the message as Trust Level 0 unless local policy assigns Level 1 or 2, 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>: The per-transport-source intake budgets of Section 8.2 limit the throughput of any single transmitter that does not rotate its L2 address. They do not bound an attacker that does (Section 10.2).</t></li>
      </ul>
      <t>Trickle suppression does not mitigate fabricated SOS floods: it suppresses redundant copies of one MsgID, whereas a flood of fabricated SOS messages consists of distinct MsgIDs.</t>
      <t>Geographic evaluation is delegated to emergency responder analysis; the protocol does not attempt algorithmic verification of SOS legitimacy.</t>
    </section>
    <section anchor="signer-resolution-and-key-certification" title="Signer Resolution and Key Certification" numbered="true">
      <t><strong>Signer resolution.</strong> The OEPB header carries no key identifier. To verify a signed packet, the Application Layer performs trial verification: it attempts verification under each root anchor, then under each currently valid key in its trust store, and stops at the first success. Implementations MUST bound the number of candidate keys tried per packet to <tt>MAX_VERIFY_CANDIDATES = 32</tt> and SHOULD order candidates by likelihood (for example, most recently successful first). A packet for which no candidate verifies is Trust Level 0. Each Ed25519 verification costs approximately 0.5-2 ms on constrained hardware (Section 10.8), so an unverifiable packet costs up to <tt>MAX_VERIFY_CANDIDATES</tt> verifications; the intake budgets of Section 8.2 bound the rate at which an attacker can impose this cost. Deployments SHOULD keep the number of concurrently valid keys below <tt>MAX_VERIFY_CANDIDATES</tt>. A key-identifier hint is a candidate extension for a future version.</t>
      <t><strong>Key certification.</strong> An AUTH announcement (auth_action=0x01) whose signature verifies under a root anchor certifies the announced key: the key enters the trust store at Trust Level 3. Certification depth is limited to one: a key certified by a root anchor (a sub-authority key) MUST NOT certify further keys, and an announcement signed by a sub-authority key is never treated as a certification.</t>
      <t><strong>Rotation.</strong> An AUTH announcement signed by a sub-authority key K already in the trust store is a rotation announcement: the announced key K' becomes the successor of K and inherits K's trust level. A key MUST NOT have more than one successor; the first valid rotation announcement received is accepted, and a second rotation announcement signed by the same key MUST be ignored and SHOULD be reported to the user or operator as a possible key compromise. The validity of a successor MUST NOT extend beyond the validity of the root-certified key at the start of its rotation chain, so that a chain of rotations cannot outlive its root certification without the root anchor re-certifying.</t>
      <t><strong>Validity.</strong> The <tt>validity</tt> field of an announcement is a duration in seconds counted from the Timestamp of the AUTH packet that carries it. A key whose validity has elapsed MUST NOT be used for verification of messages whose Timestamp is later than its expiry.</t>
      <t><strong>Revocation authorization.</strong> An AUTH revocation (auth_action=0x02) MUST be accepted only if its signature verifies under (a) a root anchor, (b) the revoked key itself, or (c) the key that certified or announced the revoked key (the root anchor for a sub-authority key, or the predecessor for a rotation successor). Revocations that do not verify under one of these keys MUST NOT modify the trust store or the deny-list of Section 8.2. A revocation signed by a root anchor also revokes every successor of the revoked key. A revocation signed by the revoked key itself or by its predecessor revokes only that key; its successors remain valid unless separately revoked. This prevents an adversary holding a compromised, superseded key from revoking the current key. Superseded keys expire through their validity and need not be revoked; revocation signals compromise. Revocation applies only to keys announced via AUTH; root anchors cannot be revoked in band (Section 10.9).</t>
      <t><strong>Unsigned AUTH.</strong> AUTH packets MUST be signed. Unsigned AUTH packets are discarded on ingress by every node, including relays (Section 7).</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. The ingress freshness check of Section 7 discards any packet older than <tt>MAX_EXPIRATION_WINDOW</tt> or more than <tt>MAX_FUTURE_SKEW</tt> in the future, and the deduplication cache retains each accepted MsgID for <tt>MAX_EXPIRATION_WINDOW</tt>; together these bound the replay window to <tt>MAX_EXPIRATION_WINDOW</tt>. Two residual cases remain. First, capacity eviction (Section 8.1) can remove an entry before its window expires, after which a replay within the window is accepted as novel; this is bounded by <tt>MAX_CACHE_SIZE</tt>. Second, the clock-bootstrap exception of Section 11.1 temporarily widens the freshness window on nodes with unsynchronized clocks. A packet timestamped in the past may be legitimate (the originating node had a wrong clock) or a replay; implementations cannot distinguish the two.</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. Two MIL-level backstops bound this attack: (1) the per-transport-source intake budget <tt>MAX_PKT_RATE</tt> (Section 8.2), with the stricter unauthenticated-SOS sub-limit, caps acceptance from any single L2 source; and (2) the Global Intake Limit (Section 8.3) applies WFQ-ordered tail drop when queue depth is exceeded. The per-key token bucket of Section 8.2 is not an amplification backstop: it is applied only at the Application Layer, after forwarding, and relays forward regardless of it. Implementations SHOULD additionally monitor total forwarding rate and apply backpressure when it exceeds a locally configured threshold.</t>
      <t>An attacker that rotates its L2 source address defeats every per-source budget. Such an attacker can inject an unbounded number of distinct unsigned SOS messages, each accepted as novel, and can saturate the SOS WFQ class (and, through it, a large share of airtime). This is a fundamental residual risk of a design that must accept unauthenticated SOS from unknown devices; the Global Intake Limit bounds queue growth but cannot distinguish genuine from fabricated SOS traffic.</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 under a Trust Level 3 key (Section 9.5).</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. The Trickle termination bounds (Section 6.3) limit the transmissions spent on any one message to <tt>MAX_TRICKLE_TX</tt> per binding, but they do not limit the number of distinct novel messages an attacker can inject; that is bounded only by the intake budgets and the Global Intake Limit of Section 8, subject to the L2-address-rotation caveat of Section 10.2. 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 (Sections 5.4 and 9.5) applies to keys announced via AUTH 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 anchor="signature-substitution" title="Signature Substitution" numbered="true">
      <t><strong>Attack.</strong> The signature is excluded from the MsgID (it cannot be included, since the MsgID is part of the signature input), and relays forward signed packets without verifying them. An adversary within radio range that overhears a genuine signed EVAC or ALERT can immediately rebroadcast it with the same header and payload but garbage signature bytes. A node that receives the altered copy first caches the MsgID; without mitigation it would discard the later genuine copy as a duplicate, and every terminal reachable only through such nodes would receive only the unverifiable copy, degrading an authority alert to Trust Level 0.</t>
      <t><strong>Mitigation.</strong> The bounded signature-variant re-admission rule of Section 7.2 lets a node accept and forward up to <tt>MAX_SIG_VARIANTS = 2</tt> additional copies of a cached MsgID whose signatures differ from every copy already seen. A genuine copy arriving after one forged copy is therefore still forwarded and delivered to the Application Layer, which verifies it and presents it at the correct trust level. Nodes that have already verified a genuine copy may decline to forward later invalid variants (Section 7.2, item 5).</t>
      <t><strong>Residual risk.</strong> An adversary that delivers <tt>1 + MAX_SIG_VARIANTS</tt> distinct forged copies to a node before the genuine copy arrives exhausts that node's variant budget, and the genuine copy is then discarded there. The adversary must win this race separately in each radio neighborhood it wants to affect and spends at least three transmissions per message per neighborhood; the genuine copy still reaches nodes the adversary does not cover through other paths. Each accepted variant also costs one extra forwarding transmission per binding. Eliminating the attack entirely would require relays to verify signatures before forwarding, which this specification rejects because relays cannot be assumed to hold authority keys (Section 9). A larger <tt>MAX_SIG_VARIANTS</tt> raises the cost of the attack at the price of more airtime spent on forged copies; this trade-off is one of the questions of the experiment (Section 1.3).</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 the ingress freshness check of Section 7 and for cache eviction relative to the local clock. A node whose real-time clock is wrong by more than <tt>MAX_EXPIRATION_WINDOW</tt> (24 hours) in one direction, or by more than <tt>MAX_FUTURE_SKEW</tt> in the other, would reject received packets as stale or future-dated, isolating itself from the mesh. The heuristic below is the only permitted exception to the freshness check.</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 freshness check of Section 7 (<tt>MAX_EXPIRATION_WINDOW</tt> in the past, <tt>MAX_FUTURE_SKEW</tt> in the future).</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="implementation-status" title="Implementation Status" numbered="true">
    <t>(Note to the RFC Editor: please remove this section and the reference to <xref target="RFC7942"/> before publication.)</t>
    <t>This section records the status of known implementations of the protocol defined by this specification at the time of posting of this Internet-Draft, and is based on a proposal described in <xref target="RFC7942"/>. The description of implementations in this section is intended to assist the IETF in its decision processes in progressing drafts to RFCs. Please note that the listing of any individual implementation here does not imply endorsement by the IETF. Furthermore, no effort has been spent to verify the information presented here that was supplied by IETF contributors. This is not intended as, and must not be construed to be, a catalog of available implementations or their features. Readers are advised to note that other implementations may exist.</t>
    <t>According to <xref target="RFC7942"/>, &quot;this will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature. It is up to the individual working groups to use this information as they see fit&quot;.</t>
    <t>All implementations below are by the document author and are available in the project repository (https://github.com/karansharma1732/OEPB). There are no independent implementations.</t>
    <ul>
      <li><t><strong>Test-vector script</strong> (<tt>simulator/python/gen_test_vectors.py</tt>, Python, uses the <tt>cryptography</tt> library): implements the canonical 40-byte header, MsgID computation, and Ed25519 signing and verification of Section 5.3. It reproduces the test vector of Appendix A.2 byte for byte. It does not implement forwarding, Trickle, or any transport.</t></li>
      <li><t><strong>Protocol simulators</strong> (<tt>simulator/python/</tt>, Python): <tt>trickle_sim.py</tt> is the discrete-event simulator that produced the results of Section 6.1; the scenario simulator (<tt>simulator.py</tt> and supporting modules) exercises the forwarding, trust, and WFQ logic. Both are behavioral models only. The scenario simulator uses a legacy header structure, not the canonical wire format, and neither simulator models a radio or MAC layer.</t></li>
      <li><t><strong>Android prototypes</strong> (BroadcasterApp and ReceiverApp, Kotlin): use a non-canonical 48-byte header (Appendix B), are NOT wire-compatible with this specification, perform a mock flag check instead of Ed25519 verification, and run over Android Nearby Connections rather than the BLE binding of <xref target="OEPB-BLE"/>.</t></li>
      <li><t><strong>BLE binding</strong> <xref target="OEPB-BLE"/>: no implementation.</t></li>
    </ul>
    <t>No over-the-air or real-hardware testing of the protocol as specified has been performed. All quantitative evidence in this document comes from simulation.</t>
  </section>
</middle>
<back>
  <references>
    <name>References</name>
  <references>
    <name>Normative References</name>
    <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
      <front>
        <title>Key words for use in RFCs to Indicate Requirement Levels</title>
        <author initials="S." surname="Bradner" fullname="S. Bradner"/>
        <date month="March" year="1997"/>
      </front>
      <seriesInfo name="BCP" value="14"/>
      <seriesInfo name="RFC" value="2119"/>
      <seriesInfo name="DOI" value="10.17487/RFC2119"/>
    </reference>
    <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
      <front>
        <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
        <author initials="B." surname="Leiba" fullname="B. Leiba"/>
        <date month="May" year="2017"/>
      </front>
      <seriesInfo name="BCP" value="14"/>
      <seriesInfo name="RFC" value="8174"/>
      <seriesInfo name="DOI" value="10.17487/RFC8174"/>
    </reference>
    <reference anchor="RFC6206" target="https://www.rfc-editor.org/info/rfc6206">
      <front>
        <title>The Trickle Algorithm</title>
        <author initials="P." surname="Levis" fullname="P. Levis"/>
        <author initials="T." surname="Clausen" fullname="T. Clausen"/>
        <author initials="J." surname="Hui" fullname="J. Hui"/>
        <author initials="O." surname="Gnawali" fullname="O. Gnawali"/>
        <author initials="J." surname="Ko" fullname="J. Ko"/>
        <date month="March" year="2011"/>
      </front>
      <seriesInfo name="RFC" value="6206"/>
      <seriesInfo name="DOI" value="10.17487/RFC6206"/>
    </reference>
    <reference anchor="RFC8032" target="https://www.rfc-editor.org/info/rfc8032">
      <front>
        <title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title>
        <author initials="S." surname="Josefsson" fullname="S. Josefsson"/>
        <author initials="I." surname="Liusvaara" fullname="I. Liusvaara"/>
        <date month="January" year="2017"/>
      </front>
      <seriesInfo name="RFC" value="8032"/>
      <seriesInfo name="DOI" value="10.17487/RFC8032"/>
    </reference>
    <reference anchor="RFC8949" target="https://www.rfc-editor.org/info/rfc8949">
      <front>
        <title>Concise Binary Object Representation (CBOR)</title>
        <author initials="C." surname="Bormann" fullname="C. Bormann"/>
        <author initials="P." surname="Hoffman" fullname="P. Hoffman"/>
        <date month="December" year="2020"/>
      </front>
      <seriesInfo name="STD" value="94"/>
      <seriesInfo name="RFC" value="8949"/>
      <seriesInfo name="DOI" value="10.17487/RFC8949"/>
    </reference>
    <reference anchor="RFC8610" target="https://www.rfc-editor.org/info/rfc8610">
      <front>
        <title>Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures</title>
        <author initials="H." surname="Birkholz" fullname="H. Birkholz"/>
        <author initials="C." surname="Vigano" fullname="C. Vigano"/>
        <author initials="C." surname="Bormann" fullname="C. Bormann"/>
        <date month="June" year="2019"/>
      </front>
      <seriesInfo name="RFC" value="8610"/>
      <seriesInfo name="DOI" value="10.17487/RFC8610"/>
    </reference>
  </references>
  <references>
    <name>Informative References</name>
    <reference anchor="RFC5050" target="https://www.rfc-editor.org/info/rfc5050">
      <front>
        <title>Bundle Protocol Specification</title>
        <author initials="K." surname="Scott" fullname="K. Scott"/>
        <author initials="S." surname="Burleigh" fullname="S. Burleigh"/>
        <date month="November" year="2007"/>
      </front>
      <seriesInfo name="RFC" value="5050"/>
      <seriesInfo name="DOI" value="10.17487/RFC5050"/>
    </reference>
    <reference anchor="RFC9171" target="https://www.rfc-editor.org/info/rfc9171">
      <front>
        <title>Bundle Protocol Version 7</title>
        <author initials="S." surname="Burleigh" fullname="S. Burleigh"/>
        <author initials="K." surname="Fall" fullname="K. Fall"/>
        <author initials="E." surname="Birrane, III" fullname="E. Birrane, III"/>
        <date month="January" year="2022"/>
      </front>
      <seriesInfo name="RFC" value="9171"/>
      <seriesInfo name="DOI" value="10.17487/RFC9171"/>
    </reference>
    <reference anchor="RFC9172" target="https://www.rfc-editor.org/info/rfc9172">
      <front>
        <title>Bundle Protocol Security (BPSec)</title>
        <author initials="E." surname="Birrane, III" fullname="E. Birrane, III"/>
        <author initials="K." surname="McKeever" fullname="K. McKeever"/>
        <date month="January" year="2022"/>
      </front>
      <seriesInfo name="RFC" value="9172"/>
      <seriesInfo name="DOI" value="10.17487/RFC9172"/>
    </reference>
    <reference anchor="RFC8126" target="https://www.rfc-editor.org/info/rfc8126">
      <front>
        <title>Guidelines for Writing an IANA Considerations Section in RFCs</title>
        <author initials="M." surname="Cotton" fullname="M. Cotton"/>
        <author initials="B." surname="Leiba" fullname="B. Leiba"/>
        <author initials="T." surname="Narten" fullname="T. Narten"/>
        <date month="June" year="2017"/>
      </front>
      <seriesInfo name="BCP" value="26"/>
      <seriesInfo name="RFC" value="8126"/>
      <seriesInfo name="DOI" value="10.17487/RFC8126"/>
    </reference>
    <reference anchor="RFC6550" target="https://www.rfc-editor.org/info/rfc6550">
      <front>
        <title>RPL: IPv6 Routing Protocol for Low-Power and Lossy Networks</title>
        <author initials="T." surname="Winter" fullname="T. Winter"/>
        <author initials="P." surname="Thubert" fullname="P. Thubert"/>
        <author initials="A." surname="Brandt" fullname="A. Brandt"/>
        <author initials="J." surname="Hui" fullname="J. Hui"/>
        <author initials="R." surname="Kelsey" fullname="R. Kelsey"/>
        <author initials="P." surname="Levis" fullname="P. Levis"/>
        <author initials="K." surname="Pister" fullname="K. Pister"/>
        <author initials="R." surname="Struik" fullname="R. Struik"/>
        <author initials="JP." surname="Vasseur" fullname="JP. Vasseur"/>
        <author initials="R." surname="Alexander" fullname="R. Alexander"/>
        <date month="March" year="2012"/>
      </front>
      <seriesInfo name="RFC" value="6550"/>
      <seriesInfo name="DOI" value="10.17487/RFC6550"/>
    </reference>
    <reference anchor="RFC6621" target="https://www.rfc-editor.org/info/rfc6621">
      <front>
        <title>Simplified Multicast Forwarding</title>
        <author initials="J." surname="Macker" fullname="J. Macker"/>
        <date month="May" year="2012"/>
      </front>
      <seriesInfo name="RFC" value="6621"/>
      <seriesInfo name="DOI" value="10.17487/RFC6621"/>
    </reference>
    <reference anchor="RFC7731" target="https://www.rfc-editor.org/info/rfc7731">
      <front>
        <title>Multicast Protocol for Low-Power and Lossy Networks (MPL)</title>
        <author initials="J." surname="Hui" fullname="J. Hui"/>
        <author initials="R." surname="Kelsey" fullname="R. Kelsey"/>
        <date month="February" year="2016"/>
      </front>
      <seriesInfo name="RFC" value="7731"/>
      <seriesInfo name="DOI" value="10.17487/RFC7731"/>
    </reference>
    <reference anchor="RFC7942" target="https://www.rfc-editor.org/info/rfc7942">
      <front>
        <title>Improving Awareness of Running Code: The Implementation Status Section</title>
        <author initials="Y." surname="Sheffer" fullname="Y. Sheffer"/>
        <author initials="A." surname="Farrel" fullname="A. Farrel"/>
        <date month="July" year="2016"/>
      </front>
      <seriesInfo name="BCP" value="205"/>
      <seriesInfo name="RFC" value="7942"/>
      <seriesInfo name="DOI" value="10.17487/RFC7942"/>
    </reference>
    <reference anchor="TRICKLE-2004">
      <front>
        <title>Trickle: A Self-Regulating Algorithm for Code Propagation and Maintenance in Wireless Sensor Networks</title>
        <author fullname="Philip Levis" initials="P." surname="Levis"></author>
        <author fullname="Neil Patel" initials="N." surname="Patel"></author>
        <author fullname="David Culler" initials="D." surname="Culler"></author>
        <author fullname="Scott Shenker" initials="S." surname="Shenker"></author>
        <date year="2004" month="March"/>
      </front>
      <seriesInfo name="Proceedings" value="1st USENIX Symposium on Networked Systems Design and Implementation (NSDI 2004)"/>
    </reference>
    <reference anchor="SERVAL">
      <front>
        <title>The Serval Project: Practical Wireless Ad Hoc Mobile Telecommunications</title>
        <author fullname="Paul Gardner-Stephen" initials="P." surname="Gardner-Stephen"><organization>Flinders University</organization></author>
        <author fullname="Jeremy Arns" initials="J." surname="Arns"><organization>Flinders University</organization></author>
        <date year="2011" month="December"/>
      </front>
      <seriesInfo name="Technical Report" value="Flinders University, Australia"/>
    </reference>
    <reference anchor="BT-MESH" target="https://www.bluetooth.com/specifications/specs/mesh-protocol/">
      <front>
        <title>Mesh Protocol Specification</title>
        <author><organization>Bluetooth Special Interest Group</organization></author>
        <date year="2023" month="September"/>
      </front>
      <seriesInfo name="Version" value="1.1"/>
    </reference>
    <reference anchor="EPIDEMIC">
      <front>
        <title>Epidemic Routing for Partially Connected Ad Hoc Networks</title>
        <author fullname="Amin Vahdat" initials="A." surname="Vahdat"><organization>Duke University</organization></author>
        <author fullname="David Becker" initials="D." surname="Becker"><organization>Duke University</organization></author>
        <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><organization>IEEE</organization></author>
        <date year="2011" month="September"/>
      </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><organization>Meshtastic Project</organization></author>
        <date year="2020"/>
      </front>
    </reference>
    <reference anchor="APRS" target="https://www.aprs.org/doc/APRS101.PDF">
      <front>
        <title>Automatic Packet Reporting System -- Protocol Specification</title>
        <author fullname="Bob Bruninga" initials="B." surname="Bruninga"><organization>US Naval Academy</organization></author>
        <date year="2000"/>
      </front>
      <seriesInfo name="APRS101" value="APRS Protocol Reference 1.0.1"/>
    </reference>
    <reference anchor="BRIAR" target="https://code.briarproject.org/briar/briar-spec">
      <front>
        <title>Briar Protocol Specifications (Bramble Transport, Synchronisation, and Rendezvous Protocols)</title>
        <author><organization>Briar Project</organization></author>
        <date/>
      </front>
    </reference>
    <reference anchor="BRIDGEFY-BREAK" target="https://eprint.iacr.org/2021/214">
      <front>
        <title>Mesh Messaging in Large-scale Protests: Breaking Bridgefy</title>
        <author fullname="Martin R. Albrecht" initials="M." surname="Albrecht"></author>
        <author fullname="Jorge Blasco" initials="J." surname="Blasco"></author>
        <author fullname="Rikke Bjerg Jensen" initials="R." surname="Jensen"></author>
        <author fullname="Lenka Marekova" initials="L." surname="Marekova"></author>
        <date year="2021" month="May"/>
      </front>
      <seriesInfo name="DOI" value="10.1007/978-3-030-75539-3_16"/>
      <seriesInfo name="Proceedings" value="CT-RSA 2021, LNCS 12704"/>
    </reference>
    <reference anchor="DISASTER-RADIO" target="https://disaster.radio">
      <front>
        <title>Disaster Radio: Open Source LoRa Mesh Communication</title>
        <author><organization>Disaster Radio Project</organization></author>
        <date year="2019"/>
      </front>
    </reference>
    <reference anchor="OEPB-BLE">
      <front>
        <title>OEPB Transport Binding: Bluetooth Low Energy</title>
        <author fullname="Karan Sharma" initials="K." surname="Sharma"><organization>Independent</organization></author>
        <date year="2026" month="September"/>
      </front>
      <seriesInfo name="Internet-Draft" value="draft-sharma-oepb-binding-ble-01"/>
    </reference>
  </references>
  </references>
  <section anchor="test-vectors-and-routing-example" title="Test Vectors and Routing Example" numbered="true">
    <section anchor="end-to-end-broadcast-flow" title="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, Timestamp freshness, 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="complete-verifiable-test-vector" title="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 (54 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>Script for generating and verifying this vector: <tt>simulator/python/gen_test_vectors.py</tt></t>
    </section>
  </section>
  <section anchor="android-prototype-notes" title="Android Prototype Notes" numbered="true">
    <t>The Android prototypes (BroadcasterApp / ReceiverApp) use a 48-byte fixed header that differs from the canonical 40-byte wire format defined in Section 5.1. The prototype 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>Both formats carry Version, Msg Type, TTL, an 8-byte Nonce, and a 16-byte MsgID. Relative to the canonical format, the prototype header has no Hop Count field, a 4-byte CreatedTime instead of the 8-byte Timestamp, a 1-byte Flags field instead of 2 bytes, and no Payload Length field; it adds 8-byte GeoScope and SenderID fields that the canonical format deliberately omits (Section 3.4). Its payload is a UTF-8 string rather than CBOR, and it carries no signature bytes. Its MsgID is computed over the prototype fields rather than the canonical input of Section 5.3.</t>
    <t>The prototypes predate the canonical wire format and are not interoperable with implementations of this specification. Their signature check is a mock that treats a packet as verified when the SIGNED and AUTHORITY_HINT flags are both set; it performs no Ed25519 verification. Implementations of this specification MUST verify signatures as specified in Sections 5.3 and 9.5.</t>
  </section>
  <section anchor="changes-since-draft-sharma-oepb-00" title="Changes since draft-sharma-oepb-00" numbered="true">
    <t>(Note to the RFC Editor: please remove this appendix before publication.)</t>
    <t>Identifiers refer to the pre-submission review findings for this revision.</t>
    <ul>
      <li><t>B1: Rendered as an Independent Submission; appendices moved to back matter; references generated once.</t></li>
      <li><t>B2: Added ingress freshness check (<tt>MAX_FUTURE_SKEW</tt> = 1 hour) to Section 7; Sections 10.1 and 11.1 reference it.</t></li>
      <li><t>B3: Added bounded signature-variant re-admission (Section 7.2, <tt>MAX_SIG_VARIANTS</tt> = 2) and Section 10.11.</t></li>
      <li><t>B4: AUTH revocations must verify under a root anchor, the revoked key, or its certifier; deny-list entries require a root-anchor signature.</t></li>
      <li><t>B5: New Section 9.5 on signer resolution (<tt>MAX_VERIFY_CANDIDATES</tt> = 32), certification depth, rotation, and validity; unsigned AUTH dropped on ingress.</t></li>
      <li><t>B6: Trickle contribution restated relative to MPL (RFC 7731) and Trickle's code-propagation origin.</t></li>
      <li><t>B7: New Section 1.2, Relationship to IETF Work.</t></li>
      <li><t>B8: New Section 13, Implementation Status; Appendix B renamed and corrected.</t></li>
      <li><t>S1: Imax stated as a 1000 ms cap on doubling.</t></li>
      <li><t>S2: Appendix A.2 signature input size corrected to 54 bytes.</t></li>
      <li><t>S3: Section 6.1 defines delivery over the connected component and reports component size.</t></li>
      <li><t>S4: &quot;Optimal tradeoff&quot; replaced by &quot;performed best among the values tested&quot;.</t></li>
      <li><t>S5: DTN comparison rewritten; latency and custody claims removed.</t></li>
      <li><t>S6: Section 10.2 rewritten; L2 address rotation stated as a fundamental residual risk.</t></li>
      <li><t>S7: Incorrect &quot;Forwarding Caps&quot; mitigation removed from Section 9.4.</t></li>
      <li><t>S8: Capacity eviction is LRU by arrival, not by Timestamp.</t></li>
      <li><t>S9: Cancellation state held only in the bounded tombstone set.</t></li>
      <li><t>S11: Related work corrected (Meshtastic, Serval, Bluetooth Mesh, Bridgefy) and Briar added.</t></li>
      <li><t>S12: New Section 1.3, Experiment Scope.</t></li>
      <li><t>S15: BLE 5.x wording corrected (extended advertising requires chaining).</t></li>
      <li><t>N1-N10: Editorial corrections (signing-status wording, AUTHORITY_HINT scope, BCP 14 usage, energy-exhaustion wording, CDDL citation, HTTPS APRS link, shortened abstract).</t></li>
      <li><t>Section 9.5: only a root-anchor-signed revocation cascades to successors; a revocation signed by the revoked key or its predecessor revokes only that key.</t></li>
      <li><t>Section 9.5: a key MUST NOT have more than one successor; the first valid rotation announcement received is accepted.</t></li>
      <li><t>References: undated <xref target="BRIAR"/> reference (date removed).</t></li>
    </ul>
  </section>
</back>
</rfc>
