<?xml version="1.0" encoding="utf-8"?>
<?xml-model href="rfc7991bis.rnc"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>

<rfc category="std" 
     docName="draft-mututi-quip-00" 
     ipr="trust200902" 
     submissionType="IETF" 
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="QUIP">QUIC Identity Protocol</title>
    <seriesInfo name="Internet-Draft" value="draft-mututi-quip-00"/>
    
    <author fullname="Junior Joseph Mututi" 
            initials="J. J."
            surname="Mututi">
      <organization>Individual</organization>
      <address>
        <email>jjmututicloud@gmail.com</email>
      </address>
    </author>
    
    <date year="2026" month="May" day="12"/>
    
    <area>Security</area>
    <workgroup>dispatch</workgroup>
    
    <keyword>QUIC</keyword>
    <keyword>Identity</keyword>
    <keyword>Federation</keyword>
    <keyword>DANE</keyword>
    <keyword>Gossip</keyword>
    
    <abstract>
      <t>This document specifies QUIP (QUIC Identity Protocol), a federated application protocol providing portable cryptographic identity, verifiable server trust, deterministic state synchronization, and built-in accountability. QUIP runs over QUIC (RFC 9000) and uses a strict deterministic CBOR profile (QUIP-CBOR). Three conformance profiles are defined: Basic (messaging), Documents (content addressing), and Media (real-time transport). The protocol enables users to own a portable NodeId independent of service providers, servers to authenticate via DANE+DNSSEC with deployable fallback modes, and peers to detect and throttle misbehavior through signed violation receipts propagated via gossip.</t>
    </abstract>
  </front>

  <middle>
    <section anchor="intro" numbered="true" toc="default">
      <name>Introduction</name>
      <t>QUIP defines a federation-native protocol that ensures:</t>
      <ul>
        <li>Portable identity independent of domain providers</li>
        <li>Verifiable server authenticity without reliance solely on certification authorities</li>
        <li>Deterministic global state convergence</li>
        <li>Cryptographic accountability for misbehavior</li>
      </ul>
      <t>QUIP operates directly over QUIC <xref target="RFC9000"/> and eliminates reliance on HTTP-based federation layers.</t>
      
      <section anchor="minimal_example" numbered="true" toc="default">
        <name>Minimal Working Example</name>
        <t>The following example demonstrates a complete QUIP flow:</t>
        <artwork><![CDATA[
Alice (NodeId A) → a.com → b.com → Bob (NodeId B)

1. Identity Setup
   • a.com issues primary attestation binding user@a.com to NodeId A
   • Requires subject signature (proof of possession)

2. Sending a Message
   • Alice signs message with private key A
   • a.com forwards to b.com over QUIC + DANE
   • b.com verifies signature + attestation + policies
   • Bob receives message

3. Accountability
   • If a.com misbehaves, b.com creates signed violation receipt
   • Receipt gossips to federation
   • Automatic throttling after independent witness threshold
]]></artwork>
      </section>
      
      <section anchor="non_goals" numbered="true" toc="default">
        <name>Non-Goals</name>
        <t>QUIP does NOT guarantee:</t>
        <ul>
          <li><em>Anonymity</em> (use Tor or similar) — a design choice</li>
          <li><em>Metadata confidentiality</em> — connection patterns are observable</li>
          <li><em>Resistance to global passive adversaries</em> — traffic analysis remains possible</li>
          <li><em>Byzantine consensus</em> — deterministic merge is not Byzantine fault tolerant</li>
          <li><em>Economic Sybil resistance</em> — independent witness definition provides operational heuristic only</li>
          <li><em>Witness collusion resistance</em> — a federation with &gt;=3 colluding witnesses can falsely attest violations; deployments must rely on legal/commercial incentives</li>
        </ul>
        <t><em>Note on categorization:</em> The items above mix design choices (anonymity, metadata confidentiality) with explicit security limitations (collusion resistance, Byzantine consensus). All are intentional non-goals of the protocol.</t>
      </section>
    </section>

    <section anchor="terminology" numbered="true" toc="default">
      <name>Terminology</name>
      <t>The key words <bcp14>MUST</bcp14>, <bcp14>MUST NOT</bcp14>, <bcp14>REQUIRED</bcp14>, <bcp14>SHALL</bcp14>, <bcp14>SHALL NOT</bcp14>, <bcp14>SHOULD</bcp14>, <bcp14>SHOULD NOT</bcp14>, <bcp14>RECOMMENDED</bcp14>, <bcp14>NOT RECOMMENDED</bcp14>, <bcp14>MAY</bcp14>, and <bcp14>OPTIONAL</bcp14> 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>
      
      <dl>
        <dt><tt>NodeId</tt></dt><dd>32-byte Ed25519 public key (raw bytes)</dd>
        <dt><tt>Genesis NodeId</tt></dt><dd>Root identity in a rotation chain; the oldest known NodeId</dd>
        <dt><tt>Attestation</tt></dt><dd>Signed CBOR object binding identity claims</dd>
        <dt><tt>Primary attestation</tt></dt><dd>Attestation binding a specific <tt>user@domain</tt> address to a NodeId</dd>
        <dt><tt>Vector clock</tt></dt><dd>Map of issuer → counter, used for causality tracking</dd>
        <dt><tt>Gossip</tt></dt><dd>Propagation mechanism for state updates</dd>
        <dt><tt>Violation receipt</tt></dt><dd>Signed proof of protocol violation</dd>
        <dt><tt>Profile</tt></dt><dd>Conformance level (Basic, Documents, Media)</dd>
      </dl>
    </section>

    <section anchor="protocol_states" numbered="true" toc="default">
      <name>Protocol States</name>
      
      <section anchor="state_definitions" numbered="true" toc="default">
        <name>State Definitions</name>
        <t>QUIP connections <bcp14>SHALL</bcp14> be in one of the following states:</t>
        
        <dl>
          <dt><tt>INIT</tt></dt><dd>Initial state before discovery. No messages sent.</dd>
          <dt><tt>DISCOVERING</tt></dt><dd>Performing DNS discovery. <bcp14>MAY</bcp14> send DNS queries.</dd>
          <dt><tt>CONNECTING</tt></dt><dd>Establishing QUIC connection. <bcp14>MAY</bcp14> send QUIC handshake.</dd>
          <dt><tt>HANDSHAKING</tt></dt><dd>Exchanging QUIP handshake. Control stream active; no application streams.</dd>
          <dt><tt>SYNCING</tt></dt><dd>Synchronizing gossip state. Accept gossip; <bcp14>MAY</bcp14> defer message delivery.</dd>
          <dt><tt>ACTIVE</tt></dt><dd>Normal operation. All streams fully functional.</dd>
          <dt><tt>DEGRADED</tt></dt><dd>Operating with reduced capabilities. Rate limits increased; new streams discouraged.</dd>
          <dt><tt>REVOKED</tt></dt><dd>Identity or peer revoked. No messages accepted or sent.</dd>
          <dt><tt>CLOSED</tt></dt><dd>Connection terminated. No further state transitions.</dd>
        </dl>
      </section>
      
      <section anchor="state_transitions" numbered="true" toc="default">
        <name>State Transitions</name>
        <t>The following transitions are normative:</t>
        
        <table align="center">
          <thead>
            <tr><th>From</th><th>To</th><th>Trigger</th><th>Required Action</th></tr>
          </thead>
          <tbody>
            <tr><td>INIT</td><td>DISCOVERING</td><td>Application requests connection</td><td>Perform DNS SRV/TXT lookup</td></tr>
            <tr><td>DISCOVERING</td><td>CONNECTING</td><td>DNS resolution succeeds</td><td>Initiate QUIC handshake</td></tr>
            <tr><td>CONNECTING</td><td>HANDSHAKING</td><td>QUIC connection established</td><td>Send QUIP handshake on stream 0</td></tr>
            <tr><td>HANDSHAKING</td><td>SYNCING</td><td>Handshake complete, profiles compatible</td><td>Begin gossip sync on stream 1</td></tr>
            <tr><td>HANDSHAKING</td><td>CLOSED</td><td>Profile mismatch or handshake error</td><td>Send error, close connection</td></tr>
            <tr><td>SYNCING</td><td>ACTIVE</td><td>Initial sync complete</td><td>Normal operation begins</td></tr>
            <tr><td>SYNCING</td><td>CLOSED</td><td>Sync timeout or unrecoverable error</td><td>Send error, close connection</td></tr>
            <tr><td>ACTIVE</td><td>DEGRADED</td><td>Resource exhaustion or policy violation</td><td>Reduce functionality</td></tr>
            <tr><td>ACTIVE</td><td>REVOKED</td><td>Receipt of valid revocation attesting this peer</td><td>Terminate all active streams</td></tr>
            <tr><td>ACTIVE</td><td>CLOSED</td><td>Connection loss or explicit close</td><td>Clean up state</td></tr>
            <tr><td>REVOKED</td><td>CLOSED</td><td>Any</td><td>Final cleanup</td></tr>
            <tr><td>DEGRADED</td><td>ACTIVE</td><td>Resource recovery</td><td>Resume normal operation</td></tr>
          </tbody>
        </table>
        
        <t>State transitions not listed above are not permitted and <bcp14>MUST</bcp14> cause a connection error (<xref target="error_codes_registry"/> code 17: PROTOCOL_VIOLATION).</t>
      </section>
      
      <section anchor="protocol_invariants" numbered="true" toc="default">
        <name>Protocol Invariants</name>
        <t>Implementations <bcp14>MUST</bcp14> enforce:</t>
        <ol>
          <li><em>Determinism</em>: All state transitions (<xref target="gossip_consistency"/>) <bcp14>MUST</bcp14> produce identical results across peers</li>
          <li><em>Signature Coverage</em>: All externally visible objects <bcp14>MUST</bcp14> be signed with domain separation (<xref target="signature_computation"/>)</li>
          <li><em>Identity Continuity</em>: Identity <bcp14>MUST</bcp14> be traceable to a genesis NodeId through a verifiable rotation chain</li>
          <li><em>Canonical Encoding</em>: All serialized data <bcp14>MUST</bcp14> use QUIP-CBOR (<xref target="quip_cbor_profile"/>)</li>
          <li><em>No Duplicate Keys</em>: CBOR maps <bcp14>MUST NOT</bcp14> contain duplicate keys</li>
          <li><em>No Indefinite Lengths</em>: Indefinite-length byte strings and text strings are PROHIBITED</li>
        </ol>
      </section>
    </section>

    <section anchor="architecture" numbered="true" toc="default">
      <name>Architecture Overview</name>
      <t>Layered model (bottom to top):</t>
      <ol>
        <li>QUIC transport (TLS 1.3) — encryption, multiplexing, congestion control</li>
        <li>Identity and attestation layer — NodeIds, bindings, trust models</li>
        <li>Deterministic state machine — canonical CBOR, vector clocks, gossip</li>
        <li>Profile layer — Basic / Documents / Media feature activation</li>
        <li>Application layer — messaging, media, B2B, documents</li>
      </ol>
    </section>

    <section anchor="identity_model" numbered="true" toc="default">
      <name>Identity Model</name>
      
      <section anchor="nodeid" numbered="true" toc="default">
        <name>NodeId</name>
        <t>Every user has a NodeId — an Ed25519 public key (32 bytes). The corresponding private key is never disclosed to any domain or third party. NodeIds are encoded as raw byte strings in CBOR.</t>
      </section>
      
      <section anchor="attestations" numbered="true" toc="default">
        <name>Attestations</name>
        <t>All attestations are signed CBOR objects.</t>
        
        <section anchor="subject_signature" numbered="true" toc="default">
          <name>Subject Signature Computation</name>
          <t>The subject signs the following QUIP-CBOR array:</t>
          <artwork><![CDATA[
[
  "QUIP-ATTESTATION-SUBJECT-V1",
  type,                    ; string
  subject,                 ; NodeId or address
  issuer,                  ; domain or NodeId
  [notBefore, notAfter]    ; Unix timestamps (seconds)
]
]]></artwork>
        </section>
        
        <section anchor="issuer_signature" numbered="true" toc="default">
          <name>Issuer Signature Computation</name>
          <t>The issuer signs the following QUIP-CBOR array:</t>
          <artwork><![CDATA[
[
  "QUIP-ATTESTATION-ISSUER-V1",
  type,
  subject,
  issuer,
  [notBefore, notAfter],
  subject_signature        ; 64 bytes
]
]]></artwork>
          <t>The complete attestation on the wire is:</t>
          <artwork><![CDATA[
tagged(65536, [
  "primary_binding",       ; discriminator
  type,
  subject,
  issuer,
  [notBefore, notAfter],
  subject_signature,
  issuer_signature
])
]]></artwork>
        </section>
      </section>
      
      <section anchor="key_rotation" numbered="true" toc="default">
        <name>Key Rotation</name>
        <artwork><![CDATA[
tagged(65536, [
  "key_rotation",
  old_NodeId,              ; 32 bytes
  new_NodeId,              ; 32 bytes
  timestamp,               ; Unix milliseconds (int64)
  signature                ; 64 bytes
])
]]></artwork>
        
        <t>Signature computation:</t>
        <artwork><![CDATA[
signature = Ed25519_sign(
  old_private_key,
  "QUIP-ROTATION-V1" || QUIP-CBOR([
    "key_rotation",
    old_NodeId,
    new_NodeId,
    timestamp
  ])
)
]]></artwork>
        
        <t>Rotation validation rules: Receivers <bcp14>MUST</bcp14> reject:</t>
        <ul>
          <li>Cyclic chains (NodeId appears twice)</li>
          <li>Duplicate NodeIds in the same chain</li>
          <li>Chains with non-monotonic timestamps (timestamps must increase)</li>
          <li>Multiple successors from the same NodeId unless the previous successor is revoked</li>
          <li>Rotations where the old key is already revoked</li>
          <li>Chains exceeding maximum depth of 32 (configurable)</li>
        </ul>
      </section>
      
      <section anchor="genesis_discovery" numbered="true" toc="default">
        <name>Genesis Discovery</name>
        <t>The Genesis NodeId is the oldest known NodeId in a rotation chain.</t>
        <t>First message rule: If a receiver encounters a NodeId with no prior state, and the message is signed by a key that is not clearly the genesis, the sender <bcp14>MUST</bcp14> include the full rotation chain. Failure results in error <tt>KEY_ROTATION_CHAIN_MISSING</tt> (<xref target="error_codes_registry"/> code 15).</t>
      </section>
      
      <section anchor="identity_trust_modes" numbered="true" toc="default">
        <name>Identity Trust Modes</name>
        <t>The <tt>identity_trust_mode</tt> bitmask is defined as:</t>
        
        <table align="center">
          <thead>
            <tr><th>Bit</th><th>Name</th><th>Description</th></tr>
          </thead>
          <tbody>
            <tr><td>0</td><td>SIMPLE</td><td>Accept primary attestations from any domain</td></tr>
            <tr><td>1</td><td>VERIFIED</td><td>Require attestations from certified providers (<xref target="verified_mode_pki"/>)</td></tr>
            <tr><td>2-15</td><td>Reserved</td><td>Reserved for future use</td></tr>
          </tbody>
        </table>
        
        <t>Negotiation: The effective trust mode is the bitwise AND of local and remote modes. If the result has no bits set, the connection proceeds with the lowest common mode (SIMPLE) and <bcp14>MUST</bcp14> log a warning.</t>
        <t>Downgrade behavior: VERIFIED mode <bcp14>MUST NOT</bcp14> downgrade to SIMPLE without explicit operator configuration. Any downgrade <bcp14>MUST</bcp14> be logged.</t>
      </section>
    </section>

    <section anchor="trust_model" numbered="true" toc="default">
      <name>Trust Model</name>
      
      <section anchor="server_authentication_modes" numbered="true" toc="default">
        <name>Server Authentication Modes</name>
        
        <table align="center">
          <thead>
            <tr><th>Mode</th><th>Requirement</th><th>Use Case</th></tr>
          </thead>
          <tbody>
            <tr><td>COMPAT (default)</td><td>Web PKI + <bcp14>SHOULD</bcp14> use DANE if available</td><td>General deployment</td></tr>
            <tr><td>STRICT (optional)</td><td>DNSSEC + DANE <bcp14>REQUIRED</bcp14></td><td>High-security environments</td></tr>
            <tr><td>LEGACY (deprecated)</td><td>Web PKI only</td><td>Legacy transition</td></tr>
          </tbody>
        </table>
      </section>
      
      <section anchor="independent_witness" numbered="true" toc="default">
        <name>Independent Witness Definition</name>
        <t>A witness domain qualifies as independent for violation receipt validation if ALL conditions hold:</t>
        <ol>
          <li>Distinct DNSSEC-signed domain (<xref target="RFC4033"/>, <xref target="RFC4034"/>, <xref target="RFC4035"/>)</li>
          <li>Distinct TLSA record <xref target="RFC6698"/></li>
          <li>Distinct /24 IPv4 or /48 IPv6 prefix</li>
        </ol>
        <t>Additional weighting (<bcp14>SHOULD</bcp14>): Implementations <bcp14>SHOULD</bcp14> also consider distinct ASN (Autonomous System Number), distinct DNSSEC KSK (Key Signing Key), historical trust scoring based on past witness accuracy, and observed federation longevity (minimum 30 days active).</t>
      </section>
      
      <section anchor="dns_downgrade_protection" numbered="true" toc="default">
        <name>DNS Downgrade Protection</name>
        <t>After TLS handshake completion, the client <bcp14>MUST</bcp14> verify that the server's presented certificate and DANE TLSA record (if applicable) are consistent with the TXT capabilities advertisement from DNS. Inconsistencies <bcp14>MUST</bcp14> be logged and, in STRICT mode, cause connection termination.</t>
      </section>
      
      <section anchor="handshake_transcript_binding" numbered="true" toc="default">
        <name>Handshake Transcript Binding</name>
        <t>The QUIP handshake <bcp14>MUST</bcp14> be cryptographically bound to the QUIC TLS session using the TLS exporter interface <xref target="RFC8446"/>, Section 7.5.</t>
        
        <t>Transcript canonicalization:</t>
        <t>The client and server handshake payloads are embedded as CBOR byte strings containing the exact transmitted bytes:</t>
        <artwork><![CDATA[
[
  h'<raw client handshake bytes>',
  h'<raw server handshake bytes>'
]
]]></artwork>
        
        <t>Sequence of operations:</t>
        <ol>
          <li>TLS handshake completes (both peers have established session keys)</li>
          <li>QUIP handshake bytes are transmitted on stream 0 (client first, then server)</li>
          <li>Both peers buffer the exact bytes they send and receive (no re-encoding)</li>
          <li>After both handshake messages have been exchanged, each peer computes:</li>
        </ol>
        <artwork><![CDATA[
binding = TLS-Exporter("EXPORTER-QUIP-BINDING",
    SHA-256(QUIP-CBOR(handshake_array)), 32)
]]></artwork>
        <ol start="5">
          <li>Because both peers use the same TLS session and the same canonicalized handshake array, they derive <em>identical binding values</em> locally</li>
          <li>The binding is used as a local consistency check: each peer can verify that the handshake parameters it is using are consistent with the binding it computed</li>
          <li>No binding value is ever transmitted</li>
        </ol>
      </section>
      
      <section anchor="verified_mode_governance" numbered="true" toc="default">
        <name>Verified Mode Governance</name>
        <t>Governance and policy requirements for VERIFIED mode (trust anchor authorization, provider certification criteria, dispute resolution, and antitrust/competition safeguards) are deployment-specific and outside the scope of this document. Implementations in VERIFIED mode <bcp14>MUST</bcp14> rely on local policy to define acceptable trust anchors and certification authorities.</t>
      </section>
    </section>

    <section anchor="verified_mode_pki" numbered="true" toc="default">
      <name>Verified Mode PKI</name>
      
      <section anchor="trust_anchor_format" numbered="true" toc="default">
        <name>Trust Anchor Format</name>
        <t>Trust anchors are distributed as signed CBOR objects:</t>
        <artwork><![CDATA[
tagged(65536, [
  "trust_anchor",
  anchor_id,               ; string (e.g., "quip-root-v1")
  public_key,              ; 32 bytes (Ed25519)
  valid_from,              ; Unix timestamp (seconds)
  valid_until,             ; Unix timestamp (seconds)
  distribution_point,      ; string URI
  signature                ; 64 bytes (self-signed or cross-signed)
])
]]></artwork>
      </section>
      
      <section anchor="trust_anchor_distribution" numbered="true" toc="default">
        <name>Trust Anchor Distribution</name>
        <t>Trust anchors are distributed via:</t>
        <ol>
          <li><em>Hardcoded</em> — Implementations <bcp14>MAY</bcp14> ship with a set of trusted roots</li>
          <li><em>DNS-based</em> — <tt>_quip._trust.root.domain</tt> TXT records containing anchor hashes</li>
          <li><em>Transparency log</em> — Optional certificate transparency-style log</li>
        </ol>
      </section>
      
      <section anchor="attestation_provider_certificate" numbered="true" toc="default">
        <name>Attestation Provider Certificate</name>
        <artwork><![CDATA[
tagged(65536, [
  "attestation_provider",
  provider_NodeId,         ; 32 bytes
  domain,                  ; string
  issuer,                  ; NodeId or anchor_id of issuer
  issued_at,               ; Unix timestamp (seconds)
  expires_at,              ; Unix timestamp (seconds, max 90 days)
  capabilities,            ; array of strings
  signature                ; 64 bytes (by issuer)
])
]]></artwork>
      </section>
      
      <section anchor="certificate_path_validation" numbered="true" toc="default">
        <name>Certificate Path Validation</name>
        <t>When receiving a provider certificate chain, peers <bcp14>MUST</bcp14> perform the following validation:</t>
        
        <t>Path building order:</t>
        <ol>
          <li>Start from the end-entity (provider) certificate</li>
          <li>Chain to issuer using <tt>issuer</tt> field (NodeId or anchor_id)</li>
          <li>Continue until reaching a known trust anchor</li>
          <li>Maximum chain depth: 8</li>
        </ol>
        
        <t>Trust anchor matching: Trust anchors are identified by <tt>anchor_id</tt> string. Implementations <bcp14>MUST</bcp14> support exact string matching. Wildcard matching is NOT permitted.</t>
        
        <t>Signature validation: All signatures <bcp14>MUST</bcp14> use Ed25519 <xref target="RFC8032"/>. Future versions may negotiate additional algorithms.</t>
        
        <t>Expiry precedence: Certificates with <tt>expires_at</tt> in the past <bcp14>MUST</bcp14> be rejected. Trust anchors with <tt>valid_until</tt> in the past <bcp14>SHOULD</bcp14> be rejected (grace window of 24 hours permitted for rollover).</t>
        
        <t>Rollover handling: Trust anchors <bcp14>SHOULD</bcp14> have overlapping validity windows during rollover. During overlap, either anchor is considered valid. After old anchor expires, it <bcp14>MUST NOT</bcp14> be accepted.</t>
        
        <t>Cross-signing: Cross-signed certificates are permitted if they chain to a trust anchor. Maximum chain depth applies to the merged path.</t>
        
        <t>Revocation check: Before accepting a certificate, check revocation status per <xref target="provider_revocation_freshness"/>. Revoked certificates <bcp14>MUST</bcp14> be rejected regardless of validity period.</t>
      </section>
      
      <section anchor="provider_revocation_freshness" numbered="true" toc="default">
        <name>Provider Revocation Freshness</name>
        <t>Peers <bcp14>MUST</bcp14> enforce freshness limits on provider revocation lists:</t>
        
        <table align="center">
          <thead>
            <tr><th>Condition</th><th>Behavior</th></tr>
          </thead>
          <tbody>
            <tr><td>Revocation list age &lt; 24 hours</td><td>Normal operation</td></tr>
            <tr><td>Revocation list age 24-72 hours</td><td>DEGRADED mode, log warning</td></tr>
            <tr><td>Revocation list age &gt; 72 hours</td><td>VERIFIED mode <bcp14>MUST</bcp14> fail closed; reject all VERIFIED-mode attestations</td></tr>
          </tbody>
        </table>
      </section>
      
      <section anchor="dns_trust_anchor_bootstrapping" numbered="true" toc="default">
        <name>DNS Trust Anchor Bootstrapping</name>
        <t>DNS-distributed trust anchors are advisory until chained to an existing trusted anchor or implementation trust store. Implementations <bcp14>MUST</bcp14> validate the DNSSEC chain for any DNS-discovered anchor. The first anchor in a deployment <bcp14>MAY</bcp14> be installed out-of-band (e.g., via package management, configuration file, or hardcoding). Once an anchor is trusted, it may be used to validate subsequent anchor updates.</t>
      </section>
    </section>

    <section anchor="transport" numbered="true" toc="default">
      <name>Transport</name>
      
      <section anchor="connection_establishment" numbered="true" toc="default">
        <name>Connection Establishment</name>
        <t>QUIC connection with ALPN <tt>"quip"</tt>. The first client-initiated bidirectional stream opened after QUIC connection establishment (stream ID 0) is designated the <em>QUIP Control Stream</em>. The second client-initiated bidirectional stream (stream ID 4) is designated the <em>QUIP Gossip Stream</em>.</t>
        
        <table align="center">
          <thead>
            <tr><th>Logical Role</th><th>Stream Type</th><th>Stream ID (Client)</th><th>Stream ID (Server)</th></tr>
          </thead>
          <tbody>
            <tr><td>Control stream</td><td>Client bidirectional</td><td>0</td><td>1</td></tr>
            <tr><td>Gossip stream</td><td>Client bidirectional</td><td>4</td><td>5</td></tr>
            <tr><td>Application streams</td><td>Client bidirectional</td><td>8, 12, ...</td><td>9, 13, ...</td></tr>
          </tbody>
        </table>
        
        <t>All control messages (errors, rate advisories) are sent as CBOR arrays on the Control Stream.</t>
        
        <t>Handshake sequencing: No application streams (streams other than the Control and Gossip streams) <bcp14>SHALL</bcp14> be processed until the QUIP handshake completes and transcript binding verification succeeds. The Control Stream and Gossip Stream <bcp14>MAY</bcp14> be used during handshake.</t>
        
        <t>Phase 0: DNS Discovery</t>
        <t>Query <tt>_quip._udp.domain.example</tt> SRV and TXT:</t>
        <artwork><![CDATA[
_quip._udp.domain.example. TXT
    "v=2; profiles=basic,documents; trust=compat; quic=:443"
]]></artwork>
        
        <t>Phase 1: QUIP Handshake (Control Stream)</t>
        <t>Client sends:</t>
        <artwork><![CDATA[
[
  2,                    ; version
  0b111,                ; profiles bitmask
  "compat",             ; server_trust_mode
  0b01,                 ; identity_trust_mode (VERIFIED)
  {                     ; capabilities
    0: true,            ; datagram_support
    1: ["opus", "vp9"], ; media_codecs
    2: 4096             ; max_message_size
  },
  ["revocations/#"],    ; subscriptions
  {                     ; vector_clocks
    "revocation_list": {"a.com": 42}
  }
]
]]></artwork>
        <t>Server responds with identical structure.</t>
        <t>Both peers compute <tt>active_profiles = local.profiles &amp; remote.profiles</tt>. If zero, send error (<xref target="error_messages"/>) and close.</t>
      </section>
      
      <section anchor="wire_format" numbered="true" toc="default">
        <name>Wire Format</name>
        <artwork><![CDATA[
+------------------+----------------------------------+
| varint length    | QUIP-CBOR object                 |
+------------------+----------------------------------+
]]></artwork>
        <t>The CBOR object <bcp14>MUST</bcp14> be a single complete top-level item with no trailing bytes.</t>
      </section>
      
      <section anchor="stream_semantics" numbered="true" toc="default">
        <name>Stream Semantics</name>
        <table align="center">
          <thead>
            <tr><th>Logical Role</th><th>Direction</th><th>Reliability</th><th>Ordering</th></tr>
          </thead>
          <tbody>
            <tr><td>Control</td><td>Bidirectional</td><td>Reliable</td><td>Strict</td></tr>
            <tr><td>Gossip</td><td>Bidirectional</td><td>Reliable</td><td>Strict</td></tr>
            <tr><td>Application</td><td>Profile-dependent</td><td>Mixed</td><td>Mixed</td></tr>
          </tbody>
        </table>
      </section>
      
      <section anchor="bootstrap_discovery" numbered="true" toc="default">
        <name>Bootstrap Discovery</name>
        <t>Priority order:</t>
        <ol>
          <li>DNS SRV + TXT (<bcp14>MUST</bcp14>)</li>
          <li>QUIC Well-Known: <tt>["WELL_KNOWN", "/peer"]</tt> on Control Stream (<bcp14>MUST</bcp14>)</li>
          <li>Cached endpoints (<bcp14>SHOULD</bcp14>)</li>
          <li>HTTPS fallback (<bcp14>OPTIONAL</bcp14>, DEPRECATED)</li>
        </ol>
        
        <t>The full bootstrap handshake (<tt>GOSSIP_BOOTSTRAP</tt> exchange) is defined in <xref target="gossip_consistency"/>.</t>
      </section>
    </section>

    <section anchor="message_envelope" numbered="true" toc="default">
      <name>Message Envelope</name>
      
      <section anchor="envelope_structure" numbered="true" toc="default">
        <name>Envelope Structure</name>
        <t>The signed payload is a CBOR array, not a map:</t>
        <artwork><![CDATA[
[
  "message",
  payload,              ; application CBOR
  NodeId,               ; 32 bytes
  sequence,             ; 64-bit uint (max 2^62-1)
  timestamp,            ; 64-bit Unix milliseconds
  message_id            ; 32 bytes (SHA-256)
]
]]></artwork>
        <t>The wire representation is:</t>
        <artwork><![CDATA[
tagged(65536, [
  "message",
  payload,
  NodeId,
  sequence,
  timestamp,
  message_id,
  signature            ; 64 bytes
])
]]></artwork>
      </section>
      
      <section anchor="signature_computation" numbered="true" toc="default">
        <name>Signature Computation (Domain Separation)</name>
        <t>All signatures in QUIP use standard Ed25519 <xref target="RFC8032"/> without pre-hashing, with explicit domain separation strings prepended to the message.</t>
        <artwork><![CDATA[
signature = Ed25519_sign(
  private_key,
  domain_separator || QUIP-CBOR(signed_payload_array)
)
]]></artwork>
        
        <table align="center">
          <thead>
            <tr><th>Object Type</th><th>Domain Separator (UTF-8)</th></tr>
          </thead>
          <tbody>
            <tr><td>Message envelope</td><td><tt>"QUIP-MESSAGE-V1"</tt></td></tr>
            <tr><td>Gossip message</td><td><tt>"QUIP-GOSSIP-V1"</tt></td></tr>
            <tr><td>Key rotation</td><td><tt>"QUIP-ROTATION-V1"</tt></td></tr>
            <tr><td>Attestation (subject)</td><td><tt>"QUIP-ATTESTATION-SUBJECT-V1"</tt></td></tr>
            <tr><td>Attestation (issuer)</td><td><tt>"QUIP-ATTESTATION-ISSUER-V1"</tt></td></tr>
            <tr><td>Violation receipt</td><td><tt>"QUIP-VIOLATION-V1"</tt></td></tr>
          </tbody>
        </table>
      </section>
      
      <section anchor="error_messages" numbered="true" toc="default">
        <name>Error Messages</name>
        <t>Errors are sent as CBOR arrays on the Control Stream:</t>
        <artwork><![CDATA[
["ERROR", error_code, message_id, error_text]
]]></artwork>
        <t>Where <tt>error_code</tt> is a uint (<xref target="error_codes_registry"/>), <tt>message_id</tt> is 32 bytes (may be null for handshake errors), and <tt>error_text</tt> is a human-readable string.</t>
      </section>
      
      <section anchor="rate_advisory_messages" numbered="true" toc="default">
        <name>Rate Advisory Messages</name>
        <t>Rate advisories are sent as CBOR arrays on the Control Stream:</t>
        <artwork><![CDATA[
["RATE_ADVISORY", limit_type, current_rate, allowed_rate]
]]></artwork>
        <t>The <tt>limit_type</tt> field is a string matching the resource type being rate-limited (e.g., <tt>"message"</tt>, <tt>"gossip"</tt>, <tt>"datagram"</tt>).</t>
      </section>
      
      <section anchor="sequence_validation" numbered="true" toc="default">
        <name>Sequence Validation Rules</name>
        <t>Sequence numbers are scoped to <tt>(genesis_NodeId, discriminator)</tt> where discriminator is the string from the signed payload array (e.g., <tt>"message"</tt>, <tt>"document"</tt>, <tt>"gossip"</tt>).</t>
        
        <t>Rules:</t>
        <ul>
          <li>Sequence numbers <bcp14>MUST</bcp14> be strictly increasing per scope</li>
          <li>Gaps <bcp14>MAY</bcp14> be buffered up to a limit of 256 missing entries</li>
          <li>Out-of-order delivery is permitted, but sequence validation applies on receive</li>
          <li>Duplicates with the same <tt>message_id</tt> are rejected</li>
          <li>Retransmissions <bcp14>MUST</bcp14> reuse the identical <tt>message_id</tt></li>
        </ul>
      </section>
      
      <section anchor="message_id_construction" numbered="true" toc="default">
        <name>Message ID Construction</name>
        <artwork><![CDATA[
message_id = SHA-256("QUIP-MESSAGE-ID-V1" || QUIP-CBOR([
  genesis_NodeId,
  NodeId,
  discriminator,
  sequence,
  timestamp
]))
]]></artwork>
      </section>
      
      <section anchor="timestamp_validation" numbered="true" toc="default">
        <name>Timestamp Validation</name>
        <t>Timestamps are advisory only. Sequence numbers dominate ordering.</t>
        <ul>
          <li><em>Soft window (MUST accept):</em> ±300,000 ms (5 minutes)</li>
          <li><em>Hard window (MAY accept):</em> ±3,600,000 ms (1 hour) with warning</li>
          <li><em>Outside hard window:</em> MUST reject</li>
        </ul>
        <t>Implementations <bcp14>MUST NOT</bcp14> use timestamps for causality determination.</t>
      </section>
    </section>

    <section anchor="gossip_consistency" numbered="true" toc="default">
      <name>Gossip and Consistency</name>
      
      <section anchor="vector_clocks" numbered="true" toc="default">
        <name>Vector Clocks</name>
        <t>Map from issuer → counter.</t>
        <t>Issuer canonical forms: Domain: text string (major type 3). NodeId: byte string, 32 bytes (major type 2). Mixed representations for the same issuer are PROHIBITED.</t>
        <t>Maximum vector clock entries: 1024. Entries beyond this limit <bcp14>SHOULD</bcp14> be pruned (oldest issuers first).</t>
      </section>
      
      <section anchor="gossip_message_format" numbered="true" toc="default">
        <name>Gossip Message Format</name>
        <t>The signed payload is a CBOR array:</t>
        <artwork><![CDATA[
[
  "gossip",
  resource_type,         ; "attestations" | "revocations" | "violations"
  resource_id,           ; string or bytes
  vector_clock,          ; map {issuer: counter}
  payload,               ; signed resource object
  ttl,                   ; uint (3-7)
  sender_NodeId          ; 32 bytes
]
]]></artwork>
        
        <t>The wire representation is:</t>
        <artwork><![CDATA[
tagged(65536, [
  "gossip",
  resource_type,
  resource_id,
  vector_clock,
  payload,
  ttl,
  sender_NodeId,
  signature
])
]]></artwork>
      </section>
      
      <section anchor="resource_authority_model" numbered="true" toc="default">
        <name>Resource Authority Model</name>
        <table align="center">
          <thead>
            <tr><th>Resource Type</th><th>Authoritative Issuer</th><th>Mutability</th></tr>
          </thead>
          <tbody>
            <tr><td><tt>attestations</tt></td><td>Attestation issuer</td><td>Immutable after issuance</td></tr>
            <tr><td><tt>revocations</tt></td><td>Revocation issuer</td><td>Monotonic (add-only)</td></tr>
            <tr><td><tt>violations</tt></td><td>Witness peer</td><td>Immutable</td></tr>
          </tbody>
        </table>
      </section>
      
      <section anchor="anti_entropy_protocol" numbered="true" toc="default">
        <name>Anti-Entropy Protocol</name>
        <t>SYNC request:</t>
        <artwork><![CDATA[
["SYNC", resource_type, resource_id, their_clock]
]]></artwork>
        
        <t>SYNC response:</t>
        <artwork><![CDATA[
{
  "clock": merged_clock,
  "deltas": [payload1, payload2, ...],
  "next_token": continuation_token,  ; optional
  "complete": true|false
}
]]></artwork>
      </section>
      
      <section anchor="conflict_resolution" numbered="true" toc="default">
        <name>Conflict Resolution</name>
        <t>When updates are concurrent (neither vector clock dominates the other), the deterministic merge order is:</t>
        <ol>
          <li><em>Causal check:</em> If one clock has all issuers with counters &gt;= the other clock, that clock wins (causal dominance)</li>
          <li><em>If concurrent:</em> Lexicographic comparison of sorted <tt>(issuer, counter)</tt> tuples as QUIP-CBOR</li>
          <li><em>If equal:</em> Higher NodeId (bytewise) of the signer of the update payload</li>
          <li><em>If equal:</em> Smaller SHA-256 of the update payload</li>
        </ol>
      </section>
      
      <section anchor="gossip_ttl" numbered="true" toc="default">
        <name>Gossip TTL</name>
        <ul>
          <li>Default: 5</li>
          <li>Range: 3-7</li>
          <li>Decrement before re-gossip; TTL=0 not re-gossiped</li>
        </ul>
      </section>
    </section>

    <section anchor="rate_limiting_accountability" numbered="true" toc="default">
      <name>Rate Limiting and Accountability</name>
      
      <section anchor="sequence_numbers" numbered="true" toc="default">
        <name>Sequence Numbers</name>
        <t>Every reliable message carries a sequence number per <tt>(sender, resource_type)</tt>.</t>
        <ul>
          <li>64-bit unsigned integer</li>
          <li>Maximum permitted value: 2^62 - 1 (approximately 4.6e18)</li>
          <li>Implementations <bcp14>MUST</bcp14> trigger a key rotation warning when the sequence number reaches 2^61 (50% of max)</li>
          <li>If a sender approaches 2^62 - 1, they <bcp14>MUST</bcp14> rotate their NodeId (<xref target="key_rotation"/>) before the next increment</li>
          <li>Overflow beyond 2^62 - 1 is a provable violation (<xref target="error_codes_registry"/> code 16)</li>
        </ul>
      </section>
      
      <section anchor="violation_receipts" numbered="true" toc="default">
        <name>Violation Receipts</name>
        <t>When a peer detects a violation (e.g., sequence gap, rate exceedance), it creates a signed violation receipt and gossips it.</t>
        <t>Validation requirement: A violation receipt is considered valid only if corroborated by at least 3 independent witnesses as defined in <xref target="independent_witness"/>. If fewer than 3 qualified domains exist in the federation, the threshold equals the number of domains.</t>
        <t>Receipt signature:</t>
        <artwork><![CDATA[
signature = Ed25519_sign(
  private_key,
  "QUIP-VIOLATION-V1" || QUIP-CBOR(violation_data)
)
]]></artwork>
      </section>
    </section>

    <section anchor="resource_limits" numbered="true" toc="default">
      <name>Resource Limits</name>
      <t>Implementations <bcp14>MUST</bcp14> enforce the following limits:</t>
      
      <table align="center">
        <thead>
          <tr><th>Resource</th><th>Limit</th><th>Behavior When Exceeded</th></tr>
        </thead>
        <tbody>
          <tr><td>Maximum CBOR object size</td><td>64 KB</td><td>Reject with error</td></tr>
          <tr><td>Maximum gossip message size</td><td>64 KB</td><td>Reject with error</td></tr>
          <tr><td>Maximum document size</td><td>16 MB</td><td>Reject with error</td></tr>
          <tr><td>Maximum attestation chain depth</td><td>8</td><td>Reject with error</td></tr>
          <tr><td>Maximum rotation chain depth</td><td>32</td><td>Reject with error</td></tr>
          <tr><td>Maximum vector clock entries</td><td>1024</td><td>Prune oldest</td></tr>
          <tr><td>Maximum replay cache entries</td><td>100,000</td><td>LRU eviction</td></tr>
          <tr><td>Maximum pending sequence gaps</td><td>256</td><td>Discard oldest</td></tr>
        </tbody>
      </table>
    </section>

    <section anchor="conformance_profiles" numbered="true" toc="default">
      <name>Conformance Profiles</name>
      
      <table align="center">
        <thead>
          <tr><th>Profile</th><th>Required Features</th></tr>
        </thead>
        <tbody>
          <tr><td>Basic</td><td>NodeId, attestations, DANE (COMPAT), message envelope, rate limiting, gossip</td></tr>
          <tr><td>Documents (Companion Document)</td><td>Adds: content addressing, schema registry, collections. Specified in a separate document.</td></tr>
          <tr><td>Media (Experimental)</td><td>See <xref target="experimental_features"/></td></tr>
        </tbody>
      </table>
      
      <t>The Documents profile features (content addressing by hash, schema registry, document collections) are specified in a companion Internet-Draft titled "QUIP Documents Profile".</t>
    </section>

    <section anchor="experimental_features" numbered="true" toc="default">
      <name>Experimental Features</name>
      <t>The following features are marked experimental in this version and <bcp14>MAY</bcp14> change incompatibly in future versions. Implementations <bcp14>SHOULD</bcp14> log a warning when experimental features are used.</t>
      
      <table align="center">
        <thead>
          <tr><th>Feature</th><th>Status</th></tr>
        </thead>
        <tbody>
          <tr><td>Media profile</td><td>Incomplete; separate document planned</td></tr>
          <tr><td>Routing resource type</td><td>Not fully specified; use at own risk</td></tr>
        </tbody>
      </table>
      
      <t>The Media profile uses QUIC datagrams as specified in <xref target="RFC9221"/>.</t>
    </section>

    <section anchor="security_considerations" numbered="true" toc="default">
      <name>Security Considerations</name>
      
      <section anchor="threat_model_summary" numbered="true" toc="default">
        <name>Threat Model Summary</name>
        <t>QUIP defends against: domain impersonation (via subject signatures), replay attacks (via message_id cache), BGP hijacking (via DANE binding), DNS poisoning (via DNSSEC), split-brain/fork (via deterministic merge), gossip amplification (via TTL and rate limits), Sybil witnesses (via independent witness definition — raises operational cost of Sybil-style witness fabrication).</t>
        <t>QUIP does NOT defend against: anonymity attacks, metadata confidentiality, global passive adversaries, Byzantine consensus, economic Sybil resistance, or witness collusion (relies on legal/commercial incentives).</t>
      </section>
      
      <section anchor="replay_attacks" numbered="true" toc="default">
        <name>Replay Attacks</name>
        <t>Domain separation (<xref target="signature_computation"/>) prevents cross-context replay. The <tt>message_id</tt> cache provides per-message protection.</t>
      </section>
      
      <section anchor="downgrade_attacks" numbered="true" toc="default">
        <name>Downgrade Attacks</name>
        <t>DNS downgrade protection (<xref target="dns_downgrade_protection"/>) and handshake transcript binding (<xref target="handshake_transcript_binding"/>) prevent silent capability stripping. STRICT mode refuses downgrades.</t>
      </section>
      
      <section anchor="canonicalization_attacks" numbered="true" toc="default">
        <name>Canonicalization Attacks</name>
        <t>QUIP-CBOR (<xref target="quip_cbor_profile"/>) eliminates encoding ambiguity. Duplicate keys and indefinite lengths are rejected. QUIP-CBOR is defined as an application profile of <xref target="RFC8949"/>.</t>
      </section>
    </section>

    <section anchor="privacy_considerations" numbered="true" toc="default">
      <name>Privacy Considerations</name>
      <ul>
        <li>NodeId reuse enables correlation</li>
        <li>Gossip reveals topology</li>
        <li>Address bindings are public</li>
      </ul>
      <t><em>Linkability through rotation chains:</em> Key rotation preserves identity continuity for accountability. All keys in a rotation chain are cryptographically linked to the genesis NodeId. Rotating keys does NOT provide unlinkability or anonymity.</t>
    </section>

    <section anchor="iana_considerations" numbered="true" toc="default">
      <name>IANA Considerations</name>
      
      <section anchor="alpn_registration" numbered="true" toc="default">
        <name>ALPN Protocol ID Registration</name>
        <t>IANA is requested to register the following ALPN protocol ID:</t>
        <dl>
          <dt>Protocol:</dt><dd>QUIP</dd>
          <dt>ID:</dt><dd>"quip"</dd>
          <dt>Reference:</dt><dd>This document</dd>
        </dl>
      </section>
      
      <section anchor="error_codes_registry" numbered="true" toc="default">
        <name>QUIP Error Codes Registry</name>
        <t>IANA is requested to create a registry titled "QUIP Error Codes" with the following initial contents:</t>
        
        <table align="center">
          <thead>
            <tr><th>Code</th><th>Name</th><th>Description</th></tr>
          </thead>
          <tbody>
            <tr><td>1</td><td>INVALID_SIGNATURE</td><td>Signature verification failed</td></tr>
            <tr><td>2</td><td>ATTESTATION_EXPIRED</td><td>Attestation validity period exceeded</td></tr>
            <tr><td>3</td><td>DNSSEC_FAILURE</td><td>DNSSEC validation failed</td></tr>
            <tr><td>4</td><td>RATE_LIMIT_EXCEEDED</td><td>Quota exceeded</td></tr>
            <tr><td>5</td><td>DUPLICATE_MESSAGE</td><td>message_id already seen</td></tr>
            <tr><td>6</td><td>KEY_ROTATED</td><td>Sender's NodeId rotated</td></tr>
            <tr><td>7</td><td>UNSUPPORTED_VERSION</td><td>Schema version not supported</td></tr>
            <tr><td>8</td><td>GOSSIP_RATE_LIMIT</td><td>Gossip update rate exceeded</td></tr>
            <tr><td>9</td><td>PROFILE_MISMATCH</td><td>No common profile</td></tr>
            <tr><td>10</td><td>HASH_MISMATCH</td><td>Document hash mismatch</td></tr>
            <tr><td>11</td><td>DATAGRAM_NOT_SUPPORTED</td><td>Peer does not support datagrams</td></tr>
            <tr><td>12</td><td>GOSSIP_BOOTSTRAP_FAILED</td><td>Bootstrap failed</td></tr>
            <tr><td>13</td><td>KEY_COMPROMISED</td><td>Key compromise reported</td></tr>
            <tr><td>14</td><td>GOSSIP_SYNC_TIMEOUT</td><td>Anti-entropy timeout</td></tr>
          </tbody>
        </table>
        
        <t>Registration policy: IETF Review for codes 0-127. Codes 128-255 are reserved for application-specific extensions. Error code 0 is reserved and <bcp14>MUST NOT</bcp14> be used.</t>
      </section>
      
      <section anchor="cbor_tag_registration" numbered="true" toc="default">
        <name>CBOR Tag 65536 Registration</name>
        <t>IANA is requested to register the following CBOR tag in the CBOR Tags registry <xref target="RFC9277"/>:</t>
        
        <dl>
          <dt>Tag Number:</dt><dd>65536</dd>
          <dt>Data Item:</dt><dd>CBOR array</dd>
          <dt>Semantic:</dt><dd>Container for QUIP protocol messages. The first element of the array is a string discriminator indicating the message type (e.g., "message", "gossip", "document", "key_rotation", "primary_binding").</dd>
          <dt>Point of Contact:</dt><dd>Junior Joseph Mututi &lt;jjmututicloud@gmail.com&gt;</dd>
          <dt>Fragment Identifier:</dt><dd>N/A</dd>
          <dt>Reference:</dt><dd>This document</dd>
        </dl>
      </section>
    </section>

    <section anchor="quip_cbor_profile" numbered="true" toc="default">
      <name>QUIP-CBOR Profile</name>
      <t>QUIP defines a strict deterministic CBOR profile called the QUIP Deterministic CBOR Profile (QDP). This is an application profile, not a replacement for <xref target="RFC8949"/> canonical CBOR. QDP is used exclusively within QUIP protocol messages.</t>
      
      <section anchor="encoding_rules" numbered="true" toc="default">
        <name>Encoding Rules</name>
        <table align="center">
          <thead>
            <tr><th>Class</th><th>Type</th><th>Ordering Rule</th></tr>
          </thead>
          <tbody>
            <tr><td>1</td><td>Unsigned integers</td><td>Numeric ascending, shortest encoding first</td></tr>
            <tr><td>2</td><td>Negative integers</td><td>Numeric ascending (more negative first)</td></tr>
            <tr><td>3</td><td>Byte strings</td><td>Length-ordered, then lexicographic</td></tr>
            <tr><td>4</td><td>Text strings</td><td>Length-ordered, then UTF-8 bytewise lexicographic</td></tr>
          </tbody>
        </table>
        
        <t><em>Prohibited constructs:</em> duplicate map keys, indefinite-length items, floating point values, non-minimal UTF-8, CBOR simple values other than false/true/null.</t>
      </section>
    </section>

    <section anchor="implementation_guidelines" numbered="true" toc="default">
      <name>Implementation Guidelines</name>
      
      <section anchor="state_persistence" numbered="true" toc="default">
        <name>State Persistence</name>
        <t>Implementations <bcp14>MUST</bcp14> persist vector clocks for all tracked resources, sequence number state per <tt>(genesis_NodeId, discriminator)</tt>, revocation state for known peers, and peer relationship state. Replay cache persistence is <bcp14>OPTIONAL</bcp14>.</t>
      </section>
      
      <section anchor="sequence_state_loss_recovery" numbered="true" toc="default">
        <name>Sequence State Loss Recovery</name>
        <t>If sequence state is lost after restart, the implementation <bcp14>MUST</bcp14> log a critical error, rotate the NodeId (<xref target="key_rotation"/>) to start a new sequence space, and NOT reuse prior sequence numbers.</t>
      </section>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>
      
      <references>
        <name>Normative References</name>
        
        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="S. Bradner"/>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        
        <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author initials="B." surname="Leiba" fullname="B. Leiba"/>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
        
        <reference anchor="RFC9000" target="https://www.rfc-editor.org/info/rfc9000">
          <front>
            <title>QUIC: A UDP-Based Multiplexed and Secure Transport</title>
            <author initials="J." surname="Iyengar" fullname="J. Iyengar"/>
            <author initials="M." surname="Thomson" fullname="M. Thomson"/>
            <date year="2021" month="May"/>
          </front>
          <seriesInfo name="RFC" value="9000"/>
          <seriesInfo name="DOI" value="10.17487/RFC9000"/>
        </reference>
        
        <reference anchor="RFC8949" target="https://www.rfc-editor.org/info/rfc8949">
          <front>
            <title>Concise Binary Object Representation (CBOR)</title>
            <author initials="C." surname="Bormann" fullname="C. Bormann"/>
            <author initials="P." surname="Hoffman" fullname="P. Hoffman"/>
            <date year="2020" month="December"/>
          </front>
          <seriesInfo name="RFC" value="8949"/>
          <seriesInfo name="DOI" value="10.17487/RFC8949"/>
        </reference>
        
        <reference anchor="RFC9277" target="https://www.rfc-editor.org/info/rfc9277">
          <front>
            <title>CBOR Tags Registry Revisions</title>
            <author initials="C." surname="Bormann" fullname="C. Bormann"/>
            <date year="2022" month="August"/>
          </front>
          <seriesInfo name="RFC" value="9277"/>
          <seriesInfo name="DOI" value="10.17487/RFC9277"/>
        </reference>
        
        <reference anchor="RFC6698" target="https://www.rfc-editor.org/info/rfc6698">
          <front>
            <title>DNS-Based Authentication of Named Entities (DANE) TLSA Protocol</title>
            <author initials="P." surname="Hoffman" fullname="P. Hoffman"/>
            <author initials="J." surname="Schlyter" fullname="J. Schlyter"/>
            <date year="2012" month="August"/>
          </front>
          <seriesInfo name="RFC" value="6698"/>
          <seriesInfo name="DOI" value="10.17487/RFC6698"/>
        </reference>
        
        <reference anchor="RFC8032" target="https://www.rfc-editor.org/info/rfc8032">
          <front>
            <title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title>
            <author initials="S." surname="Josefsson" fullname="S. Josefsson"/>
            <author initials="I." surname="Liusvaara" fullname="I. Liusvaara"/>
            <date year="2017" month="January"/>
          </front>
          <seriesInfo name="RFC" value="8032"/>
          <seriesInfo name="DOI" value="10.17487/RFC8032"/>
        </reference>
        
        <reference anchor="RFC4033" target="https://www.rfc-editor.org/info/rfc4033">
          <front>
            <title>DNS Security (DNSSEC) Introduction and Requirements</title>
            <author initials="R." surname="Arends" fullname="R. Arends"/>
            <author initials="R." surname="Austein" fullname="R. Austein"/>
            <author initials="M." surname="Larson" fullname="M. Larson"/>
            <author initials="D." surname="Massey" fullname="D. Massey"/>
            <author initials="S." surname="Rose" fullname="S. Rose"/>
            <date year="2005" month="March"/>
          </front>
          <seriesInfo name="RFC" value="4033"/>
          <seriesInfo name="DOI" value="10.17487/RFC4033"/>
        </reference>
        
        <reference anchor="RFC4034" target="https://www.rfc-editor.org/info/rfc4034">
          <front>
            <title>Resource Records for the DNS Security Extensions</title>
            <author initials="R." surname="Arends" fullname="R. Arends"/>
            <author initials="R." surname="Austein" fullname="R. Austein"/>
            <author initials="M." surname="Larson" fullname="M. Larson"/>
            <author initials="D." surname="Massey" fullname="D. Massey"/>
            <author initials="S." surname="Rose" fullname="S. Rose"/>
            <date year="2005" month="March"/>
          </front>
          <seriesInfo name="RFC" value="4034"/>
          <seriesInfo name="DOI" value="10.17487/RFC4034"/>
        </reference>
        
        <reference anchor="RFC4035" target="https://www.rfc-editor.org/info/rfc4035">
          <front>
            <title>Protocol Modifications for the DNS Security Extensions</title>
            <author initials="R." surname="Arends" fullname="R. Arends"/>
            <author initials="R." surname="Austein" fullname="R. Austein"/>
            <author initials="M." surname="Larson" fullname="M. Larson"/>
            <author initials="D." surname="Massey" fullname="D. Massey"/>
            <author initials="S." surname="Rose" fullname="S. Rose"/>
            <date year="2005" month="March"/>
          </front>
          <seriesInfo name="RFC" value="4035"/>
          <seriesInfo name="DOI" value="10.17487/RFC4035"/>
        </reference>
        
        <reference anchor="RFC8446" target="https://www.rfc-editor.org/info/rfc8446">
          <front>
            <title>The Transport Layer Security (TLS) Protocol Version 1.3</title>
            <author initials="E." surname="Rescorla" fullname="E. Rescorla"/>
            <date year="2018" month="August"/>
          </front>
          <seriesInfo name="RFC" value="8446"/>
          <seriesInfo name="DOI" value="10.17487/RFC8446"/>
        </reference>
      </references>
      
      <references>
        <name>Informative References</name>
        
        <reference anchor="RFC9221" target="https://www.rfc-editor.org/info/rfc9221">
          <front>
            <title>An Unreliable Datagram Extension to QUIC</title>
            <author initials="T." surname="Pauly" fullname="T. Pauly"/>
            <author initials="E." surname="Kinnear" fullname="E. Kinnear"/>
            <author initials="D." surname="Schinazi" fullname="D. Schinazi"/>
            <date year="2022" month="March"/>
          </front>
          <seriesInfo name="RFC" value="9221"/>
          <seriesInfo name="DOI" value="10.17487/RFC9221"/>
        </reference>
      </references>
    </references>
  </back>
</rfc>