<?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-02" 
     ipr="trust200902" 
     submissionType="IETF" 
     xml:lang="en"
     version="3"
     consensus="true">

  <front>
    <title abbrev="QUIP">QUIC Identity Protocol</title>
    <seriesInfo name="Internet-Draft" value="draft-mututi-quip-02"/>
    
    <author fullname="Junior Joseph Mututi" 
            initials="J. J."
            surname="Mututi">
      <organization>Individual</organization>
      <address>
        <postal>
          <street>--</street>
          <city>--</city>
          <country>Zimbabwe</country>
        </postal>
        <email>jjmututicloud@gmail.com</email>
      </address>
    </author>
    
    <date year="2026" month="June" day="25"/>
    
    <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 <xref target="RFC8032"/> 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. It uses TLS 1.3 <xref target="RFC8446"/> for transport security.</t>
    </section>

    <section anchor="changes_from_01" numbered="true" toc="default">
      <name>Changes from Version 01</name>
      <t>This version incorporates significant privacy enhancements while maintaining complete decentralization:</t>
      <ul>
        <li><strong>Decoupled transport from long-term identity:</strong> Added ephemeral session keys derived via HKDF with fresh nonce per connection. T1/T2/T3 operations use SessionKey, not permanent NodeId. Permanent NodeId revealed only on T0 for identity verification.</li>
        <li><strong>Privacy-preserving witness metadata:</strong> Replaced raw ASN and IP prefix fields with zero-knowledge diversity proofs. Witnesses prove distinct network tier without revealing actual ASN/prefix.</li>
        <li><strong>Blinded identity queries:</strong> All T0 identity queries cryptographically blinded via Pedersen commitments with relay chains (2+ independent relays).</li>
        <li><strong>Discontinuous identity mode:</strong> Added ability to break rotation chain permanently while preserving data portability via export token. Enables right to be forgotten.</li>
        <li><strong>Decentralized hardware verification:</strong> RATS integration as optional validation mechanism - no mandatory TPM, no vendor lock-in.</li>
        <li><strong>Multi-party attestation:</strong> Hardware verification performed across 3+ independent witnesses using multi-party computation. No single point of trust.</li>
        <li><strong>Threshold signatures (2-of-3):</strong> NodeId private key split across multiple devices. Any single compromised device doesn't expose full key.</li>
        <li><strong>Gossip-based revocation:</strong> No central revocation list. Compromise notices gossiped through existing witness network with 5+ independent confirmations.</li>
        <li><strong>Adaptive traffic obfuscation:</strong> Traffic mimics common protocols (HTTP/3, WebRTC, SSH) with peer-to-peer mixing. No fixed padding overhead.</li>
        <li><strong>Expanded IANA registries:</strong> Added error codes <tt>E_UNBLIND_FAILED</tt>, <tt>E_RELAY_UNREACHABLE</tt> and verbs <tt>query_blinded</tt>, <tt>discontinuity</tt>.</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 <xref target="RFC8032"/> public key (raw bytes). The root of identity.</dd>
        <dt><tt>SessionKey</tt></dt><dd>32-byte ephemeral Ed25519 key derived from NodeId via HKDF with fresh nonce per connection. Used for transport-level operations instead of exposing permanent NodeId.</dd>
        <dt><tt>BlindedQuery</tt></dt><dd>A cryptographic commitment (e.g., Pedersen commitment) of a NodeId with fresh nonce, used for privacy-preserving identity queries on T0.</dd>
        <dt><tt>DiversityProof</tt></dt><dd>Zero-knowledge proof demonstrating witness belongs to unique network tier without revealing actual ASN or prefix.</dd>
        <dt><tt>RelayChain</tt></dt><dd>List of intermediate nodes for oblivious routing of queries. MUST contain at least two relays.</dd>
        <dt><tt>ThresholdSignature</tt></dt><dd>Signature requiring t-of-n shares (e.g., 2-of-3) from independent devices. No single device has full private key.</dd>
        <dt><tt>Key Claim</tt></dt><dd>Self-signed CBOR <xref target="RFC8949"/> object asserting a NodeId with optional domain hint.</dd>
        <dt><tt>KT+TOFU</tt></dt><dd>Key Transparency + Trust On First Use -- the trust model replacing DNSSEC.</dd>
        <dt><tt>DVV</tt></dt><dd>Dotted Version Vector -- 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 <xref target="RFC8949"/> 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 <xref target="RFC8949"/> 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>

        <t><strong>Ephemeral Session Key Derivation:</strong></t>
        <t>A Key Claim may be used to derive ephemeral session keys via:</t>
        <artwork><![CDATA[
session_key = HKDF-Expand(
  HKDF-Extract(NodeId_private, nonce),
  "QUIP-session-key",
  32
)
session_pub = Ed25519_public_from_private(session_key)
]]></artwork>
        <t>Each new connection <bcp14>SHOULD</bcp14> use a fresh nonce. The session public key is used for all T1, T2, and T3 operations. The permanent NodeId is revealed only during T0 identity verification and key rotation.</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
  kt_proof,                ; CBOR map containing zero-knowledge proof
  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>Diversity Proof Structure:</strong></t>
          <artwork><![CDATA[
kt_proof = {
  "proof_type": "zkp_asn_diversity",
  "proof_data": bytes,   ; ZKP proving distinct network tier
  "commitment": bytes    ; Commitment to actual ASN/prefix
}
]]></artwork>

          <t>Witnesses <bcp14>MUST</bcp14> prove network diversity via zero-knowledge proofs. The ZKP <bcp14>MUST</bcp14> prove the witness belongs to a distinct network tier without revealing the actual ASN or prefix. Implementations <bcp14>SHOULD</bcp14> use Bulletproofs. No trusted setup is required.</t>

          <t><strong>Blinded Queries:</strong> All T0 queries for identity keys <bcp14>MUST</bcp14> be cryptographically blinded:</t>
          <artwork><![CDATA[
query_commitment = Commit(NodeId || nonce)
blinded_query = Blind(query_commitment)

["query", "key", blinded_query, relay_chain]
["query", "witnesses", blinded_query, relay_chain]
]]></artwork>

          <t>Where <tt>Commit()</tt> is a Pedersen commitment and <tt>relay_chain</tt> specifies 2+ intermediate nodes. Each relay forwards the query without learning the target identity. Responses are encrypted to the querier's session key.</t>

          <t><strong>Relay Chain Requirements:</strong></t>
          <ul>
            <li>Querier sends blinded query to first relay</li>
            <li>First relay forwards to second relay without learning target identity</li>
            <li>Second relay forwards to destination</li>
            <li>Destination processes blinded query, encrypts response</li>
            <li>Response returns through relay chain in reverse</li>
            <li>Only original querier can decrypt with session key</li>
          </ul>
          <t>Relays <bcp14>MUST NOT</bcp14> log query metadata. Relays <bcp14>MAY</bcp14> be any QUIP peer; no central relay infrastructure is required.</t>

          <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, less than 3 witnesses) -- 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) -- 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>
        </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>

          <t><strong>Discontinuous Identity Mode:</strong> Implementations <bcp14>MAY</bcp14> support DISCONTINUOUS identity mode where the user breaks the cryptographic rotation chain for privacy purposes.</t>
          
          <artwork><![CDATA[
tagged(65536, [
  "identity_discontinuity",
  old_NodeId,              ; 32 bytes
  new_NodeId,              ; 32 bytes
  timestamp,               ; Unix milliseconds
  export_token,            ; bytes (optional, for data portability)
  signature                ; 64 bytes (by old_NodeId)
])
]]></artwork>

          <t>Rules for discontinuous mode:</t>
          <ul>
            <li>The old NodeId signs a discontinuity attestation</li>
            <li>The new NodeId has NO cryptographic link to the old identity</li>
            <li><tt>KT_VERIFIED</tt> status does NOT transfer to the new identity</li>
            <li>The new identity starts in <tt>PENDING</tt>/TOFU state</li>
            <li>The <tt>export_token</tt> <bcp14>MAY</bcp14> prove ownership of old data without linking identities</li>
            <li>Once discontinuous, the old NodeId cannot be reclaimed</li>
          </ul>

          <t><strong>Right to be forgotten:</strong> Old NodeId <bcp14>MAY</bcp14> request witnesses to tombstone its key via gossip-based revocation (<xref target="gossip_revocation"/>).</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="gossip_revocation" numbered="true" toc="default">
      <name>Gossip-Based Revocation</name>
      <t>QUIP uses gossip-based revocation with no central list or authority:</t>
      
      <ul>
        <li>When compromise suspected, user signs revocation notice</li>
        <li>Notices gossiped through existing witness network (no central point)</li>
        <li>Witnesses independently verify: 5+ witnesses must confirm</li>
        <li>Once confirmed, key is tombstoned locally</li>
        <li>No central list: each witness maintains its own tombstone set</li>
      </ul>

      <t>Benefits:</t>
      <ul>
        <li>No single point of failure</li>
        <li>No trusted third party</li>
        <li>Can't be blocked/censored</li>
        <li>Gradual propagation (like DNS, but better)</li>
      </ul>

      <t><strong>Emergency Revocation:</strong> Users <bcp14>MAY</bcp14> publish revocation notices through any available witness. The witness network ensures propagation. No central revocation list is required.</t>
    </section>

    <section anchor="threshold_signatures" numbered="true" toc="default">
      <name>Threshold Signatures for Endpoint Defense</name>
      
      <t>To defend against endpoint compromise without vendor lock-in, QUIP supports threshold signatures:</t>
      
      <ul>
        <li>NodeId private key is split using Shamir Secret Sharing</li>
        <li>Shares distributed across 3+ independent devices</li>
        <li>Threshold t-of-n (e.g., 2-of-3) required to sign</li>
        <li>Any single compromised device doesn't expose full key</li>
        <li>No hardware vendor controls the entire key</li>
      </ul>

      <t>Implementation options:</t>
      <ul>
        <li>User: Mobile phone (share 1)</li>
        <li>User: Desktop/laptop (share 2)</li>
        <li>User: Hardware wallet/USB key (share 3) - OPTIONAL, not required</li>
      </ul>

      <t><strong>Key rotation when device compromised:</strong></t>
      <ul>
        <li>Generate new share for replacement device</li>
        <li>Use existing shares to update threshold</li>
        <li>No centralized authority involved</li>
      </ul>

      <t>Threshold signatures are OPTIONAL. Users <bcp14>MAY</bcp14> choose single-device keys for simplicity. The protocol is hardware-agnostic.</t>
    </section>

    <section anchor="quip_cbor" numbered="true" toc="default">
      <name>Deterministic CBOR</name>
      <t>QUIP-CBOR is <xref target="RFC8949"/> 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>

      <t><strong>Identity Separation:</strong> All T1, T2, and T3 operations <bcp14>MUST</bcp14> use the ephemeral <tt>SessionKey</tt>, not the permanent <tt>NodeId</tt>. The permanent <tt>NodeId</tt> is revealed only on T0 for identity verification purposes.</t>

      <t><strong>Traffic Obfuscation:</strong> Implementations <bcp14>SHOULD</bcp14> support adaptive traffic obfuscation:</t>
      <ul>
        <li>Traffic mimics common protocols (HTTP/3, WebRTC, SSH)</li>
        <li>Peer-to-peer traffic mixing with random relays</li>
        <li>Rate adaptation based on network conditions</li>
        <li>No fixed padding scheme - adaptive based on threat detection</li>
        <li>Minimal overhead: +10-20% instead of +100%</li>
      </ul>
      
      <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
["query_blinded", "key", blinded_query,        ; Blinded identity query
  relay_chain]
["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 + RATS (optional)</td>
            <td>High-security, regulated environments</td>
          </tr>
          <tr>
            <td>RATS-ONLY (experimental)</td>
            <td>Decentralized RATS attestation (no DNSSEC)</td>
            <td>Hardware verification without DNSSEC</td>
          </tr>
          <tr>
            <td>LEGACY (deprecated)</td>
            <td>WebPKI only</td>
            <td>Legacy transition, removal in v02</td>
          </tr>
        </tbody>
      </table>

      <t><strong>Decentralized Attestation:</strong></t>
      <ul>
        <li>No centralized attestation services (Google/Microsoft/Amazon)</li>
        <li>Witness cross-verification: 5+ independent witnesses cross-validate</li>
        <li>Multi-party computation (MPC): Attestation verification across 3+ witnesses</li>
        <li>No single point of trust</li>
      </ul>

      <t><strong>RATS Integration (Optional):</strong> Nodes <bcp14>MAY</bcp14> use RATS attestation if hardware support is available. RATS is NOT required and does NOT create vendor lock-in. The protocol works identically without hardware attestation.</t>
      
      <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 derives ephemeral session key from NodeId with fresh nonce</li>
        <li>Client sends session_pub in handshake extension</li>
        <li>Server derives its own session key and responds</li>
        <li>All subsequent T1/T2/T3 traffic uses these session keys</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 NOT</bcp14> 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 <xref target="RFC8949"/> 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>
            <tr><td>0x09</td><td><tt>E_UNBLIND_FAILED</tt></td><td>Failed to unblind commitment</td></tr>
            <tr><td>0x0A</td><td><tt>E_RELAY_UNREACHABLE</tt></td><td>Relay in chain unreachable</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>query_blinded</tt></td><td>T0 CTRL</td><td>Blinded identity query with relay chain</td></tr>
            <tr><td><tt>discontinuity</tt></td><td>T0 CTRL</td><td>Break rotation chain permanently</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 -- 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 anchor="decentralized_threats" numbered="true" toc="default">
        <name>Decentralized Threat Model</name>
        
        <t>QUIP's defense-in-depth WITHOUT centralization:</t>
        
        <table align="center">
          <thead>
            <tr><th>Threat</th><th>QUIP Mitigation</th><th>Decentralized?</th></tr>
          </thead>
          <tbody>
            <tr><td>State-level zero-day</td><td>Multi-party computation across independent witnesses</td><td>YES</td></tr>
            <tr><td>Endpoint compromise</td><td>Threshold signatures - no single device has full key</td><td>YES</td></tr>
            <tr><td>Traffic volume/time correlation</td><td>Adaptive obfuscation mimicking other protocols</td><td>YES</td></tr>
            <tr><td>CA compromise</td><td>Self-sovereign identity</td><td>YES</td></tr>
            <tr><td>Vendor lock-in</td><td>Hardware-agnostic implementation</td><td>YES</td></tr>
            <tr><td>Centralized revocation</td><td>Gossip-based revocation</td><td>YES</td></tr>
          </tbody>
        </table>

        <t><strong>Design Principle:</strong> QUIP accepts that state-level adversaries may have capabilities beyond the protocol's defense. However, any mitigation <bcp14>MUST NOT</bcp14> reintroduce centralization. The goal is to raise the cost of attack to &gt;$10M USD while preserving full self-sovereignty.</t>

        <t><strong>Acceptable Residual Risks:</strong></t>
        <ul>
          <li>Hardware zero-days: Require 3+ simultaneous zero-days to compromise threshold signatures</li>
          <li>Global traffic analysis: Countered by adaptive obfuscation</li>
          <li>NodeId tracking: Mitigated by optional rotation</li>
          <li>Active surveillance: Mitigated by random relay selection</li>
        </ul>

        <t><strong>Unacceptable "Solutions" - Explicitly Rejected:</strong></t>
        <ul>
          <li>Centralized attestation services (Google/Microsoft/Amazon as oracles)</li>
          <li>Mandatory TPM/HSM (vendor lock-in)</li>
          <li>Centralized revocation lists (DNS-like single point)</li>
          <li>Fixed padding schemes (centralized decision)</li>
        </ul>
      </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>

      <t><strong>DISCONTINUOUS mode</strong> provides true identity unlinkability:</t>
      <ul>
        <li>Users can break the rotation chain without losing data</li>
        <li>The <tt>export_token</tt> enables data portability without identity linkage</li>
        <li>Historical accountability is traded for user privacy</li>
        <li>Witnesses <bcp14>MUST NOT</bcp14> link discontinuous identities in logs</li>
      </ul>
    </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 <xref target="RFC8032"/> 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>