﻿<?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-01" 
     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-01"/>
    
    <author fullname="Junior Joseph Mututi" 
            initials="J. J."
            surname="Mututi">
      <organization>Individual</organization>
      <address>
        <postal>
          <country>Zimbabwe</country>
        </postal>
        <email>jjmututicloud@gmail.com</email>
      </address>
    </author>
    
    <date year="2026" month="June" day="5"/>
    
    <area>Security</area>
    <workgroup>dispatch</workgroup>
    
    <keyword>QUIC</keyword>
    <keyword>Identity</keyword>
    <keyword>Federation</keyword>
    <keyword>Key Transparency</keyword>
    <keyword>TOFU</keyword>
    
    <abstract>
      <t>QUIP is a brokerless federation protocol over QUIC. It provides portable Ed25519 identities, causal consistency via Dotted Version Vectors, and queueless transport via four explicit tiers with backpressure. QUIP replaces DNSSEC-based trust with Key Transparency + Trust-On-First-Use, enabling 99% deployability while improving security against registrar compromise.</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 trust without DNSSEC deployment barriers</li>
        <li>Deterministic causal consistency via dotted version vectors</li>
        <li>Queueless transport with explicit backpressure</li>
        <li>Cryptographic accountability for misbehavior</li>
      </ul>
      
      <t>Unlike HTTP/3 + gRPC, QUIP provides:</t>
      <ul>
        <li><em>Portable ID</em>: No OAuth, no IdP. The Ed25519 key is identity</li>
        <li><em>Causal consistency</em>: Dotted version vectors built-in, not bolted on</li>
        <li><em>Backpressure</em>: <tt>EAGAIN</tt> contract, not hidden buffers</li>
        <li><em>Fire-and-forget</em>: T3 datagrams for ephemeral events</li>
        <li><em>Brokerless</em>: No server owns the namespace</li>
      </ul>
      
      <t>QUIP addresses five specific gaps in current federation protocols: browser-centric transport constraints that freeze QUIC behind HTTP/3, WebPKI incumbency that blocks self-sovereign identity, database causality techniques that remain internal to storage systems, infrastructure incentives that reward hidden buffering, and standards governance that resists removing HTTP from the critical path. A detailed discussion of the market, regulatory, and technical forces that make this composition viable now is provided in <xref target="why_quip"/>.</t>

      <t>QUIP operates directly over QUIC <xref target="RFC9000"/> and eliminates reliance on HTTP-based federation layers.</t>
    </section>

    

    <section anchor="changes_from_00" numbered="true" toc="default">
      <name>Changes from Version 00</name>
      <t>This version represents a significant redesign based on implementation experience and community feedback:</t>
      <ul>
        <li>Replaced DNSSEC/DANE with Key Transparency + Trust On First Use (KT+TOFU)</li>
        <li>Added four normative transport tiers (T0-T3) with queueless semantics</li>
        <li>Replaced vector clocks with dotted version vectors for scalability to 100k writers</li>
        <li>Removed domain authority over identity; Key Claim is self-signed</li>
        <li>Defined four native verbs (CTRL, SYNC, BULK, EVENT) replacing opaque payloads</li>
        <li>Removed X.509 complexity; WebPKI only for bootstrap</li>
      
        <li>Added "Why QUIP, Why Now" section establishing problem context</li>
        <li>Added explicit state machines for T1 SYNC and T2 BULK streams</li>
        <li>Defined error recovery procedures with backoff timers</li>
        <li>Specified witness bootstrap rotation and emergency revocation mechanism</li>
        <li>Added DVV pruning algorithm with flattening semantics</li>
        <li>Extended seq_reset window to max(60s, heartbeat_interval * 3)</li>
        <li>Added T3 datagram congestion control integration</li>
        <li>Split <tt>announce</tt> verb into <tt>announce_key</tt> and <tt>announce_witness</tt></li>
        <li>Added IANA registry for QUIP verbs</li>
        <li>Added CDDL schemas (Appendix A), test vectors (Appendix B), and performance expectations (Appendix C)</li>
        <li>Added LEGACY mode deprecation timeline</li>
      </ul>
    </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). The root of identity.</dd>
        <dt><tt>Key Claim</tt></dt><dd>Self-signed CBOR object asserting a NodeId with optional domain hint.</dd>
        <dt><tt>KT+TOFU</tt></dt><dd>Key Transparency + Trust On First Use &#x2014; the trust model replacing DNSSEC.</dd>
        <dt><tt>DVV</tt></dt><dd>Dotted Version Vector &#x2014; causal consistency primitive scaling to O(writers).</dd>
        <dt><tt>KT_WITNESS</tt></dt><dd>Signed statement from a peer attesting to observed Key Claim.</dd>
        <dt><tt>heartbeat_interval</tt></dt><dd>The configured keepalive interval between peers, in seconds. Default value is 30 seconds. Used in the replay protection bound for <tt>seq_reset</tt> (<xref target="seq_reset"/>).</dd>
      </dl>
    </section>

    <section anchor="handshake" numbered="true" toc="default">
      <name>Handshake and Profile Negotiation</name>
      
      <t>Upon QUIC connection establishment with ALPN <tt>"quip"</tt>, peers exchange a handshake on the Control Stream (T0, stream 0) before any application streams become active.</t>
      
      <t>Handshake format (CBOR array):</t>
      <artwork><![CDATA[
[
  1,                    ; version (uint)
  0b111,                ; capabilities bitmask (bits 0-2: CTRL/SYNC/BULK/EVENT all supported)
  "compat",             ; server_trust_mode
  {                     ; extensions (optional)
    "max_message_size": 65536,
    "witness_min_age": 604800
  }
]
]]></artwork>
      
      <t><strong>Capability Bits:</strong> Bit 0 indicates support for KT+TOFU (default), bit 1 indicates support for DANE STRICT mode, bit 2 indicates support for T3 datagrams.</t>

      <t>The bitmask is interpreted as follows: bit 0 (value 0x01) indicates support for KT+TOFU identity verification; bit 1 (value 0x02) indicates support for DANE STRICT server authentication mode; bit 2 (value 0x04) indicates support for T3 unreliable datagram transport. All other bits <bcp14>MUST</bcp14> be set to zero by senders and <bcp14>MUST</bcp14> be ignored by receivers until defined by a future version of this protocol.</t>
      
      <t>Server responds with identical structure.</t>
      
      <t>Both peers compute the intersection of capabilities. If no common capabilities exist, the connection <bcp14>MUST</bcp14> be closed with error <tt>E_PROFILE_MISMATCH</tt> (error code 0x08).</t>
      
      <t><strong>Version negotiation:</strong> Future versions of QUIP <bcp14>MAY</bcp14> define new ALPN identifiers (e.g., <tt>"quip-2"</tt>). The ALPN identifier <tt>"quip"</tt> refers to version 1 of the protocol.</t>
    </section>

    <section anchor="identity_model" numbered="true" toc="default">
      <name>Identity Model</name>
      
      <section anchor="key_claim" numbered="true" toc="default">
        <name>Key Claim</name>
        <t>A Key Claim is a self-signed CBOR object that asserts a user's
        NodeId and provides a hint about reachability. It is the root of
        identity in QUIP v01. Unlike v00, there is no primary attestation
        from a domain. Identity is fully self-sovereign.</t>
        
        <artwork><![CDATA[
tagged(65536, [
  "key_claim",
  NodeId,                  ; 32 bytes (Ed25519 public key)
  timestamp,               ; Unix milliseconds (int64)
  domain_hint,             ; string (optional, e.g., "user@example.net")
  signature                ; 64 bytes (self-signed)
])
]]></artwork>

        <t>The <tt>domain_hint</tt> is advisory only. It suggests where the user
        might be reachable but carries no authority. Domains become routing hints,
        not identity authorities. If a domain is compromised, users simply
        advertise a new hint; their NodeId remains unchanged.</t>
      </section>
      
      <section anchor="dvv" numbered="true" toc="default">
        <name>Dotted Version Vectors</name>
        <t>A Dotted Version Vector (DVV) is represented as:</t>
        
        <artwork><![CDATA[
{
  1: dot,   ; [writer: NodeId, counter: uint]
  2: deps   ; {* writer: NodeId => counter: uint}
}
]]></artwork>
        
        <t>Rules:</t>
        <ol>
          <li><tt>dot</tt> <bcp14>MUST</bcp14> be present for writes. Absent for reads.</li>
          <li><tt>deps</tt> <bcp14>MUST</bcp14> contain exactly one entry per writer ever seen for this resource.</li>
          <li>Map keys <bcp14>MUST</bcp14> use QUIP-CBOR canonical ordering (<xref target="quip_cbor"/>).</li>
        </ol>
        
        <t>Example: Alice (key h'alice_id') writes post #42, has seen Bob at counter 3:</t>
        <artwork><![CDATA[
{1: [h'alice_id', 1], 2: {h'alice_id': 0, h'bob_id': 3}}
]]></artwork>
        
        <t>Dotted vectors scale to 100,000 concurrent writers. The <tt>deps</tt> map
        grows only with distinct writers that have modified the resource.</t>
        
        <t><strong>Comparison:</strong> DVV A is causally after DVV B if
        A.dot.counter > B.deps[A.dot.writer] or there exists a writer
        where A.deps[writer] > B.deps[writer].</t>
        
        <t><strong>Merge (deterministic tie-breaking):</strong> When updates are concurrent
        (neither dominates), the deterministic order is:</t>
        <ol>
          <li>Higher <tt>dot.counter</tt></li>
          <li>If equal, lexicographic comparison of <tt>dot.writer</tt> as raw bytes</li>
          <li>If equal, lexicographic comparison of the QUIP-CBOR canonical serialization
              of the entire <tt>deps</tt> map, compared bytewise</li>
        </ol>
        
        <t><strong>DVV Pruning:</strong> When the <tt>deps</tt> map exceeds 1024 entries,
        implementations <bcp14>MAY</bcp14> prune the entry with the smallest counter
        among all writers. The pruned writer's counter is stored as a sentinel value;
        future operations from that writer <bcp14>MUST</bcp14> start from that counter + 1.
        This prevents unbounded growth while maintaining causality.</t>
      </section>
      
      <section anchor="kt_tofu" numbered="true" toc="default">
        <name>Key Transparency and Trust On First Use</name>
        
        <t>QUIP replaces DNSSEC/DANE with a combination of Trust On First
        Use (TOFU) and Key Transparency (KT) gossip. This achieves 99%
        deployability while providing stronger security against registrar
        compromise than DANE.</t>
        
        <section anchor="tofu" numbered="true" toc="default">
          <name>Trust On First Use (TOFU)</name>
          <t>The first time a peer presents a Key Claim, the receiving peer
          automatically pins it. No prior validation is required. This allows
          immediate communication without any external infrastructure.</t>
          
          <t>TOFU behavior:</t>
          <ul>
            <li>First seen Key Claim for a domain_hint is accepted and stored</li>
            <li>Subsequent claims <bcp14>MUST</bcp14> match the pinned key or provide a valid
                rotation chain signed by the original NodeId</li>
            <li>If a mismatch occurs without a valid rotation, the peer enters
                DEGRADED mode and alerts the user</li>
          </ul>
        </section>
        
        <section anchor="kt_gossip" numbered="true" toc="default">
          <name>Key Transparency Gossip</name>
          <t>Peers broadcast key witness statements to the control plane (T0)
          to build distributed trust.</t>
          
          <artwork><![CDATA[
tagged(65536, [
  "kt_witness",
  subject_NodeId,          ; 32 bytes (the key being witnessed)
  domain_hint,             ; string
  asn,                     ; uint (witness's ASN)
  prefix,                  ; string (witness's /24 IPv4 or /48 IPv6)
  timestamp,               ; Unix milliseconds
  valid_until,             ; Unix milliseconds (witness validity period, +30 days)
  witness_NodeId,          ; 32 bytes (the witness's key)
  signature                ; 64 bytes
])
]]></artwork>

          <t><strong>Witness validity:</strong> A witness statement is valid for
          30 days from <tt>timestamp</tt>. After <tt>valid_until</tt> expires,
          the witness <bcp14>MUST</bcp14> be re-issued. If a key has fewer than
          3 currently valid witness statements, its <tt>KT_VERIFIED</tt> status
          <bcp14>MUST</bcp14> be revoked. Witnesses <bcp14>SHOULD</bcp14> re-issue
          statements weekly.</t>
          
          <t><strong>KT_VERIFIED status lifecycle:</strong></t>
          <ul>
            <li><em>PENDING</em> (0-6 days, &lt;3 witnesses) &#x2014; TOFU only</li>
            <li><em>VERIFIED</em> (≥7 days, ≥3 valid witnesses from distinct ASNs, distinct /24 IPv4 or /48 IPv6)</li>
            <li><em>EXPIRED</em> (any witness validity period exceeded) &#x2014; status reverts to PENDING</li>
            <li><em>REVOKED</em> (explicit violation receipt tombstone)</li>
          </ul>
          
          <t>Verification threshold for <tt>KT_VERIFIED</tt>:</t>
          <ul>
            <li>≥3 independent witnesses from distinct ASNs and distinct /24 IPv4 or /48 IPv6 prefixes</li>
            <li>Each witness's Key Claim must have been first seen ≥7 days ago (age requirement)</li>
            <li>Each witness statement must have <tt>valid_until</tt> in the future</li>
          </ul>
          
          <t><strong>Witness eligibility:</strong> The 7-day age requirement
          prevents instant Sybil attacks. The 30-day witness validity period
          forces periodic re-attestation, preventing stale trust.</t>
          
          <t><strong>Bootstrap witnesses:</strong> New nodes use hardcoded seeds
          or DNS TXT <tt>_quip-witness.domain</tt>. Seeds are exempt from the
          age check but <bcp14>MUST</bcp14> have distinct ASNs. Implementations
          <bcp14>SHOULD</bcp14> ship with 5 seeds and require 3 distinct seeds
          for bootstrap.</t>
          
          <t><strong>Witness Bootstrap Rotation:</strong> When a bootstrap witness
          is rotated (e.g., key update), the witness <bcp14>MUST</bcp14> publish a
          <tt>witness_rotation</tt> attestation signed by its old key and verified
          by the new key. Peers <bcp14>SHOULD</bcp14> accept the new key after
          verifying the rotation chain.</t>
          
          <t><strong>Emergency Revocation:</strong> If a bootstrap witness is
          compromised, operators <bcp14>MAY</bcp14> publish an emergency revocation
          list (e.g., via HTTPS from a well-known location). Implementations
          <bcp14>SHOULD</bcp14> check such lists periodically (e.g., daily).</t>
        </section>
        
        <section anchor="kt_security" numbered="true" toc="default">
          <name>Security Properties</name>
          <t>DNS hijack becomes a detectable denial-of-service, not a silent
          man-in-the-middle attack. An attacker who hijacks DNS can present a
          false Key Claim, but:</t>
          <ul>
            <li>TOFU remembers the legitimate key on first connection</li>
            <li>Gossip from independent witnesses provides cross-validation</li>
            <li>A false claim without ≥3 witness confirmations is rejected</li>
          </ul>
          <t>This is stronger than DANE against registrar compromise, as no
          single authority can silently rotate keys.</t>
        </section>
        
        <section anchor="kt_rotation" numbered="true" toc="default">
          <name>Key Rotation</name>
          <t>Only the NodeId itself can sign a key rotation. Domains cannot
          revoke or rotate keys on behalf of users. This is a fundamental
          departure from v00 where domains had attestation authority.</t>
          
          <artwork><![CDATA[
tagged(65536, [
  "key_rotation",
  old_NodeId,              ; 32 bytes
  new_NodeId,              ; 32 bytes
  timestamp,               ; Unix milliseconds
  signature                ; 64 bytes (by old_NodeId)
])
]]></artwork>
          
          <t>If a user loses their private key, they cannot recover the same
          NodeId. This is intentional. Key loss results in a new identity.
          The old identity can publish a "key_compromised" attestation to warn
          peers, but this is advisory only.</t>
          
          <t><strong>Witness Requirement for Rotated Keys:</strong> A new key
          <bcp14>MUST</bcp14> be witnessed by ≥1 existing witness before
          <tt>KT_VERIFIED</tt> status transfers. This prevents an attacker from
          rotating a compromised key and immediately gaining verified status.
          The witnessing witness <bcp14>MUST</bcp14> verify that the old key
          signed the <tt>key_rotation</tt> attestation and that the new key
          appears in the payload.</t>
        </section>
        
        <section anchor="seq_reset" numbered="true" toc="default">
          <name>Sequence Number Reset</name>
          <t>If a node loses its sequence number state (e.g., after crash recovery
          without persistence), it <bcp14>MUST</bcp14> publish a <tt>seq_reset</tt>
          attestation before generating new messages. This informs peers that
          previous sequence numbers are abandoned and new messages start from 0.</t>
          
          <artwork><![CDATA[
tagged(65536, [
  "seq_reset",
  NodeId,                  ; 32 bytes
  last_known_seq,          ; uint (last sequence number before loss)
  timestamp,               ; Unix milliseconds
  signature                ; 64 bytes
])
]]></artwork>
          
          <t>Peers receiving a <tt>seq_reset</tt> <bcp14>MUST</bcp14> discard all
          prior sequence state for that NodeId and accept new messages starting
          from sequence 0. The <tt>seq_reset</tt> itself <bcp14>MUST</bcp14> be
          accepted even if its sequence number is out of order.</t>
          
          <t><strong>Replay protection:</strong> To prevent replay attacks, peers
          <bcp14>SHOULD</bcp14> reject a <tt>seq_reset</tt> whose timestamp is more
          than <tt>max(60s, heartbeat_interval * 3)</tt> behind the last seen
          message from that NodeId. A legitimate node that loses state after
          prolonged inactivity <bcp14>MAY</bcp14> still issue a reset, but the
          receiving peer <bcp14>MAY</bcp14> require additional verification
          (e.g., out-of-band confirmation) before accepting.</t>
        </section>
      </section>
    </section>

    <section anchor="quip_cbor" numbered="true" toc="default">
      <name>Deterministic CBOR</name>
      <t>QUIP-CBOR is RFC 8949 with the following additional constraints:</t>
      <ul>
        <li><em>Integers</em>: Shortest form only. <tt>0x00</tt> not <tt>0x1800</tt>.</li>
        <li><em>Maps</em>: Keys sorted by bytewise lexicographic order of their deterministic CBOR encoding.</li>
        <li><em>Floats</em>: Prohibited. Use integer + scale (e.g., <tt>{"value": 12345, "scale": 2}</tt> for 123.45).</li>
        <li><em>Tags</em>: Prohibited except CBOR tag 2/3 for bignums and tag 32 for URIs.</li>
        <li><em>Indefinite lengths</em>: Prohibited. All arrays and maps <bcp14>MUST</bcp14> be definite-length.</li>
      </ul>
      <t>All QUIP messages <bcp14>MUST</bcp14> use QUIP-CBOR. Non-canonical CBOR
      <bcp14>MUST</bcp14> be rejected with error <tt>E_BAD_ENCODING</tt>.</t>
    </section>

    <section anchor="transport_tiers" numbered="true" toc="default">
      <name>Transport Tiers</name>
      
      <t>QUIP uses four dedicated transport tiers to eliminate head-of-line
      blocking and ensure deterministic RAM usage. This is the core queueless
      behavior that distinguishes QUIP from HTTP/3 + CBOR.</t>
      
      <table align="center">
        <thead>
          <tr><th>Tier</th><th>Stream ID / Transport</th><th>Purpose</th><th>Queue Policy</th><th>Reliability</th></tr>
        </thead>
        <tbody>
          <tr>
            <td>T0 Control</td>
            <td>stream 0</td>
            <td>Handshake, errors, KT witness, key_claim</td>
            <td>Queueless (MAY block on congestion)</td>
            <td>Reliable stream</td>
          </tr>
          <tr>
            <td>T1 Sync</td>
            <td>stream 4</td>
            <td>DVV exchange, anti-entropy, state reconciliation</td>
            <td>Queueless (<tt>EAGAIN</tt> on window=0)</td>
            <td>Reliable stream</td>
          </tr>
          <tr>
            <td>T2 Bulk</td>
            <td>streams 8, 12, 16...</td>
            <td>Messages, documents, reliable data transfer</td>
            <td><tt>EAGAIN</tt> on window=0</td>
            <td>Reliable stream</td>
          </tr>
          <tr>
            <td>T3 Event</td>
            <td>N/A &#x2014; QUIC DATAGRAM (RFC 9221)</td>
            <td>Media, telemetry, presence, ephemeral events</td>
            <td>Drop if congested</td>
            <td>Unreliable datagram</td>
          </tr>
        </tbody>
      </table>
      
      <t><strong>Note on T3:</strong> T3 uses QUIC datagrams per <xref target="RFC9221"/>,
      which have no stream ID. Datagrams are unreliable and dropped on congestion.
      No backpressure applies; senders <bcp14>MUST</bcp14> tolerate loss.</t>
      
      <t><strong>Deterministic RAM:</strong> Each tier has fixed buffer limits.
      No unbounded queues.</t>
      <ul>
        <li>T0: MAY block on congestion; no application-layer queuing</li>
        <li>T1/T2: Ordered queue with fixed size; if full, sender receives <tt>EAGAIN</tt></li>
        <li>T3: No queuing; datagrams dropped if congestion encountered</li>
      </ul>
      
      <t><strong>Backpressure Contract:</strong></t>
      <ul>
        <li><strong>T1 SYNC and T2 BULK:</strong> When a sender attempts to write
            and the receiver's flow control window is zero, the implementation
            <bcp14>MUST</bcp14> return <tt>EAGAIN</tt> (or equivalent) rather than
            buffering the data. This ensures backpressure propagates to the
            application, preventing hidden buffer bloat.</li>
        <li><strong>T0 Control:</strong> <bcp14>MAY</bcp14> block. T0 is low-volume
            gossip; blocking prevents split-brain during witness propagation.</li>
      </ul>
      
      <t><strong>HOL blocking elimination:</strong> Because streams are independent,
      a large bulk transfer on T2 does not block control messages on T0 or
      sync on T1. Each tier has its own flow control.</t>
      
      <t><strong>T3 Congestion Control Integration:</strong> T3 datagrams
      <bcp14>SHOULD</bcp14> be paced based on the QUIC connection's congestion
      window. When the congestion window is full, T3 datagrams <bcp14>MUST</bcp14>
      be dropped; senders <bcp14>SHOULD</bcp14> implement adaptive rate limiting
      to match the congestion window.</t>
    </section>

    <section anchor="stream_state_machines" numbered="true" toc="default">
      <name>T1 and T2 Stream State Machines</name>
      
      <t><strong>T1 SYNC Stream (stream 4):</strong></t>
      <ul>
        <li><em>State INITIAL:</em> Waiting for <tt>["get", ...]</tt> or <tt>["sync", ...]</tt></li>
        <li><em>State SYNCING:</em> Processing DVV exchange; on completion, send <tt>["sync", ...]</tt> with deltas</li>
        <li><em>State IDLE:</em> No outstanding operations; may remain open</li>
        <li><em>State ERROR:</em> Unrecoverable error; stream reset</li>
      </ul>
      
      <t><strong>T2 BULK Streams (streams 8, 12, 16...):</strong></t>
      <ul>
        <li><em>State INITIAL:</em> Waiting for <tt>["send_start", ...]</tt></li>
        <li><em>State TRANSFERRING:</em> Receiving <tt>["send_chunk", ...]</tt>; track sequence numbers</li>
        <li><em>State VERIFYING:</em> Final chunk received; computing hash</li>
        <li><em>State COMPLETE:</em> Transfer successful; stream may be closed</li>
        <li><em>State ABORTED:</em> Hash mismatch or error; stream reset</li>
      </ul>
    </section>

    <section anchor="error_recovery" numbered="true" toc="default">
      <name>Error Recovery Procedures</name>
      
      <t>When a non-fatal error occurs (e.g., <tt>E_RATE_LIMIT</tt>, <tt>E_FLOW_CONTROL_BLOCK</tt>),
      the sender <bcp14>SHOULD</bcp14> use exponential backoff with randomized jitter:</t>
      <ul>
        <li>Base delay: 1 second</li>
        <li>Maximum delay: 60 seconds</li>
        <li>Jitter: +/- 20% of the computed delay</li>
        <li>Retries: Unlimited, but the application <bcp14>MAY</bcp14> time out after a user-configured interval</li>
      </ul>
      
      <t>For fatal errors (e.g., <tt>E_PROFILE_MISMATCH</tt>, <tt>E_VIOLATION</tt>), the connection
      <bcp14>MUST</bcp14> be closed. The reporting peer <bcp14>SHOULD</bcp14> log the error for diagnostics.</t>
    </section>

    <section anchor="accountability" numbered="true" toc="default">
      <name>Accountability</name>
      
      <section anchor="rate_limiting" numbered="true" toc="default">
        <name>Rate Limiting</name>
        <t>Each <tt>NodeId</tt> gets a token bucket for T1 and T2 operations:</t>
        <ul>
          <li>Default quota: 1000 operations per minute</li>
          <li>Burst: 100 operations</li>
          <li>Exceeding quota <bcp14>MUST</bcp14> return error <tt>E_RATE_LIMIT</tt>
              with an advisory <tt>retry_after</tt> field (seconds) in the error payload</li>
        </ul>
      </section>
      
      <section anchor="violation_receipts" numbered="true" toc="default">
        <name>Violation Receipts</name>
        <t>If peer A detects equivocation or invalid signature from peer B,
        A <bcp14>MUST</bcp14> broadcast a violation receipt on T0:</t>
        
        <artwork><![CDATA[
tagged(65536, [
  "violation",
  violator_NodeId,         ; 32 bytes
  type,                    ; "equivocation" | "invalid_sig"
  evidence,                ; bytes (conflicting messages)
  signature                ; 64 bytes (by reporter)
])
]]></artwork>
        
        <t>Witnesses receiving 3+ independent violation receipts for the same
        violator <bcp14>MUST</bcp14> tombstone the violator. No consensus is
        required beyond the witness threshold. Tombstoned keys lose all
        <tt>KT_VERIFIED</tt> status and <bcp14>MUST</bcp14> be rejected.</t>
      </section>
    </section>

    <section anchor="native_verbs" numbered="true" toc="default">
      <name>Native Verbs</name>
      
      <t>QUIP defines four native verbs that correspond 1:1 to the transport
      tiers. This replaces the opaque payload approach of v00.</t>
      
      <section anchor="ctrl_verbs" numbered="true" toc="default">
        <name>CTRL Verbs (T0)</name>
        <t>Control plane operations sent on stream 0:</t>
        <artwork><![CDATA[
["announce_key", key_claim]                    ; Publish Key Claim
["announce_witness", kt_witness]               ; Publish witness statement
["query", "key", NodeId]                       ; Request Key Claim
["query", "witnesses", NodeId]                 ; Request witnesses for a key
["error", code, message_id, text]              ; Error notification
]]></artwork>

      <t>Responses to <tt>query</tt> verbs are sent on the same stream (T0) using the corresponding <tt>announce</tt> verb. A response to <tt>["query", "key", NodeId]</tt> is <tt>["announce_key", key_claim]</tt>. A response to <tt>["query", "witnesses", NodeId]</tt> is zero or more <tt>["announce_witness", kt_witness]</tt> messages, one per known witness.</t>
      </section>
      
      <section anchor="sync_verbs" numbered="true" toc="default">
        <name>SYNC Verbs (T1)</name>
        <t>State synchronization operations on stream 4. <tt>EAGAIN</tt> if
        receiver flow control window is zero.</t>
        <artwork><![CDATA[
["get", resource_id, their_dvv]                ; Request resource with DVV
["set", resource_id, new_dvv, payload]         ; Update resource
["sync", resource_id, their_dvv, deltas]       ; Bulk sync response
]]></artwork>

      <t>The receiver <bcp14>MUST</bcp14> respond to a <tt>set</tt> verb with either an updated <tt>["set", resource_id, new_dvv, payload]</tt> reflecting the accepted write, or an <tt>["error", E_DVV_CONFLICT, ...]</tt> on T0 if the DVV is rejected as stale. A successful <tt>set</tt> response carries the merged DVV so the sender can confirm causality. If the receiver accepts the write without modification, it <bcp14>MAY</bcp14> echo the same DVV back.</t>
      </section>
      
      <section anchor="bulk_verbs" numbered="true" toc="default">
        <name>BULK Verbs (T2)</name>
        <t>Large data transfer on streams 8, 12, 16... <tt>EAGAIN</tt> if
        receiver flow control window is zero.</t>
        <artwork><![CDATA[
["send_start", resource_id, total_size, hash]  ; Initiate transfer
["send_chunk", resource_id, seq, offset, bytes]; Chunked data with sequence number
["send_complete", resource_id, final_hash]     ; Finalize transfer
]]></artwork>
        
        <t><strong>Integrity verification:</strong> Each chunk includes a sequence
        number (<tt>seq</tt>) for ordering and the final hash is the SHA-256 of
        the concatenated chunks in order. Receivers <bcp14>MAY</bcp14> compute a
        running hash incrementally; if the final hash mismatches, the entire
        transfer <bcp14>MUST</bcp14> be rejected. Implementations <bcp14>MAY</bcp14>
        include per-chunk hashes for early corruption detection.</t>
      </section>
      
      <section anchor="event_verbs" numbered="true" toc="default">
        <name>EVENT Verbs (T3)</name>
        <t>Ephemeral events sent as QUIC datagrams. Unreliable. Dropped on
        congestion, no retransmission.</t>
        <artwork><![CDATA[
["emit", "presence", NodeId, status]           ; Presence update
["emit", "like", target_id, timestamp]         ; Like/ack
["emit", "media", codec, payload]              ; Real-time media chunk
]]></artwork>
      </section>
    </section>

    <section anchor="server_authentication" numbered="true" toc="default">
      <name>Server Authentication Modes</name>
      
      <t>QUIP replaces DANE+DNSSEC with KT+TOFU for the default COMPAT mode.
      STRICT mode retains DANE for environments that require it.</t>
      
      <table align="center">
        <thead>
          <tr><th>Mode</th><th>Requirement</th><th>Use Case</th></tr>
        </thead>
        <tbody>
          <tr>
            <td>COMPAT (default)</td>
            <td>WebPKI for bootstrap + KT+TOFU for identity</td>
            <td>General deployment, 99% of use cases</td>
          </tr>
          <tr>
            <td>STRICT (optional)</td>
            <td>DNSSEC + DANE + KT+TOFU</td>
            <td>High-security, regulated environments</td>
          </tr>
          <tr>
            <td>LEGACY (deprecated)</td>
            <td>WebPKI only</td>
            <td>Legacy transition, removal in v02</td>
          </tr>
        </tbody>
      </table>
      
      <t><strong>Why not DANE as default?</strong> DNSSEC deployment is at 1.3%
      globally. Requiring it would make QUIP undeployable. KT+TOFU provides
      equivalent security (3+ independent witnesses) without the deployment
      barrier. DNS hijack becomes a detectable DoS, not a silent MITM.</t>
      
      <t><strong>LEGACY mode deprecation timeline:</strong> LEGACY mode
      <bcp14>MAY</bcp14> be removed in QUIP v02, scheduled for 2027.
      Deployments <bcp14>SHOULD</bcp14> migrate to COMPAT mode.</t>
    </section>

    <section anchor="connection_establishment" numbered="true" toc="default">
      <name>Connection Establishment</name>
      
      <t>QUIC connection with ALPN <tt>"quip"</tt>.</t>
      
      <t><strong>T0 Control Stream (Stream 0):</strong> Designated immediately.</t>
      <t><strong>T1 Sync Stream (Stream 4):</strong> Designated immediately.</t>
      <t><strong>T2/T3:</strong> T2 streams opened on demand; T3 uses QUIC datagrams.</t>
      
      <t>Handshake sequencing:</t>
      <ol>
        <li>Client sends handshake (<xref target="handshake"/>) on T0</li>
        <li>Server responds with handshake on T0</li>
        <li>Both peers compute capability intersection</li>
        <li>Client sends Key Claim on T0</li>
        <li>Server responds with its Key Claim on T0</li>
        <li>Both peers compute KT_VERIFIED status via witness gossip</li>
        <li>T2 and T3 traffic may begin</li>
      </ol>
      
      <t>T2/T3 traffic <bcp14>SHALL</bcp14> not be processed until the initial
      Key Claim exchange completes.</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="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 <tt>E_BAD_ENCODING</tt></td>
          </tr>
          <tr>
            <td>Maximum DVV deps entries</td>
            <td>1024</td>
            <td>Prune oldest (see DVV pruning)</td>
          </tr>
          <tr>
            <td>Maximum pending sequence gaps</td>
            <td>256</td>
            <td>Discard oldest</td>
          </tr>
          <tr>
            <td>Witness age requirement</td>
            <td>7 days (configurable)</td>
            <td>Reject witness, log warning</td>
          </tr>
          <tr>
            <td>Minimum witnesses for <tt>KT_VERIFIED</tt></td>
            <td>3 distinct ASN + prefix</td>
            <td>Key remains unverified</td>
          </tr>
          <tr>
            <td>Witness validity period</td>
            <td>30 days (configurable)</td>
            <td>Status reverts to <tt>PENDING</tt> after expiry</td>
          </tr>
        </tbody>
      </table>
    </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" 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>0x00</td><td><tt>E_OK</tt></td><td>Success</td></tr>
            <tr><td>0x01</td><td><tt>E_BAD_ENCODING</tt></td><td>Invalid CBOR encoding</td></tr>
            <tr><td>0x02</td><td><tt>E_UNKNOWN_VERB</tt></td><td>Unknown verb</td></tr>
            <tr><td>0x03</td><td><tt>E_RATE_LIMIT</tt></td><td>Rate limit exceeded</td></tr>
            <tr><td>0x04</td><td><tt>E_KT_UNVERIFIED</tt></td><td>Key not KT_VERIFIED</td></tr>
            <tr><td>0x05</td><td><tt>E_DVV_CONFLICT</tt></td><td>DVV merge conflict</td></tr>
            <tr><td>0x06</td><td><tt>E_FLOW_CONTROL_BLOCK</tt></td><td>Flow control window zero (use <tt>EAGAIN</tt>)</td></tr>
            <tr><td>0x07</td><td><tt>E_VIOLATION</tt></td><td>Violation detected</td></tr>
            <tr><td>0x08</td><td><tt>E_PROFILE_MISMATCH</tt></td><td>No common capabilities</td></tr>
          </tbody>
        </table>
        
        <t>Registration policy: IETF Review for codes 0x00-0x7F.</t>
      </section>
      
      <section anchor="verb_registry" numbered="true" toc="default">
        <name>QUIP Verbs Registry</name>
        <t>IANA is requested to create a registry titled "QUIP Verbs"
        with the following initial contents:</t>
        
        <table align="center">
          <thead>
            <tr><th>Verb</th><th>Tier</th><th>Description</th></tr>
          </thead>
          <tbody>
            <tr><td><tt>announce_key</tt></td><td>T0 CTRL</td><td>Publish Key Claim</td></tr>
            <tr><td><tt>announce_witness</tt></td><td>T0 CTRL</td><td>Publish witness statement</td></tr>
            <tr><td><tt>query</tt></td><td>T0 CTRL</td><td>Request key or witnesses</td></tr>
            <tr><td><tt>error</tt></td><td>T0 CTRL</td><td>Error notification</td></tr>
            <tr><td><tt>get</tt></td><td>T1 SYNC</td><td>Request resource with DVV</td></tr>
            <tr><td><tt>set</tt></td><td>T1 SYNC</td><td>Update resource</td></tr>
            <tr><td><tt>sync</tt></td><td>T1 SYNC</td><td>Bulk sync response</td></tr>
            <tr><td><tt>send_start</tt></td><td>T2 BULK</td><td>Initiate transfer</td></tr>
            <tr><td><tt>send_chunk</tt></td><td>T2 BULK</td><td>Chunked data</td></tr>
            <tr><td><tt>send_complete</tt></td><td>T2 BULK</td><td>Finalize transfer</td></tr>
            <tr><td><tt>emit</tt></td><td>T3 EVENT</td><td>Ephemeral event</td></tr>
          </tbody>
        </table>
        
        <t>Registration policy: IETF Review for new verbs.</t>
      </section>
      
      <section anchor="cbor_tag" numbered="true" toc="default">
        <name>CBOR Tag 65536 Registration</name>
        <t>IANA is requested to register the following CBOR tag:</t>
        <dl>
          <dt>Tag:</dt><dd>65536</dd>
          <dt>Data Item:</dt><dd>CBOR array</dd>
          <dt>Semantic:</dt><dd>Container for QUIP protocol messages</dd>
          <dt>Reference:</dt><dd>This document</dd>
        </dl>
      </section>
    </section>

    <section anchor="security_considerations" numbered="true" toc="default">
      <name>Security Considerations</name>
      
      <section anchor="threat_model" numbered="true" toc="default">
        <name>Threat Model Summary</name>
        <t>QUIP defends against:</t>
        <ul>
          <li>Domain impersonation (via self-signed Key Claims + KT witnesses)</li>
          <li>Replay attacks (via message_id cache and seq_reset timestamp bound)</li>
          <li>DNS hijacking (downgraded to detectable DoS via KT+TOFU)</li>
          <li>Split-brain/fork (via DVV deterministic merge)</li>
          <li>Gossip amplification (via TTL and rate limits)</li>
        </ul>
        <t>QUIP does NOT defend against:</t>
        <ul>
          <li>Anonymity attacks (use Tor)</li>
          <li>Witness collusion (requires ≥3 independent ASNs + prefixes)</li>
          <li>Key loss (no recovery mechanism &#x2014; intentional)</li>
        </ul>
      </section>
      
      <section anchor="kt_attacks" numbered="true" toc="default">
        <name>Key Transparency Attack Analysis</name>
        <t><strong>Sybil witnesses:</strong> An attacker spawning N witnesses in
        the same ASN fails ASN diversity requirement. Mitigation: ASN diversity
        + /24 diversity required. Cost estimate: $3k/month per distinct ASN
        minimum. For 3-of-N security, attacker budget must exceed $9k/month
        to control all witnesses.</t>
        
        <t><strong>Eclipse attack on KT gossip:</strong> An attacker controlling
        all of a peer's gossip connections could suppress witness statements.
        Mitigation: Witness set must include ≥1 out-of-band verified seed.
        Implementations <bcp14>SHOULD</bcp14> ship with 5 seeds from 3 distinct
        organizations.</t>
        
        <t><strong>Age requirement:</strong> The 7-day minimum age for witnesses
        prevents instant Sybil attacks. An attacker must maintain infrastructure
        for 7 days before their witnesses become eligible. This window aligns
        with certificate transparency log monitoring periods.</t>
        
        <t><strong>Witness expiry:</strong> The 30-day witness validity period
        forces periodic re-attestation, preventing stale trust. A key that loses
        all valid witnesses reverts to TOFU-only <tt>PENDING</tt> status.</t>
      </section>
      
      <section anchor="seq_reset_attacks" numbered="true" toc="default">
        <name>Sequence Reset Attack Analysis</name>
        <t>A <tt>seq_reset</tt> with a timestamp significantly older than the last
        seen message could indicate an attempted replay. The <tt>max(60s, heartbeat_interval * 3)</tt>
        bound limits the replay window. An attacker who compromises a NodeId's
        private key can issue a <tt>seq_reset</tt> with a fresh timestamp, but
        this also allows key rotation; the witness requirement for <tt>KT_VERIFIED</tt>
        status transfer provides a separate defense.</t>
      </section>
    </section>

    <section anchor="privacy_considerations" numbered="true" toc="default">
      <name>Privacy Considerations</name>
      
      <t>QUIP's design has several privacy implications that implementers and
      deployers <bcp14>MUST</bcp14> consider:</t>
      
      <ul>
        <li><strong>NodeId reuse</strong> enables correlation of a user's activity
            across different services and over time. Unlike ephemeral identifiers,
            the Ed25519 key is permanent.</li>
        <li><strong>KT witness statements</strong> include the witness's ASN and
            IPv4/IPv6 prefix. This creates a richer topology map than v00, where
            witness independence was based only on domain names. A peer that
            receives many witness statements can infer network topology.</li>
        <li><strong>Gossip propagation</strong> reveals which keys a peer is
            interested in and which witnesses it trusts.</li>
        <li><strong>Domain hints</strong> in Key Claims are advisory but may
            reveal a user's network location or affiliation.</li>
      </ul>
      
      <t><strong>Mitigations (implementations <bcp14>SHOULD</bcp14> support):</strong></t>
      <ul>
        <li>Key rotation (<xref target="kt_rotation"/>) to limit correlation windows</li>
        <li>Tor or VPN transport for metadata protection</li>
        <li>Ephemeral NodeIds for privacy-sensitive interactions (application-layer)</li>
        <li>Relay routing to hide origin IP from direct peers</li>
      </ul>
      
      <t><strong>Linkability through rotation chains:</strong> Key rotation preserves
      identity continuity for accountability. All keys in a rotation chain are
      cryptographically linked to the genesis NodeId. This linkage is intentional
      and permanent. Rotating keys does NOT provide unlinkability or anonymity.</t>
    </section>

    <section anchor="implementation_status" numbered="true" toc="default">
      <name>Implementation Status</name>
      <t>This section records the status of known implementations of the
      QUIP protocol at the time of publication of this Internet-Draft.
      It is provided to aid interoperability and will be removed before
      publication as an RFC. See <xref target="RFC7942"/> for the
      terminology and intent of this section.</t>
      
      <t><em>Reference Implementation:</em> A reference implementation
      is planned but not yet available at the time of this submission.
      The author intends to publish a minimal implementation before the
      expiration of this draft. Interested parties should contact the
      author for updates.</t>
      
      <t><em>Other Implementations:</em> No other implementations are
      known at this time.</t>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>
      
      <references>
        <name>Normative References</name>
        
        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="S. Bradner"/>
            <date 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="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="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>
        
        <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>
        <name>Informative References</name>
        
        <reference anchor="RFC7942" target="https://www.rfc-editor.org/info/rfc7942">
          <front>
            <title>Improving Awareness of Running Code: The Implementation Status Section</title>
            <author initials="Y." surname="Sheffer" fullname="Y. Sheffer"/>
            <author initials="A." surname="Farrel" fullname="A. Farrel"/>
            <date year="2016" month="July"/>
          </front>
          <seriesInfo name="BCP" value="205"/>
          <seriesInfo name="RFC" value="7942"/>
          <seriesInfo name="DOI" value="10.17487/RFC7942"/>
        </reference>

        <reference anchor="RFC9114" target="https://www.rfc-editor.org/info/rfc9114">
          <front>
            <title>HTTP/3</title>
            <author initials="M." surname="Bishop" fullname="M. Bishop"/>
            <date year="2022" month="June"/>
          </front>
          <seriesInfo name="RFC" value="9114"/>
          <seriesInfo name="DOI" value="10.17487/RFC9114"/>
        </reference>
      </references>
    </references>
  
    <section anchor="why_quip" numbered="false" toc="default">
      <name>Why QUIP, Why Now</name>
      
      <t>QUIP combines five existing primitives into a coherent federation protocol: QUIC transport, Ed25519 self-sovereign identity, Dotted Version Vectors, Key Transparency with Trust-On-First-Use, and explicit <tt>EAGAIN</tt> backpressure. None of these primitives are new. Their composition is.</t>
      
      <t><strong>Why this composition did not exist earlier</strong></t>
      
      <ol>
        <li><strong>Browser-centric standards froze the transport layer.</strong> QUIC was standardized for HTTP/3 <xref target="RFC9114"/>. The IETF and W3C charters presumed HTTP semantics for all web-adjacent protocols. Raw QUIC with application-defined streams, datagrams, and flow-control contracts was treated as an implementation detail, not a platform. Browsers still do not expose QUIC datagrams or stream-level <tt>EAGAIN</tt> to JavaScript. Any federation protocol that assumed HTTP as transport inherited head-of-line blocking and hidden buffering.</li>
        
        <li><strong>WebPKI incumbency blocked self-sovereign identity.</strong> Ed25519 keys and self-signed certificates have existed since 2011. But deployment reality favored WebPKI because browsers and operating systems ship CA bundles. Federation protocols either delegated identity to OAuth/OIDC brokers or adopted domain-based DANE. DANE depends on DNSSEC, which remains at ∼1.3% global deployment. The alternative — Trust-On-First-Use with Key Transparency gossip — was proven in Certificate Transparency and CONIKS, but not standardized for end-user identity.</li>
        
        <li><strong>Database techniques stayed inside databases.</strong> Dotted Version Vectors were published in 2012 and deployed in Riak, Cassandra, and similar systems. They were never exposed as a wire primitive because federation protocols assumed eventual consistency was an application problem. The result was either O(nodes) vector clocks that fail at federation scale, or last-write-wins.</li>
        
        <li><strong>Infrastructure incentives rewarded buffering.</strong> gRPC, GraphQL, and REST frameworks hide backpressure behind in-memory queues. For a decade, RAM was cheap and SREs absorbed the cost. A protocol that returns <tt>EAGAIN</tt> instead of buffering would have been rejected as "hard to use." The operational pain of OOM kills was socialized across the industry, not attributed to the protocol.</li>
        
        <li><strong>Standards governance resisted deletion.</strong> A queueless, brokerless protocol requires removing HTTP, DNSSEC, and WebPKI from the critical path. Working groups chartered to "extend HTTP" cannot publish a document that says "do not use HTTP." The technical arguments existed; the procedural venue did not.</li>
      </ol>
      
      <t><strong>Why now</strong></t>
      
      <ol>
        <li><strong>Regulatory pressure.</strong> The EU Digital Markets Act requires designated gatekeepers to support third-party federation. ActivityPub demonstrated demand but also exposed scalability and identity weaknesses. Gatekeepers now have legal and financial incentives to adopt a protocol that is both brokerless and deployable without DNSSEC.</li>
        
        <li><strong>Cost pressure.</strong> AI inference and real-time applications have made RAM and tail latency first-order costs. A 10 GB per-server buffer is no longer "free." The <tt>EAGAIN</tt> contract in QUIP converts hidden memory growth into visible backpressure, shifting the optimization burden from SREs to application developers.</li>
        
        <li><strong>Implementation maturity.</strong> Production QUIC stacks — <tt>quinn</tt>, <tt>s2n-quic</tt>, <tt>msquic</tt> — are stable and support datagrams <xref target="RFC9221"/>. Rust and Swift now have mature Ed25519 and CBOR implementations. The engineering cost to implement QUIP dropped from "research project" to "3 months for one engineer."</li>
        
        <li><strong>Existence proof.</strong> Mastodon and Bluesky proved users want federation. Discord and WhatsApp proved users expect real-time without head-of-line blocking. The market is educated. The missing piece was a transport that provides causality, identity, and backpressure without brokers or DNSSEC.</li>
      </ol>
      
      <t>QUIP exists now because the pain of the status quo — DMA fines, OOM kills, DNS hijacks, and merge conflicts — finally exceeds the political cost of deleting HTTP, DNSSEC, and WebPKI from the federation path.</t>
      
      <t>The primitives were ready. The incentives were not. Now they are.</t>
    </section>
  </back>
</rfc>