<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc [
<!ENTITY nbsp "&#160;">
]>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     category="info"
     docName="draft-choudhary-rcoap-00"
     ipr="trust200902"
     obsoletes="" updates="" submissionType="IETF"
     xml:lang="en" version="3">

  <front>
    <title abbrev="RCOAP">Ratcheted CoAP: A Forward-Secure Delta over OSCORE for
    Highly Constrained Wake-Send-Sleep Devices</title>

    <seriesInfo name="Internet-Draft" value="draft-choudhary-rcoap-00"/>

    <author fullname="Divyanshu Choudhary" initials="D." surname="Choudhary">
      <address>
        <email>divyanshuchoudhary2508@gmail.com</email>
      </address>
    </author>

    <date year="2026" month="August" day="29"/>

    <area>Security</area>
    <workgroup>Individual Submission</workgroup>

    <keyword>OSCORE</keyword>
    <keyword>CoAP</keyword>
    <keyword>forward secrecy</keyword>
    <keyword>key ratchet</keyword>
    <keyword>constrained devices</keyword>

    <abstract>
      <t>
        This document specifies RCOAP, a compact, zero-round-trip, link-layer
        agnostic object-security mechanism for highly constrained devices
        that transmit infrequently. RCOAP is a targeted delta over OSCORE
        (<xref target="RFC8613"/>): instead of a single long-lived Sender
        Key, RCOAP derives a fresh symmetric key for every message via a
        one-way hash ratchet. This bounds the impact of physical device
        capture to future messages only, at the cost of a modest per-message
        size increase and the loss of future secrecy. RCOAP is explicitly
        scoped to a narrow niche left open between OSCORE and EDHOC
        (<xref target="RFC9528"/>): devices for which even EDHOC's one-time
        handshake cost is disproportionate to their message rate or compute
        budget. This document is a first individual submission, has not
        been reviewed by the IETF, and requests feedback in particular from
        the LAKE and CoRE working groups on whether this gap is real and
        worth standardizing, or already adequately covered.
      </t>
    </abstract>

  </front>

  <middle>

    <section anchor="intro" numbered="true" toc="default">
      <name>Introduction</name>
      <t>
        OSCORE <xref target="RFC8613"/> provides end-to-end confidentiality,
        integrity, and replay protection for CoAP <xref target="RFC7252"/>
        with no handshake and minimal per-message overhead, by deriving a
        Sender Key once from a shared Common Context and reusing it for the
        lifetime of the security context (up to 2^40 messages). This is an
        excellent fit for constrained devices that wake, send, and sleep.
      </t>
      <t>
        It has one gap by design: the Sender Key is static. If a device is
        physically captured and its key material is extracted, every
        message that device ever sent becomes retroactively decryptable.
        For unattended field devices -- soil sensors, wildlife trackers,
        disaster-response beacons, agricultural nodes -- physical capture
        is a realistic threat, not a theoretical one.
      </t>
      <t>
        EDHOC <xref target="RFC9528"/> was standardized by the LAKE working
        group specifically to close this gap: a compact authenticated
        Diffie-Hellman handshake that establishes an OSCORE security
        context with genuine, DH-strength forward secrecy. For the large
        majority of constrained deployments, EDHOC followed by OSCORE is
        the correct, already-standardized answer, and this document does
        not attempt to replace it.
      </t>
      <t>
        EDHOC's handshake, however, is not free: published measurements
        show on the order of 130 bytes and 1.5 round trips across its three
        messages, and hundreds of milliseconds to several seconds of
        compute on typical constrained microcontrollers (see
        <xref target="motivation"/>). For devices that wake extremely
        rarely relative to their operational lifetime, or that sit on
        links where every round trip is expensive or unreliable (deep
        LoRa, satellite backhaul), that one-time cost can dominate the
        device's entire energy or airtime budget. RCOAP is offered as a
        narrower, explicitly weaker-guarantee alternative for that specific
        residual niche.
      </t>
      <t>
        RCOAP replaces OSCORE's static Sender Key with a one-way hash
        ratchet: each transmission derives a new key from the previous one
        via HKDF, and the old key is never needed again. Capturing a
        device's current ratchet state exposes only messages sent after
        capture, never messages sent before it. This is a strictly weaker
        property than EDHOC's DH-based forward secrecy -- it rests on the
        one-wayness of a hash function against an adversary who has not
        yet captured the device, not on the hardness of a Diffie-Hellman
        problem -- but it requires no interactivity at all, matching
        OSCORE's zero-round-trip behavior exactly.
      </t>
      <t>
        This document is an individual submission at an early stage. It has
        not received IETF review. <xref target="status"/> and
        <xref target="limitations"/> describe validation performed to date
        and open problems. The author is specifically seeking feedback on
        whether the niche described in <xref target="motivation"/> is real
        and narrow enough to matter, or whether EDHOC's cost, in practice,
        is already acceptable for essentially all real deployments -- in
        which case this document should not proceed.
      </t>
    </section>

    <section anchor="motivation" numbered="true" toc="default">
      <name>Motivation and Applicability</name>
      <t>
        RCOAP is applicable only to a narrow class of deployments where all
        of the following hold:
      </t>
      <ul>
        <li>The device wakes and transmits rarely relative to its
        operational lifetime (e.g., hourly or less), such that a one-time
        handshake's amortized cost is not negligible.</li>
        <li>The device's compute budget makes even EDHOC's Diffie-Hellman
        operations (hundreds of milliseconds to seconds on typical
        constrained MCUs) a significant fraction of its energy budget per
        wake cycle.</li>
        <li>The link is expensive or unreliable per round trip (e.g., deep
        LoRa, satellite), such that avoiding any handshake -- even a
        1.5-round-trip one -- has outsized value.</li>
        <li>A weaker, symmetric-key-based forward-secrecy guarantee is an
        acceptable trade-off against EDHOC's stronger Diffie-Hellman-based
        guarantee for the application's risk model.</li>
      </ul>
      <t>
        Outside this intersection, EDHOC plus OSCORE is almost certainly
        the better-engineered, better-reviewed, and already-standardized
        choice, and implementers should use it instead. This document does
        not claim RCOAP is a general improvement over EDHOC; it claims a
        specific, bounded residual gap and asks the working groups closest
        to this space to judge whether that gap is worth filling.
      </t>
    </section>

    <section anchor="nongoals" numbered="true" toc="default">
      <name>Non-Goals</name>
      <ul>
        <li>RCOAP is not a general-purpose transport-security replacement
        for TCP/TLS, UDP/DTLS, or QUIC.</li>
        <li>RCOAP does not address multi-path delivery, congestion control,
        or large payload transfer.</li>
        <li>RCOAP does not provide future secrecy. Compromise of the
        current ratchet state permits computation of, and forgery under,
        all subsequent keys until the receiver detects an anomaly and the
        device is re-provisioned. This is an explicit, documented trade-off
        of the non-interactive design, not an oversight.</li>
      </ul>
    </section>

    <section anchor="provisioning" numbered="true" toc="default">
      <name>Root Provisioning</name>
      <t>
        At provisioning time, out of band (e.g. USB, NFC, or factory
        flashing), the device and the receiver are configured with a shared
        32-byte root secret K0, generated by a cryptographically secure
        random number generator. The device additionally stores a 4-byte
        DeviceID and a message counter n, initialized to zero. The receiver
        stores the same values plus a lookahead cache described in
        <xref target="resync"/>.
      </t>
    </section>

    <section anchor="ratchet" numbered="true" toc="default">
      <name>Key Ratchet</name>
      <t>
        Each key in the chain is derived from its predecessor by:
      </t>
      <artwork><![CDATA[
K_n = HKDF-Expand-SHA256(K_{n-1}, info="ratchet-wake", L=32)
]]></artwork>
      <t>
        This derivation is one-way: possession of K_n does not permit
        recomputation of any K_0 through K_(n-1). It requires a single
        HMAC-SHA256 invocation, well within budget on Cortex-M0+, ESP32,
        and nRF52-class hardware.
      </t>
      <t>
        The device MUST advance the ratchet and increment n before
        attempting transmission, and MUST persist the updated (K_current,
        n) pair to non-volatile storage before radio activity begins, so
        that a power loss during transmission cannot cause key reuse
        across two messages.
      </t>
    </section>

    <section anchor="wire" numbered="true" toc="default">
      <name>Wire Format</name>
      <t>
        The wire format deliberately mirrors OSCORE's compact flag-byte-
        plus-variable-fields philosophy so the delta against
        <xref target="RFC8613"/> Section 6 is easy to audit.
      </t>
      <artwork><![CDATA[
Byte 0:       Flag byte
                bits 0-2: counter length (n bytes, 1-4)
                bit 3:    ack-requested flag
                bits 4-7: reserved, MUST be 0
Byte 1-4:     DeviceID (4 bytes, fixed-width; not compressed like
              OSCORE's variable-length kid, on the assumption that
              deployments in this niche are small enough that a fixed-
              width lookup outweighs variable-length savings)
Byte 5..5+n:  Counter (n bytes, big-endian; matches OSCORE's Partial IV
              encoding convention)
(12 bytes,
 not on wire): Nonce = SHA-256(DeviceID || Counter)[0:12], computed
              independently by both sides, never transmitted
Payload:      ChaCha20-Poly1305 ciphertext under key K_n
Trailer:      16-byte Poly1305 authentication tag
]]></artwork>
      <t>
        Minimum overhead in this configuration is 22 bytes (5-byte
        flag+DeviceID, 1-byte counter, 16-byte tag), larger than OSCORE's
        best case of roughly 4 bytes, because RCOAP is link-layer agnostic
        and cannot rely on an underlying CoAP header to already carry part
        of this framing. An optional compact mode, using a shorter
        authentication tag and an implicit, pre-shared DeviceID mapping,
        can match OSCORE's own per-payload-size overhead exactly at the
        cost of reduced forgery resistance (2^-64) and a bound on the
        number of devices sharing a gateway (256); see the accompanying
        implementation report for measurements.
      </t>
    </section>

    <section anchor="resync" numbered="true" toc="default">
      <name>Replay Protection and Resynchronization</name>
      <t>
        The receiver precomputes and caches the next W ratchet-derived keys
        ahead of the last-accepted counter n_last, where W defaults to 32,
        matching the default replay window size in
        <xref target="RFC8613"/> Section 3.2.2. An incoming message is
        accepted if its counter falls within [n_last+1, n_last+W] and its
        Poly1305 tag verifies under the corresponding derived key. On
        acceptance, the receiver advances its own ratchet state to that
        point and discards all older cached keys, which is what makes
        forward secrecy hold on the receiver side as well as the device
        side.
      </t>
      <t>
        If a device's counter has drifted beyond the window (for example,
        after W or more consecutive lost transmissions), an explicit
        resynchronization exchange is required. This is intentionally the
        rare, interactive path; RCOAP's zero-round-trip property applies
        to the common case, not to recovery from extended message loss.
        A full resync protocol is described in a companion document
        rather than this specification, to keep the base wire format's
        review scope narrow; see the implementation report referenced in
        <xref target="status"/>.
      </t>
    </section>

    <section anchor="ack" numbered="true" toc="default">
      <name>Optional Acknowledgement</name>
      <t>
        An acknowledgement is sent only if bit 3 of the flag byte was set
        on the corresponding request. Its format is the echoed counter,
        at the same width as the request, followed by a Poly1305 tag over
        that counter, keyed with K_n. A device that did not set the
        ack-requested bit MUST NOT open a receive window, to minimize
        radio-on time in the default, non-acknowledged path.
      </t>
    </section>

    <section anchor="comparison" numbered="true" toc="default">
      <name>Comparison to OSCORE and EDHOC+OSCORE</name>
      <table>
        <name>Property comparison</name>
        <thead>
          <tr>
            <th>Property</th>
            <th>OSCORE alone</th>
            <th>EDHOC + OSCORE</th>
            <th>RCOAP</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Forward secrecy</td>
            <td>No</td>
            <td>Yes (DH-based)</td>
            <td>Yes (hash-ratchet-based, weaker guarantee)</td>
          </tr>
          <tr>
            <td>Handshake</td>
            <td>None</td>
            <td>One-time, ~130 bytes, 1.5 RTT</td>
            <td>None (every message zero-RTT)</td>
          </tr>
          <tr>
            <td>Steady-state per-message overhead</td>
            <td>Lowest</td>
            <td>Same as OSCORE after setup</td>
            <td>Slightly higher than OSCORE, even in compact mode</td>
          </tr>
          <tr>
            <td>Re-keying cost</td>
            <td>N/A</td>
            <td>Requires a fresh handshake</td>
            <td>Free; every wake is a new key</td>
          </tr>
          <tr>
            <td>Device capture exposes</td>
            <td>All historical messages</td>
            <td>Messages until next handshake</td>
            <td>Only future messages</td>
          </tr>
          <tr>
            <td>Maturity</td>
            <td>RFC since 2019, deployed</td>
            <td>RFC since 2024, active deployment interest</td>
            <td>Individual draft, self-reviewed only</td>
          </tr>
        </tbody>
      </table>
    </section>

    <section anchor="status" numbered="true" toc="default">
      <name>Implementation Status</name>
      <t>
        This section records the status of a reference implementation at
        the time of this submission, per the guidance of
        <xref target="RFC7942"/>. It is expected to be removed before
        publication as an RFC, should this document proceed that far.
      </t>
      <t>
        A Rust reference implementation exists and has been exercised as
        follows: 35 unit tests covering core logic; 13 hand-written
        adversarial tests (replay, forgery, tampering, boundary conditions,
        cross-device confusion), all blocked; 600,000 fuzz inputs against
        the decoder and receiver with zero panics; 40 simulated abrupt
        process kills across 500-plus messages with zero observed key or
        counter reuse; an independent Python implementation built from the
        specification text alone, demonstrating full bidirectional
        interoperability; and execution of the on-chip logic, unmodified,
        under three independent emulators (QEMU ARM Cortex-M3, Renode
        nRF52840-DK, and QEMU RISC-V).
      </t>
      <t>
        The implementation has never been run on physical hardware, and
        this specification and its implementation have not received
        independent human security review. Both are necessary before any
        production use; see <xref target="limitations"/>.
      </t>
    </section>

    <section anchor="secconsid" numbered="true" toc="default">
      <name>Security Considerations</name>
      <t>
        RCOAP provides forward secrecy against physical device capture:
        an adversary who extracts a device's current ratchet key and
        counter cannot recover keys used for prior messages, because the
        ratchet derivation is one-way. This guarantee rests on the
        pseudorandomness of HKDF-SHA256 and does not rely on any
        computational hardness assumption analogous to Diffie-Hellman;
        implementers requiring the stronger, better-studied guarantee
        should use EDHOC <xref target="RFC9528"/> with OSCORE instead.
      </t>
      <t>
        RCOAP provides no future secrecy. An adversary who extracts the
        current key and counter can compute and forge all subsequent
        messages until the compromise is detected and the device is
        re-provisioned with a fresh root secret out of band. Applications
        with a risk model that requires bounding the impact of an
        undetected, ongoing compromise, rather than only a discrete
        capture-and-inspect event, are not well served by RCOAP.
      </t>
      <t>
        The nonce derivation, SHA-256(DeviceID || Counter), is
        deterministic and depends on the counter never repeating under a
        given key, which the ratchet-plus-persist-before-transmit design
        in <xref target="ratchet"/> is intended to guarantee; an
        implementation that fails to persist (K_current, n) before radio
        activity risks nonce reuse under key reuse following a crash or
        power loss, which would be catastrophic for the AEAD's
        confidentiality guarantee.
      </t>
      <t>
        The optional compact mode traffic-offs a shorter authentication
        tag for reduced per-message size; implementers MUST evaluate
        whether the resulting forgery resistance is acceptable for their
        threat model before enabling it, and MUST NOT exceed the device
        count bound associated with that tag length.
      </t>
      <t>
        This specification and its reference implementation have not
        undergone independent cryptographic review. No claims in this
        document should be treated as validated for production use ahead
        of such review; see <xref target="limitations"/>.
      </t>
    </section>

    <section anchor="iana" numbered="true" toc="default">
      <name>IANA Considerations</name>
      <t>
        This document has no IANA actions at this time. Should this work
        proceed, allocation of a flag-byte reserved-bit registry, or reuse
        of an existing COSE/CoAP registry, may be proposed in a future
        revision.
      </t>
    </section>

    <section anchor="limitations" numbered="true" toc="default">
      <name>Open Issues and Limitations</name>
      <ul>
        <li>No formal or symbolic security analysis (e.g. Tamarin or
        ProVerif model) exists yet; only informal, self-conducted
        adversarial analysis.</li>
        <li>The resynchronization exchange after large counter drift is
        not fully specified in this document.</li>
        <li>Multi-replica receiver coordination (a load-balanced fleet of
        receivers sharing ratchet state) is undesigned.</li>
        <li>CoAP extensions Block-wise Transfer and Observe are not yet
        addressed.</li>
        <li>Distributed, many-source denial-of-service is only partially
        mitigated; single-source flooding is bounded, many-source flooding
        is not.</li>
        <li>The applicability niche described in <xref target="motivation"/>
        has not been validated against real deployment data; feedback from
        LAKE and CoRE participants on whether it is real and significant
        is explicitly requested.</li>
      </ul>
    </section>

    <section anchor="ack-section" numbered="true" toc="default">
      <name>Acknowledgements</name>
      <t>
        This document builds directly on the design of OSCORE
        <xref target="RFC8613"/> and takes its comparison baseline from
        EDHOC <xref target="RFC9528"/>, developed by the IETF LAKE working
        group. Any errors in characterizing either are the author's own.
      </t>
    </section>

  </middle>

  <back>
    <references>
      <name>Normative References</name>
      <reference anchor="RFC8613" target="https://www.rfc-editor.org/info/rfc8613">
        <front>
          <title>Object Security for Constrained RESTful Environments (OSCORE)</title>
          <author initials="G." surname="Selander"/>
          <author initials="J." surname="Mattsson"/>
          <author initials="F." surname="Palombini"/>
          <author initials="L." surname="Seitz"/>
          <date year="2019" month="July"/>
        </front>
        <seriesInfo name="RFC" value="8613"/>
        <seriesInfo name="DOI" value="10.17487/RFC8613"/>
      </reference>
      <reference anchor="RFC9528" target="https://www.rfc-editor.org/info/rfc9528">
        <front>
          <title>Ephemeral Diffie-Hellman Over COSE (EDHOC)</title>
          <author initials="G." surname="Selander"/>
          <author initials="J." surname="Mattsson"/>
          <author initials="F." surname="Palombini"/>
          <date year="2024" month="March"/>
        </front>
        <seriesInfo name="RFC" value="9528"/>
        <seriesInfo name="DOI" value="10.17487/RFC9528"/>
      </reference>
      <reference anchor="RFC7252" target="https://www.rfc-editor.org/info/rfc7252">
        <front>
          <title>The Constrained Application Protocol (CoAP)</title>
          <author initials="Z." surname="Shelby"/>
          <author initials="K." surname="Hartke"/>
          <author initials="C." surname="Bormann"/>
          <date year="2014" month="June"/>
        </front>
        <seriesInfo name="RFC" value="7252"/>
        <seriesInfo name="DOI" value="10.17487/RFC7252"/>
      </reference>
    </references>
    <references>
      <name>Informative References</name>
      <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"/>
          <author initials="A." surname="Farrel"/>
          <date year="2016" month="July"/>
        </front>
        <seriesInfo name="RFC" value="7942"/>
        <seriesInfo name="DOI" value="10.17487/RFC7942"/>
      </reference>
    </references>

    <section anchor="perf" numbered="true" toc="default">
      <name>Per-Payload-Size Overhead (Informative)</name>
      <t>
        Measured against the reference implementation described in
        <xref target="status"/>, comparing OSCORE's typical overhead to
        RCOAP in both its full and compact modes:
      </t>
      <table>
        <name>Overhead by payload size</name>
        <thead>
          <tr><th>Payload</th><th>OSCORE</th><th>RCOAP (full)</th><th>RCOAP (compact)</th></tr>
        </thead>
        <tbody>
          <tr><td>4 bytes</td><td>15 B</td><td>26 B (+73%)</td><td>15 B (+0%)</td></tr>
          <tr><td>16 bytes</td><td>27 B</td><td>38 B (+41%)</td><td>27 B (+0%)</td></tr>
          <tr><td>256 bytes</td><td>267 B</td><td>278 B (+4%)</td><td>267 B (+0%)</td></tr>
        </tbody>
      </table>
      <t>
        Compact mode's byte parity with OSCORE is achieved by shortening
        the authentication tag; see <xref target="secconsid"/> for the
        associated trade-off before using compact mode.
      </t>
    </section>

  </back>

</rfc>
