<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc [
  <!ENTITY RFC2119 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml">
  <!ENTITY RFC8174 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml">
  <!ENTITY RFC8439 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8439.xml">
  <!ENTITY RFC5869 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5869.xml">
  <!ENTITY RFC7748 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7748.xml">
  <!ENTITY RFC8610 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8610.xml">
  <!ENTITY RFC8949 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8949.xml">
  <!ENTITY RFC6335 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6335.xml">
  <!ENTITY RFC8126 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8126.xml">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     category="exp"
     docName="draft-myclerk-protocol-03"
     ipr="trust200902"
     obsoletes=""
     updates=""
     submissionType="independent"
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="MyClerk Protocol">The MyClerk Protocol: Tiered Security Communication for Distributed Family Systems</title>

    <seriesInfo name="Internet-Draft" value="draft-myclerk-protocol-03"/>

    <author fullname="Michael J. Arcan" initials="M.J." surname="Arcan">
      <organization>Arcan Consulting</organization>
      <address>
        <email>rfc@arcan-consulting.de</email>
        <uri>https://myclerk.eu</uri>
      </address>
    </author>

    <date year="2026" month="April" day="27"/>

    <area>Applications</area>
    <workgroup>Independent Submission</workgroup>

    <keyword>protocol</keyword>
    <keyword>family</keyword>
    <keyword>distributed</keyword>
    <keyword>encryption</keyword>
    <keyword>smart home</keyword>

    <abstract>
      <t>
        This document specifies the MyClerk Protocol, a tiered-security
        communication protocol designed for distributed family orchestration
        systems. The protocol provides six security tiers ranging from 1-byte
        minimal overhead for tunneled messages to 144-byte full security for
        critical operations. It supports multiple transport mechanisms including
        NATS, Matrix, WebSocket, and direct TCP, while maintaining end-to-end
        encryption using ChaCha20-Poly1305 AEAD with hybrid post-quantum key
        establishment combining ML-KEM-768 and X25519. A classical-only mode
        (X25519 without ML-KEM) remains available for resource-constrained
        devices and legacy interoperability.
      </t>
      <t>
        The protocol is transport-agnostic, federation-capable, and optimized
        for environments ranging from resource-constrained IoT devices to
        full-featured desktop clients.
      </t>
    </abstract>

  </front>

  <middle>

    <!-- ============================================================ -->
    <section anchor="introduction">
      <name>Introduction</name>

      <t>
        Modern families operate across multiple locations and devices: a primary
        home with network-attached storage, a vacation house with a mini-PC,
        grandparents with a Raspberry Pi, and mobile devices requiring access
        while traveling. The MyClerk Protocol addresses the communication
        requirements of such distributed family systems.
      </t>

      <t>
        Traditional protocols impose significant overhead that becomes
        problematic for constrained channels. The MyClerk Protocol introduces
        tiered security levels, allowing applications to select appropriate
        overhead based on the security requirements of each operation.
      </t>

      <section anchor="requirements-language">
        <name>Requirements Language</name>
        <t>
          The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
          "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
          "OPTIONAL" 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>
      </section>

      <section anchor="terminology">
        <name>Terminology</name>

        <dl>
          <dt>Node</dt>
          <dd>A device participating in a MyClerk deployment, such as a server,
              desktop client, mobile device, or IoT device.</dd>

          <dt>Core Node</dt>
          <dd>A node classified as stable and reliable, expected to maintain
              high availability (>95% uptime over 30 days).</dd>

          <dt>Bonus Node</dt>
          <dd>A node with variable availability, used opportunistically for
              additional redundancy.</dd>

          <dt>Family</dt>
          <dd>A group of users and nodes sharing a common trust domain and
              cryptographic key hierarchy.</dd>

          <dt>Federation</dt>
          <dd>The interconnection of multiple families for resource sharing
              or communication.</dd>

          <dt>Tier</dt>
          <dd>A security level (0-5) determining the header structure and
              cryptographic protections applied to a message.</dd>

          <dt>Session</dt>
          <dd>A stateful connection between two endpoints with established
              cryptographic keys.</dd>
        </dl>
      </section>

    </section>

    <!-- ============================================================ -->
    <section anchor="protocol-overview">
      <name>Protocol Overview</name>

      <t>
        The MyClerk Protocol is a binary protocol using MessagePack
        <xref target="RFC8949"/> for payload encoding. It defines six security
        tiers with increasing header sizes and cryptographic protections.
      </t>

      <section anchor="design-goals">
        <name>Design Goals</name>

        <ol>
          <li><strong>Tiered Security:</strong> 1-144 bytes overhead depending
              on security requirements.</li>
          <li><strong>Transport Agnostic:</strong> Operates over NATS, Matrix,
              WebSocket, TCP, or other transports.</li>
          <li><strong>Federation Ready:</strong> Supports multi-server,
              multi-family deployments.</li>
          <li><strong>Future Proof:</strong> Extensible operations and feature
              negotiation.</li>
          <li><strong>Post-Quantum Security:</strong> Default key establishment
              for Tier 4 and Tier 5 is resistant to attacks by cryptographically
              relevant quantum computers (CRQCs), using a hybrid of ML-KEM-768
              <xref target="FIPS203"/> and X25519 <xref target="RFC7748"/>,
              while retaining a classical-only mode for resource-constrained
              devices.</li>
        </ol>
      </section>

      <section anchor="default-port">
        <name>Default Port</name>

        <t>
          When using TCP or UDP as the transport protocol, implementations
          SHOULD use port 5657 as the default listening port. This port is
          registered with IANA for the "myclerk" service (see
          <xref target="iana-port"/>).
        </t>

        <t>
          Implementations MAY use alternative ports when:
        </t>

        <ul>
          <li>Operating behind a reverse proxy or load balancer</li>
          <li>Running multiple instances on the same host</li>
          <li>Required by local network policies</li>
        </ul>

        <t>
          Service discovery mechanisms (such as mDNS or DNS-SD) SHOULD advertise
          the actual port in use, regardless of whether it matches the default.
        </t>
      </section>

      <section anchor="security-tiers-overview">
        <name>Security Tiers Overview</name>

        <table anchor="tier-overview-table">
          <name>Security Tier Summary</name>
          <thead>
            <tr>
              <th>Tier</th>
              <th>Header</th>
              <th>Encryption</th>
              <th>Auth</th>
              <th>KEX</th>
              <th>Use Case</th>
            </tr>
          </thead>
          <tbody>
            <tr><td>0</td><td>1 B</td><td>None (tunneled)</td><td>None</td><td>--</td><td>Inside session</td></tr>
            <tr><td>1</td><td>4 B</td><td>None</td><td>None</td><td>--</td><td>Fire-and-forget</td></tr>
            <tr><td>2</td><td>6 B</td><td>Optional</td><td>CRC-16</td><td>--</td><td>Home automation</td></tr>
            <tr><td>3</td><td>12 B</td><td>ChaCha20-Poly1305</td><td>HMAC-32</td><td>from T4/T5</td><td>Conversational</td></tr>
            <tr><td>4</td><td>14 B</td><td>ChaCha20-Poly1305</td><td>HMAC-64</td><td>hybrid</td><td>Key exchange</td></tr>
            <tr><td>5</td><td>14 B+tag</td><td>ChaCha20-Poly1305</td><td>HMAC-256</td><td>hybrid</td><td>Max security</td></tr>
          </tbody>
        </table>
        <t>
          KEX abbreviations: "hybrid" denotes ML-KEM-768 + X25519 hybrid key
          establishment; "from T4/T5" indicates the session key is derived in
          a separate Tier 4 or Tier 5 handshake and inherited by subsequent
          Tier 3 traffic.
        </t>
      </section>

    </section>

    <!-- ============================================================ -->
    <section anchor="message-format">
      <name>Message Format</name>

      <t>
        All messages consist of a header, optional payload, and optional trailer.
        The header format varies by security tier.
      </t>

      <section anchor="common-header">
        <name>Common Header Fields</name>

        <t>
          The first byte (Flags) is present in all tiers and has the following
          structure:
        </t>

        <artwork><![CDATA[
 0
 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|V V|T T T|C|S|E|
+-+-+-+-+-+-+-+-+

V: Protocol Version (2 bits) - 0 or 1
T: Security Tier (3 bits) - Values 0-5
C: Compressed (1 bit) - Payload is compressed
S: Stream (1 bit) - Server-push stream message
E: Encrypted (1 bit) - Payload is encrypted
]]></artwork>
      </section>

      <section anchor="tier0-header">
        <name>Tier 0 Header (1 byte)</name>

        <t>
          Tier 0 is used for messages tunneled inside an already-secure session.
          It provides minimal overhead.
        </t>

        <artwork><![CDATA[
 0
 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|0 0|0 0 0|C|S|E|
+-+-+-+-+-+-+-+-+
]]></artwork>

        <t>
          Tier 0 messages MUST only be sent within an established Tier 3+
          session. Implementations receiving a Tier 0 message outside of a
          secure session MUST discard it.
        </t>
      </section>

      <section anchor="tier1-header">
        <name>Tier 1 Header (4 bytes)</name>

        <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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V V|0 0 1|C|S|E|        Operation Code         |   Sequence    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork>

        <dl>
          <dt>Operation Code (16 bits)</dt>
          <dd>Identifies the operation. See <xref target="operations"/>.</dd>

          <dt>Sequence (8 bits)</dt>
          <dd>Message sequence number, wrapping at 255.</dd>
        </dl>
      </section>

      <section anchor="tier2-header">
        <name>Tier 2 Header (6 bytes)</name>

        <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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V V|0 1 0|C|S|E|        Operation Code         |   Sequence    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Session ID           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork>

        <dl>
          <dt>Session ID (16 bits)</dt>
          <dd>Identifies the session context for this message.</dd>
        </dl>

        <t>
          Tier 2 messages SHOULD include a CRC-16 trailer for error detection.
        </t>
      </section>

      <section anchor="tier3-header">
        <name>Tier 3 Header (12 bytes)</name>

        <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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V V|0 1 1|C|S|E|        Operation Code         |   Sequence    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Session ID           |           Timestamp           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Timestamp (cont.)        |             Nonce             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork>

        <dl>
          <dt>Timestamp (32 bits)</dt>
          <dd>Unix timestamp in seconds. Used for replay protection.</dd>

          <dt>Nonce (16 bits)</dt>
          <dd>Random nonce component. Combined with timestamp and counter
              to form the full 96-bit nonce for ChaCha20-Poly1305.</dd>
        </dl>

        <t>
          Tier 3 messages with the E flag set MUST be encrypted using
          ChaCha20-Poly1305 as specified in <xref target="RFC8439"/>.
        </t>
      </section>

      <section anchor="tier4-header">
        <name>Tier 4 Header (14 bytes)</name>

        <t>
          Tier 4 carries the messages that establish a session (SESSION_INIT,
          SESSION_ACK). Earlier drafts of this document carried the 32-byte
          X25519 ECDH public key inline in a 42-byte header. With the move to
          a hybrid post-quantum KEX the key material grew to 1184 bytes
          (ML-KEM-768 encapsulation key) plus 1088 bytes (ML-KEM-768
          ciphertext) plus the existing 32 bytes of X25519 per direction,
          which no longer fits in any sensibly-sized fixed header.
          Consequently, Tier 4 headers no longer carry KEX material inline;
          all public keys and ciphertexts are transported in the
          SESSION_INIT / SESSION_ACK payloads (see
          <xref target="session-init-payload"/>), and the header retains only
          session and nonce identifiers.
        </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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V V|1 0 0|C|S|E|        Operation Code         |   Sequence    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Session ID           |           Timestamp           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Timestamp (cont.)        |             Nonce             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            Key ID                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork>

        <dl>
          <dt>Key ID (32 bits)</dt>
          <dd>Identifier for the session key being used or negotiated. Zero
              during the initial SESSION_INIT before a key has been
              established.</dd>
        </dl>
      </section>

      <section anchor="tier5-header">
        <name>Tier 5 Header (14 bytes + Poly1305 Tag)</name>

        <t>
          Tier 5 uses the same 14-byte header as Tier 4 but appends a full
          Poly1305 authentication tag after the header (before the payload):
        </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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    [Tier 4 Header - 14 bytes]                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                   Poly1305 Tag (16 bytes)                     |
|                                                               |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork>

        <t>
          Prior drafts of this document mandated an additional HMAC-SHA256
          trailer on Tier 5 as a post-quantum resilience workaround against
          potential future quantum attacks on Poly1305. With hybrid ML-KEM-768
          key establishment now baked into Tier 4/5 (see
          <xref target="key-derivation"/>), that trailer is redundant and has
          been removed. Implementations conforming to this draft MUST NOT
          emit an HMAC-SHA256 trailer on Tier 5 messages.
        </t>
      </section>

      <section anchor="request-correlation">
        <name>Request Correlation (Version 1)</name>

        <t>
          Version 0 of the protocol correlates responses to requests by
          Operation Code. This limits each connection to one outstanding
          request per Operation Code, preventing parallel requests for
          the same operation (e.g., multiple concurrent thumbnail fetches).
        </t>

        <t>
          Version 1 extends each tier-specific header with a 32-bit
          Request ID field, inserted after the tier-specific fields and
          before the payload. The Version field in the Flags byte (bits
          0-1) distinguishes V0 from V1.
        </t>

        <t>
          Example: Tier 1 Version 1 Header (8 bytes):
        </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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 1|0 0 1|C|S|E|        Operation Code         |   Sequence    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Request ID                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork>

        <t>Header sizes by version:</t>

        <table anchor="header-sizes-by-version">
          <name>Header Sizes: Version 0 vs Version 1</name>
          <thead>
            <tr><th>Tier</th><th>V0</th><th>V1</th><th>Delta</th></tr>
          </thead>
          <tbody>
            <tr><td>0</td><td>1 byte</td><td>5 bytes</td><td>+4</td></tr>
            <tr><td>1</td><td>4 bytes</td><td>8 bytes</td><td>+4</td></tr>
            <tr><td>2</td><td>6 bytes</td><td>10 bytes</td><td>+4</td></tr>
            <tr><td>3</td><td>12 bytes</td><td>16 bytes</td><td>+4</td></tr>
            <tr><td>4</td><td>42 bytes</td><td>46 bytes</td><td>+4</td></tr>
            <tr><td>5</td><td>58 bytes</td><td>62 bytes</td><td>+4</td></tr>
          </tbody>
        </table>

        <section anchor="request-id-semantics">
          <name>Request ID Semantics</name>

          <dl>
            <dt>Format</dt>
            <dd>32-bit unsigned integer, big-endian byte order.</dd>

            <dt>Generation</dt>
            <dd>Client-generated, monotonically increasing per connection.</dd>

            <dt>Echo</dt>
            <dd>The server MUST echo the Request ID from the request in
                its response.</dd>

            <dt>Fire-and-Forget</dt>
            <dd>A Request ID of 0x00000000 indicates fire-and-forget;
                no response correlation is expected.</dd>

            <dt>Wrap</dt>
            <dd>When the counter reaches 0xFFFFFFFF, it MUST wrap to
                0x00000001, skipping zero.</dd>
          </dl>
        </section>

        <section anchor="version-backward-compat">
          <name>Backward Compatibility</name>

          <t>
            Servers MUST support Version 0 and Version 1 simultaneously.
            The version is determined by bits 0-1 of the Flags byte.
            A response MUST use the same version as the request that
            triggered it.
          </t>

          <t>
            Clients that support Version 1 SHOULD set their version bits
            to 01 and include a Request ID in every request. When
            communicating with a Version 0 server that ignores the
            Request ID, the client MUST fall back to Operation Code
            correlation.
          </t>
        </section>

      </section>

    </section>

    <!-- ============================================================ -->
    <section anchor="nonce-construction">
      <name>Nonce Construction</name>

      <t>
        ChaCha20-Poly1305 requires a 96-bit (12-byte) nonce that MUST NOT be
        reused with the same key. The MyClerk Protocol constructs nonces as
        follows:
      </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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Timestamp (32 bits)                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Random (32 bits)                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Counter (32 bits)                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork>

      <dl>
        <dt>Timestamp (32 bits)</dt>
        <dd>Unix epoch seconds. Provides cross-session replay protection.</dd>

        <dt>Random (32 bits)</dt>
        <dd>Cryptographically random value generated per session using a
            CSPRNG. Provides 2^32 possible values per second.</dd>

        <dt>Counter (32 bits)</dt>
        <dd>Per-message counter starting at 0, incremented for each message.
            Allows 2^32 messages per session.</dd>
      </dl>

      <t>
        All fields are encoded in big-endian byte order.
      </t>

      <t>
        This construction provides a collision probability of less than 2^-80
        per year at 1 million operations per second, assuming proper CSPRNG
        implementation.
      </t>
    </section>

    <!-- ============================================================ -->
    <section anchor="key-derivation">
      <name>Key Derivation</name>

      <t>
        Session keys are derived using HKDF as specified in
        <xref target="RFC5869"/> with SHA-256 as the hash function.
      </t>

      <section anchor="hybrid-key-exchange">
        <name>Hybrid Key Exchange</name>

        <t>
          Tier 4+ sessions establish a shared symmetric key using a hybrid
          construction that combines classical X25519 ECDH
          <xref target="RFC7748"/> with post-quantum ML-KEM-768
          <xref target="FIPS203"/>. The hybrid output is secure as long as at
          least one of the two primitives remains unbroken: an adversary that
          eventually breaks X25519 (e.g. by running Shor's algorithm on a
          cryptographically relevant quantum computer) still has to defeat
          ML-KEM, and vice versa.
        </t>

        <t>
          ML-KEM-768 (NIST category 3, approximately AES-192-equivalent
          security) is the default parameter set. ML-KEM-1024 MAY be offered
          by implementations requiring higher security margin; ML-KEM-512 is
          NOT RECOMMENDED for new deployments.
        </t>

        <t>
          The initiator generates an ephemeral X25519 key pair and an
          ephemeral ML-KEM-768 decapsulation key pair, and sends both public
          keys in SESSION_INIT (see <xref target="session-init-payload"/>).
          The responder generates its own ephemeral X25519 key pair,
          encapsulates against the initiator's ML-KEM encapsulation key to
          obtain the PQ shared secret and its ciphertext, and returns the
          X25519 public key together with the ML-KEM ciphertext in
          SESSION_ACK.
        </t>

        <t>
          Both sides then compute the combined shared secret:
        </t>

        <artwork><![CDATA[
ss_classical = X25519(local_x25519_priv, remote_x25519_pub)

; Responder: (ct, ss_pq) = ML-KEM-768.Encapsulate(initiator_mlkem_pub)
; Initiator: ss_pq       = ML-KEM-768.Decapsulate(local_mlkem_priv, ct)

combined_secret = ss_classical || ss_pq   ; 32 + 32 = 64 bytes

transcript_hash = SHA-256(
    SESSION_INIT_bytes  ||
    SESSION_ACK_bytes
)

session_key = HKDF-SHA256(
    IKM  = combined_secret,
    salt = nonce_initiator || nonce_responder,
    info = "myclerk-session-v1-hybrid" || transcript_hash,
    L    = 32
)
]]></artwork>

        <t>
          The concatenation order <tt>ss_classical || ss_pq</tt> is fixed and
          normative. Implementations that swap the order derive a different
          session key and will fail to communicate; this is a deliberate
          fail-closed property, not a bug.
        </t>

        <t>
          The <tt>transcript_hash</tt> folded into the HKDF <tt>info</tt>
          parameter binds the session key to the exact bytes of the handshake
          as observed by the deriving endpoint. An on-path attacker who
          modifies any handshake field -- stripping a capability,
          downgrading <tt>kex-mode</tt>, swapping nonces, altering any
          declared parameter -- causes the two endpoints to derive
          different session keys, and the first post-handshake Tier 3 or
          Tier 5 frame fails its AEAD check. See
          <xref target="kex-downgrade-protection"/> for the full security
          argument.
        </t>
      </section>

      <section anchor="classical-only-mode">
        <name>Classical-only Key Exchange (Legacy / Constrained)</name>

        <t>
          Implementations that cannot afford the ~2.3 KB of wire overhead of
          the hybrid handshake (e.g. ESP32-class devices on low-bandwidth
          modem links, or legacy clients predating this draft) MAY negotiate
          classical-only mode by omitting the ML-KEM fields from SESSION_INIT
          and signalling <tt>kex-mode: classical-only</tt>. The responder
          MUST either accept and mirror classical-only in SESSION_ACK, or
          refuse the session if local policy requires PQ.
        </t>

        <t>
          In classical-only mode the derivation reduces to:
        </t>

        <artwork><![CDATA[
combined_secret = X25519(local_x25519_priv, remote_x25519_pub)

transcript_hash = SHA-256(SESSION_INIT_bytes || SESSION_ACK_bytes)

session_key = HKDF-SHA256(
    IKM  = combined_secret,
    salt = nonce_initiator || nonce_responder,
    info = "myclerk-session-v1-classical" || transcript_hash,
    L    = 32
)
]]></artwork>

        <t>
          The <tt>info</tt> string intentionally differs between hybrid and
          classical-only derivations so that a key produced in one mode cannot
          be mistaken for a key in the other mode -- a domain-separation
          precaution against cross-protocol attacks.
        </t>

        <t>
          Classical-only sessions MUST NOT be used for data requiring
          long-term confidentiality (conservatively: more than 10 years),
          because an attacker who records the traffic today and gains access
          to a cryptographically relevant quantum computer later can recover
          the session key. Implementations SHOULD log classical-only
          negotiations for audit purposes.
        </t>
      </section>

      <section anchor="key-rotation">
        <name>Key Rotation</name>

        <t>
          Keys MUST be rotated after any of the following conditions:
        </t>

        <ul>
          <li>2^32 messages sent (nonce exhaustion)</li>
          <li>24 hours elapsed (time-based)</li>
          <li>Explicit KEY_ROTATE operation received</li>
        </ul>

        <t>Rotated keys are derived as:</t>

        <artwork><![CDATA[
new_key = HKDF-SHA256(
    IKM  = current_key,
    salt = "rotate",
    info = rotation_counter (4 bytes, big-endian),
    L    = 32
)
]]></artwork>
      </section>
    </section>

    <!-- ============================================================ -->
    <section anchor="operations">
      <name>Protocol Operations</name>

      <t>
        Operations are identified by a 16-bit operation code. The operation
        space is divided into ranges:
      </t>

      <table anchor="opcode-ranges">
        <name>Operation Code Ranges</name>
        <thead>
          <tr>
            <th>Range</th>
            <th>Category</th>
          </tr>
        </thead>
        <tbody>
          <tr><td>0x0000-0x00FF</td><td>Core Operations (Session, Key Management)</td></tr>
          <tr><td>0x0100-0x01FF</td><td>Standard Operations (Device, Identity, Messaging)</td></tr>
          <tr><td>0x0200-0x02FF</td><td>Resource Sharing (Streams, GPU, Routing)</td></tr>
          <tr><td>0x0300-0x03FF</td><td>Federation</td></tr>
          <tr><td>0x0400-0x04FF</td><td>Billing and Economics</td></tr>
          <tr><td>0x0500-0x05FF</td><td>Virtual File System (VFS)</td></tr>
          <tr><td>0x0600-0x06FF</td><td>Hardware Passthrough (USB, GPIO, I2C, SPI, CAN)</td></tr>
          <tr><td>0x0700-0x07FF</td><td>Knowledge Base</td></tr>
          <tr><td>0x0800-0x08FF</td><td>Settings &amp; Configuration</td></tr>
          <tr><td>0x0900-0x09FF</td><td>Room/Channel Management</td></tr>
          <tr><td>0x0A00-0x0AFF</td><td>Media Handling</td></tr>
          <tr><td>0x0B00-0x0BFF</td><td>Telephony (Voice, Video, SMS, IVR)</td></tr>
          <tr><td>0x0C00-0x0CFF</td><td>Calendar &amp; Events</td></tr>
          <tr><td>0x0D00-0x0DFF</td><td>Tasks, Shopping &amp; Gamification</td></tr>
          <tr><td>0x0E00-0x0EFF</td><td>Smart Home Devices</td></tr>
          <tr><td>0x0F00-0x0FFF</td><td>Automation Rules</td></tr>
          <tr><td>0x1000-0x10FF</td><td>Maya AI Assistant</td></tr>
          <tr><td>0x1100-0x11FF</td><td>Synchronization &amp; VFS Federation</td></tr>
          <tr><td>0x1200-0x12FF</td><td>Orchestration (Notifications, Finance)</td></tr>
          <tr><td>0x1300-0x13FF</td><td>Presence &amp; Status (Education)</td></tr>
          <tr><td>0x1400-0x14FF</td><td>Health (Social, Community)</td></tr>
          <tr><td>0x1500-0x15FF</td><td>Location &amp; Mobility</td></tr>
          <tr><td>0x1600-0x16FF</td><td>Debug, Testing &amp; Plugins</td></tr>
          <tr><td>0x1700-0x17FF</td><td>Mobile Device Management (MDM)</td></tr>
          <tr><td>0x1800-0x18FF</td><td>Legal Documents &amp; Care Directives</td></tr>
          <tr><td>0x1900-0x19FF</td><td>Mobility &amp; Vehicle Management</td></tr>
          <tr><td>0x1A00-0x1AFF</td><td>Travel &amp; Vacation</td></tr>
          <tr><td>0x1B00-0x1BFF</td><td>Audit &amp; Compliance</td></tr>
          <tr><td>0x1C00-0x1CFF</td><td>Audio Pipeline</td></tr>
          <tr><td>0x1D00-0x1DFF</td><td>Desktop Client</td></tr>
          <tr><td>0x1E00-0xEFFF</td><td>Unassigned (reserved for future standard categories)</td></tr>
          <tr><td>0xF000-0xFFFE</td><td>Vendor Extensions (third-party/vendor-specific use only)</td></tr>
          <tr><td>0xFFFF</td><td>Reserved</td></tr>
        </tbody>
      </table>

      <section anchor="core-operations">
        <name>Core Operations (0x0000-0x00FF)</name>

        <section anchor="session-management">
          <name>Session Management (0x0000-0x000F)</name>

          <table>
            <name>Session Management Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0000</td><td>NOP</td><td>No operation</td></tr>
              <tr><td>0x0001</td><td>KEEPALIVE</td><td>Session keepalive</td></tr>
              <tr><td>0x0002</td><td>KEEPALIVE_ACK</td><td>Keepalive acknowledgment</td></tr>
              <tr><td>0x0003</td><td>SESSION_INIT</td><td>Initialize session</td></tr>
              <tr><td>0x0004</td><td>SESSION_ACK</td><td>Session acknowledgment</td></tr>
              <tr><td>0x0005</td><td>SESSION_CLOSE</td><td>Close session</td></tr>
              <tr><td>0x0006</td><td>SESSION_CLOSE_ACK</td><td>Close acknowledgment</td></tr>
              <tr><td>0x0007</td><td>SESSION_RESUME</td><td>Resume session with ticket</td></tr>
              <tr><td>0x0008</td><td>SESSION_RESUMED</td><td>Session resumed</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="key-management">
          <name>Key Management (0x0010-0x001F)</name>

          <table>
            <name>Key Management Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0010</td><td>KEY_EXCHANGE_INIT</td><td>Initiate key exchange</td></tr>
              <tr><td>0x0011</td><td>KEY_EXCHANGE_RESPONSE</td><td>Key exchange response</td></tr>
              <tr><td>0x0012</td><td>KEY_EXCHANGE_COMPLETE</td><td>Key exchange complete</td></tr>
              <tr><td>0x0016</td><td>SESSION_ROTATE</td><td>Rotate session key</td></tr>
              <tr><td>0x0017</td><td>SESSION_REVOKE</td><td>Revoke session key</td></tr>
            </tbody>
          </table>
        </section>

      </section>

      <section anchor="standard-operations">
        <name>Standard Operations (0x0100-0x01FF)</name>

        <t>
          Standard Operations cover authentication, device registration,
          messaging, and identity management. The 0x0100-0x018F range is
          defined for authentication, key exchange, sessions, device
          registration, backup codes, and messaging. The 0x0190-0x01EF
          range is allocated to identity management operations.
        </t>

        <section anchor="identity-management">
          <name>Identity Management (0x0190-0x01EF)</name>

          <t>
            Identity Management operations handle user lifecycle, profile
            management, authentication credentials, and two-factor
            authentication. All Identity Management operations MUST be
            sent at Tier 3 (Encrypted) or higher.
          </t>

          <section anchor="identity-user-ops">
            <name>User Identity (0x0190-0x019F)</name>

            <table>
              <name>User Identity Operations</name>
              <thead>
                <tr><th>Code</th><th>Name</th><th>Description</th></tr>
              </thead>
              <tbody>
                <tr><td>0x0190</td><td>USER_CREATE</td><td>Create user account</td></tr>
                <tr><td>0x0191</td><td>USER_GET</td><td>Get user information</td></tr>
                <tr><td>0x0192</td><td>USER_UPDATE</td><td>Update user account</td></tr>
                <tr><td>0x0193</td><td>USER_DELETE</td><td>Delete user account</td></tr>
                <tr><td>0x0194</td><td>USER_LIST</td><td>List users</td></tr>
                <tr><td>0x0195</td><td>USER_SEARCH</td><td>Search users</td></tr>
              </tbody>
            </table>
          </section>

          <section anchor="identity-moderation-ops">
            <name>User Moderation (0x01A0-0x01AF)</name>

            <table>
              <name>User Moderation Operations</name>
              <thead>
                <tr><th>Code</th><th>Name</th><th>Description</th></tr>
              </thead>
              <tbody>
                <tr><td>0x01A0</td><td>USER_BLOCK</td><td>Block user</td></tr>
                <tr><td>0x01A1</td><td>USER_UNBLOCK</td><td>Unblock user</td></tr>
                <tr><td>0x01A2</td><td>USER_MUTE</td><td>Mute user</td></tr>
                <tr><td>0x01A3</td><td>USER_UNMUTE</td><td>Unmute user</td></tr>
              </tbody>
            </table>
          </section>

          <section anchor="identity-profile-ops">
            <name>Profile and Avatar (0x01B0-0x01BF)</name>

            <table>
              <name>Profile and Avatar Operations</name>
              <thead>
                <tr><th>Code</th><th>Name</th><th>Description</th></tr>
              </thead>
              <tbody>
                <tr><td>0x01B0</td><td>PROFILE_GET</td><td>Get user profile</td></tr>
                <tr><td>0x01B1</td><td>PROFILE_UPDATE</td><td>Update user profile</td></tr>
                <tr><td>0x01B2</td><td>AVATAR_SET</td><td>Set user avatar</td></tr>
                <tr><td>0x01B3</td><td>AVATAR_GET</td><td>Get user avatar</td></tr>
              </tbody>
            </table>
          </section>

          <section anchor="identity-preferences-ops">
            <name>Preferences (0x01C0-0x01CF)</name>

            <table>
              <name>Preferences Operations</name>
              <thead>
                <tr><th>Code</th><th>Name</th><th>Description</th></tr>
              </thead>
              <tbody>
                <tr><td>0x01C0</td><td>PREFERENCES_GET</td><td>Get user preferences</td></tr>
                <tr><td>0x01C1</td><td>PREFERENCES_SET</td><td>Set user preferences</td></tr>
              </tbody>
            </table>
          </section>

          <section anchor="identity-credential-ops">
            <name>Password and Email (0x01D0-0x01DF)</name>

            <table>
              <name>Password and Email Operations</name>
              <thead>
                <tr><th>Code</th><th>Name</th><th>Description</th></tr>
              </thead>
              <tbody>
                <tr><td>0x01D0</td><td>PASSWORD_CHANGE</td><td>Change password</td></tr>
                <tr><td>0x01D1</td><td>PASSWORD_RESET</td><td>Reset password</td></tr>
                <tr><td>0x01D2</td><td>EMAIL_CHANGE</td><td>Change email address</td></tr>
                <tr><td>0x01D3</td><td>EMAIL_VERIFY</td><td>Verify email address</td></tr>
              </tbody>
            </table>

            <t>
              PASSWORD_CHANGE requires the current password in the payload.
              PASSWORD_RESET initiates an out-of-band reset flow. EMAIL_CHANGE
              triggers a verification email to the new address; the change is
              not effective until EMAIL_VERIFY is completed.
            </t>
          </section>

          <section anchor="identity-totp-ops">
            <name>TOTP Two-Factor Authentication (0x01E0-0x01EF)</name>

            <table>
              <name>TOTP Operations</name>
              <thead>
                <tr><th>Code</th><th>Name</th><th>Description</th></tr>
              </thead>
              <tbody>
                <tr><td>0x01E0</td><td>TOTP_ENABLE</td><td>Enable TOTP for account</td></tr>
                <tr><td>0x01E1</td><td>TOTP_DISABLE</td><td>Disable TOTP for account</td></tr>
                <tr><td>0x01E2</td><td>TOTP_VERIFY</td><td>Verify TOTP code</td></tr>
              </tbody>
            </table>

            <t>
              TOTP_ENABLE returns a shared secret and provisioning URI
              compatible with RFC 6238. The client MUST verify the secret
              by submitting a valid TOTP code via TOTP_VERIFY before the
              enablement is finalized. TOTP_DISABLE requires a valid TOTP
              code or backup code for confirmation.
            </t>
          </section>

        </section>

      </section>

      <section anchor="resource-sharing-operations">
        <name>Resource Sharing Operations (0x0200-0x02FF)</name>

        <t>
          Resource Sharing operations enable devices to expose and consume
          resources across the network. These operations support video, audio,
          HID, and GPU services.
        </t>

        <section anchor="resource-device-management">
          <name>Device Management (0x0200-0x020F)</name>

          <table>
            <name>Device Management Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0200</td><td>DEVICE_LIST</td><td>List available devices</td></tr>
              <tr><td>0x0201</td><td>DEVICE_INFO</td><td>Get device information</td></tr>
              <tr><td>0x0202</td><td>DEVICE_SUBSCRIBE</td><td>Subscribe to device events</td></tr>
              <tr><td>0x0203</td><td>DEVICE_UNSUBSCRIBE</td><td>Unsubscribe from device</td></tr>
              <tr><td>0x0204</td><td>DEVICE_LOCK</td><td>Lock device for exclusive use</td></tr>
              <tr><td>0x0205</td><td>DEVICE_UNLOCK</td><td>Release device lock</td></tr>
              <tr><td>0x0206</td><td>DEVICE_CONFIGURE</td><td>Configure device parameters</td></tr>
              <tr><td>0x0207</td><td>DEVICE_CAPABILITIES</td><td>Query device capabilities</td></tr>
              <tr><td>0x020B</td><td>DEVICE_DISCOVER</td><td>List all connected devices (including unshared)</td></tr>
            </tbody>
          </table>

          <t>
            DEVICE_LIST (0x0200) returns only devices currently being shared.
            DEVICE_DISCOVER (0x020B) returns all connected devices regardless
            of sharing status, enabling provisioning workflows.
          </t>
        </section>

        <section anchor="resource-stream-operations">
          <name>Stream Operations (0x0210-0x021F)</name>

          <table>
            <name>Stream Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0210</td><td>STREAM_START</td><td>Start data stream</td></tr>
              <tr><td>0x0211</td><td>STREAM_STOP</td><td>Stop data stream</td></tr>
              <tr><td>0x0212</td><td>STREAM_DATA</td><td>Stream data payload</td></tr>
              <tr><td>0x0213</td><td>STREAM_CONFIGURE</td><td>Configure stream parameters</td></tr>
              <tr><td>0x0214</td><td>STREAM_QUALITY</td><td>Adjust quality settings</td></tr>
              <tr><td>0x0215</td><td>STREAM_PAUSE</td><td>Pause stream</td></tr>
              <tr><td>0x0216</td><td>STREAM_RESUME</td><td>Resume paused stream</td></tr>
            </tbody>
          </table>

          <t>
            Stream types are indicated in the STREAM_START payload:
          </t>

          <ul>
            <li>0x01: Video (H.264, MJPEG)</li>
            <li>0x02: Audio (Opus, PCM)</li>
            <li>0x03: HID (evdev events)</li>
            <li>0x04: Serial (byte stream)</li>
          </ul>
        </section>

        <section anchor="resource-gpu-operations">
          <name>GPU Service Operations (0x0220-0x022F)</name>

          <t>
            GPU operations enable queue-based access to inference services
            (LLM, TTS, STT, Image Generation).
          </t>

          <table>
            <name>GPU Service Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0220</td><td>GPU_REQUEST</td><td>Submit GPU request</td></tr>
              <tr><td>0x0221</td><td>GPU_RESPONSE</td><td>GPU response (streaming)</td></tr>
              <tr><td>0x0222</td><td>GPU_STATUS</td><td>Query service status</td></tr>
              <tr><td>0x0223</td><td>GPU_CANCEL</td><td>Cancel pending request</td></tr>
              <tr><td>0x0224</td><td>GPU_QUEUE_INFO</td><td>Queue position and ETA</td></tr>
            </tbody>
          </table>

          <t>
            GPU service types:
          </t>

          <ul>
            <li>0x01: LLM (Large Language Model)</li>
            <li>0x02: TTS (Text-to-Speech)</li>
            <li>0x03: STT (Speech-to-Text)</li>
            <li>0x04: ImageGen (Image Generation)</li>
          </ul>
        </section>

        <section anchor="resource-routing-acl">
          <name>Dynamic Routing and ACL (0x0240-0x024F)</name>

          <t>
            Dynamic routing enables Hub-controlled device assignment and
            per-client access control. A Hub can redirect device streams
            between clients dynamically.
          </t>

          <table>
            <name>Dynamic Routing Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0240</td><td>ROUTE_CREATE</td><td>Create device route</td></tr>
              <tr><td>0x0241</td><td>ROUTE_DELETE</td><td>Delete device route</td></tr>
              <tr><td>0x0242</td><td>ROUTE_LIST</td><td>List active routes</td></tr>
              <tr><td>0x0243</td><td>ROUTE_MODIFY</td><td>Modify existing route</td></tr>
              <tr><td>0x0244</td><td>ACL_SET</td><td>Set access control</td></tr>
              <tr><td>0x0245</td><td>ACL_GET</td><td>Get access control</td></tr>
              <tr><td>0x0246</td><td>ACL_GRANT</td><td>Grant client access</td></tr>
              <tr><td>0x0247</td><td>ACL_REVOKE</td><td>Revoke client access</td></tr>
              <tr><td>0x0248</td><td>ROUTE_PRIORITY</td><td>Set routing priority</td></tr>
            </tbody>
          </table>

          <t>
            Access modes:
          </t>

          <ul>
            <li>0x00: None (no access)</li>
            <li>0x01: Read-only</li>
            <li>0x02: Write-only</li>
            <li>0x03: Read-write</li>
            <li>0x04: Exclusive (single client)</li>
          </ul>
        </section>

        <section anchor="resource-client-assignment">
          <name>Client Assignment Operations (0x0250-0x025F)</name>

          <t>
            Client Assignment operations enable Hub-managed device provisioning.
            A Hub can assign devices to clients, and servers can request approval
            for sharing new devices through a token-based workflow.
          </t>

          <table>
            <name>Client Assignment Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0250</td><td>CLIENT_REGISTER</td><td>Register client with server</td></tr>
              <tr><td>0x0251</td><td>CLIENT_HEARTBEAT</td><td>Client keepalive</td></tr>
              <tr><td>0x0252</td><td>CLIENT_ASSIGN</td><td>Assign device to client</td></tr>
              <tr><td>0x0253</td><td>CLIENT_REVOKE</td><td>Revoke device from client</td></tr>
              <tr><td>0x0254</td><td>CLIENT_STATUS</td><td>Query client status</td></tr>
              <tr><td>0x0255</td><td>CLIENT_LIST</td><td>List registered clients</td></tr>
              <tr><td>0x0256</td><td>CLIENT_INFO</td><td>Get client information</td></tr>
              <tr><td>0x0257</td><td>DEVICE_REQUEST_CREATE</td><td>Create device sharing request</td></tr>
              <tr><td>0x0258</td><td>DEVICE_REQUEST_LIST</td><td>List pending device requests</td></tr>
              <tr><td>0x0259</td><td>DEVICE_REQUEST_DETAILS</td><td>Get request details</td></tr>
              <tr><td>0x025A</td><td>DEVICE_REQUEST_RESPOND</td><td>Approve/reject device request</td></tr>
              <tr><td>0x025B</td><td>DEVICE_REQUEST_CANCEL</td><td>Cancel pending request</td></tr>
            </tbody>
          </table>

          <t>
            Device Request Workflow:
          </t>

          <ol>
            <li>Hub queries server with DEVICE_DISCOVER (0x020B) to list available devices</li>
            <li>Hub administrator creates request via DEVICE_REQUEST_CREATE (0x0257)</li>
            <li>Server queries pending requests via DEVICE_REQUEST_LIST (0x0258)</li>
            <li>Server retrieves details via DEVICE_REQUEST_DETAILS (0x0259)</li>
            <li>Server administrator approves/rejects via DEVICE_REQUEST_RESPOND (0x025A)</li>
          </ol>

          <t>
            Request states:
          </t>

          <ul>
            <li>0x00: Pending (awaiting server approval)</li>
            <li>0x01: Approved (all devices accepted)</li>
            <li>0x02: Partially Approved (subset of devices accepted)</li>
            <li>0x03: Rejected (request denied)</li>
            <li>0x04: Expired (token timeout)</li>
            <li>0x05: Cancelled (hub cancelled request)</li>
          </ul>
        </section>

      </section>

      <section anchor="hardware-passthrough-operations">
        <name>Hardware Passthrough Operations (0x0600-0x06FF)</name>

        <t>
          Hardware Passthrough operations enable low-level access to hardware
          interfaces. Unlike service-based resource sharing, these operations
          provide direct protocol-level access to hardware buses.
        </t>

        <section anchor="hw-usb-operations">
          <name>USB Operations (0x0600-0x060F)</name>

          <t>
            USB passthrough virtualizes USB at the URB (USB Request Block) level,
            allowing any USB device to appear as natively connected on the client.
          </t>

          <table>
            <name>USB Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0600</td><td>USB_DEVICE_LIST</td><td>List USB devices</td></tr>
              <tr><td>0x0601</td><td>USB_DEVICE_ATTACH</td><td>Attach USB device</td></tr>
              <tr><td>0x0602</td><td>USB_DEVICE_DETACH</td><td>Detach USB device</td></tr>
              <tr><td>0x0603</td><td>USB_CONTROL_TRANSFER</td><td>USB control transfer</td></tr>
              <tr><td>0x0604</td><td>USB_BULK_TRANSFER</td><td>USB bulk transfer</td></tr>
              <tr><td>0x0605</td><td>USB_INTERRUPT_TRANSFER</td><td>USB interrupt transfer</td></tr>
              <tr><td>0x0606</td><td>USB_ISOCHRONOUS_TRANSFER</td><td>USB isochronous transfer</td></tr>
              <tr><td>0x0607</td><td>USB_GET_DESCRIPTOR</td><td>Get USB descriptor</td></tr>
              <tr><td>0x0608</td><td>USB_SET_CONFIGURATION</td><td>Set USB configuration</td></tr>
              <tr><td>0x0609</td><td>USB_SET_INTERFACE</td><td>Set USB interface</td></tr>
              <tr><td>0x060A</td><td>USB_CLEAR_HALT</td><td>Clear endpoint halt</td></tr>
              <tr><td>0x060B</td><td>USB_RESET</td><td>Reset USB device</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="hw-serial-operations">
          <name>Serial Operations (0x0610-0x061F)</name>

          <t>
            Serial passthrough supports RS-232, RS-485, and UART interfaces.
          </t>

          <table>
            <name>Serial Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0610</td><td>SERIAL_PORT_LIST</td><td>List serial ports</td></tr>
              <tr><td>0x0611</td><td>SERIAL_PORT_OPEN</td><td>Open serial port</td></tr>
              <tr><td>0x0612</td><td>SERIAL_PORT_CLOSE</td><td>Close serial port</td></tr>
              <tr><td>0x0613</td><td>SERIAL_PORT_CONFIGURE</td><td>Configure baud, parity, etc.</td></tr>
              <tr><td>0x0614</td><td>SERIAL_DATA_WRITE</td><td>Write to serial port</td></tr>
              <tr><td>0x0615</td><td>SERIAL_DATA_READ</td><td>Read from serial port</td></tr>
              <tr><td>0x0616</td><td>SERIAL_CONTROL_SET</td><td>Set control lines (DTR, RTS)</td></tr>
              <tr><td>0x0617</td><td>SERIAL_CONTROL_GET</td><td>Get control line status</td></tr>
              <tr><td>0x0618</td><td>SERIAL_BREAK</td><td>Send break condition</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="hw-gpio-operations">
          <name>GPIO Operations (0x0620-0x062F)</name>

          <t>
            GPIO operations enable control of General Purpose Input/Output pins.
          </t>

          <table>
            <name>GPIO Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0620</td><td>GPIO_CHIP_LIST</td><td>List GPIO chips</td></tr>
              <tr><td>0x0621</td><td>GPIO_LINE_INFO</td><td>Get line information</td></tr>
              <tr><td>0x0622</td><td>GPIO_LINE_REQUEST</td><td>Request GPIO line</td></tr>
              <tr><td>0x0623</td><td>GPIO_LINE_RELEASE</td><td>Release GPIO line</td></tr>
              <tr><td>0x0624</td><td>GPIO_LINE_SET</td><td>Set line value</td></tr>
              <tr><td>0x0625</td><td>GPIO_LINE_GET</td><td>Get line value</td></tr>
              <tr><td>0x0626</td><td>GPIO_LINE_WATCH</td><td>Watch for edge events</td></tr>
              <tr><td>0x0627</td><td>GPIO_EVENT</td><td>GPIO edge event notification</td></tr>
              <tr><td>0x0628</td><td>GPIO_PWM_CONFIGURE</td><td>Configure PWM output</td></tr>
              <tr><td>0x0629</td><td>GPIO_PWM_SET</td><td>Set PWM duty cycle</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="hw-i2c-operations">
          <name>I2C Operations (0x0630-0x063F)</name>

          <t>
            I2C (Inter-Integrated Circuit) bus operations for sensor and
            peripheral communication.
          </t>

          <table>
            <name>I2C Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0630</td><td>I2C_BUS_LIST</td><td>List I2C buses</td></tr>
              <tr><td>0x0631</td><td>I2C_BUS_SCAN</td><td>Scan for devices on bus</td></tr>
              <tr><td>0x0632</td><td>I2C_TRANSFER</td><td>I2C read/write transfer</td></tr>
              <tr><td>0x0633</td><td>I2C_WRITE_BYTE</td><td>Write single byte</td></tr>
              <tr><td>0x0634</td><td>I2C_READ_BYTE</td><td>Read single byte</td></tr>
              <tr><td>0x0635</td><td>I2C_WRITE_BLOCK</td><td>Write data block</td></tr>
              <tr><td>0x0636</td><td>I2C_READ_BLOCK</td><td>Read data block</td></tr>
              <tr><td>0x0637</td><td>I2C_SMBUS_COMMAND</td><td>SMBus protocol command</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="hw-spi-operations">
          <name>SPI Operations (0x0640-0x064F)</name>

          <t>
            SPI (Serial Peripheral Interface) operations for high-speed
            peripheral communication.
          </t>

          <table>
            <name>SPI Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0640</td><td>SPI_BUS_LIST</td><td>List SPI buses</td></tr>
              <tr><td>0x0641</td><td>SPI_DEVICE_OPEN</td><td>Open SPI device</td></tr>
              <tr><td>0x0642</td><td>SPI_DEVICE_CLOSE</td><td>Close SPI device</td></tr>
              <tr><td>0x0643</td><td>SPI_CONFIGURE</td><td>Configure mode, speed, bits</td></tr>
              <tr><td>0x0644</td><td>SPI_TRANSFER</td><td>Full-duplex SPI transfer</td></tr>
              <tr><td>0x0645</td><td>SPI_WRITE</td><td>SPI write-only</td></tr>
              <tr><td>0x0646</td><td>SPI_READ</td><td>SPI read-only</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="hw-can-operations">
          <name>CAN Bus Operations (0x0650-0x065F)</name>

          <t>
            CAN (Controller Area Network) bus operations for automotive and
            industrial protocols.
          </t>

          <table>
            <name>CAN Bus Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0650</td><td>CAN_INTERFACE_LIST</td><td>List CAN interfaces</td></tr>
              <tr><td>0x0651</td><td>CAN_INTERFACE_OPEN</td><td>Open CAN interface</td></tr>
              <tr><td>0x0652</td><td>CAN_INTERFACE_CLOSE</td><td>Close CAN interface</td></tr>
              <tr><td>0x0653</td><td>CAN_CONFIGURE</td><td>Configure bitrate, mode</td></tr>
              <tr><td>0x0654</td><td>CAN_FRAME_SEND</td><td>Send CAN frame</td></tr>
              <tr><td>0x0655</td><td>CAN_FRAME_RECEIVE</td><td>Receive CAN frame</td></tr>
              <tr><td>0x0656</td><td>CAN_FILTER_SET</td><td>Set receive filter</td></tr>
              <tr><td>0x0657</td><td>CAN_ERROR_STATUS</td><td>Get error counters</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="hw-onewire-operations">
          <name>1-Wire Operations (0x0660-0x066F)</name>

          <t>
            1-Wire bus operations for temperature sensors, iButtons, and
            similar devices.
          </t>

          <table>
            <name>1-Wire Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0660</td><td>ONEWIRE_BUS_LIST</td><td>List 1-Wire buses</td></tr>
              <tr><td>0x0661</td><td>ONEWIRE_SEARCH</td><td>Search for devices</td></tr>
              <tr><td>0x0662</td><td>ONEWIRE_RESET</td><td>Reset bus</td></tr>
              <tr><td>0x0663</td><td>ONEWIRE_READ_ROM</td><td>Read device ROM</td></tr>
              <tr><td>0x0664</td><td>ONEWIRE_MATCH_ROM</td><td>Select device by ROM</td></tr>
              <tr><td>0x0665</td><td>ONEWIRE_SKIP_ROM</td><td>Skip ROM (single device)</td></tr>
              <tr><td>0x0666</td><td>ONEWIRE_READ</td><td>Read bytes</td></tr>
              <tr><td>0x0667</td><td>ONEWIRE_WRITE</td><td>Write bytes</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="hw-gsm-modem-operations">
          <name>GSM Modem Operations (0x0670-0x067F)</name>

          <t>
            GSM modem operations provide direct access to cellular modems for
            SMS, GNSS (GPS), voice calls, and USSD services. These operations
            abstract the underlying AT command interface.
          </t>

          <table>
            <name>GSM Modem Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0670</td><td>GSM_MODEM_INIT</td><td>Initialize GSM modem</td></tr>
              <tr><td>0x0671</td><td>GSM_MODEM_STATUS</td><td>Get modem status</td></tr>
              <tr><td>0x0672</td><td>GSM_NETWORK_REG</td><td>Network registration status</td></tr>
              <tr><td>0x0673</td><td>GSM_SIGNAL_QUALITY</td><td>Signal quality (RSSI, BER)</td></tr>
              <tr><td>0x0674</td><td>GSM_SMS_SEND</td><td>Send SMS via AT commands</td></tr>
              <tr><td>0x0675</td><td>GSM_SMS_RECEIVE</td><td>Receive SMS notification</td></tr>
              <tr><td>0x0676</td><td>GSM_SMS_LIST</td><td>List SMS messages</td></tr>
              <tr><td>0x0677</td><td>GSM_SMS_DELETE</td><td>Delete SMS from SIM</td></tr>
              <tr><td>0x0678</td><td>GSM_USSD_SEND</td><td>Send USSD command</td></tr>
              <tr><td>0x0679</td><td>GSM_USSD_RESPONSE</td><td>USSD response</td></tr>
              <tr><td>0x067A</td><td>GSM_GNSS_ENABLE</td><td>Enable/disable GNSS module</td></tr>
              <tr><td>0x067B</td><td>GSM_GNSS_POSITION</td><td>Get GNSS position fix</td></tr>
              <tr><td>0x067C</td><td>GSM_GNSS_CONFIG</td><td>Configure GNSS</td></tr>
              <tr><td>0x067D</td><td>GSM_VOICE_DIAL</td><td>Initiate voice call</td></tr>
              <tr><td>0x067E</td><td>GSM_VOICE_HANGUP</td><td>Hangup voice call</td></tr>
              <tr><td>0x067F</td><td>GSM_VOICE_ANSWER</td><td>Answer incoming call</td></tr>
            </tbody>
          </table>

          <t>
            GSM modem types supported:
          </t>

          <ul>
            <li>SIM7600: 4G LTE Cat-4 with GNSS</li>
            <li>SIM800: 2G GSM/GPRS</li>
            <li>Quectel EC25: 4G LTE</li>
          </ul>
        </section>

      </section>

      <section anchor="telephony-sms">
        <name>Telephony: SMS Gateway (0x0B50-0x0B7F)</name>

        <t>
          The SMS Gateway operations provide application-level SMS handling for
          the MyClerk platform. Unlike the low-level GSM Modem operations which
          deal with AT commands and hardware, these operations provide
          intelligent message routing, TAN/OTP detection, and emergency
          fallback services. These are standard protocol operations in the
          Telephony category (0x0B00-0x0BFF).
        </t>

        <section anchor="sms-gateway-operations">
          <name>SMS Gateway Operations (0x0B50-0x0B5F)</name>

          <table>
            <name>SMS Gateway Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0B50</td><td>SMS_CREATE</td><td>Create outgoing SMS</td></tr>
              <tr><td>0x0B51</td><td>SMS_SEND</td><td>Send SMS via gateway</td></tr>
              <tr><td>0x0B52</td><td>SMS_RECEIVE</td><td>Incoming SMS notification</td></tr>
              <tr><td>0x0B53</td><td>SMS_STATUS</td><td>Query message delivery status</td></tr>
              <tr><td>0x0B54</td><td>SMS_LIST</td><td>List messages in gateway</td></tr>
              <tr><td>0x0B55</td><td>SMS_DELETE</td><td>Delete message from gateway</td></tr>
              <tr><td>0x0B56</td><td>SMS_ROUTE_ADD</td><td>Add routing rule</td></tr>
              <tr><td>0x0B57</td><td>SMS_ROUTE_REMOVE</td><td>Remove routing rule</td></tr>
              <tr><td>0x0B58</td><td>SMS_ROUTE_LIST</td><td>List routing rules</td></tr>
              <tr><td>0x0B59</td><td>SMS_GATEWAY_STATUS</td><td>Gateway health status</td></tr>
            </tbody>
          </table>
        </section>

        <section anchor="sms-parsing-operations">
          <name>SMS Parsing Operations (0x0B60-0x0B6F)</name>

          <t>
            SMS Parsing operations handle intelligent classification and
            extraction of structured data from SMS messages.
          </t>

          <table>
            <name>SMS Parsing Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0B60</td><td>SMS_PARSED</td><td>Parsed SMS event</td></tr>
              <tr><td>0x0B61</td><td>SMS_CLASSIFY</td><td>Classify SMS type</td></tr>
              <tr><td>0x0B62</td><td>SMS_TAN_RECEIVED</td><td>TAN/OTP received event</td></tr>
              <tr><td>0x0B63</td><td>SMS_TAN_ANNOUNCE</td><td>Announce TAN to family</td></tr>
              <tr><td>0x0B64</td><td>SMS_TAN_CLAIM</td><td>Claim TAN ownership</td></tr>
              <tr><td>0x0B65</td><td>SMS_TAN_EXPIRE</td><td>TAN expiration notification</td></tr>
              <tr><td>0x0B66</td><td>SMS_DELIVERY_RECEIVED</td><td>Delivery notification received</td></tr>
              <tr><td>0x0B67</td><td>SMS_APPOINTMENT_RECEIVED</td><td>Appointment SMS received</td></tr>
              <tr><td>0x0B68</td><td>SMS_SPAM_DETECTED</td><td>Spam SMS detected</td></tr>
              <tr><td>0x0B69</td><td>SMS_ALERT_RECEIVED</td><td>Alert/warning SMS received</td></tr>
            </tbody>
          </table>

          <t>
            SMS classification types:
          </t>

          <ul>
            <li>0x01: TAN/OTP (banking, 2FA codes)</li>
            <li>0x02: Delivery notification (package tracking)</li>
            <li>0x03: Appointment reminder</li>
            <li>0x04: Marketing/Spam</li>
            <li>0x05: Alert/Warning (weather, emergency)</li>
            <li>0x06: Personal message</li>
            <li>0x07: Unknown</li>
          </ul>
        </section>

        <section anchor="emergency-gateway-operations">
          <name>Emergency Gateway Operations (0x0B70-0x0B7F)</name>

          <t>
            Emergency Gateway operations provide fallback communication when
            primary channels (internet, Matrix) are unavailable. The SMS
            gateway automatically activates emergency mode during outages.
          </t>

          <table>
            <name>Emergency Gateway Operations</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Description</th></tr>
            </thead>
            <tbody>
              <tr><td>0x0B70</td><td>EMERGENCY_GATEWAY_STATUS</td><td>Gateway health status</td></tr>
              <tr><td>0x0B71</td><td>EMERGENCY_INTERNET_DOWN</td><td>Internet outage detected</td></tr>
              <tr><td>0x0B72</td><td>EMERGENCY_INTERNET_UP</td><td>Internet restored</td></tr>
              <tr><td>0x0B73</td><td>EMERGENCY_SMS_ALERT</td><td>Emergency alert via SMS</td></tr>
              <tr><td>0x0B74</td><td>EMERGENCY_SMS_COMMAND</td><td>Emergency command via SMS</td></tr>
              <tr><td>0x0B75</td><td>EMERGENCY_LOCATION_REQUEST</td><td>Request device location</td></tr>
              <tr><td>0x0B76</td><td>EMERGENCY_LOCATION_RESPONSE</td><td>Device location response</td></tr>
              <tr><td>0x0B77</td><td>EMERGENCY_HEALTH_CHECK</td><td>Remote health check request</td></tr>
              <tr><td>0x0B78</td><td>EMERGENCY_HEALTH_RESPONSE</td><td>Health check response</td></tr>
              <tr><td>0x0B79</td><td>EMERGENCY_MODE_ACTIVATE</td><td>Activate emergency mode</td></tr>
              <tr><td>0x0B7A</td><td>EMERGENCY_MODE_DEACTIVATE</td><td>Deactivate emergency mode</td></tr>
            </tbody>
          </table>

          <t>
            Emergency mode features:
          </t>

          <ul>
            <li>Automatic activation when internet connectivity is lost</li>
            <li>Predefined SMS commands for remote device control</li>
            <li>Location sharing via GNSS coordinates in SMS</li>
            <li>Health monitoring with battery and connectivity status</li>
            <li>Graceful transition back to normal operation</li>
          </ul>

          <t>
            Note: As of the reference implementation, SMS Gateway operations (0xF350-0xF35F),
            SMS Parsing operations (0xF360-0xF36F), and Emergency Gateway operations
            (0xF370-0xF37F) have been relocated to the Telephony category (0x0B50-0x0B7F)
            for consistency. The vendor extension range assignments are retained for
            backwards compatibility but implementations SHOULD use the Telephony range.
          </t>
        </section>

      </section>

      <section anchor="application-operations">
        <name>Application Operations (0x0700-0x1DFF)</name>
        <t>
          Application-layer operations covering knowledge management, settings,
          messaging, telephony, calendar, tasks, smart home, automation, AI assistant,
          synchronization, orchestration, presence, health, location, plugins, MDM,
          legal documents, mobility, travel, audit, audio pipeline, and desktop
          client operations are defined in the companion document <xref target="MYCLERK-OPS"/>.
        </t>
        <t>
          The companion document serves as the authoritative registry for all
          application-layer operation codes in the 0x0700-0x1DFF range, following
          the "Assigned Numbers" pattern established by Bluetooth SIG specifications.
          This separation allows the core protocol specification to remain stable
          while application operations evolve independently.
        </t>
      </section>

    </section>

    <!-- ============================================================ -->
    <section anchor="payload-formats">
      <name>Payload Formats</name>

      <t>
        Payloads are encoded using MessagePack (a subset of CBOR). This section
        defines payload structures using CDDL <xref target="RFC8610"/>.
      </t>

      <section anchor="session-init-payload">
        <name>SESSION_INIT Payload</name>

        <t>
          The initiator MUST always include its X25519 public key. It
          SHOULD additionally include its ML-KEM-768 encapsulation key (and
          set <tt>kex-mode: hybrid-mlkem768</tt>) to negotiate the hybrid
          post-quantum KEX. If the initiator cannot afford the 1184-byte
          ML-KEM public, it MAY omit <tt>mlkem-public</tt> and set
          <tt>kex-mode: classical-only</tt>; servers that require PQ by
          policy will refuse such a session.
        </t>

        <sourcecode type="cddl"><![CDATA[
session-init = {
    nonce: bstr .size 8,
    timestamp: uint,
    kex-mode: kex-mode-type,
    x25519-public: bstr .size 32,
    ; mlkem-public REQUIRED when kex-mode = hybrid-mlkem768
    ? mlkem-public: bstr .size 1184,
    ? capabilities: [* capability],
    ? device-id: bstr .size 16,
}

kex-mode-type = &(
    classical-only:    0,  ; X25519 only (legacy / constrained)
    hybrid-mlkem768:   1,  ; ML-KEM-768 + X25519 (default)
    ; 2 reserved for future hybrid-mlkem1024
)

capability = &(
    compression-lz4:     0,
    compression-zstd:    1,
    encryption-chacha20: 2,
    encryption-aes256gcm:3,
    fragmentation:       4,
    streaming:           5,
    federation:          6,
    vfs:                 8,
    request-correlation: 11,
    pq-mlkem768:         12, ; signals ML-KEM-768 support
)
]]></sourcecode>
      </section>

      <section anchor="session-ack-payload">
        <name>SESSION_ACK Payload</name>

        <t>
          The responder MUST echo a <tt>selected-kex-mode</tt>. When that
          mode is <tt>hybrid-mlkem768</tt>, the responder MUST include
          <tt>mlkem-ciphertext</tt>: the 1088-byte ML-KEM ciphertext produced
          by encapsulating against the initiator's encapsulation key.
        </t>

        <sourcecode type="cddl"><![CDATA[
session-ack = {
    session-id: uint .size 2,
    nonce: bstr .size 8,
    selected-tier: uint .le 5,
    selected-kex-mode: kex-mode-type,
    x25519-public: bstr .size 32,
    ; mlkem-ciphertext REQUIRED when
    ; selected-kex-mode = hybrid-mlkem768
    ? mlkem-ciphertext: bstr .size 1088,
    ? selected-capabilities: [* capability],
}
]]></sourcecode>
      </section>

      <section anchor="session-resume-payload">
        <name>SESSION_RESUME Payload</name>

        <sourcecode type="cddl"><![CDATA[
session-resume = {
    old-session-id: uint .size 2,
    ticket: bstr .size 64,
}

; Ticket structure (encrypted with server key, AES-256-GCM):
; - session-key: 32 bytes
; - device-id: 16 bytes
; - issued-at: 4 bytes (Unix timestamp)
; - expires-at: 4 bytes (Unix timestamp)
; - ticket-nonce: 8 bytes
]]></sourcecode>
      </section>

    </section>

    <!-- ============================================================ -->
    <section anchor="tier-compatibility">
      <name>Tier Compatibility</name>

      <t>
        When endpoints support different maximum tiers, they MUST negotiate
        to the highest common tier. The server MUST respond with the minimum
        of its supported tier and the client's requested tier.
      </t>

      <t>
        Servers MAY enforce minimum tier requirements for specific operations.
        If a client requests an operation at an insufficient tier, the server
        MUST respond with error code 0x12 (FORBIDDEN) and include the required
        tier in the error payload.
      </t>

      <section anchor="minimum-tier-requirements">
        <name>Minimum Tier Requirements</name>

        <t>
          The following operations have minimum tier requirements:
        </t>

        <table>
          <name>Minimum Tier Requirements</name>
          <thead>
            <tr><th>Operation Category</th><th>Minimum Tier</th></tr>
          </thead>
          <tbody>
            <tr><td>Lock/Unlock (physical access)</td><td>3</td></tr>
            <tr><td>Key Exchange</td><td>4</td></tr>
            <tr><td>Federation Operations</td><td>4</td></tr>
            <tr><td>Emergency Operations</td><td>3</td></tr>
          </tbody>
        </table>
      </section>

    </section>

    <!-- ============================================================ -->
    <section anchor="error-handling">
      <name>Error Handling</name>

      <t>
        Error codes are 8-bit values organized into ranges:
      </t>

      <table anchor="error-codes">
        <name>Error Codes</name>
        <thead>
          <tr><th>Range</th><th>Category</th></tr>
        </thead>
        <tbody>
          <tr><td>0x00-0x0F</td><td>Success</td></tr>
          <tr><td>0x10-0x1F</td><td>Client Errors</td></tr>
          <tr><td>0x20-0x2F</td><td>Server Errors</td></tr>
          <tr><td>0x30-0x3F</td><td>Federation Errors</td></tr>
          <tr><td>0xF0-0xFF</td><td>Reserved</td></tr>
        </tbody>
      </table>

      <section anchor="specific-error-codes">
        <name>Specific Error Codes</name>

        <dl>
          <dt>0x00 OK</dt>
          <dd>Operation completed successfully.</dd>

          <dt>0x10 BAD_REQUEST</dt>
          <dd>Malformed message or invalid parameters.</dd>

          <dt>0x11 UNAUTHORIZED</dt>
          <dd>Authentication required or failed.</dd>

          <dt>0x12 FORBIDDEN</dt>
          <dd>Insufficient permissions or tier.</dd>

          <dt>0x13 NOT_FOUND</dt>
          <dd>Requested resource does not exist.</dd>

          <dt>0x17 INVALID_SESSION</dt>
          <dd>Session expired or invalid.</dd>

          <dt>0x20 INTERNAL_ERROR</dt>
          <dd>Server encountered an unexpected error.</dd>

          <dt>0x21 SERVICE_UNAVAILABLE</dt>
          <dd>Service temporarily unavailable.</dd>

          <dt>0x22 TIMEOUT</dt>
          <dd>Operation timed out.</dd>
        </dl>
      </section>

    </section>

    <!-- ============================================================ -->
    <section anchor="security-considerations">
      <name>Security Considerations</name>

      <section anchor="nonce-reuse">
        <name>Nonce Reuse</name>
        <t>
          Reusing a nonce with the same key in ChaCha20-Poly1305 completely
          compromises the confidentiality and authenticity of all messages
          encrypted with that key-nonce pair. Implementations MUST ensure
          nonces are never reused by:
        </t>
        <ul>
          <li>Using cryptographically random values for the Random field</li>
          <li>Maintaining a monotonic counter per session</li>
          <li>Rotating keys before counter exhaustion</li>
        </ul>
      </section>

      <section anchor="replay-protection">
        <name>Replay Protection</name>
        <t>
          Tier 3+ messages include timestamps for replay protection.
          Implementations SHOULD reject messages with timestamps more than
          5 minutes in the past or future. Session resumption tickets include
          a nonce that MUST be tracked to prevent replay attacks.
        </t>
      </section>

      <section anchor="tier-downgrade">
        <name>Tier Downgrade Attacks</name>
        <t>
          An attacker might attempt to force communication at a lower tier.
          Servers MUST enforce minimum tier requirements for sensitive
          operations. Clients SHOULD warn users when connecting at a lower
          tier than expected.
        </t>
      </section>

      <section anchor="key-compromise">
        <name>Key Compromise</name>
        <t>
          If a session key is compromised, an attacker can decrypt all messages
          in that session. The 24-hour automatic key rotation limits the window
          of exposure. For forward secrecy, implementations SHOULD use ephemeral
          ECDH keys for each session.
        </t>
      </section>

      <section anchor="post-quantum">
        <name>Post-Quantum Considerations</name>

        <t>
          Tier 4 and Tier 5 sessions use hybrid post-quantum key
          establishment by default, combining ML-KEM-768
          <xref target="FIPS203"/> with X25519 <xref target="RFC7748"/> via
          concatenation and HKDF-SHA256 extraction (see
          <xref target="hybrid-key-exchange"/>). The hybrid output remains
          secure as long as at least one of the two primitives does, which
          defeats both a future cryptographically relevant quantum computer
          (CRQC) running Shor's algorithm against X25519 and any currently
          unknown classical break of ML-KEM.
        </t>

        <t>
          The symmetric layer (ChaCha20-Poly1305 with 256-bit keys) is
          considered post-quantum secure: Grover's algorithm reduces the
          effective key strength to 128 bits, which remains computationally
          infeasible to brute-force. No change to the symmetric primitive is
          required and none is prescribed.
        </t>

        <t>
          Classical-only mode (<tt>kex-mode: classical-only</tt>) MAY be used
          by resource-constrained implementations (e.g. deeply embedded
          devices where the 1184-byte ML-KEM encapsulation key is infeasible
          over a low-bandwidth modem link) or for interoperability with
          legacy endpoints predating this draft. Classical-only mode MUST NOT
          be used for data requiring long-term confidentiality (conservatively,
          more than 10 years) due to store-now-decrypt-later attacks.
        </t>

        <t>
          Implementations MUST NOT negotiate classical-only mode when at
          least one endpoint signals the <tt>pq-mlkem768</tt> capability and
          local policy requires PQ for the session's intended use.
        </t>
      </section>

      <section anchor="kex-downgrade-protection">
        <name>KEX Mode Downgrade Protection</name>

        <t>
          Like tier negotiation (<xref target="tier-downgrade"/>), KEX-mode
          negotiation is vulnerable to active on-path downgrade attempts.
          An attacker could strip <tt>mlkem-public</tt> from SESSION_INIT or
          remove the <tt>pq-mlkem768</tt> capability to force classical-only.
          This draft binds the full handshake to the session key to make such
          modifications detectable.
        </t>

        <t>
          Specifically, both endpoints fold a transcript hash of the
          complete SESSION_INIT and SESSION_ACK byte sequences into the
          HKDF-SHA256 <tt>info</tt> parameter during session key derivation
          (see <xref target="hybrid-key-exchange"/>). Any modification of any
          handshake field by an intermediary causes the two endpoints to
          observe different transcript hashes, derive different session keys,
          and fail AEAD verification on the first Tier 3 or Tier 5 frame.
          The domain separator strings
          <tt>"myclerk-session-v1-hybrid"</tt> and
          <tt>"myclerk-session-v1-classical"</tt> additionally prevent a
          hybrid-derived key from being confused with a classical-derived key
          of the same inputs.
        </t>

        <t>
          Implementations MUST:
        </t>

        <ol>
          <li>Include the exact wire-form bytes of SESSION_INIT and
              SESSION_ACK in the transcript hash, in the order they were
              sent.</li>
          <li>Refuse to complete a session where the responder's selected
              KEX mode is weaker than the mode the initiator offered AND the
              local policy requires the stronger mode.</li>
          <li>Log classical-only negotiations for audit purposes so
              operators can detect systemic downgrade attempts.</li>
        </ol>
      </section>

      <section anchor="ml-kem-hazards">
        <name>ML-KEM Implementation Hazards</name>

        <t>
          ML-KEM-768 implementations MUST observe the following safety
          properties. These are standard Fujisaki-Okamoto precautions but
          are called out explicitly because ahistorical implementations have
          repeatedly failed at them.
        </t>

        <ol>
          <li><strong>Constant-time decapsulation.</strong> The decapsulation
              routine MUST run in time independent of the secret key and the
              ciphertext contents, to prevent timing side channels that can
              recover the private key over repeated queries.</li>
          <li><strong>Implicit rejection.</strong> On a ciphertext-validity
              failure, decapsulation MUST return a pseudo-random shared
              secret derived from the private key and the ciphertext (the
              Fujisaki-Okamoto transform's "implicit rejection" branch),
              NOT an error. Returning an error leaks ciphertext-validity
              information to the attacker.</li>
          <li><strong>Private-key hygiene.</strong> ML-KEM decapsulation
              private keys MUST be cleared from memory (e.g. via
              <tt>crypto/subtle.ConstantTimeCompare</tt>-adjacent zero-wipe
              helpers) once the session key has been derived and the
              ephemeral has no further use.</li>
        </ol>

        <t>
          Implementations SHOULD use a well-reviewed library rather than
          implementing ML-KEM from scratch. In the Go ecosystem the standard
          library <tt>crypto/mlkem</tt> package (available since Go 1.24)
          satisfies all three requirements and is the RECOMMENDED choice;
          the <tt>liboqs</tt> project, <tt>BoringSSL</tt>'s ML-KEM
          implementation, and <tt>libcrux</tt> are also suitable
          alternatives.
        </t>
      </section>

    </section>

    <!-- ============================================================ -->
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>

      <section anchor="iana-port">
        <name>Service Name and Port Number Registration</name>

        <t>
          IANA is requested to register the following service name and port
          number in the "Service Name and Transport Protocol Port Number
          Registry" <xref target="RFC6335"/>:
        </t>

        <dl>
          <dt>Service Name:</dt>
          <dd>myclerk</dd>

          <dt>Port Number:</dt>
          <dd>5657</dd>

          <dt>Transport Protocol(s):</dt>
          <dd>TCP, UDP</dd>

          <dt>Description:</dt>
          <dd>MyClerk Protocol</dd>

          <dt>Assignee:</dt>
          <dd>IESG &lt;iesg@ietf.org&gt;</dd>

          <dt>Contact:</dt>
          <dd>IETF Chair &lt;chair@ietf.org&gt;</dd>

          <dt>Reference:</dt>
          <dd>This document</dd>
        </dl>

        <t>
          TCP is the primary transport for control messages, synchronization,
          authentication, and VFS operations. UDP is used for real-time streaming
          (video, audio) and low-latency sensor telemetry where latency is
          prioritized over reliability.
        </t>
      </section>

      <section anchor="iana-opcodes">
        <name>Operation Code Registry</name>

        <t>
          IANA is requested to create a new registry titled "MyClerk Protocol
          Operation Codes" with the following structure:
        </t>

        <dl>
          <dt>Registration Procedure:</dt>
          <dd>Expert Review per <xref target="RFC8126"/></dd>

          <dt>Reference:</dt>
          <dd>This document</dd>
        </dl>

        <t>
          The initial entries are the operation codes defined in
          <xref target="operations"/> of this document, organized into the
          following ranges:
        </t>

        <table>
          <thead>
            <tr>
              <th>Range</th>
              <th>Category</th>
              <th>Reference</th>
            </tr>
          </thead>
          <tbody>
            <tr><td>0x0001-0x00FF</td><td>Core Operations</td><td>Section 4</td></tr>
            <tr><td>0x0100-0x01FF</td><td>Standard Operations (Device, Identity, Messaging)</td><td>Section 5</td></tr>
            <tr><td>0x0200-0x02FF</td><td>Resource Sharing (Streams, GPU, Routing)</td><td>Section 6</td></tr>
            <tr><td>0x0300-0x03FF</td><td>Federation</td><td>Section 6</td></tr>
            <tr><td>0x0400-0x04FF</td><td>Billing and Economics</td><td>Section 6</td></tr>
            <tr><td>0x0500-0x05FF</td><td>Virtual File System (VFS)</td><td>draft-myclerk-vfs</td></tr>
            <tr><td>0x0600-0x06FF</td><td>Hardware Passthrough (USB, GPIO, I2C, SPI, CAN)</td><td>Section 6</td></tr>
            <tr><td>0x0700-0x07FF</td><td>Knowledge Base</td><td>Section 6</td></tr>
            <tr><td>0x0800-0x08FF</td><td>Settings &amp; Configuration</td><td>Section 6</td></tr>
            <tr><td>0x0900-0x09FF</td><td>Room/Channel Management</td><td>Section 6</td></tr>
            <tr><td>0x0A00-0x0AFF</td><td>Media Handling</td><td>Section 6</td></tr>
            <tr><td>0x0B00-0x0BFF</td><td>Telephony (Voice, Video, SMS, IVR)</td><td>Section 6</td></tr>
            <tr><td>0x0C00-0x0CFF</td><td>Calendar &amp; Events</td><td>Section 6</td></tr>
            <tr><td>0x0D00-0x0DFF</td><td>Tasks, Shopping &amp; Gamification</td><td>Section 6</td></tr>
            <tr><td>0x0E00-0x0EFF</td><td>Smart Home Devices</td><td>Section 6</td></tr>
            <tr><td>0x0F00-0x0FFF</td><td>Automation Rules</td><td>Section 6</td></tr>
            <tr><td>0x1000-0x10FF</td><td>Maya AI Assistant</td><td>Section 6</td></tr>
            <tr><td>0x1100-0x11FF</td><td>Synchronization &amp; VFS Federation</td><td>Section 6</td></tr>
            <tr><td>0x1200-0x12FF</td><td>Orchestration (Notifications, Finance)</td><td>Section 6</td></tr>
            <tr><td>0x1300-0x13FF</td><td>Presence &amp; Status (Education)</td><td>Section 6</td></tr>
            <tr><td>0x1400-0x14FF</td><td>Health (Social, Community)</td><td>Section 6</td></tr>
            <tr><td>0x1500-0x15FF</td><td>Location &amp; Mobility</td><td>Section 6</td></tr>
            <tr><td>0x1600-0x16FF</td><td>Debug, Testing &amp; Plugins</td><td>Section 6</td></tr>
            <tr><td>0x1700-0x17FF</td><td>Mobile Device Management (MDM)</td><td>[MYCLERK-OPS]</td></tr>
            <tr><td>0x1800-0x18FF</td><td>Legal Documents &amp; Care Directives</td><td>[MYCLERK-OPS]</td></tr>
            <tr><td>0x1900-0x19FF</td><td>Mobility &amp; Vehicle Management</td><td>[MYCLERK-OPS]</td></tr>
            <tr><td>0x1A00-0x1AFF</td><td>Travel &amp; Vacation</td><td>[MYCLERK-OPS]</td></tr>
            <tr><td>0x1B00-0x1BFF</td><td>Audit &amp; Compliance</td><td>[MYCLERK-OPS]</td></tr>
            <tr><td>0x1C00-0x1CFF</td><td>Audio Pipeline</td><td>[MYCLERK-OPS]</td></tr>
            <tr><td>0x1D00-0x1DFF</td><td>Desktop Client</td><td>[MYCLERK-OPS]</td></tr>
            <tr><td>0x1E00-0xEFFF</td><td>Unassigned</td><td>This document</td></tr>
            <tr><td>0xF000-0xFFFE</td><td>Vendor Extensions (third-party/vendor-specific use only)</td><td>This document</td></tr>
            <tr><td>0xFFFF</td><td>Reserved</td><td>This document</td></tr>
          </tbody>
        </table>
      </section>
    </section>

  </middle>

  <back>

    <references>
      <name>References</name>

      <references>
        <name>Normative References</name>
        &RFC2119;
        &RFC5869;
        &RFC6335;
        &RFC7748;
        &RFC8126;
        &RFC8174;
        &RFC8439;
        &RFC8610;
        &RFC8949;

        <reference anchor="FIPS203" target="https://doi.org/10.6028/NIST.FIPS.203">
          <front>
            <title>Module-Lattice-Based Key-Encapsulation Mechanism Standard</title>
            <author>
              <organization>National Institute of Standards and Technology</organization>
            </author>
            <date month="August" year="2024"/>
          </front>
          <seriesInfo name="FIPS" value="203"/>
        </reference>
      </references>

      <references>
        <name>Informative References</name>
        <reference anchor="MYCLERK-OPS">
          <front>
            <title>MyClerk Protocol Application Operations Registry</title>
            <author fullname="Michael J. Arcan" initials="M.J." surname="Arcan">
              <organization>Arcan Consulting</organization>
            </author>
            <date year="2026"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-myclerk-protocol-ops-00"/>
        </reference>
      </references>

    </references>

    <section anchor="acknowledgements" numbered="false">
      <name>Acknowledgements</name>
      <t>
        This specification is part of the MyClerk project, a privacy-first
        family orchestration platform currently in development. For more
        information, visit https://myclerk.eu.
      </t>
    </section>

  </back>

</rfc>
