Skip to main content

The DNSCrypt Protocol
draft-denis-dprive-dnscrypt-11

Document Type Active Internet-Draft (individual)
Author Frank Denis
Last updated 2026-07-23
RFC stream (None)
Intended RFC status (None)
Formats
Stream Stream state (No stream defined)
Consensus boilerplate Unknown
RFC Editor Note (None)
IESG IESG state I-D Exists
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-denis-dprive-dnscrypt-11
Network Working Group                                           F. Denis
Internet-Draft                                    Individual Contributor
Intended status: Informational                              23 July 2026
Expires: 24 January 2027

                         The DNSCrypt Protocol
                     draft-denis-dprive-dnscrypt-11

Abstract

   The DNSCrypt protocol is designed to encrypt and authenticate DNS
   traffic between clients and resolvers.

   This document specifies the protocol and its implementation,
   providing a standardized approach to securing DNS communications.

   DNSCrypt improves confidentiality, integrity, and resistance to
   attacks affecting the original DNS protocol while maintaining
   compatibility with existing DNS infrastructure.

About This Document

   This note is to be removed before publishing as an RFC.

   The latest revision of this draft can be found at
   https://dnscrypt.github.io/dnscrypt-protocol/.  Status information
   for this document may be found at https://datatracker.ietf.org/doc/
   draft-denis-dprive-dnscrypt/.

   Source for this draft and an issue tracker can be found at
   https://github.com/DNSCrypt/dnscrypt-protocol.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

Denis                    Expires 24 January 2027                [Page 1]
Internet-Draft                  DNSCrypt                       July 2026

   This Internet-Draft will expire on 24 January 2027.

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
   2.  Conventions And Definitions . . . . . . . . . . . . . . . . .   4
   3.  Protocol Flow . . . . . . . . . . . . . . . . . . . . . . . .   4
   4.  Protocol Components . . . . . . . . . . . . . . . . . . . . .   6
   5.  Protocol Description  . . . . . . . . . . . . . . . . . . . .   9
     5.1.  Overview  . . . . . . . . . . . . . . . . . . . . . . . .   9
     5.2.  Transport . . . . . . . . . . . . . . . . . . . . . . . .  11
     5.3.  Session Establishment . . . . . . . . . . . . . . . . . .  11
     5.4.  Query Processing  . . . . . . . . . . . . . . . . . . . .  12
       5.4.1.  Padding For Client Queries Over UDP . . . . . . . . .  12
       5.4.2.  Client Queries Over UDP . . . . . . . . . . . . . . .  13
       5.4.3.  Padding For Client Queries Over TCP . . . . . . . . .  14
       5.4.4.  Client Queries Over TCP . . . . . . . . . . . . . . .  15
       5.4.5.  Padding For Resolver Responses  . . . . . . . . . . .  15
       5.4.6.  Resolver Responses Over UDP . . . . . . . . . . . . .  16
       5.4.7.  Resolver Responses Over TCP . . . . . . . . . . . . .  17
     5.5.  Certificates  . . . . . . . . . . . . . . . . . . . . . .  17
   6.  Conformance Checklist . . . . . . . . . . . . . . . . . . . .  23
   7.  Implementation Status . . . . . . . . . . . . . . . . . . . .  25
   8.  Security Considerations . . . . . . . . . . . . . . . . . . .  25
     8.1.  Protocol Security . . . . . . . . . . . . . . . . . . . .  25
     8.2.  Implementation Security . . . . . . . . . . . . . . . . .  26
     8.3.  Attack Mitigation . . . . . . . . . . . . . . . . . . . .  27
     8.4.  Privacy Considerations  . . . . . . . . . . . . . . . . .  28
     8.5.  Operational Security  . . . . . . . . . . . . . . . . . .  28
   9.  Operational Considerations  . . . . . . . . . . . . . . . . .  29
   10. Anonymized DNSCrypt . . . . . . . . . . . . . . . . . . . . .  31
     10.1.  Protocol Overview  . . . . . . . . . . . . . . . . . . .  31
     10.2.  Client Queries . . . . . . . . . . . . . . . . . . . . .  31
     10.3.  Relay Behavior . . . . . . . . . . . . . . . . . . . . .  33
     10.4.  Operational Considerations . . . . . . . . . . . . . . .  34
   11. Post-Quantum Key Exchange (PQDNSCrypt)  . . . . . . . . . . .  35
     11.1.  Key Encapsulation Instead of Key Agreement . . . . . . .  35

Denis                    Expires 24 January 2027                [Page 2]
Internet-Draft                  DNSCrypt                       July 2026

     11.2.  PQ Certificates  . . . . . . . . . . . . . . . . . . . .  36
     11.3.  Certificate Retrieval Amplification  . . . . . . . . . .  38
     11.4.  PQ Key Derivation  . . . . . . . . . . . . . . . . . . .  39
     11.5.  PQ Query and Response Format . . . . . . . . . . . . . .  40
     11.6.  Padding and Transport  . . . . . . . . . . . . . . . . .  41
     11.7.  Stateless Resumption . . . . . . . . . . . . . . . . . .  41
       11.7.1.  Issuing a Ticket . . . . . . . . . . . . . . . . . .  42
       11.7.2.  Resuming . . . . . . . . . . . . . . . . . . . . . .  43
       11.7.3.  Resumption Considerations  . . . . . . . . . . . . .  45
     11.8.  PQ and Anonymized DNSCrypt . . . . . . . . . . . . . . .  46
     11.9.  PQ Downgrade Protection  . . . . . . . . . . . . . . . .  47
     11.10. PQ Security Considerations . . . . . . . . . . . . . . .  47
   12. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  48
   13. Appendix 1: The Box-XChaChaPoly Algorithm . . . . . . . . . .  48
     13.1.  Conventions and Definitions  . . . . . . . . . . . . . .  48
     13.2.  HChaCha20  . . . . . . . . . . . . . . . . . . . . . . .  49
     13.3.  Test Vector For The HChaCha20 Block Function . . . . . .  49
     13.4.  ChaCha20_DJB . . . . . . . . . . . . . . . . . . . . . .  50
     13.5.  XChaCha20_DJB  . . . . . . . . . . . . . . . . . . . . .  50
     13.6.  XChaCha20_DJB-Poly1305 . . . . . . . . . . . . . . . . .  50
     13.7.  The Box-XChaChaPoly Algorithm  . . . . . . . . . . . . .  51
   14. Appendix 2: DNSCrypt Test Vectors . . . . . . . . . . . . . .  52
     14.1.  Pinned Inputs  . . . . . . . . . . . . . . . . . . . . .  52
     14.2.  Public Keys and Shared Key . . . . . . . . . . . . . . .  54
     14.3.  Certificate  . . . . . . . . . . . . . . . . . . . . . .  54
     14.4.  Certificate Retrieval  . . . . . . . . . . . . . . . . .  55
     14.5.  Client Query (UDP) . . . . . . . . . . . . . . . . . . .  56
     14.6.  Server Response (UDP)  . . . . . . . . . . . . . . . . .  58
     14.7.  Padding and Transport Notes  . . . . . . . . . . . . . .  59
     14.8.  Negative Cases . . . . . . . . . . . . . . . . . . . . .  59
   15. Appendix 3: PQ Test Vector Structure  . . . . . . . . . . . .  60
     15.1.  Provisional Assignments  . . . . . . . . . . . . . . . .  60
     15.2.  Pinned Inputs  . . . . . . . . . . . . . . . . . . . . .  61
     15.3.  Profile Extension and Signature Input  . . . . . . . . .  62
     15.4.  Full X-Wing Query  . . . . . . . . . . . . . . . . . . .  64
     15.5.  Full Response and Ticket Issuance  . . . . . . . . . . .  65
     15.6.  Resumed Query and Response . . . . . . . . . . . . . . .  66
     15.7.  Negative Cases . . . . . . . . . . . . . . . . . . . . .  67
     15.8.  Generated Values . . . . . . . . . . . . . . . . . . . .  68
   16. Normative References  . . . . . . . . . . . . . . . . . . . .  70
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  71

1.  Introduction

   The Domain Name System (DNS) [RFC1035] is a critical component of
   Internet infrastructure, but its original design did not include
   security features to protect the confidentiality and integrity of
   queries and responses.

Denis                    Expires 24 January 2027                [Page 3]
Internet-Draft                  DNSCrypt                       July 2026

   This fundamental security gap exposes DNS traffic to eavesdropping,
   tampering, and various attacks that can compromise user privacy and
   network security.

   To address these vulnerabilities, this document defines the DNSCrypt
   protocol, which encrypts and authenticates DNS queries and responses,
   providing strong confidentiality, integrity, and resistance to
   attacks affecting the original DNS protocol.

   The protocol is designed to be lightweight, extensible, and simple to
   implement securely on top of existing DNS infrastructure, offering a
   practical solution for securing DNS communications without requiring
   significant changes to current systems.

   The following sections detail the protocol's design, starting with an
   overview of its operation and then progressing through the technical
   specifications needed for implementation.

2.  Conventions And Definitions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
   "OPTIONAL" in this document are to be interpreted as described in
   BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
   capitals, as shown here.

3.  Protocol Flow

   The DNSCrypt protocol consists of two distinct phases:

   1.  *Initial Setup Phase* (one-time):

       *  The client requests the server's certificate

       *  The server responds with its certificate containing public
          keys

   2.  *Ongoing Communication Phase* (repeated as needed):

       *  The client sends encrypted DNS queries

       *  The server responds with encrypted DNS responses

   The following diagram illustrates the complete protocol flow:

Denis                    Expires 24 January 2027                [Page 4]
Internet-Draft                  DNSCrypt                       July 2026

   +--------+                    +--------+
   |        |                    |        |
   | Client |                    | Server |
   |        |                    |        |
   +--------+                    +--------+
       |                             |
       | 1. Request Certificate      |
       |---------------------------->|
       |                             |
       | 2. Certificate Response     |
       |<----------------------------|
       |                             |
       | 3. Encrypted Query          |
       |---------------------------->|
       |                             |
       | 4. Encrypted Query          |
       |---------------------------->|
       |                             |
       | 5. Encrypted Response       |
       |<----------------------------|
       |                             |
       | 6. Encrypted Response       |
       |<----------------------------|
       |                             |
       | 7. Encrypted Query          |
       |---------------------------->|
       |                             |
       | 8. Encrypted Response       |
       |<----------------------------|
       |                             |
       |                             |

   The initial setup phase (steps 1-2) occurs only when:

   *  A client first starts using a DNSCrypt server

   *  The client's cached certificate expires

   *  The client detects a certificate with a higher serial number

   After the initial setup, the client and server engage in the ongoing
   communication phase (steps 3-8), where encrypted queries and
   responses are exchanged as needed.

   This phase can be repeated indefinitely until the certificate expires
   or a new certificate is available.

Denis                    Expires 24 January 2027                [Page 5]
Internet-Draft                  DNSCrypt                       July 2026

   The ongoing communication phase operates with several important
   characteristics that distinguish it from traditional DNS:

   1.  *Stateless Operation*: Each query and response is independent.
       The server does not maintain state between queries.

   2.  *Out-of-Order Responses*: Responses may arrive in a different
       order than the queries were sent.  Each response is self-
       contained and can be processed independently.

   3.  *Concurrent Queries*: A client can send multiple queries without
       waiting for earlier responses, and responses can be processed
       independently as they arrive.

   With this understanding of the protocol flow, we can now examine the
   specific components that make up DNSCrypt packets and their
   structure.

4.  Protocol Components

   The DNSCrypt protocol defines specific packet structures for both
   client queries and server responses.

   These components work together to provide the security properties
   described in the previous section.

   Definitions for client queries:

   *  <dnscrypt-query>: <client-magic> <client-pk> <client-nonce>
      <encrypted-query>

   *  <client-magic>: an 8 byte identifier for the resolver certificate
      chosen by the client (see the Certificates section).

   *  <client-pk>: the client's public key, whose length depends on the
      encryption algorithm defined in the chosen certificate.

   *  <client-sk>: the client's secret key.

   *  <resolver-pk>: the resolver's public key.

Denis                    Expires 24 January 2027                [Page 6]
Internet-Draft                  DNSCrypt                       July 2026

   *  <client-nonce>: a unique query identifier for a given (<client-
      sk>, <resolver-pk>) tuple.  Every newly encrypted DNSCrypt query
      for the same (<client-sk>, <resolver-pk>) tuple MUST use a
      distinct <client-nonce> value, even when the plaintext DNS query
      is being retried.  Retransmitting the same already-encrypted
      DNSCrypt packet does not require changing its nonce.  The length
      of <client-nonce> is determined by the chosen encryption
      algorithm.

   *  AE: the authenticated encryption function for the selected
      certificate.  For Box-XChaChaPoly and PQDNSCrypt (see the Post-
      Quantum Key Exchange section), it is the XChaCha20_DJB-Poly1305
      construction of Appendix 1, whose output is the 16-byte
      authentication tag followed by the ciphertext.  This is the NaCl
      secretbox layout, in which the one-time Poly1305 key is taken from
      the start of the keystream; it is not the AEAD of [RFC8439], and
      the two are not interchangeable.  See Appendix 1 for details.

   *  <encrypted-query>: AE(<shared-key>, <client-nonce> <client-nonce-
      pad>, <client-query> <client-query-pad>)

   *  <shared-key>: the shared key derived from <resolver-pk> and
      <client-sk>, using the key exchange algorithm defined in the
      chosen certificate.

   *  <client-query>: the unencrypted client query.  The query is not
      modified; in particular, the query flags are not altered.  The
      DNS-over-TCP two-byte length prefix is transport framing and is
      not part of the plaintext encrypted by DNSCrypt.

   *  <client-nonce-pad>: <client-nonce> length is half the nonce length
      required by the encryption algorithm.  In client queries, the
      other half, <client-nonce-pad> is filled with NUL bytes.  For <es-
      version> 0x00 0x02 (the encryption-system identifier carried in
      the certificate; see the Certificates section), the encryption
      algorithm uses a 24-byte nonce, so <client-nonce> is 12 bytes and
      <client-nonce-pad> is the remaining 12 NUL bytes.

   *  <client-query-pad>: the variable-length padding.

   Definitions for server responses:

   *  <dnscrypt-response>: <resolver-magic> <nonce> <encrypted-response>

   *  <resolver-magic>: the 0x72 0x36 0x66 0x6e 0x76 0x57 0x6a 0x38 byte
      sequence

   *  <nonce>: <client-nonce> <resolver-nonce>

Denis                    Expires 24 January 2027                [Page 7]
Internet-Draft                  DNSCrypt                       July 2026

   *  <client-nonce>: the nonce sent by the client in the related query.

   *  <client-pk>: the client's public key.

   *  <resolver-sk>: the resolver's secret key.

   *  <resolver-nonce>: a unique response identifier for a given
      (<client-pk>, <resolver-sk>) tuple.  The length of <resolver-
      nonce> depends on the chosen encryption algorithm.  It MUST NOT
      consist only of NUL bytes: the response nonce would then equal the
      query nonce, reusing a key and nonce pair for two different
      plaintexts.  A resolver that picks <resolver-nonce> uniformly at
      random, as deployed resolvers do, satisfies both requirements.

   *  AE: the authenticated encryption function for the selected
      certificate, as described for client queries above.

   *  <encrypted-response>: AE(<shared-key>, <nonce>, <resolver-
      response> <resolver-response-pad>)

   *  <shared-key>: the shared key derived from <resolver-sk> and
      <client-pk>, using the key exchange algorithm defined in the
      chosen certificate.

   *  <resolver-response>: the unencrypted resolver response.  The
      response is not modified; in particular, the query flags are not
      altered.  The DNS-over-TCP two-byte length prefix is transport
      framing and is not part of the plaintext encrypted by DNSCrypt.

   *  <resolver-response-pad>: the variable-length padding.

   The following diagram shows the structure of a DNSCrypt query packet:

Denis                    Expires 24 January 2027                [Page 8]
Internet-Draft                  DNSCrypt                       July 2026

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         Client Magic                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                      Client Public Key                        +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                        Client Nonce                           +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                       Encrypted Query                         +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   The following diagram shows the structure of a DNSCrypt response
   packet:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Resolver Magic                         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                          Nonce                                +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                      Encrypted Response                       +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   These packet structures form the foundation for the protocol
   operations described in the next section, which details how clients
   and servers use these components to establish secure communications.

5.  Protocol Description

5.1.  Overview

   Building on the protocol flow and components described earlier, this
   section provides a detailed examination of how the DNSCrypt protocol
   operates.

   The protocol follows a well-defined sequence of steps:

Denis                    Expires 24 January 2027                [Page 9]
Internet-Draft                  DNSCrypt                       July 2026

   1.  The DNSCrypt client sends a DNS query to a DNSCrypt server to
       retrieve the server's public keys.

   2.  The client generates its own key pair.

   3.  The client encrypts unmodified DNS queries using a server's
       public key, padding them as necessary, and concatenates them to a
       nonce and a copy of the client's public key.  The resulting
       output is transmitted to the server via standard DNS transport
       mechanisms [RFC1035].

   4.  Encrypted queries are decrypted by the server using the attached
       client public key and the server's own secret key.  The output is
       a regular DNS packet that doesn't require any special processing.

   5.  To send an encrypted response, the server truncates the DNS
       response and sets the TC flag if the encrypted response would not
       fit within the size limit, adds padding, and encrypts the result
       using the shared key and a nonce made of the client's nonce
       followed by the resolver's nonce.  The resulting packet is sent
       to the client using standard DNS mechanisms.

   6.  The client authenticates and decrypts the response using the
       shared key and the nonce included in the response.  If the
       response was truncated, the client retries over TCP [RFC7766] and
       can adjust internal parameters.  If not, the output is a regular
       DNS response that can be directly forwarded to applications and
       stub resolvers.

   Key features of the DNSCrypt protocol include:

   *  Stateless operation: Every query can be processed independently
      from other queries, with no session identifiers required.

   *  Flexible key management: Clients can replace their keys whenever
      they want, without extra interactions with servers.

   *  Proxy support: DNSCrypt packets can securely be proxied without
      having to be decrypted, allowing client IP addresses to be hidden
      from resolvers ("Anonymized DNSCrypt").

   *  Shared infrastructure: Recursive DNS servers can accept DNSCrypt
      queries on the same IP address and port used for regular DNS
      traffic.

   *  Attack mitigation: DNSCrypt mitigates two common security
      vulnerabilities in regular DNS over UDP: amplification [RFC5358]
      and fragmentation attacks.

Denis                    Expires 24 January 2027               [Page 10]
Internet-Draft                  DNSCrypt                       July 2026

   These key features enable DNSCrypt to provide robust security while
   maintaining practical deployability.

   The protocol's transport characteristics further support these goals.

5.2.  Transport

   The DNSCrypt protocol can use the UDP and TCP transport protocols.

   DNSCrypt clients and resolvers SHOULD support the protocol via UDP,
   and MUST support it over TCP.

   Both TCP and UDP connections using DNSCrypt SHOULD employ port 443 by
   default.

   The choice of port 443 helps DNSCrypt traffic blend with HTTPS
   traffic, providing some protection against traffic analysis.

   A complete encrypted <dnscrypt-query> packet MUST NOT exceed 4096
   bytes, and resolvers MUST accept queries up to this size over both
   UDP and TCP.

   This bound matches deployed implementations: clients never send
   larger queries, and resolvers stop reading beyond a few kilobytes.

   Once transport is established, the next step is session establishment
   through certificate exchange.

5.3.  Session Establishment

   From the client's perspective, a DNSCrypt session is initiated when
   the client sends an unauthenticated DNS query to a DNSCrypt-capable
   resolver.

   This DNS query contains encoded information about the certificate
   versions supported by the client and a public identifier of the
   desired provider.

   The resolver sends back a collection of signed certificates that the
   client MUST verify using the pre-distributed provider public key.

   Each certificate includes a validity period, a serial number, a
   version that defines a key exchange mechanism, an authenticated
   encryption algorithm and its parameters, as well as a short-term
   public key, known as the resolver public key.

Denis                    Expires 24 January 2027               [Page 11]
Internet-Draft                  DNSCrypt                       July 2026

   Resolvers have the ability to support various algorithms and can
   concurrently advertise multiple short-term public keys (resolver
   public keys).

   The client picks the one with the highest serial number among the
   currently valid ones that match a supported protocol version.

   Every certificate contains a unique magic number that the client MUST
   include at the beginning of their queries.

   This allows the resolver to identify which certificate the client
   selected for crafting a particular query.

   The encryption algorithm, resolver public key, and client magic
   number from the chosen certificate are then used by the client to
   send encrypted queries.

   These queries include the client public key.

   With the knowledge of the chosen certificate and corresponding secret
   key, along with the client's public key, the resolver is able to
   verify, decrypt the query, and then encrypt the response utilizing
   identical parameters.

   Once the session is established through certificate exchange, the
   ongoing query processing follows specific rules for different
   transport protocols and padding requirements.

5.4.  Query Processing

5.4.1.  Padding For Client Queries Over UDP

   Before encryption takes place, queries are padded according to the
   ISO/IEC 7816-4 standard.

   Padding begins with a single byte holding the value 0x80, followed by
   any number of NUL bytes.

   The padding length MUST be at least 1 byte, because ISO/IEC 7816-4
   padding always appends the initial 0x80 delimiter.

   A resolver that has authenticated and decrypted a query MUST accept
   this padding format; it MUST NOT reject a query solely because the
   plaintext length is not a multiple of 64 bytes.

Denis                    Expires 24 January 2027               [Page 12]
Internet-Draft                  DNSCrypt                       July 2026

   <min-query-len> is a variable target length for the complete
   encrypted <dnscrypt-query> packet, including <client-magic>, <client-
   pk>, <client-nonce>, the authentication tag, and the encrypted padded
   DNS query.

   It is initially 256 bytes, and implementations MAY use a larger
   initial value, such as 512 bytes.

   A client pads the plaintext so that the complete UDP DNSCrypt packet
   is at least <min-query-len> bytes; when practical, the padded
   plaintext <client-query> <client-query-pad> SHOULD be a multiple of
   64 bytes.

   This target is a sender-side anti-amplification and privacy
   parameter, not an additional receiver-side validity check.

5.4.2.  Client Queries Over UDP

   UDP-based client queries need to follow the padding guidelines
   outlined in the previous section.

   Each UDP packet MUST hold one query, with the complete content
   comprising the <dnscrypt-query> structure specified in the Protocol
   Components section.

   A DNSCrypt UDP datagram may be fragmented at the IP layer like any
   other UDP datagram, and a client MAY send multiple independent
   queries from the same source port.

   Upon receiving a query, the resolver may choose to either disregard
   it or send back a response encrypted using DNSCrypt.

   The client MUST authenticate and, if authentication succeeds, decrypt
   the response with the help of the resolver's public key, the shared
   secret, and the response nonce.

   The client MUST verify that the <client-nonce> prefix of the response
   nonce matches a currently outstanding query.

   In case the response fails verification, or the <client-nonce> does
   not match a currently outstanding query, it MUST be disregarded by
   the client.

   If the response has the TC flag set, the client MUST:

   1.  send the query again using TCP [RFC7766]

Denis                    Expires 24 January 2027               [Page 13]
Internet-Draft                  DNSCrypt                       July 2026

   2.  update its future UDP padding target if its local size estimator
       indicates that larger UDP queries would have avoided truncation

   <min-query-len> MUST be capped so that the full length of a DNSCrypt
   packet does not exceed the maximum size supported by the transport
   path.

   A client MAY increase or decrease this value over time.

   The adjustment algorithm is implementation-defined.

   While UDP queries require careful length management due to truncation
   concerns, TCP queries follow different padding rules due to the
   reliable nature of the transport.

5.4.3.  Padding For Client Queries Over TCP

   Queries MUST undergo padding using the ISO/IEC 7816-4 format before
   being encrypted.

   The padding starts with a byte valued 0x80 followed by a variable
   number of NUL bytes.

   TCP has no UDP amplification constraint, but padding still hides the
   exact DNS query length.

   A client SHOULD add a random padding component and SHOULD avoid
   deterministic plaintext lengths for repeated queries.

   A resolver MUST accept any authenticated plaintext that is valid ISO/
   IEC 7816-4 padding and parses as a DNS message, whatever the padded
   length; deployed receivers already behave this way.

   For example, an originally unpadded 56-byte DNS query can be validly
   padded as:

   <56-bytes-query> 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00

   or

   <56-bytes-query> 0x80 (0x00 * 71)

   or

   <56-bytes-query> 0x80 (0x00 * 135)

   or

Denis                    Expires 24 January 2027               [Page 14]
Internet-Draft                  DNSCrypt                       July 2026

   <56-bytes-query> 0x80 (0x00 * 199)

5.4.4.  Client Queries Over TCP

   The sole differences between encrypted client queries transmitted via
   TCP and those sent using UDP lie in the padding length calculation
   and the inclusion of a two-byte big-endian length prefix for the
   encrypted DNSCrypt packet.

   Cleartext DNS query payloads are not prefixed by their length before
   encryption, even when the DNSCrypt packet is sent over TCP.

   The two-byte TCP length prefix is added after encryption and covers
   the complete <dnscrypt-query> packet.

   Unlike UDP queries, a query sent over TCP can be shorter than the
   response.

   After having received a response from the resolver, the client and
   the resolver MUST close the TCP connection to ensure security and
   comply with this revision of the protocol, which prohibits multiple
   transactions over the same TCP connection.

5.4.5.  Padding For Resolver Responses

   Before encryption takes place, responses are padded according to the
   ISO/IEC 7816-4 format.

   Padding begins with a single byte holding the value 0x80, followed by
   any number of NUL bytes.

   When the transport size budget permits, the resolver SHOULD pad
   <resolver-response> <resolver-response-pad> to a multiple of 64
   bytes.

   The padding length SHOULD be between 1 and 256 bytes, including the
   initial 0x80 byte.

   The padding length SHOULD be computed as a deterministic function of
   either (<resolver-sk>, <client-nonce>) or (<shared-key>, <client-
   nonce>), for example with a pseudorandom function, so that
   retransmitted queries receive identically padded responses.

   The requirement prevents response padding from becoming an extra
   source of linkable server behavior while still allowing stateless
   operation.

Denis                    Expires 24 January 2027               [Page 15]
Internet-Draft                  DNSCrypt                       July 2026

   If the preferred padding would make an encrypted UDP response exceed
   the triggering query size or the resolver's UDP maximum, the resolver
   MAY use a shorter valid ISO/IEC 7816-4 padding length, or truncate
   the DNS response and set the DNS TC flag before padding and
   encryption.

   A client MUST accept any authenticated response whose plaintext has
   valid ISO/IEC 7816-4 padding and parses as a DNS response; it MUST
   NOT reject a response solely because the plaintext length is not a
   multiple of 64 bytes or because the padding length is outside the
   preferred range above.

5.4.6.  Resolver Responses Over UDP

   The resolver MUST authenticate and decrypt client queries before
   forwarding them to the upstream DNS resolution path.

   Queries that cannot be authenticated, decrypted, unpadded, or parsed
   as DNS messages MUST be ignored.

   Any client-supplied nonce value MUST be accepted for decryption.

   A resolver MAY ignore or refuse queries encrypted with client public
   keys that are not authorized by local policy, but a public resolver
   that accepts anonymous clients MUST accept arbitrary client public
   keys, subject only to the cryptographic checks of Appendix 2, such as
   low-order key rejection.

   Responses sent over UDP MUST be padded as described in "Padding For
   Resolver Responses" and encrypted as <dnscrypt-response>.

   As in standard DNS, the decrypted response MUST echo the transaction
   ID and question of the decrypted query; deployed clients discard
   responses that do not.

   The resolver MUST NOT send an encrypted DNSCrypt response over UDP
   that is larger than the encrypted DNSCrypt query packet that
   triggered it.

   If the full encrypted response packet would be larger than the query
   packet even with minimal padding, the resolver MUST truncate the DNS
   response and set the DNS TC flag before padding and encryption.

   A resolver MUST NOT stay silent instead: the query was authenticated,
   and a dropped response leaves the client waiting out a retransmission
   timeout, whereas a truncated response makes it retry over TCP
   immediately.

Denis                    Expires 24 January 2027               [Page 16]
Internet-Draft                  DNSCrypt                       July 2026

   If the resolver sends a truncated response, the encrypted truncated
   response MUST still be equal to or shorter than the encrypted query
   packet.

5.4.7.  Resolver Responses Over TCP

   The resolver MUST authenticate and decrypt client queries as
   described for UDP.

   Queries that cannot be authenticated, decrypted, unpadded, or parsed
   as DNS messages MUST be ignored.

   Responses sent over TCP MUST be padded as described in "Padding For
   Resolver Responses" and encrypted as <dnscrypt-response>.

   The complete encrypted response packet is then prefixed with a two-
   byte big-endian length.

   Cleartext DNS response payloads are not prefixed by their length
   before encryption, even when the DNSCrypt packet is sent over TCP.

   Unlike UDP responses, TCP responses MUST be sent unmodified even if
   their encrypted length exceeds the encrypted query length.

   The complete encrypted response MUST nevertheless be smaller than
   4096 bytes, because deployed clients reject larger DNSCrypt packets;
   a resolver whose DNS response would exceed this limit truncates it
   and sets the TC flag before padding and encryption.

   The query and response processing rules described above depend on the
   certificate information obtained during session establishment.

   The certificate format and management procedures are critical to the
   protocol's security.

5.5.  Certificates

   The following diagram shows the structure of a DNSCrypt certificate:

Denis                    Expires 24 January 2027               [Page 17]
Internet-Draft                  DNSCrypt                       July 2026

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         Cert Magic                            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          ES Version           |    Protocol Minor Version     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                         Signature                             +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                      Resolver Public Key                      +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Client Magic                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                          Serial                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                          TS Start                             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                          TS End                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                        Extensions                             +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   To initiate a DNSCrypt session, a client transmits an ordinary
   unencrypted TXT DNS query to the resolver's IP address and DNSCrypt
   port.

   A client MAY use UDP or TCP according to local policy.

   Clients SHOULD try UDP first and retry over TCP after failure,
   timeout, or truncation.  A PQ-capable client uses the rollover-sized
   padding target defined in Certificate Retrieval Amplification;
   although this can cause IP fragmentation, fragmented UDP works on
   most paths.  A client on a path already known to block fragmented UDP
   MAY use TCP immediately.

   A resolver MUST serve certificates over both UDP and TCP; the UDP
   response MAY be truncated, with the TC flag set, to direct the client
   to TCP.  Deployed clients begin certificate retrieval over UDP and
   only retry over TCP after a truncated response.

   The standard name in the question (<provider name>) follows this
   scheme:

Denis                    Expires 24 January 2027               [Page 18]
Internet-Draft                  DNSCrypt                       July 2026

   <protocol-major-version> . dnscrypt-cert . <zone>

   A major protocol version has only one certificate format.

   A DNSCrypt client implementing the second version of the protocol
   SHOULD send a query with the TXT type and IN class, and a name of the
   form:

   2.dnscrypt-cert.example.com

   Clients MAY support explicitly configured provider names that do not
   follow this convention.

   Such names are non-standard and can fail through Anonymized DNSCrypt
   relays that only recognize the standard certificate prefix.

   The RD (Recursion Desired) bit MAY be set; a resolver serving a
   certificate for its own provider name ignores it.

   A certificate query sent over UDP MAY include an EDNS(0) [RFC6891]
   OPT pseudo-RR with an EDNS(0) Padding option [RFC7830].

   This padding is part of the DNS request length used for UDP anti-
   amplification checks.

   The padding bytes are NUL bytes and carry no protocol data.

   A resolver MUST ignore the padding contents when matching the
   question name and MUST NOT use the advertised EDNS(0) UDP payload
   size as an amplification budget.

   The zone MUST be a valid DNS name, but MAY not be registered in the
   DNS hierarchy.

   A single provider name can be shared by multiple resolvers operated
   by the same entity, and a resolver can respond to multiple provider
   names, especially to support multiple protocol versions
   simultaneously.

   In order to use a DNSCrypt-enabled resolver, a client must know the
   following information:

   *  The resolver IP address and port

   *  The provider name

   *  The provider public key

Denis                    Expires 24 January 2027               [Page 19]
Internet-Draft                  DNSCrypt                       July 2026

   The provider public key is a long-term key whose sole purpose is to
   verify the certificates.

   It is never used to encrypt or verify DNS queries.

   A single provider public key can be employed to sign multiple
   certificates.

   For example, an organization operating multiple resolvers can use a
   unique provider name and provider public key across all resolvers,
   and just provide a list of IP addresses and ports.

   Each resolver MAY have its unique set of certificates that can be
   signed with the same key.

   It is RECOMMENDED that certificates are signed using specialized
   hardware rather than directly on the resolvers themselves.

   Once signed, resolvers SHOULD make these certificates available to
   clients.

   Signing certificates on dedicated hardware helps ensure security and
   integrity, as it isolates the process from potential vulnerabilities
   present in the resolver's system.

   A successful response to a certificate request contains one or more
   TXT records, each record containing a certificate encoded as follows:

   *  <cert>: <cert-magic> <es-version> <protocol-minor-version>
      <signature> <resolver-pk> <client-magic> <serial> <ts-start> <ts-
      end> <extensions>

   *  <cert-magic>: 0x44 0x4e 0x53 0x43

   *  <es-version>: the cryptographic construction to use with this
      certificate.  For the Box-XChaChaPoly construction of Appendix 1,
      that is, the X25519 key exchange with the XChaCha20_DJB-Poly1305
      authenticated encryption algorithm, <es-version> MUST be 0x00
      0x02.  PQDNSCrypt uses 0x00 0x03; these values are summarized
      below.

   *  <protocol-minor-version>: 0x00 0x00

   *  <signature>: a 64-byte signature of (<resolver-pk> <client-magic>
      <serial> <ts-start> <ts-end> <extensions>) using the Ed25519
      algorithm and the provider secret key.  Ed25519 MUST be used in
      this version of the protocol.

Denis                    Expires 24 January 2027               [Page 20]
Internet-Draft                  DNSCrypt                       July 2026

   *  <resolver-pk>: the resolver short-term public key, which is 32
      bytes when using X25519.

   *  <client-magic>: an 8-byte value identifying this certificate; the
      client copies it verbatim into the first 8 bytes of every query
      built from this certificate.  It is an opaque identifier and MAY
      be a truncated resolver public key.  A provider MUST NOT issue two
      concurrently valid certificates with the same <client-magic>, MUST
      NOT use a value starting with 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      (seven all-zero bytes) in order to avoid confusion with the QUIC
      protocol [RFC9000], and MUST NOT use the reserved <resume-magic>
      value defined in Stateless Resumption.

   *  <serial>: a 4-byte serial number in big-endian format.  If more
      than one certificate is valid for the encryption system the client
      selected, the client MUST prefer the certificate with a higher
      serial number.

   *  <ts-start>: the date the certificate is valid from, as a big-
      endian 4-byte unsigned Unix timestamp.  It MUST be strictly
      earlier than <ts-end>; deployed clients reject certificates whose
      validity interval is empty or inverted.

   *  <ts-end>: the date the certificate is valid until (inclusive), as
      a big-endian 4-byte unsigned Unix timestamp.

   *  <extensions>: empty in the current protocol version, but may
      contain additional data in future revisions, including minor
      versions.  The computation and verification of the signature MUST
      include the extensions.  An implementation not supporting these
      extensions MUST ignore them.

   Certificates made of this information, without extensions, are 116
   bytes long.

   With the addition of <cert-magic>, <es-version>, and <protocol-minor-
   version>, the record is 124 bytes long.

   The following encryption systems are defined by this document:

   0x00 0x02, Box-XChaChaPoly:  The resolver public key is 32 bytes, and
      the client public key in queries is 32 bytes.  The nonce is split
      into a 12-byte client nonce and a 12-byte resolver nonce.  The
      shared key is HChaCha20(X25519(pk, sk), 16 NUL bytes).  The
      certificate extensions field is empty in this revision; unknown
      extensions are ignored after signature verification.

   0x00 0x03, X-Wing PQDNSCrypt:  The resolver public key is 1216 bytes,

Denis                    Expires 24 January 2027               [Page 21]
Internet-Draft                  DNSCrypt                       July 2026

      and the client key-exchange field (<client-kex>) in queries is
      1120 bytes.  The nonce is split into a 12-byte client nonce and a
      12-byte resolver nonce.  The shared key is derived with HKDF-
      SHA256 as defined in "PQ Key Derivation".  The certificate
      extensions field contains the required 12-byte PQ profile
      extension.

   Each TXT answer record carries exactly one certificate blob.

   A client reads <cert-magic>, <es-version>, and <protocol-minor-
   version> first.

   If <es-version> is not supported, the client MUST ignore that
   certificate blob as a whole.

   It MUST NOT try to guess the <resolver-pk> length.

   Within a TXT record, the certificate is carried in the record's
   RDATA, which is a sequence of length-prefixed character-strings
   [RFC1035].

   A client reconstructs the certificate by concatenating these
   character-strings in order, after removing the single length octet
   that precedes each one.

   A 124-byte classical certificate fits in a single character-string,
   whereas a larger certificate spans several character-strings that
   MUST be concatenated in this way before the certificate is parsed.

   After receiving a set of certificates, the client checks their
   validity based on the current date and filters out certificates for
   unsupported encryption systems.

   The client then applies local policy for the resolver.

   If local policy or provisioning says that a resolver supports or
   requires a specific profile, such as PQDNSCrypt, the client MUST
   select only certificates for that profile and MUST NOT fall back to a
   different profile.

   Otherwise, if multiple supported profiles remain, the client chooses
   the most preferred supported profile according to local policy, and
   then chooses the valid certificate with the highest serial number
   within that profile.

   A client with no profile preference MAY treat all supported profiles
   as one set and choose the highest serial number among them, using
   local policy to break ties.

Denis                    Expires 24 January 2027               [Page 22]
Internet-Draft                  DNSCrypt                       July 2026

   DNSCrypt queries sent by the client MUST use the <client-magic>
   header of the chosen certificate, as well as the specified encryption
   system and public key.

   The client MUST refresh certificates periodically and early enough to
   avoid using expired certificates.

   An hourly refresh interval is suitable, but not required.

   After a refresh, the client switches to a new certificate if:

   *  The current certificate is not present or not valid anymore,

   or

   *  A certificate with a higher serial number than the current one is
      available.

   The certificate management system ensures that cryptographic keys
   remain fresh and that clients can smoothly transition to updated
   certificates.

   With the core protocol mechanics now established, we can examine
   implementation considerations.

6.  Conformance Checklist

   A conformant DNSCrypt v2 client implementation has enough information
   in this document to:

   *  Build and parse DNS wire-format TXT certificate queries for the
      configured provider name, using UDP or TCP according to local
      policy and retrying over TCP when a direct TCP retry is
      appropriate.

   *  Reconstruct certificates from DNS TXT character-strings, verify
      the Ed25519 signature with the configured provider public key,
      reject unsupported or invalid certificates, and choose a valid
      certificate for a supported encryption system according to serial
      number and local profile policy.

   *  Generate a client key pair and a unique <client-nonce> for each
      newly encrypted query under the same client secret key and
      resolver public key.

Denis                    Expires 24 January 2027               [Page 23]
Internet-Draft                  DNSCrypt                       July 2026

   *  Pad DNS queries with ISO/IEC 7816-4 padding, encrypt them with the
      selected certificate parameters, and send exactly one <dnscrypt-
      query> per UDP datagram or one length-prefixed packet per TCP
      connection.

   *  Authenticate responses, verify that the returned nonce starts with
      an outstanding <client-nonce>, remove padding, and forward the
      unmodified DNS response to the caller.

   *  Retry over TCP when an authenticated UDP response carries the DNS
      TC flag, and maintain a UDP padding target that keeps later
      encrypted UDP responses within the query size when practical.

   A conformant DNSCrypt v2 resolver implementation has enough
   information in this document to:

   *  Generate, sign, serve, rotate, and retire resolver certificates
      without using the long-term provider key for query traffic.

   *  Select the certificate matching an incoming <client-magic>, derive
      the shared key from the client public key, authenticate and
      decrypt the query, reject bad padding or malformed DNS payloads
      silently, and pass the decrypted DNS query to the resolver path.

   *  Pad, encrypt, and frame responses using the nonce (<client-nonce>
      <resolver-nonce>), respecting the UDP anti-amplification guidance
      and the TCP length-prefix rules.

   *  Serve classical certificate responses over UDP, and add larger PQ
      certificate records over UDP only when the complete response is no
      larger than the triggering request; otherwise set TC and rely on a
      padded UDP query or TCP as described below.

   A conformant Anonymized DNSCrypt relay implementation has enough
   information in this document to:

   *  Accept length-prefixed TCP and unframed UDP Anonymized DNSCrypt
      queries.

   *  Validate the target address, target port, and inner query prefix
      before forwarding.

   *  Forward the inner query to the target resolver over UDP without
      decrypting or modifying it.

   *  Forward only valid upstream responses that match the relayed query
      and do not violate the response-size rule, adding only TCP framing
      when returning a response to a TCP client.

Denis                    Expires 24 January 2027               [Page 24]
Internet-Draft                  DNSCrypt                       July 2026

7.  Implementation Status

   _Note: This section is to be removed before publishing as an RFC._

   Multiple implementations of the protocol described in this document
   have been developed and verified for interoperability.

   A comprehensive list of known implementations can be found at
   https://dnscrypt.info/implementations.

   The successful deployment of multiple interoperable implementations
   demonstrates the protocol's maturity.

   However, proper implementation requires careful attention to security
   considerations.

8.  Security Considerations

   This section discusses security considerations for the DNSCrypt
   protocol.

8.1.  Protocol Security

   The DNSCrypt protocol provides several security benefits:

   1.  *Confidentiality*: DNS queries and responses are encrypted with
       the authenticated-encryption construction selected by the
       certificate.  The current classical and PQ constructions in this
       document use XChaCha20_DJB-Poly1305 as defined in Appendix 1,
       preventing eavesdropping of DNS traffic.  For example, a query
       for "example.com" would be encrypted and appear as random data to
       an observer.

   2.  *Integrity*: Message authentication using the Poly1305 tag in
       Appendix 1 ensures that responses cannot be tampered with in
       transit.  Any modification to the encrypted response would be
       detected and rejected by the client.

   3.  *Authentication*: The use of Ed25519 for certificate signatures,
       together with the key-exchange mechanism selected by the
       certificate, provides strong authentication of resolvers.
       Clients can verify they are communicating with the intended
       resolver and not an impostor.

   4.  *Short-Term Resolver Keys*: Resolver certificates carry short-
       term public keys, limiting the impact of key compromise and
       enabling regular key rotation.

Denis                    Expires 24 January 2027               [Page 25]
Internet-Draft                  DNSCrypt                       July 2026

   These fundamental security properties depend on correct
   implementation practices.

   Several implementation-specific security aspects require particular
   attention.

8.2.  Implementation Security

   Implementations should consider the following security aspects:

   1.  *Key Management*:

       *  Resolvers MUST rotate their short-term key pairs at most every
          24 hours

       *  Previous resolver secret keys MUST be retained while unexpired
          served certificates still refer to them, and MUST be discarded
          as soon as no such certificate remains, or immediately if the
          key is believed to be compromised; the full rule appears in
          Operational Considerations

       *  Provider secret keys used for certificate signing SHOULD be
          stored in hardware security modules (HSMs)

       *  Example: A resolver might generate new key pairs daily at
          midnight UTC

   2.  *Nonce Management*:

       *  Nonces MUST NOT be reused for a given shared secret

       *  Clients SHOULD generate <client-nonce> values using either a
          cryptographically secure random number generator with enough
          entropy to make collisions negligible for the lifetime of the
          shared secret, or a secret-key pseudorandom construction, such
          as encrypting a timestamp and any counter or random bits
          needed for uniqueness using a block cipher.  Such
          constructions MUST NOT expose wall-clock time or other stable
          client state to observers, and MUST still provide nonce
          uniqueness for the lifetime of the shared secret

       *  Clients SHOULD NOT include unencrypted timestamps in nonce
          values, especially when Anonymized DNSCrypt, Tor, SOCKS, or
          other proxying or anonymity systems are used

Denis                    Expires 24 January 2027               [Page 26]
Internet-Draft                  DNSCrypt                       July 2026

       *  Clients can quickly discard stale responses by keeping local
          state for outstanding queries, including their <client-nonce>
          values and expiration deadlines, and rejecting responses for
          nonces that are unknown, already answered, or expired

   3.  *Padding*:

       *  Implementations MUST use the specified padding scheme to
          prevent traffic analysis

       *  The minimum query length SHOULD be adjusted based on network
          conditions

       *  Example: A 50-byte query might be padded to 256 bytes to
          prevent size-based fingerprinting

   4.  *Certificate Validation*:

       *  Clients MUST verify certificate signatures using the
          provider's public key

       *  Certificates MUST be checked for validity periods

       *  Clients MUST prefer certificates with higher serial numbers
          within the selected encryption system

       *  Example: A client might cache valid certificates and check for
          updates hourly

   Proper implementation of these security measures provides the
   foundation for the protocol's attack mitigation capabilities.

8.3.  Attack Mitigation

   DNSCrypt provides protection against several types of attacks:

   1.  *DNS Spoofing*: The use of authenticated encryption prevents
       spoofed responses.  An attacker cannot forge responses without
       the server's secret key.

   2.  *Amplification Attacks*: UDP encrypted responses are limited by
       the size of the encrypted query that triggered them, and client
       padding targets help keep the amplification factor bounded
       [RFC5358].  Certificate retrieval has separate rules because it
       is unauthenticated and uses ordinary DNS TXT responses.

Denis                    Expires 24 January 2027               [Page 27]
Internet-Draft                  DNSCrypt                       July 2026

   3.  *Fragmentation Attacks*: The protocol mitigates fragmentation
       risks by padding queries, allowing truncated UDP responses, and
       retrying over TCP when necessary.

   4.  *Replay Exposure Reduction*: Nonces make responses query-
       specific.  Clients can discard late, duplicate, or unrelated
       responses by checking the returned <client-nonce> against local
       outstanding-query state and request deadlines, without exposing
       timestamps in plaintext nonce values.

   While DNSCrypt effectively mitigates these attacks, implementers
   should also be aware of privacy considerations that extend beyond
   basic protocol security.

8.4.  Privacy Considerations

   While DNSCrypt encrypts DNS traffic, there are some privacy
   considerations:

   1.  *Resolver Knowledge*: Resolvers can still see the client's IP
       address unless Anonymized DNSCrypt is used.  This can reveal the
       client's location and network.

   2.  *Query Patterns*: Even with encryption, the size and timing of
       queries may reveal information.  Padding helps mitigate this but
       doesn't eliminate it completely.

   3.  *Nonce Metadata*: Client nonces are visible on the wire.
       Encoding unencrypted timestamps or other stable or linkable state
       in nonce values can disclose clock information or support client
       fingerprinting, particularly when relays or anonymity networks
       are used.  Clients SHOULD prefer nonce constructions that reveal
       no wall-clock time to observers.

   4.  *Certificate Requests*: Initial certificate requests are
       unencrypted but only return public data.  This is a one-time
       exposure per session.

   These privacy considerations complement the security measures and
   should inform operational practices for DNSCrypt deployments.

8.5.  Operational Security

   Operators should consider:

   1.  *Key Distribution*: Provider public keys should be distributed
       securely to clients.  This might involve:

Denis                    Expires 24 January 2027               [Page 28]
Internet-Draft                  DNSCrypt                       July 2026

       *  Publishing keys on secure websites

       *  Using DNSSEC-signed records

       *  Including keys in software distributions

   2.  *Certificate Management*: Certificates should be signed on
       dedicated hardware, not on resolvers.  This provides:

       *  Better key protection

       *  Centralized certificate management

       *  Reduced attack surface

   3.  *Access Control*: Resolvers may implement access control based on
       client public keys.  This can:

       *  Prevent abuse

       *  Enable service differentiation

       *  Support business models

   4.  *Monitoring*: Operators should monitor for unusual patterns that
       may indicate attacks:

       *  High query rates from single clients

       *  Unusual query patterns

       *  Certificate request anomalies

   These operational security practices work together with the technical
   security measures to provide comprehensive protection.

   Additional operational considerations extend beyond security to
   include practical deployment aspects.

9.  Operational Considerations

   Special attention should be paid to the uniqueness of the generated
   secret keys.

   Client public keys can be used by resolvers to authenticate clients,
   link queries to customer accounts, and unlock business-specific
   features such as redirecting specific domain names to a sinkhole.

Denis                    Expires 24 January 2027               [Page 29]
Internet-Draft                  DNSCrypt                       July 2026

   A resolver that restricts service to known clients MAY respond only
   to an allowed set of client public keys.

   A resolver that serves arbitrary, anonymous clients MUST accept any
   client public key as a matter of policy; cryptographic checks, such
   as the rejection of low-order public keys in Appendix 2, still apply.

   In particular, an anonymous client can generate a new key pair for
   every session, or even for every query.

   This mitigates the ability for a resolver to group queries by client
   public keys and discover the set of IP addresses a user might have
   been operating.

   Resolvers MUST rotate each short-term key pair every 24 hours at
   most.

   After a key rotation, a resolver MUST continue accepting queries for
   every unexpired certificate it still serves, which requires retaining
   the corresponding resolver secret keys.

   Once all certificates for an old resolver key have expired or been
   withdrawn, the resolver MUST discard that old secret key.

   If an old resolver key is believed to be compromised, the resolver
   MUST withdraw the related certificates and discard the key instead of
   continuing to accept it.

   Provider public keys MAY be published as DNSSEC-signed TXT records
   [RFC1035], in the same zone as the provider name.

   For example, a query for the TXT type on the name
   "2.pubkey.example.com" may return a signed record containing a
   hexadecimal-encoded provider public key for the provider name
   "2.dnscrypt-cert.example.com".

   As a client is likely to reuse the same key pair many times, servers
   are encouraged to cache shared keys instead of performing the X25519
   operation for each query.

   This makes the computational overhead of DNSCrypt negligible compared
   to plain DNS.

   While DNSCrypt provides strong encryption and authentication, some
   use cases require additional privacy protection.

   The Anonymized DNSCrypt extension addresses scenarios where hiding
   client IP addresses from resolvers is necessary.

Denis                    Expires 24 January 2027               [Page 30]
Internet-Draft                  DNSCrypt                       July 2026

10.  Anonymized DNSCrypt

   While DNSCrypt encrypts DNS traffic, DNS server operators can still
   observe client IP addresses.

   Anonymized DNSCrypt is an extension to the DNSCrypt protocol that
   allows queries and responses to be relayed by an intermediate server,
   hiding the client's IP address from the resolver.

   This extension maintains all the security properties of standard
   DNSCrypt while adding an additional layer of privacy protection.

10.1.  Protocol Overview

   Anonymized DNSCrypt works by having the client send encrypted queries
   to a relay server, which then forwards them to the actual DNSCrypt
   resolver.

   The relay server cannot decrypt the queries or responses, and the
   resolver only sees the relay's IP address.

[Client]----(encrypted query)--->[Relay]----(encrypted query)--->[Server]

[Client]<--(encrypted response)--[Relay]<--(encrypted response)--[Server]

   Key properties of Anonymized DNSCrypt:

   *  The relay cannot decrypt or modify queries and responses

   *  The resolver only sees the relay's IP address, not the client's

   *  A DNSCrypt server can simultaneously act as a relay

   *  The protocol works over both UDP and TCP

10.2.  Client Queries

   The following diagram shows the structure of an Anonymized DNSCrypt
   query packet:

Denis                    Expires 24 January 2027               [Page 31]
Internet-Draft                  DNSCrypt                       July 2026

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         Anon Magic                            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                        Server IP (IPv6)                       +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        Server Port        |                                   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+                                   +
   |                                                               |
   +                     DNSCrypt Query                            +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   An Anonymized DNSCrypt query is a standard DNSCrypt query prefixed
   with information about the target server:

   <anondnscrypt-query> ::=
       <anon-magic> <server-ip> <server-port> <dnscrypt-query>

   Where:

   *  <anon-magic>: 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x00

   *  <server-ip>: 16 bytes encoded IPv6 address (IPv4 addresses are
      mapped to IPv6 using ::ffff:<ipv4 address> [RFC4291])

   *  <server-port>: 2 bytes in big-endian format

   *  <dnscrypt-query>: either a standard encrypted DNSCrypt query or
      the unencrypted TXT certificate query used to retrieve resolver
      certificates.

   For example, a query for a server at 192.0.2.1:443 would be prefixed
   with:

   0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x00
   0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
   0xff 0xff 0xc0 0x00 0x02 0x01 0x01 0xbb

   An Anonymized DNSCrypt query sent over UDP is sent as this exact byte
   string.

   An Anonymized DNSCrypt query sent over TCP is prefixed with a two-
   byte big-endian length that covers the complete <anondnscrypt-query>
   byte string.

Denis                    Expires 24 January 2027               [Page 32]
Internet-Draft                  DNSCrypt                       July 2026

   The relay removes the TCP length prefix before validating the packet
   and adds a new TCP length prefix when returning the upstream response
   to a TCP client.

10.3.  Relay Behavior

   Relays MUST:

   1.  Accept queries over both TCP and UDP

   2.  Communicate with upstream servers over UDP, even if client
       queries were sent to the relay over TCP

   3.  Validate incoming packets:

       *  Check that the target IP is not in a private, loopback, link-
          local, multicast, unspecified, or otherwise locally routed
          range

       *  Verify the port number is in an allowed range

       *  Ensure the inner <dnscrypt-query> doesn't start with <anon-
          magic>

       *  Reject the inner <dnscrypt-query> if its first 8 bytes are
          0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01, to avoid protocol
          confusion with QUIC [RFC9000]; relays MAY reject broader
          reserved prefixes by local policy

   4.  Forward the inner <dnscrypt-query> unmodified to the target
       server over UDP, without the Anonymized DNSCrypt prefix

   5.  Verify server responses:

       *  For encrypted DNSCrypt responses, check that the response is
          no larger than the inner query packet forwarded upstream

       *  For certificate responses, check that the response transaction
          ID and query name match the relayed certificate query, and
          that the response is no larger than the inner query packet
          forwarded upstream

       *  Validate the response format (either starts with resolver
          magic or is a certificate response)

       *  Forward valid responses unmodified to the client, adding only
          the TCP length prefix when the client connection used TCP

Denis                    Expires 24 January 2027               [Page 33]
Internet-Draft                  DNSCrypt                       July 2026

   A relay MAY briefly cache a validated certificate response and replay
   it for identical certificate queries, rewriting only the DNS
   transaction ID; deployed relays cache certificate responses for a few
   minutes.

   Address validation is performed after decoding <server-ip>.

   If the decoded address is an IPv4-mapped IPv6 address, the relay
   applies the IPv4 policy to the embedded IPv4 address.

   Relay operators SHOULD maintain an explicit allowlist or denylist of
   target ranges.

   At minimum, relays MUST reject targets that are not globally
   routable, including unspecified, loopback, link-local, multicast,
   private-use, unique-local, documentation, benchmarking, and other
   special-use addresses.

   These relay requirements ensure that anonymization does not
   compromise the security properties of the underlying DNSCrypt
   protocol.

   Proper deployment requires additional operational considerations.

10.4.  Operational Considerations

   When using Anonymized DNSCrypt:

   1.  Clients should choose relays and servers operated by different
       entities

   2.  Having relays and servers on different networks is recommended

   3.  Relay operators should:

       *  Refuse forwarding to reserved IP ranges [RFC1918]

       *  Restrict allowed server ports (typically only allowing port
          443)

       *  Monitor for abuse

   These operational guidelines help ensure that Anonymized DNSCrypt
   deployments provide the intended privacy benefits while maintaining
   security and preventing abuse.

Denis                    Expires 24 January 2027               [Page 34]
Internet-Draft                  DNSCrypt                       July 2026

11.  Post-Quantum Key Exchange (PQDNSCrypt)

   The key exchange described so far relies on X25519 [RFC7748], which a
   sufficiently capable quantum computer would be able to break.

   An attacker who records DNSCrypt traffic today could therefore
   decrypt it once such a computer exists.

   This section defines the PQ extension, which performs the key
   exchange with a hybrid post-quantum mechanism while leaving the rest
   of the protocol unchanged: the certificate system, the packet
   framing, the authenticated encryption, the nonces, the padding
   philosophy, and Anonymized DNSCrypt all carry over.

   A DNSCrypt deployment that uses this extension is referred to as
   PQDNSCrypt.

   PQ is introduced as a new encryption system version (<es-version>
   0x00 0x03) inside the existing version 2 certificate format.

   It is not a new major protocol version, and it does not change the
   certificate lookup name.

   A resolver MAY advertise a PQ certificate alongside a classical
   certificate under the same provider name, and a client that does not
   implement PQ ignores the <es-version> value it does not recognize,
   exactly as already required.

   The values that PQ introduces, namely the <es-version>, the resume
   magic, the ticket parameters, and the profile identifiers, are
   provisional assignments used by this document and by the test vectors
   in Appendix 3.

   They are expected to be confirmed before publication.

11.1.  Key Encapsulation Instead of Key Agreement

   Classical DNSCrypt uses a non-interactive key agreement: the resolver
   publishes an X25519 public key in its certificate, the client places
   its own X25519 public key in <client-pk>, and both sides compute the
   same shared secret.

   A post-quantum key encapsulation mechanism (KEM) does not offer a
   non-interactive key agreement, but it fits the same single-message
   exchange.

   The resolver generates a KEM key pair and publishes the public
   (encapsulation) key in the <resolver-pk> field of its certificate.

Denis                    Expires 24 January 2027               [Page 35]
Internet-Draft                  DNSCrypt                       July 2026

   The client runs the KEM encapsulation against <resolver-pk>,
   obtaining a ciphertext and a shared secret, and places the ciphertext
   in the <client-pk> field.

   The resolver runs the KEM decapsulation on the received ciphertext
   using its secret key and recovers the same shared secret.

   The <client-pk> field therefore carries a KEM ciphertext rather than
   a client public key, and its length is determined by the <es-version>
   of the chosen certificate; the PQ text refers to the value carried in
   this field as <client-kex>.

   The resolver remains stateless: it derives the shared secret from a
   single client message, with no per-client state.

   Everything after the shared secret is shared with classical DNSCrypt,
   with the small additions described in this section.

   PQ uses X-Wing [I-D.connolly-cfrg-xwing-kem], a hybrid KEM that
   combines ML-KEM-768 [FIPS203] with X25519 [RFC7748].

   Being a hybrid, the shared secret remains secure as long as either
   ML-KEM-768 or X25519 is unbroken, which protects against both a
   future quantum break of X25519 and an unexpected weakness in ML-KEM-
   768.

   The X-Wing encapsulation key is 1216 bytes, the ciphertext is 1120
   bytes, and the shared secret is 32 bytes.

11.2.  PQ Certificates

   A PQ certificate uses the version 2 certificate format without
   modification.

   The <es-version> field is 0x00 0x03, and the <resolver-pk> field
   holds the 1216-byte X-Wing encapsulation key.

   The <client-magic> retains its role as a unique 8-byte certificate
   selector that MUST NOT begin with seven zero bytes; because a KEM
   ciphertext is freshly generated for every query, <client-magic> is an
   opaque identifier and is never a truncated public key.

   The Ed25519 signature input is unchanged.

   It MUST cover (<resolver-pk> <client-magic> <serial> <ts-start> <ts-
   end> <extensions>), exactly as for classical certificates, so that
   provider signing procedures do not require a second code path.

Denis                    Expires 24 January 2027               [Page 36]
Internet-Draft                  DNSCrypt                       July 2026

   The PQ profile metadata is authenticated through the already-signed
   <extensions> field, which for a PQ certificate contains a profile
   extension:

   <pq-profile-ext> ::= "PQD" <ext-version> <es-version> <kdf-id>
                         <aead-id> <resolver-pk-len> <client-kex-len>

   where <ext-version> is 0x01, <kdf-id> is 0x01 for HKDF-SHA256
   [RFC5869], <aead-id> is 0x01 for the XChaCha20_DJB-Poly1305
   construction of Appendix 1, and <resolver-pk-len> and <client-kex-
   len> are the encapsulation-key and ciphertext lengths as two-byte
   big-endian integers.

   A client implementing PQ MUST require this extension on a PQ
   certificate and MUST reject the certificate if the <es-version> on
   the wire or the field lengths disagree with the signed copies in the
   extension.

   The existing signature already provides implicit integrity for <es-
   version>, because <resolver-pk> is signed and its length follows from
   <es-version>: altering the version shifts the signed region and
   causes verification to fail, as long as distinct encryption systems
   use distinct <resolver-pk> lengths.

   The signed profile extension makes the binding explicit and preserves
   it should a future encryption system reuse an existing length.

   PQ certificates are approximately 1.3 KB before DNS TXT record
   framing.

   A single 1320-byte PQ certificate requires six TXT character-strings
   and therefore about 1338 bytes as one answer RR; a response
   containing one classical 124-byte certificate and one PQ certificate
   is typically about 1.5 KB, depending on the provider name.

   A response with two classical certificates and two PQ certificates is
   typically about 3.0 KB.

   A response with one classical certificate and three PQ certificates
   will normally exceed 4096 octets.

   A certificate response that contains a PQ certificate exceeds 512
   bytes, so retrieval relies on a sufficiently padded UDP query, TCP
   [RFC7766], or both.

   A 4096-octet DNS response is a useful upper bound for certificate
   responses, but it is not a fragmentation-avoidance target.

Denis                    Expires 24 January 2027               [Page 37]
Internet-Draft                  DNSCrypt                       July 2026

   Operators that need maximum UDP robustness SHOULD use a lower target;
   however, one PQ certificate already exceeds the common 1232-octet UDP
   payload target once DNS framing is included.

11.3.  Certificate Retrieval Amplification

   Certificate retrieval is an unauthenticated DNS query, and PQ
   certificates are much larger than classical ones, so a resolver that
   returns one or more PQ certificates over UDP could be abused as a
   traffic amplifier in response to queries with a spoofed source
   address.

   For compatibility with deployed DNSCrypt v2 clients and resolvers, a
   resolver MAY return the small classical certificate response to an
   ordinary UDP certificate query.

   A resolver MUST NOT add PQ certificates or other large certificate
   records to a UDP certificate response unless the complete response is
   no larger than the request that triggered it.

   A client retrieving PQ certificates over UDP therefore MUST pad its
   certificate query to at least the size of the expected response,
   exactly as a query that carries a ciphertext is already large enough
   to cover its response.

   The advertised EDNS(0) [RFC6891] UDP payload size is a fragmentation-
   avoidance hint and MUST NOT be used as the amplification limit,
   because a spoofed query can advertise an arbitrarily large buffer
   while remaining small.

   To let a client size that padding, a resolver SHOULD keep its UDP
   certificate set small and predictable.

   For relay-compatible PQ deployments, resolvers SHOULD use the
   following certificate sets:

   *  Normal steady state: one classical certificate and one PQ
      certificate, typically about 1.5 KB.

   *  Rollover window: two classical certificates and two PQ
      certificates, typically about 3.0 KB.

   Resolvers SHOULD NOT exceed the rollover certificate set over UDP,
   and SHOULD keep certificate responses below 4096 octets.

   A client cannot tell from outside whether a rotation is in progress.
   A client retrieving PQ certificates over UDP therefore MUST pad its
   certificate query to cover the rollover set rather than only the

Denis                    Expires 24 January 2027               [Page 38]
Internet-Draft                  DNSCrypt                       July 2026

   steady-state set; otherwise it silently drops to the classical
   certificate for the duration of every rollover window.  This padding
   exceeds common fragmentation-avoidance targets, but clients SHOULD
   try UDP first because fragmented UDP works on most paths, and retry
   over TCP only after timeout or truncation.

   If the certificate response containing the PQ set would be larger
   than the request, the resolver MUST NOT return that oversized PQ
   response over UDP; it SHOULD instead return the classical certificate
   response with the TC flag set, so a classical-only client can proceed
   while a PQ-capable client learns that more certificates may be
   available.

   Operators MAY serve the classical certificate over UDP while
   requiring a padded query or TCP for larger PQ certificate sets.

   This affects neither the certificate format nor the lookup name.

   Because a resolver can withhold PQ certificates from a truncated UDP
   response, a PQ-capable client MUST honor the TC flag on a certificate
   response and retry the certificate query over TCP when TCP to the
   resolver is available.

   A client that ignores the TC flag would only ever observe the
   certificates present in the UDP response and could silently fail to
   use PQ even against a resolver that supports it.

11.4.  PQ Key Derivation

   For a PQ query, the shared secret is the 32-byte X-Wing shared
   secret.

   It is not used directly as the encryption key.

   Instead, both parties derive <shared-key> with HKDF-SHA256 [RFC5869],
   binding the certificate context and the ciphertext:

   cert-context ::= "DNSCrypt-PQ-v1" <es-version>
                    <protocol-minor-version> <resolver-pk>
                    <client-magic> <serial> <ts-start> <ts-end>
                    <extensions>

   <shared-key> ::= HKDF-SHA256(IKM  = <kem-ss>,
                                salt = <es-version> <client-magic>,
                                info = cert-context <client-kex>,
                                L    = 32)

Denis                    Expires 24 January 2027               [Page 39]
Internet-Draft                  DNSCrypt                       July 2026

   where <kem-ss> is the X-Wing shared secret and <client-kex> is the
   content of the <client-pk> field, that is, the X-Wing ciphertext.

   Binding <es-version> and <client-magic> separates keys across
   certificates and any future encryption system; binding <resolver-pk>,
   <serial>, and the validity timestamps ties the key to the exact
   signed certificate; binding <client-kex> ties it to the precise
   encapsulation.

   The derived <shared-key> is then used with the XChaCha20_DJB-Poly1305
   construction of Appendix 1 and the existing 24-byte nonce
   construction: 12 client-chosen bytes followed by 12 zero bytes for
   queries, and 12 client-chosen bytes followed by 12 resolver-chosen
   bytes for responses.

11.5.  PQ Query and Response Format

   A PQ query uses the <dnscrypt-query> structure without modification;
   only the length of <client-pk> changes, to the 1120-byte X-Wing
   ciphertext.

   A PQ response uses the <dnscrypt-response> structure without
   modification on the wire, but the decrypted payload begins with a
   short control block ahead of the unmodified DNS response:

   <pq-response-plain> ::= <control-len> <control>
                            <resolver-response> <resolver-response-pad>

   <control-len> is a two-byte big-endian length.

   When it is zero, <control> is absent and the DNS response begins
   immediately after the length.

   When it is nonzero, <control> carries PQ control data, currently a
   stateless resumption ticket.

   The response padding is computed over the whole <control-len>
   <control> <resolver-response> plaintext, so the decrypted payload
   keeps the usual length alignment.

   Over UDP, the complete encrypted packet is subject to the response-
   size rule, so the <control-len> field, the <control> block, and the
   padding all count against the size of the query that triggered the
   response.

Denis                    Expires 24 January 2027               [Page 40]
Internet-Draft                  DNSCrypt                       July 2026

   When that budget is too tight to include a control block, the
   resolver MUST send the response with <control-len> zero, withholding
   ticket issuance or renewal, before resorting to DNS truncation: a
   withheld ticket costs at most one future key exchange, while a
   truncated response always costs the client a TCP round trip.

   A PQ client removes the control block after decryption and forwards
   the unmodified DNS response.

   Because the shared secret is symmetric, the resolver needs no
   additional KEM operation to encrypt a response.

11.6.  Padding and Transport

   A PQ query that carries a ciphertext includes roughly 1.1 KB in
   <client-pk>, so it is always far larger than its response.

   The minimum query target defined for client queries over UDP exists
   to prevent amplification, and that concern does not apply to a query
   that is already this large.

   A PQ query that carries a ciphertext is therefore not subject to the
   256-byte minimum target; it only needs valid ISO/IEC 7816-4 padding
   and should avoid unnecessary fragmentation.

   A resumed query, described below, carries a small ticket instead of a
   ciphertext, so it uses the regular UDP query-size target, initially
   256 bytes for the complete DNSCrypt packet.

   PQ queries and responses MUST be supported over TCP [RFC7766], and
   TCP is a first-class transport for PQ rather than only a fallback.

   A client SHOULD use a configurable UDP payload size target, 1232
   bytes by default, and SHOULD use TCP when a query would exceed it.

   A PQ query that carries a ciphertext is approximately 1220 bytes,
   which fits within a single unfragmented datagram on common paths but
   can exceed 1232 bytes once the Anonymized DNSCrypt prefix is added;
   in that case the client SHOULD use TCP.

11.7.  Stateless Resumption

   Performing a KEM decapsulation for every query is significantly more
   expensive than the classical X25519 operation, and because every
   ciphertext is distinct there is no shared-key cache to amortize it.

Denis                    Expires 24 January 2027               [Page 41]
Internet-Draft                  DNSCrypt                       July 2026

   To control this cost without keeping per-client state, PQ defines
   stateless resumption: after an initial query that carries a
   ciphertext, the resolver issues an opaque ticket that lets subsequent
   queries skip both the ciphertext and the decapsulation.

   A resolver maintains one or more server-wide ticket keys, denoted TK.

   A TK is shared by all processes answering for a given certificate and
   is rotated independently of client traffic.

   A resolver MAY retain a previous TK for a short overlap so that
   outstanding tickets continue to verify, but the overlap MUST NOT
   exceed the advertised ticket lifetime.

11.7.1.  Issuing a Ticket

   After a PQ query that carries a ciphertext has been decrypted, both
   parties hold <shared-key>.

   They derive a resumption secret:

   resume-secret ::= HKDF-SHA256(IKM  = <shared-key>,
                                 salt = <client-magic> <client-nonce>,
                                 info = "DNSCrypt-PQ-resume-secret-v1",
                                 L    = 32)

   The resolver seals the resumption secret and the metadata needed to
   validate it later under TK:

   ticket-plain ::= resume-secret <es-version> <client-magic>
                    <serial> <ts-end> <ticket-expiry>
                    <profile-extension-hash>

   ticket ::= <ticket-key-id> <ticket-nonce>
              AE(TK, <ticket-nonce>, ticket-plain)

   The fields used for ticket issuance are:

   *  <ticket-key-id>: 4 bytes identifying the resolver ticket key TK.

   *  <ticket-nonce>: 24 bytes used as the nonce for sealing ticket-
      plain.

   *  <ticket-expiry>: 4-byte big-endian Unix timestamp.

   *  <profile-extension-hash>: SHA-256(<extensions>), 32 bytes.

Denis                    Expires 24 January 2027               [Page 42]
Internet-Draft                  DNSCrypt                       July 2026

   The ticket is opaque, resolver-private state: its internal format and
   AEAD are an implementation choice and never need to interoperate
   between resolvers.

   This document's reference construction reuses the XChaCha20_DJB-
   Poly1305 AEAD of Appendix 1 with no associated data; <ticket-key-id>
   selects the ticket key, so its integrity follows from decryption
   failing under the wrong key, and a dedicated TK keeps ticket sealing
   separate from query traffic.

   The client stores the ticket together with the resume-secret it
   derived and an expiry it computes locally from the advertised
   <ticket-lifetime> and the time the ticket was received, further
   capped by the certificate expiry and local policy; the <ticket-
   expiry> field itself is sealed inside the ticket and not readable by
   the client.

   The ticket is delivered in the response control block:

   <control> ::= "PQDR" <control-version> <ticket-lifetime>
                 <ticket-len> <ticket>

   The control fields are:

   *  "PQDR": the four bytes 0x50 0x51 0x44 0x52.

   *  <control-version>: one byte.  This revision uses 0x01.

   *  <ticket-lifetime>: 4-byte big-endian lifetime in seconds.

   *  <ticket-len>: 2-byte big-endian length of <ticket> in bytes.

   *  <ticket>: the opaque ticket bytes.

   A resolver SHOULD issue a ticket in the first PQ response and MAY
   renew it on later responses; a client SHOULD adopt the most recent
   valid ticket it receives.

   A captured ticket is of no use on its own: deriving the per-query key
   requires either the resume-secret, which only the client holds, or
   TK, which only the resolver holds.

11.7.2.  Resuming

   A resumed query uses a distinct packet form, with the resume magic in
   place of <client-magic> and the ticket in place of <client-pk>:

Denis                    Expires 24 January 2027               [Page 43]
Internet-Draft                  DNSCrypt                       July 2026

   <pq-resume-query> ::= <resume-magic> <ticket-len> <ticket>
                          <client-nonce> <encrypted-query>

   <resume-magic> is the reserved 8-byte value 0x50 0x51 0x52 0x65 0x73
   0x75 0x6d 0x65 ("PQResume").

   It MUST NOT collide with any valid <client-magic>, with <resolver-
   magic>, with the Anonymized DNSCrypt <anon-magic>, or with seven
   leading zero bytes.

   The resumed-query <ticket-len> is a 2-byte big-endian length of
   <ticket> in bytes.

   On receiving a resumed query, the resolver locates the ticket key
   from <ticket-key-id>, opens the ticket, and rejects the query if the
   ticket cannot be opened, is expired, or if any sealed certificate-
   context field does not match an acceptable current certificate.

   The sealed certificate-context fields are <es-version>, <client-
   magic>, <serial>, <ts-end>, and <profile-extension-hash>; <profile-
   extension-hash> is compared to SHA-256(<extensions>) for the matched
   certificate.

   It then derives the per-query key:

   <shared-key> ::= HKDF-SHA256(IKM  = resume-secret,
                                salt = <client-magic> <client-nonce>,
                                info = "DNSCrypt-PQ-resumed-query-v1"
                                       SHA-256(<ticket>),
                                L    = 32)

   The client performs the same derivation.

   In this derivation, <client-nonce> is the fresh nonce carried in the
   resumed query itself, not the nonce of the query that produced the
   ticket, and <client-magic> is the value from the certificate under
   which the ticket was issued, which the client keeps together with the
   ticket and the resume-secret.

   The nonce construction is unchanged.

   Each resumed query thus uses a fresh key derived from its own
   <client-nonce>; clients MUST still use a distinct <client-nonce> for
   each resumed query, because repeating it would repeat both the key
   and the AEAD nonce.

Denis                    Expires 24 January 2027               [Page 44]
Internet-Draft                  DNSCrypt                       July 2026

   Responses to resumed queries reuse this per-query key, so the
   <resolver-nonce> MUST be unique per response and MUST NOT be all NUL
   bytes; a random 12-byte value satisfies this.  A replayed resumed
   query re-derives the same key, and answering it twice with the same
   <resolver-nonce> but a different response plaintext would reuse a key
   and nonce pair.

   Responses to resumed queries use the <pq-response-plain> layout like
   any PQ response; a resolver that issues no new ticket sets <control-
   len> to zero.

   If a ticket cannot be opened or validated, the resolver MUST silently
   drop the query, with no response distinguishable from any other
   dropped query.

   A client that receives no response retries with a query that carries
   a ciphertext, obtaining a fresh ticket.

11.7.3.  Resumption Considerations

   A ticket bounds forward secrecy for resumed traffic: an attacker who
   records resumed queries and later obtains a TK can open every ticket
   sealed under that TK, expired or not, and decrypt the recorded
   queries, but never the queries that carried a ciphertext.  Destroying
   each TK when it is rotated out is what limits this exposure, so
   ticket keys MUST be erased promptly at rotation.

   The ticket lifetime SHOULD be short and MUST NOT exceed the resolver
   certificate lifetime or the ticket-key lifetime.

   A ticket is also a linkable handle for its lifetime; a client that
   prioritizes unlinkability, in particular over Anonymized DNSCrypt,
   SHOULD send queries that carry a ciphertext rather than resuming.

   Because a ticket is a stable identifier that a client reuses across
   queries, a resolver that observes the same ticket from more than one
   source address can link those addresses to a single client.

   A client SHOULD therefore treat a ticket as bound to the network on
   which it was obtained: when it moves to a new network, it SHOULD
   discard the stored ticket and resume-secret and start over with a
   query that carries a ciphertext, so the new network's address cannot
   be tied to the previous one through a reused ticket.

   Resumed queries are replayable to the same extent as any stateless
   DNSCrypt query, and clients discard stale or duplicate responses with
   outstanding-query nonce tracking as usual.

Denis                    Expires 24 January 2027               [Page 45]
Internet-Draft                  DNSCrypt                       July 2026

   A resolver implementing PQ SHOULD support ticket issuance and
   resumption, since high query volumes make per-query decapsulation
   costly.

   A resolver SHOULD rate-limit decapsulation of queries that carry a
   ciphertext and prioritize valid resumed traffic under load.

11.8.  PQ and Anonymized DNSCrypt

   Anonymized DNSCrypt relays forward opaque DNSCrypt queries and
   require no changes for PQ.

   A query that carries a ciphertext keeps the classical query shape
   with a larger <client-pk> field, and a resumed query uses the resume
   shape above; both are opaque to a relay.

   The relay check that an encrypted response is no larger than the
   query is satisfied automatically for queries that carry a ciphertext,
   because they are large.

   A resumed query is small, so a client using Anonymized DNSCrypt MUST
   keep enough padding on the inner resumed query for the relay's
   encrypted-response size check to pass.

   If the client connects to the relay over TCP, the relay still
   forwards the inner query upstream over UDP, so the inner query size
   requirement remains.

   Certificate retrieval through a relay is different: the relay
   forwards the certificate query to the resolver over UDP and forwards
   a matching certificate response back to the client, and it applies
   the same response-size check, dropping any response larger than the
   query it relayed.

   A client retrieving a PQ certificate over UDP through a relay
   therefore MUST pad its certificate query to at least the size of the
   expected certificate response, as described in Certificate Retrieval
   Amplification, so the response passes both the resolver's and the
   relay's anti-amplification check.

   A client that does not, or cannot, pad far enough receives only the
   certificates that fit within the inner UDP query size, typically a
   classical certificate with the TC flag set; if even that response is
   larger than the inner query, the relay drops it.

   Retrying over TCP to an Anonymized DNSCrypt relay does not make the
   relay use TCP upstream: relays still forward the inner certificate
   query to the resolver over UDP.

Denis                    Expires 24 January 2027               [Page 46]
Internet-Draft                  DNSCrypt                       July 2026

   Nevertheless, carrying a rollover-sized inner certificate query over
   the client-to-relay TCP connection avoids IP fragmentation on that
   leg while giving the relay a large enough request to forward upstream
   and a sufficient anti-amplification budget for the response.  The
   inner query remains EDNS(0)-padded to the expected UDP response size;
   only its transport to the relay changes.

   Therefore, after a rollover-sized UDP attempt times out or returns a
   truncated certificate response, a client retrieving certificates
   through a relay SHOULD retry over TCP to the relay with an inner
   query large enough for the expected UDP certificate response.
   Alternatively, it can retrieve certificates directly from the
   resolver over TCP before using the relay for encrypted queries, with
   the associated privacy tradeoff.

11.9.  PQ Downgrade Protection

   An on-path attacker cannot forge a certificate, but it can drop the
   PQ records from an unauthenticated certificate response, leaving only
   a classical certificate and pushing the client onto a quantum-
   vulnerable exchange.

   A signature cannot prevent deletion.

   A client that has been provisioned with the knowledge that a resolver
   supports PQ, for example through a flag in the DNS stamp that already
   carries the provider name and public key, MUST NOT fall back to a
   classical <es-version> for that resolver.

   A client without such provisioning MAY fall back, accepting the
   classical risk.

11.10.  PQ Security Considerations

   Confidentiality against a future quantum adversary holds as long as
   either ML-KEM-768 or X25519 is unbroken, because X-Wing is a hybrid.

   Resolver authentication is as in classical DNSCrypt: the client
   encapsulates to a signed encapsulation key, and only the holder of
   the corresponding secret key can recover the shared secret and
   produce an authenticated response.

   The KEM ciphertext is not separately authenticated and does not need
   to be.

Denis                    Expires 24 January 2027               [Page 47]
Internet-Draft                  DNSCrypt                       July 2026

   X-Wing, through ML-KEM-768, uses implicit rejection: a malformed but
   correctly sized ciphertext yields a pseudo-random shared secret
   rather than an error, so a tampered ciphertext produces a different
   key and authentication fails.

   A resolver MUST drop such a query exactly as it drops any query that
   fails authentication, and the outcome on the wire MUST NOT reveal,
   through a distinct response, error, or timing, whether decapsulation,
   key derivation, or authentication failed; otherwise the resolver
   becomes a decapsulation oracle.

   KEM and X25519 operations SHOULD be constant-time with respect to
   secret data.

   Forward secrecy for queries that carry a ciphertext has the same
   granularity as classical resolver-key rotation, since the resolver
   KEM key is short-term and the client's encapsulation randomness is
   fresh per query.

   For resumed queries, recorded traffic remains decryptable until every
   TK able to open its ticket has been destroyed, so their forward
   secrecy follows the ticket-key lifetime.

   Nonce uniqueness is required as in classical DNSCrypt.

   For queries that carry a ciphertext, each has an independent key, so
   cross-query collisions cannot occur; for resumed queries the per-
   query key derivation uses <client-nonce>, so clients MUST keep it
   unique for the lifetime of a ticket.

12.  IANA Considerations

   This document has no IANA actions.

13.  Appendix 1: The Box-XChaChaPoly Algorithm

   The Box-XChaChaPoly algorithm combines the X25519 [RFC7748] key
   exchange mechanism with a variant of the ChaCha20-Poly1305
   construction specified in [RFC8439].

13.1.  Conventions and Definitions

   *  x[a..]: the subarray of x starting at index a, and extending to
      the last index of x

   *  x[a..b]: the subarray of x starting at index a and ending
      immediately before index b.

Denis                    Expires 24 January 2027               [Page 48]
Internet-Draft                  DNSCrypt                       July 2026

   *  LOAD32_LE(p): returns a 32-bit unsigned integer from the 4-byte
      array p

   *  STORE32_LE(p, x): stores the 32-bit unsigned integer x into the
      4-byte array p

13.2.  HChaCha20

   HChaCha20 is the subkey derivation step used by the extended-nonce
   ChaCha20 construction in this appendix.

   The HChaCha20 function takes the following input parameters:

   *  <k>: secret key

   *  <in>: a 128-bit input

   and returns a 256-bit keyed hash.

   The function can be implemented using an existing IETF-compliant
   ChaCha20 implementation as follows:

   block_bytes = ChaCha20(msg={0}**64, nonce=in[4..16],
                          counter=LOAD32_LE(in[0..4]), key=k)

   block_out[0] = LOAD32_LE(block_bytes[ 0..][0..4]) - 0x61707865
   block_out[1] = LOAD32_LE(block_bytes[ 4..][0..4]) - 0x3320646e
   block_out[2] = LOAD32_LE(block_bytes[ 8..][0..4]) - 0x79622d32
   block_out[3] = LOAD32_LE(block_bytes[12..][0..4]) - 0x6b206574
   block_out[4] =
      LOAD32_LE(block_bytes[48..][0..4]) - LOAD32_LE(in[ 0..][0..4])
   block_out[5] =
      LOAD32_LE(block_bytes[52..][0..4]) - LOAD32_LE(in[ 4..][0..4])
   block_out[6] =
      LOAD32_LE(block_bytes[56..][0..4]) - LOAD32_LE(in[ 8..][0..4])
   block_out[7] =
      LOAD32_LE(block_bytes[60..][0..4]) - LOAD32_LE(in[12..][0..4])

   for i in 0..8:
       STORE32_LE(out[i * 4..][0..4], block_out[i])

   return out

13.3.  Test Vector For The HChaCha20 Block Function

Denis                    Expires 24 January 2027               [Page 49]
Internet-Draft                  DNSCrypt                       July 2026

   k:    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f

   in:   000102030405060708090a0b0c0d0e0f

   out:  51e3ff45a895675c4b33b46c64f4a9ace110d34df6a2ceab486372bacbd3eff6

13.4.  ChaCha20_DJB

   As opposed to the version standardized for IETF protocols, ChaCha20
   was originally designed to have a 8 byte nonce.

   For the needs of TLS, [RFC8439] changed this by setting N_MIN and
   N_MAX to 12, at the expense of a smaller internal counter.

   DNSCrypt uses ChaCha20 as originally specified, with N_MIN = N_MAX =
   8.

   We refer to this variant as ChaCha20_DJB.

   The internal counter in ChaCha20_DJB is 4 bytes larger than ChaCha20.

   There are no other differences between ChaCha20_DJB and ChaCha20.

13.5.  XChaCha20_DJB

   XChaCha20_DJB can be constructed from an existing ChaCha20
   implementation and the HChaCha20 function.

   All that needs to be done is:

   1.  Pass the key and the first 16 bytes of the 24-byte nonce to
       HChaCha20 to obtain the subkey.

   2.  Use the subkey and remaining 8 byte nonce with ChaCha20_DJB.

13.6.  XChaCha20_DJB-Poly1305

   XChaCha20 is a stream cipher and offers no integrity guarantees
   without being combined with a MAC algorithm (e.g. Poly1305).

   XChaCha20_DJB-Poly1305 adds an authentication tag to the ciphertext
   encrypted with XChaCha20_DJB.

   It is the combined mode used by the NaCl secretbox and crypto_box
   constructions, instantiated with XChaCha20_DJB.

Denis                    Expires 24 January 2027               [Page 50]
Internet-Draft                  DNSCrypt                       July 2026

   The one-time Poly1305 key is taken from the start of the keystream,
   and the message is encrypted with the keystream that immediately
   follows it.

   No separate keystream block is reserved for the Poly1305 key, so this
   layout differs from the AEAD of [RFC8439], where the message starts
   at block counter 1 and the rest of the first keystream block is
   discarded.

   Concretely, for a key <k>, nonce <n>, and message <m>:

   *  <k>: encryption key

   *  <n>: 24-byte nonce

   *  <m>: message to encrypt

   *  <keystream>: the XChaCha20_DJB keystream produced from <k> and
      <n>, starting at block counter 0.

   *  <poly-key>: <keystream>[0..32], the one-time Poly1305 key.  These
      bytes are not transmitted.

   *  <ct>: <m> XOR <keystream>[32..32 + length(<m>)], the ciphertext.

   *  <tag>: Poly1305(<poly-key>, <ct>), the 16-byte tag.

   *  XChaCha20_DJB-Poly1305(<k>, <n>, <m>): <tag> || <ct>

   Equivalently, XChaCha20_DJB is run over the buffer <zero32> || <m>,
   where <zero32> is 32 NUL bytes, starting at block counter 0; the
   first 32 output bytes are taken as <poly-key>, and the remaining
   length(<m>) bytes are <ct>.

13.7.  The Box-XChaChaPoly Algorithm

   The Box-XChaChaPoly algorithm combines the key exchange mechanism
   X25519 defined [RFC7748] with the XChaCha20_DJB-Poly1305
   authenticated encryption algorithm.

   *  <k>: encryption key

   *  <m>: message to encrypt

   *  <n>: 24-byte nonce

   *  <pk>: recipient's public key

Denis                    Expires 24 January 2027               [Page 51]
Internet-Draft                  DNSCrypt                       July 2026

   *  <sk>: sender's secret key

   *  <zero16>: 16 NUL bytes

   *  <sk'>: HChaCha20(X25519(<pk>, <sk>), <zero16>), the shared key

   *  Box-XChaChaPoly(pk, sk, n, m): XChaCha20_DJB-Poly1305(<sk'>, <n>,
      <m>)

14.  Appendix 2: DNSCrypt Test Vectors

   This appendix provides complete, reproducible test vectors for the
   regular DNSCrypt protocol with the Box-XChaChaPoly encryption system
   of Appendix 1, that is, <es-version> 0x00 0x02: X25519 key exchange,
   the XChaCha20_DJB-Poly1305 AEAD, and Ed25519 certificate signatures.

   All randomness is pinned so the vectors are reproducible.

   Every value is given in full as a hexadecimal string, wrapped to 32
   bytes per line.

   The field and byte order of each artifact matches the Protocol
   Components and Certificates sections.

   These vectors were cross-checked byte for byte against the dnscrypt-
   proxy reference implementation.

14.1.  Pinned Inputs

   The secret keys below are the raw 32-byte X25519 scalars as stored by
   an implementation; X25519 clamps them internally.

   The provider signing key is given as its 32-byte Ed25519 seed.

Denis                    Expires 24 January 2027               [Page 52]
Internet-Draft                  DNSCrypt                       July 2026

   +===============================+========+=========================+
   | Input                         | Length | Value                   |
   +===============================+========+=========================+
   | provider Ed25519 signing seed | 32     | 00 01 02 ... 1f         |
   +-------------------------------+--------+-------------------------+
   | resolver X25519 secret key    | 32     | 20 21 22 ... 3f         |
   +-------------------------------+--------+-------------------------+
   | client X25519 secret key      | 32     | 40 41 42 ... 5f         |
   +-------------------------------+--------+-------------------------+
   | <client-magic>                | 8      | b1 b2 b3 b4 b5 b6 b7 b8 |
   +-------------------------------+--------+-------------------------+
   | <es-version>                  | 2      | 00 02                   |
   +-------------------------------+--------+-------------------------+
   | <protocol-minor-version>      | 2      | 00 00                   |
   +-------------------------------+--------+-------------------------+
   | <serial>                      | 4      | 00 00 00 01             |
   +-------------------------------+--------+-------------------------+
   | <ts-start>                    | 4      | 68 00 00 00             |
   +-------------------------------+--------+-------------------------+
   | <ts-end>                      | 4      | 68 01 51 80             |
   +-------------------------------+--------+-------------------------+
   | query <client-nonce>          | 12     | a0 a1 a2 ... ab         |
   +-------------------------------+--------+-------------------------+
   | response <resolver-nonce>     | 12     | c0 c1 c2 ... cb         |
   +-------------------------------+--------+-------------------------+
   | <extensions>                  | 0      | empty                   |
   +-------------------------------+--------+-------------------------+

                                 Table 1

   <client-magic> is chosen by the resolver and carried in the
   certificate; the client copies it verbatim into the first 8 bytes of
   every query.

   <ts-start> and <ts-end> span exactly 86400 seconds (a one-day
   validity window).

   The fixed protocol constants are <cert-magic> = 44 4e 53 43, <es-
   version> = 00 02, and <resolver-magic> = 72 36 66 6e 76 57 6a 38.

   The example DNS messages are a query and its answer for
   www.example.com:

Denis                    Expires 24 January 2027               [Page 53]
Internet-Draft                  DNSCrypt                       July 2026

   dns-query (33 bytes), id 0x1234, RD set, A? www.example.com IN:
     12340100000100000000000003777777076578616d706c6503636f6d00000100
     01
   dns-response (49 bytes), A 93.184.216.34, TTL 3600:
     12348180000100010000000003777777076578616d706c6503636f6d00000100
     01c00c0001000100000e1000045db8d822

14.2.  Public Keys and Shared Key

   provider-ed25519-pk = Ed25519 public key for the signing seed:
     03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8
   resolver-pk = X25519 base-point mult of the resolver secret key:
     358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254
   client-pk = X25519 base-point mult of the client secret key:
     79a631eede1bf9c98f12032cdeadd0e7a079398fc786b88cc846ec89af85a51a

   x25519-shared-point = X25519(client-sk, resolver-pk)
                       = X25519(resolver-sk, client-pk):
     04c304fb1ca83cee75e206344231f33797e07d9929db670994b7c6fbeb1dc255
   shared-key = HChaCha20(key = x25519-shared-point, in = 16 NUL bytes):
     335d32f2d65e6623cbbd05b6539c9575fee16cb5405fe839ab4bd291fdf13262

   The same shared-key is computed by the client from (client-sk,
   resolver-pk) and by the resolver from (resolver-sk, client-pk).

14.3.  Certificate

   The signature covers <resolver-pk> <client-magic> <serial> <ts-start>
   <ts-end> <extensions>, with <extensions> empty in this protocol
   version:

signed input (52 bytes):
  358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254
  b1b2b3b4b5b6b7b8000000016800000068015180
signature = Ed25519.Sign(provider signing seed, signed input) (64 bytes):
  3a570ea17f47b80217977fbb455840bfd50ab32f5fbf2aabc173a6a49b7a49ca
  55362a6c5dec47657cf515e9f99382a316dfecd964b94d1c4659cac45961400c

   The full certificate, as carried in a TXT record, is 124 bytes:

Denis                    Expires 24 January 2027               [Page 54]
Internet-Draft                  DNSCrypt                       July 2026

     +========+==========================+========+=================+
     | Offset | Field                    | Length | Value           |
     +========+==========================+========+=================+
     | 0      | <cert-magic>             | 4      | 44 4e 53 43     |
     +--------+--------------------------+--------+-----------------+
     | 4      | <es-version>             | 2      | 00 02           |
     +--------+--------------------------+--------+-----------------+
     | 6      | <protocol-minor-version> | 2      | 00 00           |
     +--------+--------------------------+--------+-----------------+
     | 8      | <signature>              | 64     | 3a 57 ... 40 0c |
     +--------+--------------------------+--------+-----------------+
     | 72     | <resolver-pk>            | 32     | 35 80 ... 62 54 |
     +--------+--------------------------+--------+-----------------+
     | 104    | <client-magic>           | 8      | b1 b2 b3 b4 b5  |
     |        |                          |        | b6 b7 b8        |
     +--------+--------------------------+--------+-----------------+
     | 112    | <serial>                 | 4      | 00 00 00 01     |
     +--------+--------------------------+--------+-----------------+
     | 116    | <ts-start>               | 4      | 68 00 00 00     |
     +--------+--------------------------+--------+-----------------+
     | 120    | <ts-end>                 | 4      | 68 01 51 80     |
     +--------+--------------------------+--------+-----------------+

                                 Table 2

   certificate (124 bytes):
     444e5343000200003a570ea17f47b80217977fbb455840bfd50ab32f5fbf2aab
     c173a6a49b7a49ca55362a6c5dec47657cf515e9f99382a316dfecd964b94d1c
     4659cac45961400c358072d6365880d1aeea329adf9121383851ed21a28e3b75
     e965d0d2cd166254b1b2b3b4b5b6b7b8000000016800000068015180

14.4.  Certificate Retrieval

   The certificate lookup name is 2.dnscrypt-cert.example.com.

   With DNS transaction ID 0xabcd, RD set, one TXT/IN question, and no
   EDNS(0) padding, the DNS request is:

   certificate query (45 bytes):
     abcd0100000100000000000001320d646e7363727970742d6365727407657861
     6d706c6503636f6d0000100001

   The successful response carrying the 124-byte certificate above is
   182 bytes.

Denis                    Expires 24 January 2027               [Page 55]
Internet-Draft                  DNSCrypt                       July 2026

   This is the classical certificate response used by deployed DNSCrypt
   v2 resolvers: the flags word 0x8180 sets QR and RA, echoes RD from
   the query, and leaves RCODE at 0.  The TXT record TTL is an
   operational choice, 86400 seconds in this vector.

   If larger PQ certificate records are also available, a resolver can
   return this classical response with the TC flag set when the complete
   classical-plus-PQ response would exceed the triggering UDP request.

   certificate response with one TXT answer (182 bytes):
     abcd8180000100010000000001320d646e7363727970742d6365727407657861
     6d706c6503636f6d0000100001c00c0010000100015180007d7c444e53430002
     00003a570ea17f47b80217977fbb455840bfd50ab32f5fbf2aabc173a6a49b7a
     49ca55362a6c5dec47657cf515e9f99382a316dfecd964b94d1c4659cac45961
     400c358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd
     166254b1b2b3b4b5b6b7b8000000016800000068015180

   An EDNS(0)-padded UDP certificate query for the same question and
   transaction ID can be built by setting ARCOUNT = 1 and appending one
   OPT pseudo-RR with UDP payload size 4096 and a Padding option.

   For a 512-byte request, the Padding option data is 452 NUL bytes:

   base question length       = 45
   OPT pseudo-RR fixed header = 11
   Padding option header      = 4
   Padding option data        = 452
   total request length       = 512

   OPT pseudo-RR:
     00002910000000000001c8000c01c4 || (452 * 00)

14.5.  Client Query (UDP)

   For this fixed vector, the plaintext is the DNS query padded with
   ISO/IEC 7816-4 to 256 bytes: one 0x80 byte followed by NUL bytes.

   The complete encrypted DNSCrypt query is 324 bytes, which is above
   the initial 256-byte UDP query-size target.

   The 24-byte AEAD nonce is the 12-byte client nonce followed by 12 NUL
   bytes.

Denis                    Expires 24 January 2027               [Page 56]
Internet-Draft                  DNSCrypt                       July 2026

   padded query plaintext (256 bytes):
     12340100000100000000000003777777076578616d706c6503636f6d00000100
     0180000000000000000000000000000000000000000000000000000000000000
     0000000000000000000000000000000000000000000000000000000000000000
     0000000000000000000000000000000000000000000000000000000000000000
     0000000000000000000000000000000000000000000000000000000000000000
     0000000000000000000000000000000000000000000000000000000000000000
     0000000000000000000000000000000000000000000000000000000000000000
     0000000000000000000000000000000000000000000000000000000000000000
   query AEAD nonce (24 bytes):
     a0a1a2a3a4a5a6a7a8a9aaab000000000000000000000000
   encrypted-query = tag (16) || ciphertext (256) (272 bytes):
     2dae527c26386d5cd4e61152db6dd1812ff6aaf7644fc122afc70b1b580b18f1
     0fbc26577abc759152cde31cd0afc5c5f452f8654815469723300819bed5a120
     15c044b94d63ec1f79e48a23968e437feb8bb8720cf4e60a0499746190c8b3eb
     83aeb0d858df77794270b861f86644502be0d22d6f0b2b132e9ca68538300c8d
     68b8e3c48190cbbf96d602f38dfc3b4d642016ceeaf4bc2c2ded9483b9f9d4ee
     d703a0bebc252add8822d4b9152e30670bcde9ea75a0e3e67ea576e9b1262bb2
     b25b4f9432311b75a2238b34bf4f868da182b85dccb1762a703bba31d04d77b4
     c57ec9039663959793677588b3a74ae409b0f16374dd64cbd6d47d801725b014
     ce9ddaf6f1aa30688c8efcbfde1d5d1d

   Query on the wire (324 bytes):

     +========+===================+========+=========================+
     | Offset | Field             | Length | Value                   |
     +========+===================+========+=========================+
     | 0      | <client-magic>    | 8      | b1 b2 b3 b4 b5 b6 b7 b8 |
     +--------+-------------------+--------+-------------------------+
     | 8      | <client-pk>       | 32     | 79 a6 ... a5 1a         |
     +--------+-------------------+--------+-------------------------+
     | 40     | <client-nonce>    | 12     | a0 a1 ... ab            |
     +--------+-------------------+--------+-------------------------+
     | 52     | <encrypted-query> | 272    | 2d ae ... d5 1d         |
     +--------+-------------------+--------+-------------------------+

                                  Table 3

Denis                    Expires 24 January 2027               [Page 57]
Internet-Draft                  DNSCrypt                       July 2026

   full query wire (324 bytes):
     b1b2b3b4b5b6b7b879a631eede1bf9c98f12032cdeadd0e7a079398fc786b88c
     c846ec89af85a51aa0a1a2a3a4a5a6a7a8a9aaab2dae527c26386d5cd4e61152
     db6dd1812ff6aaf7644fc122afc70b1b580b18f10fbc26577abc759152cde31c
     d0afc5c5f452f8654815469723300819bed5a12015c044b94d63ec1f79e48a23
     968e437feb8bb8720cf4e60a0499746190c8b3eb83aeb0d858df77794270b861
     f86644502be0d22d6f0b2b132e9ca68538300c8d68b8e3c48190cbbf96d602f3
     8dfc3b4d642016ceeaf4bc2c2ded9483b9f9d4eed703a0bebc252add8822d4b9
     152e30670bcde9ea75a0e3e67ea576e9b1262bb2b25b4f9432311b75a2238b34
     bf4f868da182b85dccb1762a703bba31d04d77b4c57ec9039663959793677588
     b3a74ae409b0f16374dd64cbd6d47d801725b014ce9ddaf6f1aa30688c8efcbf
     de1d5d1d

14.6.  Server Response (UDP)

   The plaintext is the DNS response padded with ISO/IEC 7816-4 to 64
   bytes.

   The 24-byte AEAD nonce is the client nonce followed by the resolver
   nonce.

   padded response plaintext (64 bytes):
     12348180000100010000000003777777076578616d706c6503636f6d00000100
     01c00c0001000100000e1000045db8d822800000000000000000000000000000
   response AEAD nonce (24 bytes):
     a0a1a2a3a4a5a6a7a8a9aaabc0c1c2c3c4c5c6c7c8c9cacb
   encrypted-response = tag (16) || ciphertext (64) (80 bytes):
     f2670995c6d37c2f8d2016029dd5970b893de83c02815ece9b48d9fd0b0dca87
     41674142fbd8e12c1120b111f366326aa71c89823a2931ac5c860dad49685ed6
     cc22cc13e829d2e51d1c00ea64d1d39d

   Response on the wire (112 bytes):

   +========+======================+========+=========================+
   | Offset | Field                | Length | Value                   |
   +========+======================+========+=========================+
   | 0      | <resolver-magic>     | 8      | 72 36 66 6e 76 57 6a 38 |
   +--------+----------------------+--------+-------------------------+
   | 8      | <nonce>              | 24     | a0..ab (client) c0..cb  |
   |        |                      |        | (resolver)              |
   +--------+----------------------+--------+-------------------------+
   | 32     | <encrypted-response> | 80     | f2 67 ... d3 9d         |
   +--------+----------------------+--------+-------------------------+

                                 Table 4

Denis                    Expires 24 January 2027               [Page 58]
Internet-Draft                  DNSCrypt                       July 2026

   full response wire (112 bytes):
     7236666e76576a38a0a1a2a3a4a5a6a7a8a9aaabc0c1c2c3c4c5c6c7c8c9cacb
     f2670995c6d37c2f8d2016029dd5970b893de83c02815ece9b48d9fd0b0dca87
     41674142fbd8e12c1120b111f366326aa71c89823a2931ac5c860dad49685ed6
     cc22cc13e829d2e51d1c00ea64d1d39d

14.7.  Padding and Transport Notes

   The vectors fix the padded plaintext lengths so they are
   reproducible:

   *  The query plaintext is padded to 256 bytes for this vector.
      Production clients can choose larger targets for the complete
      encrypted DNSCrypt packet; for example, a client can target a 512-
      byte-or-larger UDP packet and compute the plaintext padding after
      subtracting DNSCrypt overhead.

   *  The response plaintext is padded to the smallest multiple of 64
      that holds the response plus at least one padding byte, here 64
      bytes.  The exact response padding length is otherwise an
      implementation choice, subject to the encrypted UDP response being
      no larger than the encrypted query.

   *  Over TCP the encryption is identical, but each packet is prefixed
      with a two-byte big-endian length, and the query padding length is
      chosen at random as described in Query Processing.  For the fixed
      packets above, the 324-byte query is prefixed with 01 44, and the
      112-byte response is prefixed with 00 70.

14.8.  Negative Cases

   These vectors pin the required failure behavior.

   None of them produce a distinguishable on-the-wire signal beyond "no
   response" or "certificate rejected".

   1.  Tampered ciphertext: flipping any byte of <encrypted-query> or
       <encrypted-response> makes Poly1305 verification fail.  The
       receiver MUST drop the packet.

   2.  Bad padding: after a successful decryption, the plaintext MUST
       end with a 0x80 byte followed by zero or more NUL bytes.  A
       plaintext that does not MUST be rejected.

   3.  Wrong <client-magic>: a query whose first 8 bytes do not match
       the <client-magic> of any certificate the resolver currently
       serves is not a DNSCrypt query for this resolver.  The resolver
       MUST NOT treat it as one.

Denis                    Expires 24 January 2027               [Page 59]
Internet-Draft                  DNSCrypt                       July 2026

   4.  Response nonce mismatch: the client MUST verify that the <client-
       nonce> prefix (first 12 bytes) of the response nonce matches an
       outstanding query, and otherwise drop the response.

   5.  Weak public key: if the X25519 shared point is the all-zero
       value, the public key is of low order and the shared key MUST be
       rejected.

   6.  Certificate outside its validity window: a certificate whose <ts-
       start>/<ts-end> does not include the current time MUST NOT be
       used, and among valid certificates the client picks the highest
       <serial>.

15.  Appendix 3: PQ Test Vector Structure

   This appendix fixes the exact field order and byte order for PQ.

   Long cryptographic outputs, namely KEM keys and ciphertexts, the
   Ed25519 signature, AEAD outputs, and HKDF outputs, are left as
   placeholders to be filled in by a reference implementation.

   Everything structural is pinned here, so that two implementations
   cannot disagree about layout even before the hex values exist.

   All integers are big-endian.

   Every AEAD operation is XChaCha20_DJB-Poly1305 as defined in
   Appendix 1, with the 16-byte tag prepended to the ciphertext.

   Every key derivation is HKDF-SHA256 [RFC5869].

   Placeholders are written [name: N bytes]; the concrete values they
   stand for appear in the Generated Values subsection at the end of
   this appendix.

15.1.  Provisional Assignments

   The following values are the provisional assignments used by these
   vectors.

   They are normative for the vectors but expected to be confirmed
   before publication.

Denis                    Expires 24 January 2027               [Page 60]
Internet-Draft                  DNSCrypt                       July 2026

   +==========================+=======================================+
   | Item                     | Value                                 |
   +==========================+=======================================+
   | <es-version> (X-Wing)    | 0x00 0x03                             |
   +--------------------------+---------------------------------------+
   | <resume-magic>           | 50 51 52 65 73 75 6d 65 ("PQResume")  |
   +--------------------------+---------------------------------------+
   | <kdf-id>                 | 0x01 (HKDF-SHA256)                    |
   +--------------------------+---------------------------------------+
   | <aead-id>                | 0x01 (XChaCha20_DJB-Poly1305)         |
   +--------------------------+---------------------------------------+
   | ticket AEAD              | XChaCha20_DJB-Poly1305, 24-byte nonce |
   +--------------------------+---------------------------------------+
   | <ticket-key-id>          | 4 bytes                               |
   +--------------------------+---------------------------------------+
   | <ticket-nonce>           | 24 bytes                              |
   +--------------------------+---------------------------------------+
   | <ticket-expiry>          | 4-byte Unix timestamp                 |
   +--------------------------+---------------------------------------+
   | <ticket-lifetime>        | 4-byte seconds                        |
   +--------------------------+---------------------------------------+
   | <profile-extension-hash> | SHA-256(<extensions>), 32 bytes       |
   +--------------------------+---------------------------------------+

                                 Table 5

15.2.  Pinned Inputs

   All randomness is fixed so the vectors are reproducible.

   Short values are given concretely; values produced by a primitive are
   placeholders.

   +===============================+========+=========================+
   | Input                         | Length | Value                   |
   +===============================+========+=========================+
   | provider Ed25519 signing seed | 32     | 00 01 02 ... 1f         |
   +-------------------------------+--------+-------------------------+
   | provider Ed25519 public key   | 32     | [provider-pk: 32 bytes] |
   +-------------------------------+--------+-------------------------+
   | resolver X-Wing secret seed   | 32     | 20 21 22 ... 3f         |
   +-------------------------------+--------+-------------------------+
   | resolver X-Wing public key    | 1216   | [resolver-pk: 1216      |
   |                               |        | bytes]                  |
   +-------------------------------+--------+-------------------------+
   | client X-Wing encapsulation   | 64     | 40 41 42 ... 7f         |
   | seed                          |        |                         |
   +-------------------------------+--------+-------------------------+

Denis                    Expires 24 January 2027               [Page 61]
Internet-Draft                  DNSCrypt                       July 2026

   | <es-version>                  | 2      | 00 03                   |
   +-------------------------------+--------+-------------------------+
   | <protocol-minor-version>      | 2      | 00 00                   |
   +-------------------------------+--------+-------------------------+
   | <client-magic>                | 8      | a1 b2 c3 d4 e5 f6 07 18 |
   +-------------------------------+--------+-------------------------+
   | <serial>                      | 4      | 00 00 00 01             |
   +-------------------------------+--------+-------------------------+
   | <ts-start>                    | 4      | 68 00 00 00             |
   +-------------------------------+--------+-------------------------+
   | <ts-end>                      | 4      | 68 01 51 80             |
   +-------------------------------+--------+-------------------------+
   | query <client-nonce>          | 12     | b0 b1 b2 ... bb         |
   +-------------------------------+--------+-------------------------+
   | response <resolver-nonce>     | 12     | c0 c1 c2 ... cb         |
   +-------------------------------+--------+-------------------------+
   | ticket key TK                 | 32     | 80 81 82 ... 9f         |
   +-------------------------------+--------+-------------------------+
   | <ticket-key-id>               | 4      | 00 00 00 01             |
   +-------------------------------+--------+-------------------------+
   | <ticket-nonce>                | 24     | d0 d1 d2 ... e7         |
   +-------------------------------+--------+-------------------------+
   | <ticket-expiry>               | 4      | 68 00 02 58             |
   +-------------------------------+--------+-------------------------+
   | <ticket-lifetime>             | 4      | 00 00 01 2c             |
   +-------------------------------+--------+-------------------------+
   | resumed <client-nonce>        | 12     | f0 f1 f2 ... fb         |
   +-------------------------------+--------+-------------------------+
   | resumed <resolver-nonce>      | 12     | 10 11 12 ... 1b         |
   +-------------------------------+--------+-------------------------+
   | example DNS query (A?         | 33     | [dns-query: 33 bytes]   |
   | www.example.com)              |        |                         |
   +-------------------------------+--------+-------------------------+
   | example DNS response          | var    | [dns-response]          |
   +-------------------------------+--------+-------------------------+

                                 Table 6

15.3.  Profile Extension and Signature Input

   The PQ profile extension is the entire <extensions> field in this
   revision:

Denis                    Expires 24 January 2027               [Page 62]
Internet-Draft                  DNSCrypt                       July 2026

   pq-profile-ext =
       "PQD"             50 51 44
       ext-version       01
       es-version        00 03
       kdf-id            01            (HKDF-SHA256)
       aead-id           01            (XChaCha20_DJB-Poly1305)
       resolver-pk-len   04 c0         (1216)
       client-kex-len    04 60         (1120)
                                       -> 12 bytes total

   The Ed25519 signature is computed over the existing field set,
   unchanged:

sig-input = resolver-pk (1216) || client-magic (8) || serial (4)
            || ts-start (4) || ts-end (4) || extensions (12)
          -> 1248 bytes
signature = Ed25519.Sign(provider-seed, sig-input)  = [signature: 64 bytes]

   The full certificate (92 fixed bytes + 1216-byte resolver key +
   12-byte extensions = 1320 bytes):

Denis                    Expires 24 January 2027               [Page 63]
Internet-Draft                  DNSCrypt                       July 2026

    +========+==========================+========+===================+
    | Offset | Field                    | Length | Value             |
    +========+==========================+========+===================+
    | 0      | <cert-magic>             | 4      | 44 4e 53 43       |
    +--------+--------------------------+--------+-------------------+
    | 4      | <es-version>             | 2      | 00 03             |
    +--------+--------------------------+--------+-------------------+
    | 6      | <protocol-minor-version> | 2      | 00 00             |
    +--------+--------------------------+--------+-------------------+
    | 8      | <signature>              | 64     | [signature: 64    |
    |        |                          |        | bytes]            |
    +--------+--------------------------+--------+-------------------+
    | 72     | <resolver-pk>            | 1216   | [resolver-pk:     |
    |        |                          |        | 1216 bytes]       |
    +--------+--------------------------+--------+-------------------+
    | 1288   | <client-magic>           | 8      | a1 b2 c3 d4 e5 f6 |
    |        |                          |        | 07 18             |
    +--------+--------------------------+--------+-------------------+
    | 1296   | <serial>                 | 4      | 00 00 00 01       |
    +--------+--------------------------+--------+-------------------+
    | 1300   | <ts-start>               | 4      | 68 00 00 00       |
    +--------+--------------------------+--------+-------------------+
    | 1304   | <ts-end>                 | 4      | 68 01 51 80       |
    +--------+--------------------------+--------+-------------------+
    | 1308   | <extensions>             | 12     | 50 51 44 01 00 03 |
    |        |                          |        | 01 01 04 c0 04 60 |
    +--------+--------------------------+--------+-------------------+

                                 Table 7

15.4.  Full X-Wing Query

Denis                    Expires 24 January 2027               [Page 64]
Internet-Draft                  DNSCrypt                       July 2026

(resolver-pk, resolver-sk) = X-Wing.GenerateKeyPairDerand(resolver-seed)
(ct, kem-ss)               = X-Wing.EncapsulateDerand(resolver-pk, eseed)
    ct      = [ct: 1120 bytes]
    kem-ss  = [kem-ss: 32 bytes]

cert-context = "DNSCrypt-PQ-v1"            (14 bytes)
            || es-version (00 03) || protocol-minor-version (00 00)
            || resolver-pk (1216) || client-magic (8)
            || serial (4) || ts-start (4) || ts-end (4)
            || extensions (12)

shared-key = HKDF-SHA256(
                 IKM  = kem-ss,
                 salt = es-version || client-magic
                        (10 bytes: 00 03 a1 b2 c3 d4 e5 f6 07 18),
                 info = cert-context || ct,
                 L    = 32)                  = [shared-key: 32 bytes]

query-nonce = client-nonce || (12 * 00)      (24 bytes)
plaintext   = dns-query (33) || 80 || (30 * 00)
              (padded to 64; ISO/IEC 7816-4)
encrypted-query = tag (16) || ciphertext (64)     = [enc-query: 80 bytes]

   Query on the wire (1220 bytes):

     +========+===================+========+=========================+
     | Offset | Field             | Length | Value                   |
     +========+===================+========+=========================+
     | 0      | <client-magic>    | 8      | a1 b2 c3 d4 e5 f6 07 18 |
     +--------+-------------------+--------+-------------------------+
     | 8      | <client-pk> = ct  | 1120   | [ct: 1120 bytes]        |
     +--------+-------------------+--------+-------------------------+
     | 1128   | <client-nonce>    | 12     | b0 b1 ... bb            |
     +--------+-------------------+--------+-------------------------+
     | 1140   | <encrypted-query> | 80     | [enc-query: 80 bytes]   |
     +--------+-------------------+--------+-------------------------+

                                  Table 8

15.5.  Full Response and Ticket Issuance

Denis                    Expires 24 January 2027               [Page 65]
Internet-Draft                  DNSCrypt                       July 2026

resume-secret = HKDF-SHA256(
                    IKM  = shared-key,
                    salt = client-magic || client-nonce  (20 bytes),
                    info = "DNSCrypt-PQ-resume-secret-v1",
                    L    = 32)               = [resume-secret: 32 bytes]

profile-extension-hash = SHA-256(extensions) = [peh: 32 bytes]

ticket-plain = resume-secret (32) || es-version (2) || client-magic (8)
            || serial (4) || ts-end (4) || ticket-expiry (4)
            || profile-extension-hash (32)   (86 bytes)

ticket = ticket-key-id (4) || ticket-nonce (24)
      || AE(TK, ticket-nonce, ticket-plain)
         where AE output = tag (16) || ciphertext (86)
      -> 4 + 24 + 102 = 130 bytes            = [ticket: 130 bytes]

control = "PQDR" (50 51 44 52) || control-version (01)
       || ticket-lifetime (00 00 01 2c) || ticket-len (00 82)
       || ticket (130)                       (141 bytes)

pq-response-plain = control-len (00 8d) || control (141)
                  || dns-response || pad-to-64

response-nonce = client-nonce || resolver-nonce   (24 bytes)
encrypted-response = tag (16) || ciphertext       = [enc-response]

   Response on the wire:

   +======================+========+===================================+
   | Field                | Length | Value                             |
   +======================+========+===================================+
   | <resolver-magic>     | 8      | 72 36 66 6e 76 57 6a 38           |
   +----------------------+--------+-----------------------------------+
   | <nonce>              | 24     | b0..bb (client) c0..cb            |
   |                      |        | (resolver)                        |
   +----------------------+--------+-----------------------------------+
   | <encrypted-response> | var    | [enc-response]                    |
   +----------------------+--------+-----------------------------------+

                                  Table 9

15.6.  Resumed Query and Response

Denis                    Expires 24 January 2027               [Page 66]
Internet-Draft                  DNSCrypt                       July 2026

resumed shared-key = HKDF-SHA256(
                         IKM  = resume-secret,
                         salt = client-magic || resumed-client-nonce
                                (20 bytes),
                         info = "DNSCrypt-PQ-resumed-query-v1"
                                || SHA-256(ticket),
                         L    = 32)          = [resumed-shared-key: 32 bytes]

query-nonce = resumed-client-nonce || (12 * 00)   (24 bytes)
plaintext   = dns-query || 80 || pad        (padded to 256 for this vector)
encrypted-query = tag (16) || ciphertext (256)    = [enc-query: 272 bytes]

   Resumed query on the wire (424 bytes):

     +========+===================+========+=========================+
     | Offset | Field             | Length | Value                   |
     +========+===================+========+=========================+
     | 0      | <resume-magic>    | 8      | 50 51 52 65 73 75 6d 65 |
     +--------+-------------------+--------+-------------------------+
     | 8      | <ticket-len>      | 2      | 00 82 (130)             |
     +--------+-------------------+--------+-------------------------+
     | 10     | <ticket>          | 130    | [ticket: 130 bytes]     |
     +--------+-------------------+--------+-------------------------+
     | 140    | <client-nonce>    | 12     | f0 f1 ... fb            |
     +--------+-------------------+--------+-------------------------+
     | 152    | <encrypted-query> | 272    | [enc-query: 272 bytes]  |
     +--------+-------------------+--------+-------------------------+

                                  Table 10

   The resumed response reuses resumed shared-key with nonce resumed-
   client-nonce || resumed-resolver-nonce.

   If the resolver issues no new ticket, the control block is empty
   (control-len = 00 00).

15.7.  Negative Cases

   These vectors pin the required failure behavior.

   None of them produce a distinguishable on-the-wire signal beyond "no
   response" or "certificate rejected".

   1.  Bad profile-extension length: resolver-pk-len or client-kex-len
       in the extension disagrees with the actual field length, or pq-
       profile-ext is not 12 bytes.  The client MUST reject the
       certificate.

Denis                    Expires 24 January 2027               [Page 67]
Internet-Draft                  DNSCrypt                       July 2026

   2.  <es-version> mismatch: the on-the-wire <es-version> differs from
       the copy inside the signed extension.  The client MUST reject the
       certificate.

   3.  Corrupted ticket AEAD: one byte of the sealed region of <ticket>
       in a resumed query is flipped.  AEAD opening fails, and the
       resolver MUST silently drop the query.

   4.  Expired or rotated ticket: <ticket-expiry> is in the past, or
       <ticket-key-id> names a TK that has been rotated out.  The
       resolver MUST silently drop the query; the client re-handshakes
       with a query that carries a ciphertext.

   5.  Ticket context mismatch: any sealed certificate-context field in
       the ticket (<es-version>, <client-magic>, <serial>, <ts-end>, or
       <profile-extension-hash>) does not match the resumption context.
       The resolver MUST silently drop the query.

   6.  Malformed KEM ciphertext: one byte of <client-pk> in a query that
       carries a ciphertext is flipped.  X-Wing implicit rejection
       yields a different shared secret, authentication fails, and the
       resolver MUST silently drop the query, with no distinct error or
       timing.

   7.  Repeated nonce (client obligation): reusing a <client-nonce>
       under one ticket reuses both the derived key and the AEAD nonce;
       this is a client MUST NOT.  A stateless resolver cannot detect
       it, so there is no wire vector; it is listed to make the
       obligation explicit.

   8.  Under-padded resumed query: a resumed UDP query whose complete
       packet is below the 256-byte query-size target decrypts correctly
       but violates the anti-amplification guidance, and an Anonymized
       DNSCrypt relay MAY drop its response on the response-size check.

15.8.  Generated Values

   The values below were produced by a reference generator from the
   pinned inputs above, and are reproducible by any conformant
   implementation.

   Values up to 141 bytes are given in full; longer artifacts are pinned
   by their SHA-256 digest.

   The generator self-checks against the HChaCha20 known-answer test of
   Appendix 1 and the official X-Wing known-answer test, and verifies
   that X-Wing decapsulation recovers the encapsulated secret.

Denis                    Expires 24 January 2027               [Page 68]
Internet-Draft                  DNSCrypt                       July 2026

   provider-ed25519-pk (32):
     03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8
   resolver-pk (1216, SHA-256):
     a1f324bc0701f1234fbba7b11901023b3644f3bb8c6eb4ee4368d7e859eb6228
   client-kex / ct (1120, SHA-256):
     f6bf3f238e83f24cd444f2887e8fd32d630e07dbe6ca2f2b403aaf5333030c48
   kem-ss (32):
     8dac8602d4ce5e27e81335b54b25fdcaea86e56613214ee0522db4a5e0a38d50
   shared-key (32):
     e6d4ab9cffc9b49e2a64d80d7eb2dde280f806b89e834d596ad385b1dd75e9ef
   signature (64):
     811bab04e2e70c9d946296a93b4028d7c7bb84f32f597d3cf8aba29edc1b6b97
     4acc99dd00ec62cdcae477433d10bff20e1c432e1011ad8ad5324f68a294750c

   dns-query (33):
     12340100000100000000000003777777076578616d706c6503636f6d00000100
     01
   dns-response (49):
     12348180000100010000000003777777076578616d706c6503636f6d00000100
     01c00c0001000100000e1000045db8d822
   padded query plaintext (64):
     12340100000100000000000003777777076578616d706c6503636f6d00000100
     0180000000000000000000000000000000000000000000000000000000000000
   encrypted-query (80):
     c41764468cb42d3a837c51234c08be714af49e1a6830ea6da28178e9e280d76b
     ac1b87fd7f56515f2b2cc3d4715aaa42907c282db1edff0bc3b92cd535a710e2
     64859a5bdaf67c17ffa6e1c6f6e02a50
   full query wire (1220, SHA-256):
     65c3421776283f503779916e7b5c32d0d41c885508ad892b349688db6c901233

   resume-secret (32):
     df158804e3f8ddf383ff7c9d3128491b29437a894936ec72c68aed8a9553272b
   profile-extension-hash = SHA-256(extensions) (32):
     fab3bf4996c5d2fdfc330ec958d0a5b63624bf3fbdc0fedfa9d94b0941a4060c
   ticket-plain (86):
     df158804e3f8ddf383ff7c9d3128491b29437a894936ec72c68aed8a9553272b
     0003a1b2c3d4e5f60718000000016801518068000258fab3bf4996c5d2fdfc33
     0ec958d0a5b63624bf3fbdc0fedfa9d94b0941a4060c
   ticket (130):
     00000001d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e1d90c86
     474574e0e51e82d8a29938896b0999e827138f8f452f21e044d9809f65a013cf
     ad8981be94c1354178b3e03dd518c28bcbaab962aa45246e446de7763288aa4a
     01e207725a0ae7bc95452fef3743f6083deb10cd23e2881e8d9307fc2f43bce1
     a97e
   control (141):
     50514452010000012c008200000001d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0
     e1e2e3e4e5e6e7e1d90c86474574e0e51e82d8a29938896b0999e827138f8f45
     2f21e044d9809f65a013cfad8981be94c1354178b3e03dd518c28bcbaab962aa

Denis                    Expires 24 January 2027               [Page 69]
Internet-Draft                  DNSCrypt                       July 2026

     45246e446de7763288aa4a01e207725a0ae7bc95452fef3743f6083deb10cd23
     e2881e8d9307fc2f43bce1a97e
   response plaintext, padded to 256 (256, SHA-256):
     a215df14b59d272b506224ed1f6ab5956be2bf189f847dfac4f8649c5f94d99e
   full response wire (304, SHA-256):
     33c081503d5ead4061a30d3f095fc9f226b8c01c3bbffa8fc6f4d9b15087de5c

   sha256(ticket) (32):
     fb196d81022c6b480f1340c80987088a85145194c18441928a4ae8e5a153536c
   resumed shared-key (32):
     e61f03acb2ee2ef01b952a0c312c60653267d47a2766fcfd804747fdf2fe789f
   resumed encrypted-query (272, SHA-256):
     60323805036492350ee442ee4dcb097597fb586e3f2c8a1f26feb9cdd0409b29
   resume query wire (424, SHA-256):
     34be2e331b4d7c7e808e968c5efc9f25675a9de9064cb33f7c66950e0e4e6db7
   resume response wire, no new ticket (112, SHA-256):
     2bf202dd3f33d38854450e70a02bd1a317a23bf6d79c5dae406787c9c5f34f52

16.  Normative References

   [FIPS203]  National Institute of Standards and Technology, "Module-
              Lattice-Based Key-Encapsulation Mechanism Standard",
              FIPS 203, August 2024,
              <https://doi.org/10.6028/NIST.FIPS.203>.

   [RFC1035]  Mockapetris, P., "Domain names - implementation and
              specification", STD 13, RFC 1035, DOI 10.17487/RFC1035,
              November 1987, <https://www.rfc-editor.org/info/rfc1035>.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/info/rfc2119>.

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/info/rfc8174>.

   [RFC8439]  Nir, Y. and A. Langley, "ChaCha20 and Poly1305 for IETF
              Protocols", RFC 8439, DOI 10.17487/RFC8439, June 2018,
              <https://www.rfc-editor.org/info/rfc8439>.

   [RFC7766]  Dickinson, J., Dickinson, S., Bellis, R., Mankin, A., and
              D. Wessels, "DNS Transport over TCP - Implementation
              Requirements", RFC 7766, DOI 10.17487/RFC7766, March 2016,
              <https://www.rfc-editor.org/info/rfc7766>.

Denis                    Expires 24 January 2027               [Page 70]
Internet-Draft                  DNSCrypt                       July 2026

   [RFC5358]  Damas, J. and F. Neves, "Preventing Use of Recursive
              Nameservers in Reflector Attacks", BCP 140, RFC 5358,
              DOI 10.17487/RFC5358, October 2008,
              <https://www.rfc-editor.org/info/rfc5358>.

   [RFC6891]  Damas, J., Graff, M., and P. Vixie, "Extension Mechanisms
              for DNS (EDNS(0))", STD 75, RFC 6891,
              DOI 10.17487/RFC6891, April 2013,
              <https://www.rfc-editor.org/info/rfc6891>.

   [RFC7830]  Mayrhofer, A., "The EDNS(0) Padding Option", RFC 7830,
              DOI 10.17487/RFC7830, May 2016,
              <https://www.rfc-editor.org/info/rfc7830>.

   [RFC9000]  Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based
              Multiplexed and Secure Transport", RFC 9000,
              DOI 10.17487/RFC9000, May 2021,
              <https://www.rfc-editor.org/info/rfc9000>.

   [RFC4291]  Hinden, R. and S. Deering, "IP Version 6 Addressing
              Architecture", RFC 4291, DOI 10.17487/RFC4291, February
              2006, <https://www.rfc-editor.org/info/rfc4291>.

   [RFC1918]  Rekhter, Y., Moskowitz, B., Karrenberg, D., de Groot, G.
              J., and E. Lear, "Address Allocation for Private
              Internets", BCP 5, RFC 1918, DOI 10.17487/RFC1918,
              February 1996, <https://www.rfc-editor.org/info/rfc1918>.

   [RFC7748]  Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves
              for Security", RFC 7748, DOI 10.17487/RFC7748, January
              2016, <https://www.rfc-editor.org/info/rfc7748>.

   [I-D.connolly-cfrg-xwing-kem]
              Connolly, D., Schwabe, P., and B. Westerbaan, "X-Wing:
              general-purpose hybrid post-quantum KEM", Work in
              Progress, Internet-Draft, draft-connolly-cfrg-xwing-kem-
              10, 2 March 2026, <https://datatracker.ietf.org/doc/html/
              draft-connolly-cfrg-xwing-kem-10>.

   [RFC5869]  Krawczyk, H. and P. Eronen, "HMAC-based Extract-and-Expand
              Key Derivation Function (HKDF)", RFC 5869,
              DOI 10.17487/RFC5869, May 2010,
              <https://www.rfc-editor.org/info/rfc5869>.

Author's Address

   Frank Denis
   Individual Contributor

Denis                    Expires 24 January 2027               [Page 71]
Internet-Draft                  DNSCrypt                       July 2026

   Email: fde@00f.net

Denis                    Expires 24 January 2027               [Page 72]