RFC 9498

The GNU Name System

๐Ÿ“… published November 2023, from ietf

The GNU Name System ๐Ÿ’–

Okay bestie, let's get into it! ๐ŸŽ€ This is RFC 9498, and it's an Informational doc from the Independent Submission stream, so it isn't an Internet Standard. ๐ŸŒธ It was written by M. Schanzenbach (Fraunhofer AISEC), C. Grothoff (Berner Fachhochschule), and B. Fix (GNUnet e.V.), and it's dated November 2023. ISSN: 2070-1721. โœจ It doesn't obsolete or update any other RFCs, so it's a solo queen. ๐Ÿ‘‘

Here's the vibe: GNS is a decentralized, censorship-resistant way to resolve names, and it's a privacy-friendly alternative to DNS. ๐Ÿฆ‹ The spec covers the wire format of resource records, the resolution process, the crypto stuff, and the security and privacy considerations, all for implementers. ๐Ÿ’… It wasn't developed inside the IETF and doesn't have IETF consensus, so it's just here to inform people, guide GNS implementers, and keep implementations interoperable, like the existing GNUnet ones. ๐Ÿซถ


Status of This Memo

This document is not an Internet Standards Track specification; it is published for informational purposes. ๐ŸŒˆ

This is a contribution to the RFC Series, independently of any other RFC stream. The RFC Editor chose to publish it at their discretion and makes no statement about its value for implementation or deployment. ๐Ÿ’€ Documents approved by the RFC Editor are not candidates for any level of Internet Standard; see Section 2 of RFC 7841. ๐Ÿ™ˆ

Info about the current status, errata, and how to give feedback lives at https://www.rfc-editor.org/info/rfc9498. ๐Ÿ“

Copyright (c) 2023 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. Please review these carefully, because they describe your rights and restrictions with respect to this document. ๐Ÿ’œ


1. Introduction ๐Ÿงš

This spec describes the GNU Name System (GNS), a censorship-resistant, privacy-preserving, and decentralized domain name resolution protocol. โœจ GNS cryptographically secures the binding of names to arbitrary tokens, so it can double as an alternative to some of today's public key infrastructures. ๐Ÿ‘‘

Per DNS terminology [RFC1035], GNS roughly follows the idea of a local root zone deployment (see [RFC8806]). The difference is that the design encourages alternative roots and doesn't expect every deployment to use the same root zone, or any specific one. ๐Ÿฆ‹ In the GNS reference implementation, users can autonomously and freely delegate control of names to zones through their local configurations. GNS expects each user to be in control of their setup. ๐Ÿ’… By following the guidelines in Section 9.10, users should manage to avoid any confusion about how names get resolved. ๐Ÿซถ

Name resolution and zone dissemination are based on the principle of a petname system, where users can assign local names to zones. ๐ŸŒธ GNS has its roots in ideas from the Simple Distributed Security Infrastructure [SDSI], which enables decentralized mapping of secure identifiers to memorable names. ๐Ÿ˜ญ One of the first academic descriptions of the cryptographic ideas behind GNS can be found in [GNS]. ๐Ÿ”ฅ

This document defines the normative wire format of resource records, resolution processes, cryptographic routines, and security and privacy considerations for use by implementers. ๐ŸŽ€

1.1. Requirements Notation ๐Ÿ’–

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. ๐Ÿงš Lowercase means it's just regular English, bestie, no cap. โœจ

2. Terminology โœจ

Apex Label: ๐ŸŒธ This label type is used to publish resource records in a zone so they can be resolved without giving a specific label. It's GNS's version of what DNS calls the "zone apex" [RFC4033]. The apex label is written as U+0040 (@, no quotes).

Application: ๐Ÿ’… An application is any component that uses a GNS implementation to resolve names into records and then processes what it gets back.

Blinded Zone Key: ๐Ÿฆ‹ A blinded zone key is derived from a zone key and a label. The zone key and any blinded zone key made from it can't be linked to each other unless you know the exact label used to make the blind.

Extension Label: ๐Ÿงš This label type points at the authoritative zone that the record lives in. Its main job is redirection, where the redirection target is defined relative to the authoritative zone of the redirection record (see Section 5.2). The extension label is written as U+002B (+, no quotes).

Label Separator: ๐Ÿ“ Labels in a name are split up by the label separator, U+002E (., no quotes). In GNS, every label separator in a name means delegation to another zone, with two exceptions: zone Top-Level Domains (zTLDs, explained below) and boxed records (see Section 5.3.3).

Label: ๐Ÿ’œ A GNS label is a label as defined in [RFC8499]. Labels are UTF-8 strings in Unicode Normalization Form C (NFC) [Unicode-UAX15]. The apex label and the extension label have special jobs in the resolution protocol, which the rest of this document covers. Zone administrators MAY disallow certain labels that could easily be confused with other labels through registration policies (see also Section 9.4). ๐Ÿ‘€

Name: ๐ŸŽ€ A GNS name is a domain name as defined in [RFC8499]. Names are UTF-8 strings [RFC3629] made of an ordered list of labels joined by label separators. Resolution starts from the rightmost label. GNS doesn't put length limits on names or labels. Applications MAY make sure name and label lengths work with DNS and, especially, with Internationalized Domain Names for Applications (IDNA) [RFC5890]. In the spirit of [RFC5895], applications MAY preprocess names and labels to fit DNS or to match specific user expectations, for example by following [Unicode-UTS46]. A GNS name might look exactly like a DNS name, so applications and implementers need to be careful when handling GNS names (see Section 9.10). To avoid mixing up example domains with (reserved) DNS domains, this document uses the suffix .gns.alt in line with [RFC9476]. .gns.alt is also registered in the GANA ".alt Subdomains" registry [GANA]. ๐ŸŒˆ

Resolver: ๐Ÿ”ฅ In this document, the resolver is the part of a GNS implementation that handles the recursive name resolution logic defined in Section 7.

Resource Record: ๐Ÿ“ A GNS resource record is the information attached to a label in a GNS zone. Each one contains information defined by its resource record type.

Start Zone: ๐Ÿš€ To resolve any GNS name, you first need to figure out an initial Start Zone for it. The Start Zone can be spelled out in the name itself using a zTLD. Otherwise, it's worked out through a local suffix-to-zone mapping (see Section 7.1).

Top-Level Domain (TLD): ๐Ÿ‘‘ The rightmost part of a GNS name is a GNS TLD, and it can be made of one or more labels. Unlike DNS TLDs (defined in [RFC8499]), GNS doesn't expect everyone to share the same global root zone. Instead, apart from zTLDs (see Section 4.1), GNS TLDs usually come from the local resolver's configuration (see Section 7.1), so they might not be globally unique.

Zone: ๐Ÿซถ A GNS zone holds authoritative information (resource records). Each zone is uniquely identified by its zone key. Unlike DNS zones, a GNS zone doesn't need an SOA record under the apex label.

Zone Key: ๐Ÿ”‘ The zone key is the key that uniquely identifies a zone. It's usually the public key of an asymmetric key pair. However, the established term "public key" is a bit misleading here, because in GNS a zone key may be a shared secret that should not be disclosed to unauthorized parties. ๐Ÿ™ˆ

Zone Key Derivation Function: ๐Ÿงฎ The zone key derivation function (ZKDF) blinds a zone key using a label.

Zone Publisher: ๐Ÿ“ฎ The zone publisher is the part of a GNS implementation that handles local zone management and publication, as defined in Section 6.

Zone Owner: ๐Ÿ—๏ธ The zone owner holds the secret (usually a private key). That secret, together with a label and a value to sign, lets the owner create zone signatures that can be checked against the matching blinded zone key.

Zone Top-Level Domain (zTLD): ๐Ÿ’– A zTLD is a sequence of GNS labels at the end of a GNS name. It encodes a zone's type and zone key (see Section 4.1). Zone keys are statistically unique, so zTLDs are globally unique too. A zTLD label sequence can only be told apart from an ordinary TLD label sequence by trying to decode the labels into a zone type and zone key. ๐Ÿ•ต๏ธ

Zone Type: ๐ŸŒŸ A GNS zone's type decides the cipher system and binary encoding format used for its zone key, blinded zone keys, and cryptographic signatures.


3. Overview ๐Ÿฆ‹

GNS has the three properties that people usually use to describe a petname system. Let's break them down:

  • Global names through the concept of zTLDs: ๐ŸŒ Zones can be uniquely identified by their zone keys, and those keys are statistically unique. So zTLDs are globally unique mappings to zones. That means GNS domain names with a zTLD suffix are also globally unique. The catch? Names with zTLD suffixes aren't memorable. ๐Ÿ˜ญ
  • Memorable petnames for zones: ๐Ÿงธ Users can set up local, memorable references to zones. These petnames act as zTLD monikers, giving the local operator friendly names for zones. Petnames can also be published as suggestions for other users who are searching for a good label to use for that zone. โœจ
  • A secure mapping from names to records: ๐Ÿ” GNS lets zone owners map labels to resource records, or hand off authority over the names in the subdomain a label creates to other zones. Owners can choose to publish this information so others can use it. Mappings are encrypted and signed with keys derived from the relevant label before they go into remote storage. When names are resolved, the recursive resolver verifies the signatures on resource records, delegations included. ๐Ÿ’…

In the rest of this document, the "implementer" is the developer building a GNS implementation. That includes the resolver, the zone publisher, and supporting configuration such as Start Zones (see Section 7.1). ๐Ÿ› ๏ธ

3.1. Names and Zones ๐ŸŒท

From the above, it follows that GNS can't support names that are global, secure, and memorable all at once. Instead, names are either global and not memorable, or not globally unique and memorable. ๐Ÿ™ƒ Here's an example of a global name pointing to the record "example" in a zone:

example.000G006K2TJNMD9VTCYRX7BRVV3HAEPS15E6NHDXKPJA1KAJJEG9AFF884

Now imagine a user locally configures the petname pet.gns.alt for the zone that holds the "example" record in the name above. Then example.pet.gns.alt would point to the same record as the globally unique name, but resolution would only work on the local system where the pet.gns.alt petname is configured. ๐Ÿ 

The delegation of petnames and the resolution that follows it are built on ideas from the Simple Distributed Security Infrastructure [SDSI]. In GNS, any user can create and manage any number of zones (see Section 4) as long as their system has a zone publisher implementation. โœŒ๏ธ For each zone, the zone type determines the set of cryptographic operations and the wire formats for encrypted data, public keys, and signatures. The owner can fill a zone with mappings from labels to resource records (see Section 5). A label can also be mapped to a delegation record, which delegates the matching subdomain to another zone. Circular delegations are explicitly allowed, including delegating a subdomain to its immediate parent zone. ๐Ÿ”„ To support (legacy) applications and make petnames easier to use, GNS defines auxiliary record types in addition to supporting existing DNS records. ๐ŸŽ‰

3.2. Publishing Binding Information ๐Ÿ“ฎโœจ

okay so zone contents get encrypted AND signed before they're published in remote key-value storage (see Section 6) ๐Ÿ”, and Figure 1 shows the whole vibe ๐Ÿฆ‹. the big trick is that the zone's unique identity stays hidden from the network thanks to key blinding ๐Ÿซฃ. key blinding lets you create signatures for zone contents using a blinded public/private key pair ๐Ÿ’…. the blinding comes from a deterministic key derivation using the original zone key and its corresponding private key ๐Ÿง , and the blinding factors are derived from record label values. so the zone owner can derive blinded private keys for each record set published under a label, and a resolver can derive the matching blinded public keys ๐Ÿ”‘. ngl that's so clean.

GNS implementations are expected to use decentralized remote storage entities, like distributed hash tables (DHTs) ๐ŸŒ. this keeps things available across the network without needing dedicated infrastructure โœจ. the spec for that kind of distributed storage is out of scope for this doc ๐Ÿ™…โ€โ™€๏ธ, but possible existing implementations include those based on [RFC7363], [Kademlia], or [R5N] ๐Ÿ“š.

          Host A           |     Remote      |      Host B
                           |     Storage     |
                           |                 |
                           |    +---------+  |
                           |   /         /|  |
                  Publish  |  +---------+ |  |  Publish
    +-----------+ Records  |  |         | |  |  Records +-----------+
    |   Zone    |----------|->| Record  | |<-|----------|   Zone    |
    | Publisher |          |  | Storage | |  |          | Publisher |
    +-----------+          |  |         |/   |          +-----------+
         A                 |  +---------+    |               A
         |                 |                 |               |
      +---------+          |                 |           +---------+
     /   |     /|          |                 |          /    |    /|
    +---------+ |          |                 |         +---------+ |
    |         | |          |                 |         |         | |
    |  Local  | |          |                 |         |  Local  | |
    |  Zones  | |          |                 |         |  Zones  | |
    |         |/           |                 |         |         |/
    +---------+            |                 |         +---------+

Figure 1: An Example Diagram of Two Hosts Publishing GNS Zones ๐ŸŽ€

a zone publisher implementation SHOULD be provided as part of a GNS implementation so users can create and manage zones ๐Ÿ’–. if that functionality isn't implemented, names can still be resolved if zone keys for the initial step in the name resolution have been configured (see Section 7) ๐Ÿ”ง, or if the names end with a zTLD suffix ๐Ÿซถ.


3.3. Resolving Names ๐Ÿ”

so apps use the resolver to look up GNS names ๐Ÿ’โ€โ™€๏ธ. starting from a configurable Start Zone, names get resolved by following zone delegations recursively ๐Ÿ—บ๏ธ (see Figure 2). for each label in a name, the recursive GNS resolver fetches the respective record set from the storage layer (see Section 7) ๐Ÿ“ฆ. without knowledge of the label values and the zone keys, the different derived keys are unlinkable to both the original zone key and each other ๐Ÿงฉ. this prevents zone enumeration (except via expensive online brute-force attacks) ๐Ÿ’€. to confirm the affiliation of a query, or its encrypted record set, with a specific zone, you need both the zone key and the label, and neither one is disclosed to remote storage by the protocol ๐Ÿคซ. at the same time, the blinded zone key and the digital signatures attached to each encrypted record set let resolvers and oblivious remote storage verify integrity without learning anything about the originating zone or the record sets ๐Ÿฆ‹.

                              Local Host           |   Remote
                                                   |   Storage
                                                   |
                                                   |    +---------+
                                                   |   /         /|
                                                   |  +---------+ |
   +-----------+ Name     +----------+ Recursive   |  |         | |
   |           | Lookup   |          | Resolution  |  | Record  | |
   |Application|--------->| Resolver |-------------|->| Storage | |
   |           |<---------|          |<------------|--|         |/
   +-----------+ Results  +----------+ Intermediate|  +---------+
                             A         Results     |
                             |                     |
                          +---------+              |
                         /   |     /|              |
                        +---------+ |              |
                        |         | |              |
                        |  Start  | |              |
                        |  Zones  | |              |
                        |         |/               |
                        +---------+                |

Figure 2: High-Level View of the GNS Resolution Process ๐Ÿงญ


4. Zones ๐ŸŒ

okay zones are the main character here ๐Ÿ‘‘. a zone in GNS is uniquely identified by its zone type (ztype) and zone key ๐Ÿ”‘. each zone can be referenced by its zTLD (see Section 4.1 โœจ), which is a string that encodes the zone type and zone key. the ztype is a unique 32-bit number that corresponds to a resource record type number identifying a delegation record type in the GANA "GNS Record Types" registry [GANA] ๐Ÿ“‹. it's the unique identifier for the set of cryptographic functions of the zone and the format of the delegation record type ๐Ÿง. any ztype registration MUST define the following set of cryptographic functions:

KeyGen() -> d, zkey A function for generating a new private key d and the corresponding public zone key zkey. ๐Ÿ—๏ธ

ZKDF(zkey, label) -> zkey' A ZKDF that blinds a zone key zkey using a label. zkey and zkey' must be unlinkable. furthermore, blinding zkey with different values for the label must result in different, unlinkable zkey' values. ๐ŸŒ€

S-Encrypt(zkey, label, expiration, plaintext) -> ciphertext A symmetric encryption function that encrypts the plaintext to derive ciphertext based on key material derived from the zone key zkey, a label, and an expiration timestamp. to leverage performance-enhancing caching features of certain underlying storage entities (in particular, DHTs), a deterministic encryption scheme is recommended. ๐Ÿ”’

S-Decrypt(zkey, label, expiration, ciphertext) -> plaintext A symmetric decryption function that decrypts the ciphertext into plaintext based on key material derived from the zone key, a label, and an expiration timestamp. ๐Ÿ”“

Sign(d, message) -> signature A function for signing a message using the private key d, yielding an unforgeable cryptographic signature. to leverage performance-enhancing caching features of certain underlying storage entities (in particular, DHTs), a deterministic signature scheme is recommended. โœ๏ธ

Verify(zkey, message, signature) -> boolean A function for verifying that the signature was created using the private key d corresponding to the zone key zkey, where d,zkey := KeyGen(). the function returns a boolean value of "TRUE" if the signature is valid and "FALSE" otherwise. โœ…

SignDerived(d, label, message) -> signature A function for signing a message (typically encrypted record data) that can be verified using the derived zone key zkey' := ZKDF(zkey, label). to leverage performance-enhancing caching features of certain underlying storage entities (in particular, DHTs), a deterministic signature scheme is recommended. ๐Ÿ–‹๏ธ

VerifyDerived(zkey', message, signature) -> boolean A function for verifying the signature using the derived zone key zkey' := ZKDF(zkey, label). the function returns a boolean value of "TRUE" if the signature is valid and "FALSE" otherwise. depending on the signature scheme used, this function can be identical to the Verify() function. ๐Ÿง

the cryptographic functions of the default ztypes are specified with their corresponding delegation records, as discussed in Section 5.1 ๐Ÿ“œ. to support cryptographic agility, additional ztypes MAY be defined in the future that replace or update the default ztypes defined in this document ๐Ÿ”„. all ztypes MUST be registered as dedicated zone delegation record types in the GANA "GNS Record Types" registry (see [GANA]) ๐Ÿ“. when defining new record types, the cryptographic security considerations of this document (in particular, Section 9.3) apply ๐Ÿ›ก๏ธ.


4.1. Zone Top-Level Domain (zTLD) ๐ŸŽ€

a zTLD is a string that encodes the zone type and zone key into a domain name suffix ๐Ÿท๏ธ. it's used as a globally unique reference to a zone during name resolution. it's created by encoding a binary concatenation of the zone type and zone key (see Figure 3) ๐Ÿงฉ. the encoding is a variation of Crockford Base32 encoding [CrockfordB32] called Base32GNS. the encoding and decoding symbols for Base32GNS, including this variation, are defined in Table 4, found in Appendix C ๐Ÿ“–. the functions for encoding and decoding based on Table 4 are called Base32GNS-Encode and Base32GNS-Decode, respectively.

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |       ZONE TYPE       |      ZONE KEY         /
   +-----+-----+-----+-----+                       /
   /                                               /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+

Figure 3: The Binary Representation of the zTLD ๐Ÿ’œ

the ZONE TYPE MUST be encoded in network byte order ๐Ÿ”ข. the format of the ZONE KEY depends entirely on the ZONE TYPE ๐ŸคŒ.

so a zTLD is encoded and decoded like this ๐Ÿ‘‡:

zTLD := Base32GNS-Encode(ztype||zkey)
ztype||zkey := Base32GNS-Decode(zTLD)

where "||" is the concatenation operator.

the zTLD can be used "as is" as a rightmost label in a GNS name โœจ. if an application wants to make sure the name is DNS compatible, it MAY also represent the zTLD as follows ๐Ÿ’–: if the zTLD is less than or equal to 63 characters, it can be used as a zTLD as is. if the zTLD is longer than 63 characters, it gets divided into smaller labels separated by the label separator. here, the most significant bytes of the "ztype||zkey" concatenation must be contained in the rightmost label of the resulting string, and the least significant bytes in the leftmost label. this lets the resolver figure out the ztype and zTLD length from the rightmost label, and then work out how many labels the zTLD should span ๐Ÿง . a GNS implementation MUST support the division of zTLDs in DNS-compatible label lengths ๐Ÿซถ. for example, assuming a zTLD of 130 characters, the division is as follows:

zTLD[126..129].zTLD[63..125].zTLD[0..62]

4.2. Zone Revocation โœจ

Okay bestie, revoking a zone key is a whole production ๐Ÿ’… A signed revocation message MUST be published, and it MUST be signed with the zone's private key ๐Ÿ” The message gets broadcast to the network. The broadcast mechanism itself is out of scope for this document, but [GNUnet] implements one that does efficient flooding in a distributed network ๐ŸŒŠ Revocation messages could also be distributed through a distributed ledger or a trusted central server instead ๐Ÿงš To stop flooding attacks, the revocation message MUST contain a proof of work (PoW) ๐Ÿ›ก๏ธ The revocation message, PoW included, MAY be calculated ahead of time so it can be timely โฐ

For everything below, "Argon2id" is the password-based key derivation function from [RFC9106] ๐ŸŒธ For the PoW calculations, the algorithm gets set up with these parameters:

  • S: The salt. Fixed 16-byte string: "GnsRevocationPow"
  • t: Number of iterations: 3
  • m: Memory size in KiB: 1024
  • T: Output length of hash in bytes: 64
  • p: Parallelization parameter: 1
  • v: Algorithm version: 0x13
  • y: Algorithm type (Argon2id): 2
  • X: Unused
  • K: Unused

Figure 4 shows the format of the data "P" that the PoW gets calculated on ๐Ÿฆ‹

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                      POW                      |
   +-----------------------------------------------+
   |                   TIMESTAMP                   |
   +-----------------------------------------------+
   |       ZONE TYPE       |    ZONE KEY           /
   +-----+-----+-----+-----+                       /
   /                                               /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+

Figure 4: The Format of the PoW Data

  • POW: A 64-bit value that is a solution to the PoW. In network byte order.
  • TIMESTAMP: Denotes the absolute 64-bit date when the revocation was computed. In microseconds since midnight (0 hour), January 1, 1970 UTC in network byte order.
  • ZONE TYPE: The 32-bit zone type in network byte order.
  • ZONE KEY: The 256-bit public key zkey of the zone that is being revoked. The wire format of this value is defined by the ZONE TYPE.

Usually, PoW schemes require that one POW value be found, such that a specific number of leading zeroes are found in the hash result. This number is then referred to as the difficulty of the PoW. To reduce the variance in the time it takes to calculate the PoW, a valid GNS revocation requires that a number of different PoWs (Z, as defined below) must be found that on average have at least D leading zeroes ๐Ÿงฎ

Given an average difficulty of D, the proofs have an expiration time of EPOCH. Applications MAY calculate proofs with a difficulty that is higher than D by providing POW values where there are (on average) more than D bits of leading zeroes. With each additional bit of difficulty, the lifetime of the proof is prolonged by another EPOCH. So by calculating a harder PoW, the zone owner can increase the lifetime of the proof, and therefore the persistence of the revocation message, on demand ๐Ÿ’ช

The parameters are defined as follows:

  • Z: The number of PoWs that are required. Its value is fixed at 32.
  • D: The lower limit of the average difficulty. Its value is fixed at 22.
  • EPOCH: A single epoch. Its value is fixed at 365 days in microseconds.

The revocation message wire format is illustrated in Figure 5 ๐ŸŽ€

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   TIMESTAMP                   |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                      TTL                      |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                     POW_0                     |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                       ...                     |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                    POW_(Z-1)                  |
   +-----------------------------------------------+
   |       ZONE TYPE       |    ZONE KEY           /
   +-----+-----+-----+-----+                       /
   /                                               /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+
   /                   SIGNATURE                   /
   /                                               /
   /                                               /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+

Figure 5: The Revocation Message Wire Format

  • TIMESTAMP: Denotes the absolute 64-bit date when the revocation was computed. In microseconds since midnight (0 hour), January 1, 1970 UTC in network byte order. This is the same value as the timestamp used in the individual PoW calculations.
  • TTL: Denotes the relative 64-bit time to live of the record in microseconds in network byte order. The field SHOULD be set to EPOCH * 1.1. Given an average number of leading zeroes D', then the field value MAY be increased up to (D'-D+1) * EPOCH * 1.1. Validators MAY reject messages with lower or higher values when received. โณ
  • POW_i: The values calculated as part of the PoW, in network byte order. Each POW_i MUST be unique in the set of POW values. To make uniqueness quick to verify, the POW values MUST be given in strictly monotonically increasing order in the message. ๐Ÿ”ข
  • ZONE TYPE: The 32-bit zone type corresponding to the zone key in network byte order.
  • ZONE KEY: The public key zkey of the zone that is being revoked and the key to be used to verify SIGNATURE.
  • SIGNATURE: A signature over a timestamp and the zkey of the zone that is revoked, corresponding to the key used in the PoW. The signature is created using the Sign() function of the cryptosystem of the zone and the private key (see Section 4). โœ๏ธ

The signature in the revocation message covers a 32-bit header prefixed to the TIMESTAMP, ZONE TYPE, and ZONE KEY fields. The header includes the key length and signature purpose. The wire format is illustrated in Figure 6 ๐Ÿง

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |         SIZE          |       PURPOSE (0x03)  |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   TIMESTAMP                   |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |       ZONE TYPE       |     ZONE KEY          /
   +-----+-----+-----+-----+                       /
   /                                               /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+

Figure 6: The Wire Format of the Revocation Data for Signing

  • SIZE: A 32-bit value containing the length of the signed data in bytes in network byte order.
  • PURPOSE: A 32-bit signature purpose flag. The value of this field MUST be 3. The value is encoded in network byte order. It defines the context in which the signature is created so that it cannot be reused in other parts of the protocol that might include possible future extensions. The value of this field corresponds to an entry in the GANA "GNUnet Signature Purposes" registry [GANA]. ๐Ÿ”’
  • TIMESTAMP: Field as defined in the revocation message above.
  • ZONE TYPE: Field as defined in the revocation message above.
  • ZONE KEY: Field as defined in the revocation message above.

In order to validate a revocation, the following steps MUST be taken:

  1. The signature MUST be verified against the zone key.
  2. The set of POW values MUST NOT contain duplicates; this MUST be checked by verifying that the values are strictly monotonically increasing.
  3. The average number of leading zeroes D' resulting from the provided POW values MUST be greater than or equal to D. Implementers MUST NOT use an integer data type to calculate or represent D'.
The TTL field in the revocation message is informational, so don't let it fool you ๐Ÿ‘€ A revocation MAY be discarded without checking the POW values or the signature if the TTL (in combination with TIMESTAMP) indicates that the revocation has already expired. The actual validity period of the revocation MUST be determined by examining the leading zeroes in the POW values.

The validity period of the revocation is calculated as (D'-D+1) * EPOCH * 1.1. The EPOCH gets stretched by 10% to deal with poorly synchronized clocks โฐ The validity period gets added on top of the TIMESTAMP to give the expiration date. If the current time is after the expiration date, the revocation is considered stale ๐Ÿ’€

Verified revocations MUST be stored locally. The implementation MAY discard stale revocations and evict them from the local store at any time ๐Ÿ—‘๏ธ

It is important that implementations broadcast received revocations if they are valid and not stale ๐Ÿ“ฃ Should the calculated validity period differ from the TTL field value, the calculated value MUST be used as the TTL field value when forwarding the revocation message. Systems might disagree on the current time, so implementations MAY use stale but otherwise valid revocations, but SHOULD NOT broadcast them. Forwarded stale revocations MAY be discarded by the receiver. ๐Ÿซถ

Any locally stored revocation MUST be considered during delegation record processing (see Section 7.3.4) ๐ŸŒˆ

5. Resource Records โœจ

okay bestie, so a GNS implementation SHOULD provide a mechanism for creating and managing local zones ๐Ÿ’– plus a persistence mechanism (like a local database ๐Ÿ—„๏ธ) for resource records. making a new local zone is giving pick a zone type, then make a zone key pair ๐Ÿ”‘. if this mechanism isn't implemented, no zones can be published in storage (see Section 6) and name resolution is limited to non-local Start Zones (see Section 7.1) ๐Ÿ’€.

a GNS resource record holds the data of one specific record in a zone ๐Ÿฆ‹. the format is shown in Figure 7:

0     8     16    24    32    40    48    56
+-----+-----+-----+-----+-----+-----+-----+-----+
|                   EXPIRATION                  |
+-----+-----+-----+-----+-----+-----+-----+-----+
|    SIZE   |   FLAGS   |          TYPE         |
+-----+-----+-----+-----+-----+-----+-----+-----+
|                      DATA                     /
/                                               /
/                                               /

Figure 7: The Resource Record Wire Format

here's the breakdown, it's lowkey so clean ๐Ÿงš:

  • EXPIRATION: the absolute 64-bit expiration date of the record ๐Ÿ—“๏ธ. It's microseconds since midnight (0 hour), January 1, 1970 UTC, in network byte order.
  • SIZE: the 16-bit size of the DATA field in bytes, in network byte order.
  • FLAGS: a 16-bit field for special properties of the resource record. The semantics of the different bits are defined below.
  • TYPE: the 32-bit resource record type, in network byte order. This can be one of the GNS resource records defined in Section 5, a DNS record type as defined in [RFC1035], or any of the complementary standardized DNS resource record types. Values below 2^16 are reserved for 16-bit DNS resource record types allocated by IANA [RFC6895]. Values above 2^16 are allocated by the GANA "GNS Record Types" registry [GANA].
  • DATA: the variable-length resource record data payload ๐Ÿ“ฆ. Its content is defined by the respective type of the resource record.

the FLAGS field is how you tell the world something special is going on ๐Ÿšฉ. An application creating resource records MUST set all bits in FLAGS to 0, unless it specifically understands and wants to set the respective flag. more flags can be defined in future protocol versions, so if an application or implementation runs into a flag it doesn't recognize, the flag MUST be ignored ๐Ÿ™ˆ. however, all implementations MUST understand the SHADOW and CRITICAL flags defined below. any combination of the flags below is valid โœจ. Figure 8 shows how the flags are laid out in the 16-bit FLAGS field:

0           13            14      15
+--------...+-------------+-------+---------+
| Reserved  |SUPPLEMENTAL |SHADOW |CRITICAL |
+--------...+-------------+-------+---------+

Figure 8: The Resource Record Flag Wire Format

  • CRITICAL: when this flag is set, it means processing is critical ๐Ÿšจ. Implementations that don't support the record type, or are otherwise unable to process the record, MUST abort resolution upon encountering the record in the resolution process. no vibes-based resolving here ๐Ÿ’….
  • SHADOW: when this flag is set, this record MUST be ignored by resolvers unless all (other) records of the same record type have expired ๐Ÿ‘ป. It lets zone publishers prep good performance when records change, by putting future values of records into storage. that way the future values can propagate and get cached before the transition goes live ๐ŸŒธ.
  • SUPPLEMENTAL: this is a supplemental record ๐ŸŽ€. It's provided in addition to the other records. It's not explicitly managed alongside the other records under the respective name, but it might be useful for the application.

5.1. Zone Delegation Records ๐ŸŽ€

okay so this section defines the initial set of zone delegation record types ๐Ÿ‘‘. Any implementation SHOULD support all zone types defined here, and MAY support any number of additional delegation records defined in the GANA "GNS Record Types" registry (see [GANA]). not supporting some zone types will result in resolution failures if that zone type shows up, which is valid if some zone delegation record types have been determined to be cryptographically insecure ๐Ÿ’€. Zone delegation records MUST NOT be stored or published under the apex label ๐Ÿ™…. a zone delegation record type value is the same as the respective ztype value. the ztype defines the cryptographic primitives for the zone being delegated to, and the zone delegation record payload contains the public key of the zone to delegate to ๐Ÿ”‘. a zone delegation record MUST have the CRITICAL flag set and MUST be the only non-supplemental record under a label. There MAY be inactive records of the same type with the SHADOW flag set, to make smooth key rollovers easier ๐Ÿฆ‹.

in the following, "||" is the concatenation operator of two byte strings ๐Ÿงฉ. The algorithm specification uses character strings like GNS labels or constant values. when they're used in concatenations or as input to functions, the zero terminator of the character strings MUST NOT be included ๐Ÿ™ˆ.

5.1.1. PKEY ๐Ÿ”‘

in GNS, a delegation of a label to a zone of type "PKEY" is represented through a PKEY record ๐Ÿ’–. The PKEY DATA entry wire format is shown in Figure 9:

0     8     16    24    32    40    48    56
+-----+-----+-----+-----+-----+-----+-----+-----+
|                   PUBLIC KEY                  |
|                                               |
|                                               |
|                                               |
+-----+-----+-----+-----+-----+-----+-----+-----+

Figure 9: The PKEY Wire Format

  • PUBLIC KEY: a 256-bit Ed25519 public key ๐Ÿ—๏ธ.

for PKEY zones, the zone key material is derived using the curve parameters of the twisted Edwards representation of Curve25519 [RFC7748] (the reasoning behind choosing this curve is in Section 9.3) with the ECDSA scheme [RFC6979] ๐Ÿง . the cryptographic primitives for PKEY zones use this naming convention:

  • d: a 256-bit Ed25519 private key (clamped private scalar).
  • zkey: the Ed25519 public zone key corresponding to d.
  • p: the prime of edwards25519 as defined in [RFC7748], i.e., 2^255 - 19.
  • G: the group generator (X(P),Y(P)), with X(P),Y(P) of edwards25519 as defined in [RFC7748].
  • L: the order of the prime-order subgroup of edwards25519 as defined in [RFC7748].
  • KeyGen(): the generation of the private scalar d and the curve point zkey := d*G (where G is the group generator of the elliptic curve), as defined in Section 2.2 of [RFC6979], represents the KeyGen() function โœจ.

the zone type and zone key of a PKEY are 4 + 32 bytes long ๐Ÿ“. That means a zTLD will always fit into a single label and doesn't need any further conversion ๐ŸŽ‰. given a label, the output zkey' of the ZKDF(zkey, label) function is calculated like this for PKEY zones:

ZKDF(zkey, label):
  PRK_h := HKDF-Extract("key-derivation", zkey)
  h := HKDF-Expand(PRK_h, label || "gns", 512 / 8)
  zkey' := (h mod L) * zkey
  return zkey'

the PKEY cryptosystem uses an HMAC-based key derivation function (HKDF) as defined in [RFC5869], with SHA-512 [RFC6234] for the extraction phase and SHA-256 [RFC6234] for the expansion phase ๐Ÿค“. PRK_h is key material retrieved using an HKDF that uses the string "key-derivation" as the salt and the zone key as the initial keying material. h is the 512-bit HKDF expansion result and must be interpreted in network byte order. the expansion information input is a concatenation of the label and the string "gns". the multiplication of zkey with h in ZKDF() is a point multiplication, while the multiplication of d with h in SignDerived() below is a scalar multiplication. it's a lot, but it's so worth it ๐Ÿ’….

the Sign() and Verify() functions for PKEY zones are implemented using 512-bit ECDSA deterministic signatures as specified in [RFC6979] โœ๏ธ. the same functions can be used for derived keys:

SignDerived(d, label, message):
  zkey := d * G
  PRK_h := HKDF-Extract("key-derivation", zkey)
  h := HKDF-Expand(PRK_h, label || "gns", 512 / 8)
  d' := (h * d) mod L
  return Sign(d', message)

a signature is valid for the derived public key zkey' := ZKDF(zkey, label) if the following holds:

VerifyDerived(zkey', message, signature):
  return Verify(zkey', message, signature)

the S-Encrypt() and S-Decrypt() functions use AES in counter mode as defined in [MODES] (CTR-AES256) ๐Ÿ”:

S-Encrypt(zkey, label, expiration, plaintext):
  PRK_k := HKDF-Extract("gns-aes-ctx-key", zkey)
  PRK_n := HKDF-Extract("gns-aes-ctx-iv", zkey)
  K := HKDF-Expand(PRK_k, label, 256 / 8)
  NONCE := HKDF-Expand(PRK_n, label, 32 / 8)
  BLOCK_COUNTER := 0x0000000000000001
  IV := NONCE || expiration || BLOCK_COUNTER
  return CTR-AES256(K, IV, plaintext)

S-Decrypt(zkey, label, expiration, ciphertext):
  PRK_k := HKDF-Extract("gns-aes-ctx-key", zkey)
  PRK_n := HKDF-Extract("gns-aes-ctx-iv", zkey)
  K := HKDF-Expand(PRK_k, label, 256 / 8)
  NONCE := HKDF-Expand(PRK_n, label, 32 / 8)
  BLOCK_COUNTER := 0x0000000000000001
  IV := NONCE || expiration || BLOCK_COUNTER
  return CTR-AES256(K, IV, ciphertext)

the key K and the counter Initialization Vector (IV) are derived from the record label and the zone key zkey, using an HKDF as defined in [RFC5869] ๐Ÿง. SHA-512 [RFC6234] is used for the extraction phase and SHA-256 [RFC6234] for the expansion phase. the output keying material is 32 bytes (256 bits) for the symmetric key and 4 bytes (32 bits) for the NONCE. the symmetric key K is a 256-bit AES key [RFC3826] ๐Ÿ”‘.

the nonce is combined with a 64-bit IV and a 32-bit block counter, as defined in [RFC3686] ๐Ÿงฉ. the block counter begins with a value of 1, and it's incremented to generate subsequent portions of the key stream. the block counter is a 32-bit integer value in network byte order. Figure 10 shows the format of the counter IV used by the S-Encrypt() and S-Decrypt() functions:

0     8     16    24    32
+-----+-----+-----+-----+
|         NONCE         |
+-----+-----+-----+-----+
|       EXPIRATION      |
|                       |
+-----+-----+-----+-----+
|      BLOCK COUNTER    |
+-----+-----+-----+-----+

Figure 10: Structure of the Counter IV as Used in S-Encrypt() and S-Decrypt()

5.1.2. EDKEY ๐Ÿ”โœจ

okay bestie, so in GNS, a delegation of a label to an "EDKEY" zone gets represented through an EDKEY record ๐Ÿ’… the EDKEY DATA entry wire format is in Figure 11, check it out ๐Ÿฆ‹

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   PUBLIC KEY                  |
   |                                               |
   |                                               |
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+

                   Figure 11: The EDKEY DATA Wire Format

the PUBLIC KEY is a 256-bit EdDSA zone key ๐Ÿ”‘๐Ÿ’œ

so for EDKEY zones, the zone key material is derived using the curve parameters of the twisted Edwards representation of Curve25519 [RFC7748] (a.k.a. Ed25519) with the Ed25519 scheme [ed25519] as specified in [RFC8032] ๐ŸŒˆ the naming convention for the crypto primitives goes like this:

  • d: a 256-bit EdDSA private key ๐Ÿ—๏ธ
  • a: an integer derived from d using the SHA-512 hash function as defined in [RFC8032] ๐Ÿงฎ
  • zkey: the EdDSA public key corresponding to d. it's defined as the curve point a*G where G is the group generator of the elliptic curve as defined in [RFC8032] โœจ
  • p: the prime of edwards25519 as defined in [RFC8032], i.e., 2^255 - 19 ๐Ÿ’–
  • G: the group generator (X(P),Y(P)), with X(P),Y(P) of edwards25519 as defined in [RFC8032] ๐ŸŽ€
  • L: the order of the prime-order subgroup of edwards25519 as defined in [RFC8032] ๐Ÿ‘‘
  • KeyGen(): the generation of the private key d and the associated public key zkey := a*G (where G is the group generator of the elliptic curve and a is an integer derived from d using the SHA-512 hash function) as defined in Section 5.1.5 of [RFC8032] represents the KeyGen() function ๐Ÿซถ

the zone type and zone key of an EDKEY are 4 + 32 bytes in length ๐Ÿงš which means a zTLD will always fit into a single label and doesn't need any further conversion. no cap, that's so clean ๐Ÿ“

the "EDKEY" ZKDF instantiation is based on [Tor224] ๐ŸŒธ same as above for KeyGen(), a is calculated from d using the SHA-512 hash function as defined in Section 5.1.5 of [RFC8032]. given a label, the ZKDF output gets calculated like this:

ZKDF(zkey, label):
  /* Calculate the blinding factor */
  PRK_h := HKDF-Extract("key-derivation", zkey)
  h := HKDF-Expand(PRK_h, label || "gns", 512 / 8)
  /* Ensure that h == h mod L */
  h := h mod L

  zkey' := h * zkey
  return zkey'

Implementers SHOULD employ a constant-time scalar multiplication for the constructions above to protect against timing attacks ๐Ÿ™ˆ otherwise, timing attacks could leak private key material if an attacker can predict when a system starts the publication process ๐Ÿ’€

the EDKEY cryptosystem uses an HKDF as defined in [RFC5869], with SHA-512 [RFC6234] for the extraction phase and HMAC-SHA-256 [RFC6234] for the expansion phase ๐Ÿฆ‹ PRK_h is key material retrieved using an HKDF that uses the string "key-derivation" as the salt and the zone key as the initial keying material. the blinding factor h is the 512-bit HKDF expansion result. the expansion information input is a concatenation of the label and the string "gns". the result of the HKDF must be clamped and interpreted in network byte order. a is the 256-bit integer corresponding to the 256-bit private key d. and the multiplication of zkey with h is a point multiplication ๐Ÿ”ฅ

The Sign(d, message) and Verify(zkey, message, signature) procedures MUST be implemented as defined in [RFC8032]. ๐Ÿšจ

signatures for EDKEY zones use a derived private scalar d', and this is not compliant with [RFC8032] ๐Ÿ™ƒ since the private key that corresponds to the derived private scalar isn't known, it's not possible to deterministically derive the signature part R according to [RFC8032]. instead, signatures MUST be generated as follows for any given message and private zone key: a nonce is calculated from the highest 32 bytes of the expansion of the private key d and the blinding factor h. the nonce is then hashed with the message to r. this way, the full derivation path is included in the calculation of the R value of the signature, so it's never reused for two different derivation paths or messages ๐Ÿคฏ๐Ÿ‘‘

SignDerived(d, label, message):
  /* Key expansion */
  dh := SHA-512(d)
  /* EdDSA clamping */
  a := dh[0..31]
  a[0] := a[0] & 248
  a[31] := a[31] & 127
  a[31] := a[31] | 64
  /* Calculate zkey corresponding to d */
  zkey := a * G

  /* Calculate blinding factor */
  PRK_h := HKDF-Extract("key-derivation", zkey)
  h := HKDF-Expand(PRK_h, label || "gns", 512 / 8)
  /* Ensure that h == h mod L */
  h := h mod L

  d' := (h * a) mod L
  nonce := SHA-256(dh[32..63] || h)
  r := SHA-512(nonce || message)
  R := r * G
  S := r + SHA-512(R || zkey' || message) * d' mod L
  return (R,S)

a signature (R,S) is valid for the derived public key zkey' := ZKDF(zkey, label) if the following holds:

VerifyDerived(zkey', message, signature):
  (R,S) := signature
  return S * G == R + SHA-512(R, zkey', message) * zkey'

the S-Encrypt() and S-Decrypt() functions use XSalsa20 as defined in [XSalsa20], and they use the XSalsa20-Poly1305 encryption function ๐Ÿง

S-Encrypt(zkey, label, expiration, plaintext):
  PRK_k := HKDF-Extract("gns-xsalsa-ctx-key", zkey)
  PRK_n := HKDF-Extract("gns-xsalsa-ctx-iv", zkey)
  K := HKDF-Expand(PRK_k, label, 256 / 8)
  NONCE := HKDF-Expand(PRK_n, label, 128 / 8)
  IV := NONCE || expiration
  return XSalsa20-Poly1305(K, IV, plaintext)

S-Decrypt(zkey, label, expiration, ciphertext):
  PRK_k := HKDF-Extract("gns-xsalsa-ctx-key", zkey)
  PRK_n := HKDF-Extract("gns-xsalsa-ctx-iv", zkey)
  K := HKDF-Expand(PRK_k, label, 256 / 8)
  NONCE := HKDF-Expand(PRK_n, label, 128 / 8)
  IV := NONCE || expiration
  return XSalsa20-Poly1305(K, IV, ciphertext)

the XSalsa20-Poly1305 encryption output is the encrypted ciphertext followed by the 128-bit authentication tag ๐Ÿซง so the length of the encrypted data equals the length of the data plus the 16 bytes of the auth tag โœจ

the key K and counter IV are derived from the record label and the zone key zkey using an HKDF as defined in [RFC5869]. SHA-512 [RFC6234] is used for extraction and SHA-256 [RFC6234] for expansion. the output keying material is 32 bytes (256 bits) for the symmetric key and 16 bytes (128 bits) for the NONCE. the symmetric key K is a 256-bit XSalsa20 key [XSalsa20]. no additional authenticated data (AAD) is used ๐ŸŒท

the nonce gets combined with an 8-byte IV. the IV is the expiration time of the resource record block in network byte order. the resulting counter (IV) wire format is in Figure 12 ๐ŸŽ€

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                     NONCE                     |
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   EXPIRATION                  |
   +-----+-----+-----+-----+-----+-----+-----+-----+

             Figure 12: The Counter Block Initialization Vector

5.2. Redirection Records ๐Ÿฆ‹

okay so redirection records are used to redirect resolution ๐Ÿงš any implementation SHOULD support all redirection record types defined here, and it MAY support any number of additional redirection records defined in the GANA "GNS Record Types" registry [GANA] ๐Ÿ’… redirection records MUST have the CRITICAL flag set. not supporting some record types can result in resolution failures ๐Ÿ˜ญ this can be a valid choice if some redirection record types have been determined to be insecure, or if an application has reasons to not support redirection to DNS for reasons such as complexity or security. and redirection records MUST NOT be stored or published under the apex label ๐Ÿ™ˆ

5.2.1. REDIRECT ๐ŸŒธ

a REDIRECT record is the GNS equivalent of a CNAME record in DNS โœจ a REDIRECT record MUST be the only non-supplemental record under a label. there MAY be inactive records of the same type that have the SHADOW flag set, in order to facilitate smooth changes of redirection targets. no other records are allowed. details on processing this record are in Section 7.3.1, so go check that out ๐Ÿ‘‘ a REDIRECT DATA entry is illustrated in Figure 13:

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   REDIRECT NAME               |
   /                                               /
   /                                               /
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+

                  Figure 13: The REDIRECT DATA Wire Format

REDIRECT NAME: the name to continue with. this value can be a regular name or a relative name. relative GNS names are indicated by an extension label (U+002B ("+")) as the rightmost label. the string is UTF-8 encoded and zero terminated ๐Ÿซถ

5.2.2. GNS2DNS ๐Ÿ“

a GNS2DNS record delegates resolution to DNS ๐ŸŒˆ the resource record contains a DNS name for the resolver to continue with in DNS, followed by a DNS server. both names are in the format defined in [RFC1034] for DNS names. there MAY be multiple GNS2DNS records under a label. there MAY also be DNSSEC DS records, or any other records used to secure the connection with the DNS servers, under the same label. there MAY be inactive records of the same type or types that have the SHADOW flag set, in order to facilitate smooth changes of redirection targets. no other non-supplemental record types are allowed in the same record set. a GNS2DNS DATA entry is illustrated in Figure 14 ๐Ÿง

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                      NAME                     |
   /                                               /
   /                                               /
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                 DNS SERVER NAME               |
   /                                               /
   /                                               /
   |                                               |
   +-----------------------------------------------+

                  Figure 14: The GNS2DNS DATA Wire Format

NAME: the name to continue with in DNS. the value is UTF-8 encoded and zero terminated ๐Ÿ’–

DNS SERVER NAME: the DNS server to use. this value can be an IPv4 address in dotted-decimal form, an IPv6 address in colon-hexadecimal form, or a DNS name. it can also be a relative GNS name ending with a "+" as the rightmost label. the implementation MUST check the string syntactically for an IP address in the respective notation before checking for a relative GNS name. if all three checks fail, the name MUST be treated as a DNS name. the value is UTF-8 encoded and zero terminated ๐ŸŒธ

NOTE: If an application uses DNS names obtained from GNS2DNS records in a DNS request, they MUST first be converted to an IDNA-compliant representation [RFC5890]. โš ๏ธ๐Ÿซถ

5.3. Auxiliary Records ๐ŸŽ€

okay last bit of this part: this section defines the initial set of auxiliary GNS record types ๐Ÿฆ‹ any implementation SHOULD be able to process the specified record types according to Section 7.3. ๐Ÿ’œโœจ

5.3.1. LEHO ๐ŸŽ€

Okay so LEHO stands for LEgacy HOstname, and it's basically a little hint for old-school hostnames ๐Ÿ’…. Apps can use GNS to look up IPv4 or IPv6 addresses of internet services, right? But connecting sometimes needs more than just an IP and port. It also needs the canonical DNS name of the service sent over the transport protocol ๐Ÿฆ‹. So in GNS, LEHO records hand apps the DNS name they need to connect. The big use case is HTTP virtual hosting and TLS Server Name Indication [RFC6066], where you have to supply a DNS name in the HTTP "Host"-header and the TLS handshake ๐ŸŒธ. Using a GNS name there might not work, because it might not be globally unique ๐Ÿ™ˆ. And even if uniqueness isn't an issue, the legacy service might not even know GNS exists ๐Ÿ’€.

A LEHO resource record is expected to show up together with A or AAAA resource records that carry IPv4 or IPv6 addresses ๐Ÿงš. Here's what a LEHO DATA entry looks like in Figure 15 โœจ:

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                 LEGACY HOSTNAME               |
   /                                               /
   /                                               /
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+

                    Figure 15: The LEHO DATA Wire Format

LEGACY HOSTNAME: a UTF-8 string (not zero terminated) that holds the legacy hostname ๐Ÿ“.

NOTE: If an application uses a LEHO value in an HTTP request header (like a "Host"-header), it MUST be converted to an IDNA-compliant representation [RFC5890] ๐Ÿ”ฅ.

5.3.2. NICK ๐Ÿ’–

Nickname records are how zone admins publish a label that their zone would like to be called ๐ŸŒˆ. It's a suggestion for other zones about which label to use when they create a delegation record (Section 5.1) containing this zone key ๐Ÿ‘‘. This record SHOULD only be stored locally under the apex label "@", but it MAY be returned with record sets under any label as a supplemental record ๐Ÿซถ. Section 7.3.5 explains how a resolver must process supplemental and non-supplemental NICK records โœจ. Here's the NICK DATA entry in Figure 16:

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                  NICKNAME                     |
   /                                               /
   /                                               /
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+

                    Figure 16: The NICK DATA Wire Format

NICKNAME: a UTF-8 string (not zero terminated) for the zone's preferred label ๐Ÿฆ‹. This string MUST be a valid GNS label ๐Ÿ’….

5.3.3. BOX ๐ŸŽ

GNS lookups are expected to return all the useful info in one record set, bestie ๐Ÿ’œ. This avoids extra lookups and cryptographically ties together stuff that belongs together, so an adversarial storage entity can't hand you partial answers that leave out something critical for security ๐Ÿ˜ญ๐Ÿ”’.

This whole strategy clashes with the special labels DNS uses for SRV and TLSA records ๐Ÿ™ƒ. So GNS defines the BOX record format to box those up and include them in the record set of the label they belong to โœจ. For example, a TLSA record for "_https._tcp.example.org" gets stored in the record set of "example.org" as a BOX record with service (SVC) 443 (https), protocol (PROTO) 6 (tcp), and record TYPE "TLSA" ๐ŸŒธ. For reference, see also [RFC2782] ๐Ÿ“š. Here's the BOX DATA entry in Figure 17:

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |   PROTO   |    SVC    |       TYPE            |
   +-----------+-----------------------------------+
   |                 RECORD DATA                   |
   /                                               /
   /                                               /
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+

                    Figure 17: The BOX DATA Wire Format

PROTO: the 16-bit protocol number in network byte order. Values below 2^8 are reserved for 8-bit Internet Protocol numbers allocated by IANA [RFC5237] (e.g., 6 for TCP). Values above 2^8 are allocated by the GANA "GNUnet Overlay Protocols" registry [GANA] ๐Ÿงš.

SVC: the 16-bit service value of the boxed record in network byte order. For TCP and UDP, it's the port number ๐ŸŽ€.

TYPE: the 32-bit record type of the boxed record in network byte order ๐Ÿ“.

RECORD DATA: a variable-length field holding the "DATA" format of TYPE, as defined for each TYPE. So for TYPE values below 2^16, the format is the same as that record type's binary format in DNS ๐Ÿ’œ.

  1. Record Encoding for Remote Storage ๐Ÿฆ‹

Any API that lets you store a block under a 512-bit key and retrieve one or more blocks from a key can be used by an implementation for remote storage ๐ŸŒˆ. To be useful, and to support the defined zone delegation record encodings, the API MUST permit storing blocks of size 176 bytes or more and SHOULD allow blocks of size 1024 bytes or more ๐Ÿ”ฅ. Here, an implementation is assumed to realize two procedures on top of storage:

PUT(key, block)
GET(key) -> block

A GNS implementation publishes blocks according to the properties and recommendations of the underlying remote storage. That can include a periodic refresh operation to keep published blocks available ๐Ÿซถ.

There's no mechanism for explicitly deleting individual blocks from remote storage ๐Ÿ™ˆ. However, blocks include an EXPIRATION field, which guides remote storage implementations in deciding when to delete blocks โณ. Given multiple blocks for the same key, remote storage implementations SHOULD try to preserve and return the block with the largest EXPIRATION value ๐Ÿ‘‘.

All resource records from the same zone sharing the same label are encrypted and published together in a single resource record block (RRBLOCK) in remote storage under a key q, as shown in Figure 18 โœจ. A GNS implementation MUST NOT include expired resource records in blocks. An implementation MUST use the PUT storage procedure when record sets change, to update the zone contents. Implementations MUST ensure that the EXPIRATION fields of RRBLOCKs increase strictly monotonically for every change, even if the smallest expiration time of records in the block doesn't increase ๐Ÿ’….

                           Local Host           |   Remote
                                                |   Storage
                                                |
                                                |    +---------+
                                                |   /         /|
                                                |  +---------+ |
   +-----------+                                |  |         | |
   |           |       +-----------+PUT(q, RRBLOCK) |  | Record  | |
   |    User   |       |   Zone    |----------------|->| Storage | |
   |           |       | Publisher |                |  |         |/
   +-----------+       +-----------+                |  +---------+
        |                     A                     |
        |                     | Zone records        |
        |                     | grouped by label    |
        |                     |                     |
        |                 +---------+               |
        |Create / Delete /    |    /|               |
        |and Update     +---------+ |               |
        |Local Zones    |         | |               |
        |               |  Local  | |               |
        +-------------->|  Zones  | |               |
                        |         |/                |
                        +---------+                 |

          Figure 18: Management and Publication of Local Zones in
                            Distributed Storage

Storage key derivation and record block creation are specified in the following sections and illustrated in Figure 19 ๐Ÿงš.

   +----------+ +-------+ +------------+ +-------------+
   | Zone Key | | Label | | Record Set | | Private Key |
   +----------+ +-------+ +------------+ +-------------+
       |          |            |               |
       |          |            v               |
       |          |           +-----------+    |
       |          +---------->| S-Encrypt |    |
       +----------|---------->+-----------+    |
       |          |               |    |       |
       |          |               |    v       v
       |          |               |   +-------------+
       |          +---------------|-->| SignDerived |
       |          |               |   +-------------+
       |          |               |        |
       |          v               v        v
       |      +------+        +--------------+
       +----->| ZKDF |------->| Record Block |
              +------+        +--------------+
                 |
                 v
              +------+        +-------------+
              | Hash |------->| Storage Key |
              +------+        +-------------+

         Figure 19: Storage Key and Record Block Creation Overview

6.1. The Storage Key ๐Ÿ”‘

The storage key is derived from the zone key and the respective label of the contained records ๐Ÿ’–. The required knowledge of both the zone key and the label, combined with the similarly derived symmetric secret keys and blinded zone keys, is what ensures query privacy (see [RFC8324], Section 3.5) ๐Ÿซถ.

Given a label, the storage key q is derived as follows:

q := SHA-512(ZKDF(zkey, label))

label: a UTF-8 string under which the resource records are published ๐ŸŒธ.

zkey: the zone key ๐Ÿฆ‹.

q: the 512-bit storage key under which the resource record block is published ๐Ÿ’œ. It is the SHA-512 hash [RFC6234] over the derived zone key โœจ.

6.2. Plaintext Record Data (RDATA) ๐Ÿ’–

okay so GNS records in a zone get grouped by their labels, which means every record under the same label gets published together as one single block in storage ๐Ÿ“ฆ these grouped record sets MAY be paired with supplemental records too โœจ

RDATA is the format used to encode one of those groups. Figure 20 shows the binary layout ๐Ÿ‘‡

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                 EXPIRATION                    |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |    SIZE   |    FLAGS  |        TYPE           |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                      DATA                     /
   /                                               /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   EXPIRATION                  |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |    SIZE   |    FLAGS  |        TYPE           |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                     DATA                      /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                     PADDING                   /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+

Figure 20: The RDATA Wire Format

  • EXPIRATION, SIZE, TYPE, FLAGS, and DATA: the definitions for these fields are given below Figure 7 in Section 5, so go check there ๐Ÿงš
  • PADDING: when you serialize records into RDATA, a GNS implementation MUST ensure that the size of the RDATA is a power of two using this field. The field MUST be set to zero and MUST be ignored on receipt. as a special exception ๐Ÿ™ˆ record sets with (only) a zone delegation record type are never padded

6.3. The Resource Record Block ๐ŸŽ€

okay this part is giving encryption energy ๐Ÿ” the resource records grouped in an RDATA get encrypted using the S-Encrypt() function defined by the zone type of the zone they belong to, and then they get prefixed with metadata into a resource record block (RRBLOCK) for remote storage. The GNS RRBLOCK wire format is shown in Figure 21 โœจ

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |          SIZE         |    ZONE TYPE          |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                  ZONE KEY                     /
   /                  (BLINDED)                    /
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   SIGNATURE                   |
   /                                               /
   /                                               /
   |                                               |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   EXPIRATION                  |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                    BDATA                      |
   /                                               /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+

Figure 21: The RRBLOCK Wire Format

  • SIZE: a 32-bit value with the length of the block in bytes, in network byte order. even though the message format uses a 32-bit value ๐Ÿ’… implementations MAY refuse to publish blocks beyond a certain size significantly below the theoretical block size limit of 4 GB
  • ZONE TYPE: the 32-bit ztype in network byte order
  • ZONE KEY (BLINDED): the blinded zone key ZKDF(zkey, label), which is used to verify SIGNATURE. the length and format of the blinded public key depend on the ztype
  • SIGNATURE: the signature is computed over the EXPIRATION and BDATA fields, as shown in Figure 22. the length and format of the signature depend on the ztype. it's created using the SignDerived() function of the cryptosystem of the zone (see Section 4) ๐Ÿ”‘
  • EXPIRATION: this tells you when the RRBLOCK expires. the encrypted block SHOULD be removed from storage and caches, since it's likely stale ๐Ÿฅ€ however, applications MAY continue to use non-expired individual records until they expire. the RRBLOCK expiration value MUST be computed by first working out, for each record type in the RRBLOCK, the maximum expiration time of all records of that type, including shadow records. then you take the minimum of all those expiration times. the final expiration time is the larger value of (1) the previous EXPIRATION value of a previous RRBLOCK for the same storage key plus one (if any), and (2) the computed minimum expiration time across the contained record types. this is what ensures strict monotonicity (see Section 9.3) ๐Ÿ“ˆ it's a 64-bit absolute date in microseconds since midnight (0 hour), January 1, 1970 UTC, in network byte order
  • BDATA: the encrypted RDATA, computed using S-Encrypt() with the zone key, label, and expiration time as additional inputs. its ultimate size and content are determined by the S-Encrypt() function of the ztype ๐Ÿซถ

the signature over the public key covers a 32-bit pseudo header that's conceptually prefixed to the EXPIRATION and BDATA fields. the wire format is shown in Figure 22 ๐Ÿ‘€

   0     8     16    24    32    40    48    56
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |         SIZE          |       PURPOSE (0x0F)  |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                   EXPIRATION                  |
   +-----+-----+-----+-----+-----+-----+-----+-----+
   |                    BDATA                      |
   /                                               /
   /                                               /
   +-----+-----+-----+-----+-----+-----+-----+-----+

Figure 22: The Wire Format Used for Creating the Signature of the RRBLOCK

  • SIZE: a 32-bit value with the length of the signed data in bytes, in network byte order
  • PURPOSE: a 32-bit signature purpose flag in network byte order. the value of this field MUST be 15 ๐ŸŽฏ it defines the context the signature is created in, so it can't be reused in other parts of the protocol that might include possible future extensions. the value corresponds to an entry in the GANA "GNUnet Signature Purposes" registry [GANA]
  • EXPIRATION: field as defined in the RRBLOCK message above
  • BDATA: field as defined in the RRBLOCK message above

7. Name Resolution ๐Ÿฆ‹

okay so names in GNS get resolved by recursively querying the record storage. "recursive" here means a resolver does NOT hand intermediate results back to the application. instead, it MUST respond to a resolution request with either the requested resource record or an error message if resolution fails ๐Ÿ™…โ€โ™€๏ธ Figure 23 shows how an application requests the lookup of a GNS name (1). the application MAY provide a desired record type to the resolver ๐ŸŽ€ then a Start Zone is determined (2) and the recursive resolution process kicks off. this is where the desired record type steers things. for example, if a zone delegation record type is requested, resolving the apex label in that zone gets skipped, since the desired record is already found โœจ the details on how the resolution process starts and how each iterative result (3a,3b) gets handled are in the sections below. the results of the lookup are eventually returned to the application (4) ๐Ÿ’Œ

the implementation MUST NOT filter the returned resource record sets according to the desired record type. filtering record sets is typically done by the application, not the resolver ๐Ÿ’…
                              Local Host             |   Remote
                                                     |   Storage
                                                     |
                                                     |    +---------+
                                                     |   /         /|
                                                     |  +---------+ |
   +-----------+ (1) Name +----------+               |  |         | |
   |           | Lookup   |          | (3a) GET(q)   |  | Record  | |
   |Application|----------| Resolver |---------------|->| Storage | |
   |           |<---------|          |<--------------|--|         |/
   +-----------+ (4)      +----------+ (3b) RRBLOCK  |  +---------+
                 Records     A                       |
                             |                       |
        (2) Determination of |                       |
            Start Zone       |                       |
                             |                       |
                          +---------+                |
                         /   |     /|                |
                        +---------+ |                |
                        |         | |                |
                        |  Start  | |                |
                        |  Zones  | |                |
                        |         |/                 |
                        +---------+                  |

Figure 23: The Recursive GNS Resolution Process

7.1. Start Zones ๐ŸŒธ

okay so resolving a GNS name starts with figuring out the Start Zone suffix ๐Ÿ’…. Once you've got that, recursive resolution of the rest of the name kicks off (see Section 7.2). There are two kinds of Start Zone suffixes: zTLDs and local suffix-to-zone mappings. Which suffix-to-zone mappings you have is totally up to the local system administrator or user ๐Ÿฆ‹. This dodges the whole single-hierarchy-with-a-centrally-controlled-root situation, plus the related headache of distributing and managing root servers in DNS (see Sections 3.12 and 3.10 of [RFC8324], respectively). Iconic, honestly โœจ.

For names ending with a zTLD, the Start Zone is spelled right out in the suffix of the name you're resolving ๐Ÿงš. To keep names with zTLDs unique, any implementation MUST use the given zone as the Start Zone. An implementation MUST first try to read the rightmost label as the start of a zTLD (see Section 4.1). If that label can't be (even partially) decoded, or it doesn't point to a supported ztype, the name gets treated like a normal name, and Start Zone discovery MUST continue by looking for a local suffix-to-zone mapping. If the rightmost label does have a valid ztype, the implementation MUST try to synthesize and decode the zTLD to get the Start Zone key, following Section 4.1. If the zTLD can't be synthesized or decoded, resolution fails and an error goes back to the app ๐Ÿ’€. Otherwise, the zone key MUST be used as the Start Zone:

Example name: www.example.<zTLD>
=> Start Zone: zkey of type ztype
=> Name to resolve from Start Zone: www.example

For names not ending with a zTLD, the resolver MUST work out the Start Zone through a local suffix-to-zone mapping. Those mappings MUST be configurable through a local configuration file or database, set by the user or system administrator. A suffix MAY be made up of multiple GNS labels joined together with a label separator. If more than one suffix matches the name to resolve, the longest matching suffix MUST be used. The suffix length of two results MUST NOT be equal, because that means something's misconfigured, and the implementation MUST return an error ๐Ÿ™ˆ. Here's a non-normative example of Start Zone mappings:

Example name: www.example.xyz.gns.alt
Local suffix mappings:
xyz.gns.alt = zTLD0 := Base32GNS(ztype0||zkey0)
example.xyz.gns.alt = zTLD1 := Base32GNS(ztype1||zkey1)
example.com.gns.alt = zTLD2 := Base32GNS(ztype2||zkey2)
...
=> Start Zone: zkey1
=> Name to resolve from Start Zone: www

The process above MAY be supplemented with other mechanisms if a particular application needs something different. If no Start Zone can be identified, resolution MUST fail and an error MUST be returned to the application.

7.2. Recursion โœจ

In each step of recursive name resolution, there's an authoritative zone zkey and a name to resolve. The name MAY be empty. If it is empty, it gets interpreted as the apex label @. At the very beginning, the authoritative zone is the Start Zone.

From there, the following steps run recursively, in order:

  1. Pull out the rightmost label from the name you're looking up.
  2. Calculate q from the label and zkey, as defined in Section 6.1.
  3. Make a storage query GET(q) to fetch the RRBLOCK.
  4. Check that (a) the block isn't expired, (b) the SHA-512 hash of the derived authoritative zone key zkey' from the RRBLOCK matches the query q, and (c) the signature is valid. If any of these tests fail, the RRBLOCK MUST be ignored and, if applicable, the storage lookup GET(q) MUST continue looking for other RRBLOCKs.
  5. Get the RDATA by decrypting the BDATA in the RRBLOCK using S-Decrypt() as defined by the zone type. Basically, this reverses the process described in Section 6.3.

Once a well-formed block has been decrypted, the records from RDATA go through record processing ๐Ÿ’œ.

7.3. Record Processing ๐Ÿ”ฅ

In record processing, only the valid records we got are considered. To filter records by validity, the resolver MUST at least check the expiration time and the FLAGS field of each respective record. Specifically, the resolver MUST disregard expired records. The SHADOW and SUPPLEMENTAL flags can also knock records out of consideration. If the resolver runs into a record with the CRITICAL flag set and doesn't support that record type, resolution MUST be aborted and an error MUST be returned. Information saying the critical record couldn't be processed SHOULD be returned in the error description. The implementation MAY choose not to return the reason for the failure, which just makes troubleshooting harder for the poor user ๐Ÿ˜ญ.

The next steps depend on the context of the name being resolved:

  • Case 1: If the filtered record set is a single REDIRECT record, the rest of the name gets prepended to the REDIRECT DATA, and recursion starts over from the resulting name. The details are in Section 7.3.1.
  • Case 2: If the filtered record set is nothing but one or more GNS2DNS records, resolution continues with DNS. The details are in Section 7.3.2.
  • Case 3: If the rest of the name to be resolved is of the format _SERVICE._PROTO and the record set contains one or more matching BOX records, the records inside the BOX records are the final result, and recursion ends as described in Section 7.3.3.
  • Case 4: If the current record set is a single delegation record, resolving the rest of the name gets handed off to the target zone, as described in Section 7.3.4.
  • Case 5: If there's nothing left of the name to resolve, the record set is the final result. If any NICK records are in the final result set, they MUST first be processed according to Section 7.3.5. Otherwise, the record result set is returned directly as the final result.

Finally, if none of the cases above apply, resolution fails, and the resolver MUST return an empty record set ๐Ÿฅ€.

7.3.1. REDIRECT ๐Ÿ’–

If the remaining name is empty and the desired record type is REDIRECT, resolution wraps up with the REDIRECT record. If the rightmost label of the REDIRECT NAME is the extension label U+002B ("+"), resolution carries on in GNS with the new name in the current zone. Otherwise, the resulting name goes through the default operating system name resolution process. That can trigger a GNS name resolution process of its own, depending on the system configuration. If resolution continues in DNS, the name MUST first be converted to an IDNA-compliant representation [RFC5890].

To prevent infinite loops, the resolver MUST implement loop detection or limit the number of recursive resolution steps. The loop detection MUST stay effective even if a REDIRECT found in GNS triggers later GNS lookups through the default operating system name resolution process. no endless loops, bestie ๐Ÿ”

7.3.2. GNS2DNS ๐ŸŒˆ

A resolver returns GNS2DNS records when all of the following conditions are met:

  1. The resolver encounters one or more GNS2DNS records;
  2. The remaining name is empty; and
  3. The desired record type is GNS2DNS.

Otherwise, the resolver is expected to first resolve the IP addresses of the specified DNS name servers. The DNS name MUST be converted to an IDNA-compliant representation [RFC5890] for resolution in DNS. GNS2DNS records MAY contain numeric IPv4 or IPv6 addresses, which lets the resolver skip this step. The DNS server names might themselves be names in GNS or DNS. If the rightmost label of the DNS server name is the extension label U+002B ("+"), the rest of the name is interpreted relative to the zone of the GNS2DNS record. If the DNS server name ends in a label representation of a zone key, the DNS server name is resolved against the GNS zone zkey.

Multiple GNS2DNS records can be stored under the same label, in which case the resolver MUST try all of them. The resolver MAY try them in any order or even in parallel. If multiple GNS2DNS records are present, the DNS name MUST be identical for all of them. Otherwise, it isn't clear which name the resolver is supposed to follow. If different DNS names are present, resolution fails, and an appropriate error SHOULD be returned to the application.

If there are DNSSEC DS records, or any other records used to secure the connection with the DNS servers, stored under the label, the DNS resolver SHOULD use them to secure the connection with the DNS server ๐Ÿ”.

Once the IP addresses of the DNS servers have been determined, the DNS name from the GNS2DNS record is appended to the remainder of the name to be resolved, and it's resolved by querying the DNS name server(s). The synthesized name has to be converted to an IDNA-compliant representation [RFC5890] for resolution in DNS. If that conversion isn't possible, resolution MUST be aborted and an error MUST be returned. Information indicating that the critical record could not be processed SHOULD be returned in the error description. The implementation MAY choose not to return the reason for the failure, which just makes troubleshooting harder for the user.

Since the DNS servers specified are possibly authoritative DNS servers, the GNS resolver MUST support recursive DNS resolution and MUST NOT delegate this to the authoritative DNS servers. The first successful recursive name resolution result is returned to the application. On top of that, the resolver SHOULD return the queried DNS name as a supplemental LEHO record (see Section 5.3.1) with a relative expiration time of one hour โฐ.

Once the transition from GNS to DNS is made through a GNS2DNS record, there is no "going back" ๐Ÿšซ. The (possibly recursive) resolution of the DNS name MUST NOT delegate back into GNS and should only follow the DNS specifications. For example, names contained in DNS CNAME records MUST NOT be interpreted by resolvers that support both DNS and GNS as GNS names.

GNS resolvers SHOULD offer a configuration option to disable DNS processing, to avoid information leakage and provide a consistent security profile for all name resolutions. Such resolvers would return an empty record set upon encountering a GNS2DNS record during the recursion. However, if GNS2DNS records are encountered in the record set for the apex label, and a GNS2DNS record is explicitly requested by the application, such records MUST still be returned, even if DNS support is disabled by the GNS resolver configuration ๐Ÿง.

7.3.3. BOX ๐ŸŽ€

When a BOX record is received, a GNS resolver must unbox it if the name to be resolved continues with _SERVICE._PROTO. Otherwise, the BOX record is to be left untouched. This way, TLSA (and SRV) records do not require a separate network request, and TLSA records become inseparable from the corresponding address records ๐Ÿฆ‹.

7.3.4. Zone Delegation Records โœจ

okay bestie, so when the resolver spots a zone delegation record type it knows (like PKEY or EDKEY) and there's still stuff left over in the name, it keeps going recursively with the leftover part of the name inside the GNS zone that the delegation record points to ๐Ÿฆ‹

Whenever a resolver runs into a new GNS zone, it MUST check the local revocation list (see Section 4.2) to see if that zone key got revoked ๐Ÿšซ. If the zone key was revoked, the resolution MUST fail with an empty result set ๐Ÿ’€.

Implementations MUST NOT allow multiple different zone delegations under a single label (except if some are shadow records) ๐Ÿ™…โ€โ™€๏ธ. Implementations MAY support any subset of ztypes ๐ŸŒธ. Implementations MUST NOT process zone delegation records stored under the apex label ("@") ๐Ÿ™…โ€โ™€๏ธ. If one shows up under the apex label, resolution fails and an error MUST be returned. The implementation MAY choose not to return the reason for the failure, which only affects the troubleshooting info the user gets ๐Ÿ™ˆ.

If the remainder of the name is empty and the record set only has a single delegation record, recursion keeps going with the record value as the authoritative zone, using the apex label "@" as the remaining name โœจ. The one exception: if the record type the application asked for is equal to the ztype, the delegation record itself gets returned ๐Ÿ’–.


7.3.5. NICK ๐ŸŽ€

okay NICK records only matter to the recursive resolver when the record set is the final result that's going back to the application ๐Ÿ’…. The NICK records it runs into can be either supplemental (see Section 5) or non-supplemental. If the NICK record is supplemental, the resolver only returns the record set if one of the non-supplemental records matches the queried record type. It's possible for one record set to contain both supplemental and non-supplemental NICK records ๐ŸŒˆ.

The difference between a supplemental and a non-supplemental NICK record is what lets the application match the record to the authoritative zone ๐Ÿ‘‘. Check out this example:

Query: alice.example.gns.alt (type=A)
Result:
A: 192.0.2.1
NICK: eve (non-supplemental)

Here the returned NICK record is non-supplemental. For the application, that means the NICK belongs to the zone "alice.example.gns.alt" and is published under the apex label right next to an A record. So the NICK is read like this: the zone defined by "alice.example.gns.alt" wants to be called "eve" โญ. Now compare this one:

Query: alice.example.gns.alt (type=AAAA)
Result:
AAAA: 2001:db8::1
NICK: john (supplemental)

This time the NICK record is marked as supplemental, so it belongs to the zone "example.gns.alt" and is published under the label "alice" alongside an AAAA record ๐Ÿงš. Here the NICK should be read like this: the zone defined by "example.gns.alt" wants to be called "john". This distinction is likely useful for other records published as supplemental ๐Ÿฆ‹.


8. Internationalization and Character Encoding ๐ŸŒ

Every name in GNS is encoded in UTF-8 [RFC3629] ๐Ÿ’œ. Labels MUST be canonicalized using Normalization Form C (NFC) [Unicode-UAX15] โœจ. This doesn't cover any DNS names found in DNS records, like CNAME record data. Those are internationalized through the IDNA specifications instead; see [RFC5890] ๐ŸŒธ.


9. Security and Privacy Considerations ๐Ÿ”

Okay, this part is seriously important, so pay attention ๐Ÿซถ.

9.1. Availability โฐ

To keep records available past their absolute expiration times, implementations MAY allow relative expiration time values of records to be defined locally. Records can then get published again, recurringly, with updated absolute expiration times by the implementation ๐Ÿ”.

Implementations MAY allow users to manage private records in their zones that are not published in storage. Private records get treated just like regular records when labels are resolved in local zones, but their data is completely unavailable to non-local users ๐Ÿ™ˆ.

9.2. Agility ๐Ÿ›ก๏ธ

The security of a cryptographic system depends on both how strong the algorithms are and how strong the keys are ๐Ÿ”‘. It also depends on how the protocol using them is engineered, so there are no non-cryptographic ways to bypass the security of the whole system ๐Ÿ’€. That's why developers of applications managing GNS zones SHOULD select a default ztype that's considered secure at the time they release the software. For applications aimed at end users who aren't expected to understand cryptography, the application developer MUST NOT leave the ztype selection of new zones to those end users ๐Ÿšซ.

This document is all about choosing which cryptographic algorithms GNS uses ๐Ÿ’…. The algorithms identified here aren't known to be broken (in the cryptographic sense) right now, and cryptographic research so far suggests they're likely to stay secure for the foreseeable future. But that's not forever, so new revisions of this document are expected to come out from time to time to reflect current best practices ๐Ÿ“š.

When it comes to crypto-agility: whenever an updated cryptographic scheme is needed, say to replace ECDSA over Ed25519 for PKEY records, it can simply be introduced through a new record type โœจ. Zone administrators can then swap the delegation record type for future records. The old record type sticks around, so zones can migrate to the updated zone keys bit by bit ๐Ÿฆ‹. To make sure implementations correctly generate an error message when they hit a ztype they don't support, current and future delegation records must always have the CRITICAL flag set ๐Ÿšฉ.

9.3. Cryptography ๐Ÿ”ฌ

The following considerations give background on the design choices behind the ztypes specified in this document ๐Ÿง . When specifying new ztypes as per Section 4, the same considerations apply ๐ŸŽ€.

GNS PKEY zone keys use ECDSA over Ed25519. Yes, this is an unconventional choice, since ECDSA is usually used with other curves ๐Ÿ™ƒ. But standardized ECDSA curves are problematic for a range of reasons, as described in the Curve25519 and EdDSA papers [RFC7748] [ed25519] ๐Ÿ“„. Using EdDSA directly isn't possible either, because a hash function is applied to the private key, and that would destroy the linearity that GNS key blinding depends on ๐Ÿ’€. We're not aware of anyone suggesting that using Ed25519 instead of another common curve of similar size would lower the security of ECDSA. GNS uses 256-bit curves, which means the encoded (public) keys fit into a single DNS label, and that's great for usability ๐Ÿฅฐ.

To keep ciphertext indistinguishable, you have to be careful with the IV in the counter block ๐Ÿ”. In this design, the IV always includes the expiration time of the record block. When applications store records with relative expiration times, monotonicity is implicitly ensured, because each time a block is published in storage its IV is unique. The expiration time is calculated dynamically and increases monotonically with the system time ๐Ÿ•ฐ๏ธ. Still, an implementation MUST ensure that when relative expiration times are decreased, the expiration time of the next record block MUST be after the last published block. For records where an absolute expiration time is used, the implementation MUST ensure that the expiration time is always increased when the record data changes. For example, the expiration time on the wire could be increased by a single microsecond even if the user didn't ask for a change ๐Ÿ™ˆ.

If all resource records under a label get deleted, the implementation MUST keep track of the last absolute expiration time of the last published resource block ๐Ÿ“. Implementations MAY define and use a special record type as a tombstone that preserves the last absolute expiration time, but then they MUST take care not to publish a block with such a tombstone record ๐Ÿชฆ. When new records are added under this label later, the implementation MUST ensure that the expiration times are after the last published block. Finally, to keep expiration times monotonically increasing, the implementation MUST keep a local record of the last time obtained from the system clock, so it can construct a monotonic clock if the system clock jumps backwards โช.

9.4. Abuse Mitigation ๐Ÿšจ

GNS names are UTF-8 strings, so GNS has to deal with name spoofing issues similar to the ones DNS has with internationalized domain names ๐ŸŒ. In DNS, attackers can register similar-sounding or similar-looking names (see above) to pull off phishing attacks ๐ŸŽฃ. GNS zone administrators must take this attack vector into account and build in rules to mitigate it ๐Ÿ›‘.

Also, DNS can be used to fight illegal content on the Internet by having the relevant domains seized by authorities. But those same mechanisms can be abused to impose state censorship ๐Ÿ˜ฌ. Avoiding that possibility is one of the motivations behind GNS ๐Ÿฆ‹. In GNS, TLDs aren't enumerable. By design, the resolver's Start Zone is defined locally, so a seizure is difficult and ineffective in GNS ๐Ÿ’ช.

9.5. Zone Management ๐Ÿ—๏ธ

In GNS, zone administrators need to manage and protect their zone keys ๐Ÿ”. Once a private zone key is lost, it can't be recovered, and the zone revocation message can't be computed anymore. Revocation messages can be precalculated if revocation is needed in cases where a private zone key gets lost ๐Ÿ“…. Zone administrators, and for GNS that includes end users, are required to responsibly and diligently protect their cryptographic keys ๐Ÿ’–. GNS supports signing records in advance ("offline") so that processes (such as air gaps) that aim to protect private keys can be used ๐ŸงŠ.

Similarly, users are required to manage their local Start Zone configuration ๐Ÿ . To keep names intact and available, users must make sure their local Start Zone information isn't compromised or outdated โš ๏ธ. It can be expected that zone revocations and an initial Start Zone get shipped with a GNS implementation ("drop shipping") ๐Ÿ“ฆ. Shipping an initial Start Zone configuration effectively establishes a root zone ๐Ÿ‘‘. Extending and customizing the zone is entirely up to the user ๐ŸŽจ.

While implementations following this specification will be interoperable, if two implementations connect to different remote storage entities, they're mutually unreachable ๐Ÿ™…โ€โ™€๏ธ. This can lead to a state where a record exists in the global namespace for a particular name, but the implementation isn't talking to the remote storage entity that holds the respective block, so it can't resolve it ๐Ÿ˜ญ. It's kind of like a split-horizon DNS setup ๐ŸŒ—. Which remote storage entity gets used will most likely depend on the specific application context using GNS resolution. For example, resolving hidden services within the Tor network [TorRendSpec] would suggest using Tor routers for remote storage ๐Ÿง…. Implementations of "aggregated" remote storage entities are conceivable, but they're expected to be the exception ๐ŸŒŸ.

9.6. DHTs as Remote Storage ๐Ÿงš

okay bestie, this one's lowkey a big deal ๐Ÿ’… this doc does NOT spell out how the underlying remote storage works ๐Ÿ™ˆ, but every GNS implementation needs some, so it matters. the storage's properties get passed straight down to the GNS implementation (no cap, it's inherited ๐Ÿซถ). that includes security AND the non-functional stuff like scalability and performance ๐Ÿ“ˆ. implementers should take SO much care when picking or building a DHT to use as remote storage ๐Ÿ’€ it's honestly the most important choice they'll make. DHTs with reasonable security and performance properties do exist [R5N] โœจ. it should also be considered that GNS implementations built on different DHT overlays are unlikely to be mutually reachable ๐Ÿ˜ญ they might not be able to see each other, which is so not the vibe.

9.7. Revocations ๐Ÿ’”

zone administrators are advised to pregenerate zone revocations and to securely store the revocation information if the zone key is lost, compromised, or replaced in the future ๐Ÿ”. precalculated revocations can stop being valid because of expirations or protocol changes like epoch adjustments, so implementers and users must take precautions to manage revocations properly ๐Ÿงน.

revocation payloads do not include a "new" key for key replacement. and honestly? that's on purpose ๐Ÿ™…โ€โ™€๏ธ including one would cause two major problems:

  1. if a revocation gets published after a private key was compromised, allowing key replacement would be dangerous ๐Ÿ˜ฑ. if an adversary took over the private key, they could broadcast a revocation with a key replacement. the compromised owner would have no chance to issue a revocation for it. so letting a revocation message replace a private key makes key compromise situations WORSE, not better.
  2. sometimes key revocations are used to change cryptosystems ๐Ÿ”„. migrating to another cryptosystem by replacing keys via a revocation message would only be secure as long as both cryptosystems are still secure against forgery. a planned, non-emergency migration should be done by running zones for both cipher systems in parallel for a while ๐Ÿซง. the migration would wrap up by revoking the legacy zone key only once it's deemed no longer secure and, hopefully, after most users have moved over to the replacement ๐ŸŽ€.

9.8. Zone Privacy ๐Ÿ•ต๏ธโ€โ™€๏ธ

GNS does NOT support authenticated denial of existence of names within a zone ๐Ÿ™…. record data is published in encrypted form, using keys derived from the zone key and the record label ๐Ÿ”‘. zone administrators should carefully think about whether (1) a label and zone key are public or (2) one or both should be used as a shared secret to restrict access to the corresponding record data ๐Ÿคซ. here's the tea: unlike public zone keys, low-entropy labels can be guessed by an attacker ๐Ÿ‘€. if an attacker knows the public zone key, using well-known or guessable labels effectively threatens the disclosure of the corresponding records ๐Ÿ˜ฌ.

it's worth noting that the guessing attack on labels only applies if the zone key is somehow disclosed to the adversary ๐Ÿง . GNS itself does not disclose it during a lookup or when resource records are published (since only the blinded zone keys are used on the network) ๐Ÿ™Œ. however, zone keys DO become public during revocation โš ๏ธ.

it is thus RECOMMENDED to use a label with sufficient entropy to prevent guessing attacks if any data in a resource record set is sensitive. no skipping this one, bestie ๐Ÿšจ

9.9. Zone Governance ๐Ÿ›๏ธ

while DNS is distributed, in practice it relies on centralized, trusted registrars to provide globally unique names ๐Ÿ“›. as people get more aware of how central DNS is to the Internet, various institutions are using their power (including legal means) to attack the DNS, which threatens the global availability and integrity of information on the Internet ๐Ÿ˜ค. a wider discussion of this is out of scope for this document, but analyses and investigations can be found in recent academic research works, including [SecureNS] ๐Ÿ“š.

GNS is designed to be a secure, privacy-enhancing alternative to the DNS name resolution protocol, especially when censorship or manipulation shows up ๐Ÿ›ก๏ธ. it directly addresses DNS concerns about query privacy โœจ. however, depending on the governance of the root zone, any deployment will likely suffer from the issue of a single hierarchy with a centrally controlled root, plus the related issue of distributing and managing root servers in DNS, as raised in Sections 3.12 and 3.10 of [RFC8324] respectively ๐ŸŒณ. in DNS, those issues come directly from the centralized root zone governance at the Internet Corporation for Assigned Names and Numbers (ICANN), which lets it provide globally unique names ๐ŸŒ.

in GNS, Start Zones give users local authority over their preferred root zone governance ๐Ÿ‘‘. users can replace or enhance a trusted root zone configuration provided by a third party (e.g., the implementer or a multi-stakeholder governance body like ICANN) with secure delegation of authority using local petnames ๐Ÿฅฐ, all while operating under a very strong adversary model ๐Ÿ’ช. combined with zTLDs, this gives GNS users a global, secure, and memorable mapping without a trusted authority ๐Ÿฆ‹.

any GNS implementation MAY provide a default governance model in the form of an initial Start Zone mapping ๐ŸŽ.

9.10. Namespace Ambiguity ๐Ÿซฃ

technically, the GNS protocol CAN be used to resolve names in the namespace of the global DNS ๐Ÿคฏ. but that would require the respective governance bodies and stakeholders (e.g., the IETF and ICANN) to standardize the use of GNS for this particular use case ๐Ÿ“.

this capability means GNS names may be indistinguishable from DNS names in their common display format [RFC8499], or from other special-use domain names [RFC6761], if a local Start Zone configuration maps suffixes from the global DNS to GNS zones ๐ŸŒ€. applications then become confused about which name system should resolve a given name ๐Ÿ™ƒ. this is a risk when trying to resolve a name through DNS when it's actually a GNS name, as discussed in [RFC8244] ๐Ÿšฉ. in that case, the GNS name is likely to be leaked as part of the DNS resolution ๐Ÿ˜ญ.

to prevent disclosure of queried GNS names, it is RECOMMENDED that GNS-aware applications try to resolve a given name in GNS before any other method, taking into account potential suffix-to-zone mappings and zTLDs ๐Ÿ”. suffix-to-zone mappings are expected to be configured by the user or a local administrator, so resolving in GNS matches user expectations even if the name could also be resolved through DNS ๐Ÿ’–. if no suffix-to-zone mapping exists for the name and no zTLD is found, resolution MAY continue with other methods such as DNS ๐Ÿซง. but if a suffix-to-zone mapping exists for the name or the name ends with a zTLD, it MUST be resolved using GNS, and resolution MUST NOT continue by any other means, regardless of the GNS resolution result ๐Ÿšซ.

mechanisms like the Name Service Switch (NSS) of UNIX-like operating systems are an example of how this resolution process can be implemented and used ๐Ÿง. the NSS lets system administrators configure hostname resolution precedence, and it's integrated with the system resolver implementation ๐Ÿงฉ.

for use cases where GNS names may be confused with names from other name resolution mechanisms (in particular, DNS), the ".gns.alt" domain SHOULD be used ๐Ÿท๏ธ. for use cases like implementing sinkholes to block malware sites, or serving DNS domains via GNS to bypass censorship, GNS MAY be deliberately used in ways that interfere with resolution of another name system ๐Ÿ› ๏ธ. (we love a deliberate plot twist, but know what you're doing ๐Ÿ˜Œ.)

10. GANA Considerations ๐ŸŒท

10.1. GNUnet Signature Purposes Registry

GANA [GANA] has assigned signature purposes in its "GNUnet Signature Purposes" registry, as listed in Table 1 ๐Ÿ“‹.

+=========+=================+============+==========================+
| Purpose | Name            | References | Comment                  |
+=========+=================+============+==========================+
| 3       | GNS_REVOCATION  | RFC 9498   | GNS zone key revocation  |
+---------+-----------------+------------+--------------------------+
| 15      | GNS_RECORD_SIGN | RFC 9498   | GNS record set           |
|         |                 |            | signature                |
+---------+-----------------+------------+--------------------------+

            Table 1: The GANA GNUnet Signature Purposes Registry

10.2. GNS Record Types Registry โœจ

Okay bestie, GANA [GANA] is the one managing the "GNS Record Types" registry ๐ŸŽ€ Every entry has the following format:

  • Name: the name of the record type. It's a case-insensitive ASCII string, limited to alphanumeric characters. For zone delegation records, the assigned number is the ztype value of the zone ๐Ÿฆ‹
  • Number: a 32-bit number above 65535 ๐Ÿ”ข
  • Comment: optional, brief English text about what the record type is for (in UTF-8) ๐Ÿ’ฌ
  • Contact: optional, contact info for a person you can reach for more details ๐Ÿ“‡
  • References: optional, references (like an RFC) that describe the record type ๐Ÿ“š

The registration policy here is "First Come First Served" ๐Ÿ’– It's modeled on the one in [RFC8126], and this is what GANA does:

  • Adding new entries is possible after review by any authorized GANA contributor, using a first-come-first-served policy for unique name allocation. Reviewers are responsible for making sure the chosen "Name" fits the record type. The registry will define a unique number for the entry.
  • Authorized GANA contributors who review new entries can be reached at <gns-registry@gnunet.org> ๐Ÿ’Œ
  • Any request MUST contain a unique name and a point of contact. The contact information MAY be added to the registry, with the consent of the requester. The request MAY optionally also contain relevant references as well as a descriptive comment, as defined above. ๐Ÿซถ

GANA has assigned numbers for the record types defined in this specification in the "GNS Record Types" registry, and they're listed in Table 2 ๐ŸŒˆ

     +========+==========+=========+============+====================+
     | Number | Name     | Contact | References | Comment            |
     +========+==========+=========+============+====================+
     | 65536  | PKEY     | (*)     | RFC 9498   | GNS zone           |
     |        |          |         |            | delegation (PKEY)  |
     +--------+----------+---------+------------+--------------------+
     | 65537  | NICK     | (*)     | RFC 9498   | GNS zone nickname  |
     +--------+----------+---------+------------+--------------------+
     | 65538  | LEHO     | (*)     | RFC 9498   | GNS legacy         |
     |        |          |         |            | hostname           |
     +--------+----------+---------+------------+--------------------+
     | 65540  | GNS2DNS  | (*)     | RFC 9498   | Delegation to DNS  |
     +--------+----------+---------+------------+--------------------+
     | 65541  | BOX      | (*)     | RFC 9498   | Box records        |
     +--------+----------+---------+------------+--------------------+
     | 65551  | REDIRECT | (*)     | RFC 9498   | Redirection record |
     +--------+----------+---------+------------+--------------------+
     | 65556  | EDKEY    | (*)     | RFC 9498   | GNS zone           |
     |        |          |         |            | delegation (EDKEY) |
     +--------+----------+---------+------------+--------------------+
     | (*): gns-registry@gnunet.org                                  |
     +---------------------------------------------------------------+

                Table 2: The GANA GNS Record Types Registry

10.3. .alt Subdomains Registry โœจ

GANA [GANA] manages the ".alt Subdomains" registry ๐Ÿฆ„ Quick heads-up: this GANA-operated .alt registry may or may not be taken into account by any particular implementer, and it has zero official connection to the IETF or ICANN. Not sanctioned, not associated, just vibes ๐Ÿ™ˆ

Each entry has the following format:

  • Label: the label of the subdomain, in DNS "letters, digits, hyphen" (LDH) format as defined in Section 2.3.1 of [RFC5890] ๐Ÿ”ค
  • Description: optional, brief English text about what the subdomain is for (in UTF-8) ๐Ÿ“
  • Contact: optional, contact info for a person you can reach for more details ๐Ÿ“‡
  • References: optional, references (like an RFC) that describe the record type ๐Ÿ“š

The registration policy here is also "First Come First Served" ๐Ÿ’… It's modeled on the one in [RFC8126], and GANA does the following:

  • Adding new entries is possible after review by any authorized GANA contributor, using a first-come-first-served policy for unique subdomain allocation. Reviewers are responsible for making sure the chosen "Subdomain" fits the purpose.
  • Authorized GANA contributors who review new entries can be reached at <alt-registry@gnunet.org> ๐Ÿ’Œ
  • Any request MUST contain a unique subdomain and a point of contact. The contact information MAY be added to the registry, with the consent of the requester. The request MAY optionally also contain relevant references as well as a descriptive comment, as defined above. โœจ

GANA has assigned the subdomain defined in this specification in the ".alt Subdomains" registry, as listed in Table 3 ๐ŸŒธ

       +=======+=========+============+============================+
       | Label | Contact | References | Description                |
       +=======+=========+============+============================+
       | gns   | (*)     | RFC 9498   | The .alt subdomain for GNS |
       +-------+---------+------------+----------------------------+
       | (*): alt-registry@gnunet.org                              |
       +-----------------------------------------------------------+

                 Table 3: The GANA .alt Subdomains Registry

11. IANA Considerations ๐ŸŽ€

Nothing for IANA to do here! This document has no IANA actions ๐Ÿซถ

12. Implementation and Deployment Status โœจ

Okay, the implementation scene is honestly iconic ๐Ÿ‘‘ There are two implementations that conform to this specification, one written in C and one in Go. The C implementation, which is part of GNUnet [GNUnetGNS], is the original and reference implementation ๐Ÿ’œ The Go implementation [GoGNS] shows how two GNS implementations can be interoperable when they're built on top of the same underlying DHT storage ๐Ÿงš

Right now, the GNUnet peer-to-peer network [GNUnet] is an active deployment of GNS running on its DHT [R5N] ๐ŸŒˆ The Go implementation [GoGNS] uses this deployment by building on the GNUnet DHT services available on any GNUnet peer. It shows how GNS implementations can attach to this existing deployment and take part in both name resolution and zone publication ๐Ÿ”ฅ

The self-sovereign identity system re:claimID [reclaim] uses GNS to selectively share identity attributes and attestations with third parties ๐Ÿฆ‹

Last but not least, the Ascension tool [Ascension] helps migrate DNS zones to GNS zones by translating information retrieved from a DNS zone transfer into a GNS zone ๐Ÿ’–

13. References โœจ

13.1. Normative References โœจ

okay so this is the list of docs the spec leans on hardest, bestie ๐Ÿ“š each one comes with its number, title, authors, DOI, and link so you can go read them yourself ๐Ÿค“


13.2. Informative References ๐Ÿฆ‹

these ones are the helpful background reads, the context and extra rabbit holes that make the spec click even though it doesn't lean on them as hard ๐ŸŒธ


Appendix A. Usage and Migration ๐ŸŒˆ

okay so this bit is the "why would anyone actually use this?" tour ๐Ÿ’… it walks through a bunch of specific use cases that might help you get what the protocol is for, like the vibe check before the deep dive โœจ

but (important!!) none of the considerations below are normative for GNS in any way ๐Ÿ™ˆ they're just here for context and to show what the designers were going for. it also points you at some migration paths ๐Ÿฆ‹

A.1. Zone Dissemination โœจ

Okay so becoming a zone owner is giving easy mode ๐Ÿ’…. You just generate a zone key and its matching secret key with a GNS implementation. Then you can manage your GNS resource records in a local zone database ๐Ÿ—‚๏ธ, and a GNS implementation can publish them as defined in Section 6. But for other people to resolve those records, the zone information has to be disseminated first ๐Ÿ“ฃ. You get to decide: keep the zone key and labels for a squad of selected users, or put them out there for the whole public ๐ŸŒธ.

Sharing directly with specific people is lowkey the best move, because it can help preserve zone and record privacy and lets you and the user build strong trust relationships ๐Ÿซถ. For example, a bank might send a customer letter with a QR code that holds the bank's GNS zone. The user scans it and boom, they have a strong link to the bank's zone, and with it, for example, the IP address of the online banking web site ๐Ÿฆ.

Most Internet services want to make their zones public in the most efficient way possible โšก. Zones with high reputation and trust are likely included in the default suffix-to-zone mappings of implementations, so delegation under those zones can be a viable path to going public ๐Ÿ‘‘. It's conceivable that organizations like ICANN or country-code TLD registrars could also manage GNS zones and offer registration or delegation services ๐ŸŒˆ.

Following best practices, especially the ones about security and abuse mitigation, is how zone owners and aspiring registrars earn a good reputation and, eventually, trust โœจ. That includes, of course, diligent protection of private zone key material ๐Ÿ”. Formalizing those best practices is out of scope for this specification. They should be addressed in a separate document that takes Section 9 of this document into account ๐Ÿ“š.

A.2. Start Zone Configuration ๐ŸŒท

A user is expected to install a GNS implementation if it isn't already provided through other means, like the operating system or the browser. The implementation will most likely ship with a default Start Zone configuration, which means the user can resolve GNS names ending on a zTLD or ending on any suffix-to-name mapping in that default configuration. At this point, the user may delete or otherwise modify the implementation's default configuration:

  • Deleting suffix-to-zone mappings may become necessary if the zone owner behind the mapping has lost the user's trust. For example, this could happen because of lax registration policies that lead to phishing activities. Modifying and adding new mappings are ways to heal the namespace perforation that a deletion would cause, or to simply establish a strong direct trust relationship ๐Ÿ’œ. However, this requires the user's knowledge of the respective zone keys. That information must be retrieved out of band, as illustrated in Appendix A.1: a bank may send the user a letter with a QR code that contains the GNS zone of the bank. The user scans the QR code and adds a new suffix-to-name mapping using a chosen local name for their bank. Other examples include scanning zone information off a friend's device, from a storefront, or from an advertisement. The level of trust in a zone is contextual and likely varies from user to user. Trust in a zone that comes through a letter from a bank, which may also include a credit card, is certainly different from a zone found on a random advertisement on the street. Still, this trust is immediately tangible to the user and can be reflected in the local naming as well ๐ŸŽ€.
  • Users that are also clients should facilitate modification of the Start Zone configuration, for example by providing a QR code reader or other import mechanisms ๐Ÿ“. Implementations are ideally built according to best practices and address the applicable points from Section 9. Formalizing those best practices is out of scope for this specification ๐Ÿ™ˆ.

A.3. Globally Unique Names and the Web ๐ŸŒ

HTTP virtual hosting and TLS Server Name Indication (SNI) are super common on the Web ๐Ÿ’ป. HTTP clients supply a DNS name in the HTTP "Host"-header or as part of the TLS handshake, respectively. That lets the HTTP server serve the indicated virtual host with a matching TLS certificate. The global uniqueness of DNS names is a prerequisite for those use cases ๐Ÿฆ‹.

Not all GNS names are globally unique. However, any resource record in GNS can be represented as a concatenation of a GNS label and the zTLD of the zone. It's not very memorable, but this globally unique GNS name can be leveraged to facilitate the same use cases ๐Ÿงš. Say the GNS name "www.example.gns.alt" is entered in a GNS-aware HTTP client. First, "www.example.gns.alt" is resolved using GNS, yielding a record set. Then the HTTP client determines the virtual host as follows:

If there is a LEHO record (Section 5.3.1) containing "www.example.com" in the record set, then the HTTP client uses this as the value of the "Host"-header field of the HTTP request:

GET / HTTP/1.1
Host: www.example.com

In the absence of a LEHO record, an additional GNS resolution is required to check whether "www.example.gns.alt" itself points to a zone delegation record, which implies that the record set that was originally resolved is published under the apex label.

If it does, the unique GNS name is simply the zTLD representation of the delegated zone:

GET / HTTP/1.1
Host: 000G0037FH3QTBCK15Y8BCCNRVWPV17ZC7TSGB1C9ZG2TPGHZVFV1GMG3W

On the other hand, if there is no zone delegation record for "www.example.gns.alt", then the unique GNS name is the concatenation of the leftmost label (e.g., "www") and the zTLD representation of the zone:

GET / HTTP/1.1
Host: www.000G0037FH3QTBCK15Y8BCCNRVWPV17ZC7TSGB1C9ZG2TPGHZVFV1GMG3W

Note that this second GNS resolution does not require any additional network operation, as only the local record processing differs, per the exception mentioned in the last sentence of Section 7.3.4 ๐Ÿซถ.

If the HTTP client is a browser, the unique GNS name used for virtual hosting or TLS SNI doesn't necessarily have to be shown to the user ๐Ÿ‘€. For example, the name in the URL bar may remain "www.example.gns.alt" even if the unique name in the "Host"-header differs.

A.4. Migration Paths ๐Ÿš€

DNS resolution is built into a variety of existing software components, most significantly operating systems and HTTP clients ๐Ÿ’–. This section illustrates possible migration paths for both, so legacy applications can resolve GNS names.

One efficient way to facilitate GNS name resolution is via GNS-enabled DNS server implementations ๐Ÿง. Local DNS queries are either rerouted or explicitly configured to be resolved by a "DNS-to-GNS" server that runs locally. This DNS server tries to interpret any incoming query for a name as a GNS resolution request. If no Start Zone can be found for the name and it doesn't end in a zTLD, the server tries to resolve the name in DNS. Otherwise, the name is resolved in GNS. In the latter case, the resulting record set is converted to a DNS answer packet and returned accordingly. An implementation of a DNS-to-GNS server can be found in [GNUnet].

A similar approach is to use operating system extensions such as the NSS [nsswitch] ๐Ÿฃ. It lets the system administrator configure plugins that are used for hostname resolution. A GNS nsswitch plugin can be used in a fashion similar to the DNS-to-GNS server. An implementation of a glibc-compatible nsswitch plugin for GNS can be found in [GNUnet] โœจ.

The methods above are usually also effective for HTTP client software. However, HTTP clients are commonly used in combination with TLS, and TLS certificate validation, SNI in particular, requires additional logic in HTTP clients when GNS names are in play (Appendix A.3) ๐Ÿ˜ญ. To transparently enable this functionality for migration purposes, a local GNS-aware SOCKS5 proxy [RFC1928] can be configured to resolve domain names. Like the DNS-to-GNS server, the SOCKS5 proxy is capable of resolving both GNS and DNS names. For a TLS connection request with a GNS name, the SOCKS5 proxy can terminate the TLS connection and establish a secure connection against the requested host. To establish that secure connection, the proxy may use LEHO and TLSA records stored in the record set under the GNS name. The proxy must provide a locally trusted certificate for the GNS name to the HTTP client, which usually requires generating and configuring a local trust anchor in the browser ๐Ÿ”‘. An implementation of this SOCKS5 proxy can be found in [GNUnet].


Appendix B. Example Flows ๐Ÿงš

B.1. AAAA Example Resolution ๐ŸŒˆ

                              Local Host             |   Remote
                                                     |   Storage
                                                     |
                                                     |    +---------+
                                                     |   /         /|
                                                     |  +---------+ |
   +-----------+ (1)      +----------+               |  |         | |
   |           |          |          |      (4,6)    |  | Record  | |
   |Application|----------| Resolver |---------------|->| Storage | |
   |           |<---------|          |<--------------|--|         |/
   +-----------+ (8)      +----------+      (5,7)    |  +---------+
                             A                       |
                             |                       |
                       (2,3) |                       |
                             |                       |
                             |                       |
                          +---------+                |
                         /   v     /|                |
                        +---------+ |                |
                        |         | |                |
                        |  Start  | |                |
                        |  Zones  | |                |
                        |         |/                 |
                        +---------+                  |

              Figure 24: Example Resolution of an IPv6 Address
  1. Look up AAAA record for name: "www.example.gnu.gns.alt".
  2. Determine Start Zone for "www.example.gnu.gns.alt".
  3. Start Zone: zkey0 - Remainder: "www.example".
  4. Calculate q0=SHA512(ZKDF(zkey0, "example")) and initiate GET(q0).
  5. Retrieve and decrypt RRBLOCK consisting of a single PKEY record containing zkey1.
  6. Calculate q1=SHA512(ZKDF(zkey1, "www")) and initiate GET(q1).
  7. Retrieve RRBLOCK consisting of a single AAAA record containing the IPv6 address 2001:db8::1.
  8. Return record set to application.

B.2. REDIRECT Example Resolution โœจ

okay so this one is about a REDIRECT record ๐Ÿฆ‹ the resolver starts with a name, finds a redirect along the way, and follows it until it reaches an actual AAAA answer. here's the picture first:

                              Local Host              |   Remote
                                                      |   Storage
                                                      |
                                                      |    +---------+
                                                      |   /         /|
                                                      |  +---------+ |
   +-----------+ (1)      +----------+                |  |         | |
   |           |          |          |      (4,6,8)   |  | Record  | |
   |Application|----------| Resolver |----------------|->| Storage | |
   |           |<---------|          |<---------------|--|         |/
   +-----------+ (10)     +----------+      (5,7,9)   |  +---------+
                             A                        |
                             |                        |
                       (2,3) |                        |
                             |                        |
                             |                        |
                          +---------+                 |
                         /   v     /|                 |
                        +---------+ |                 |
                        |         | |                 |
                        |  Start  | |                 |
                        |  Zones  | |                 |
                        |         |/                  |
                        +---------+                   |

Figure 25: Example Resolution of an IPv6 Address with Redirect

here's the step-by-step, bestie ๐Ÿ’…

  1. Look up the AAAA record for the name "www.example.tld.gns.alt".
  2. Determine the Start Zone for "www.example.tld.gns.alt".
  3. The Start Zone is zkey0, and the Remainder is "www.example".
  4. Calculate q0=SHA512(ZKDF(zkey0, "example")) and initiate GET(q0).
  5. Retrieve and decrypt the RRBLOCK, which holds a single PKEY record containing zkey1.
  6. Calculate q1=SHA512(ZKDF(zkey1, "www")) and initiate GET(q1).
  7. Retrieve and decrypt the RRBLOCK, which holds a single REDIRECT record containing "www2.+".
  8. Calculate q2=SHA512(ZKDF(zkey1, "www2")) and initiate GET(q2).
  9. Retrieve and decrypt the RRBLOCK, which holds a single AAAA record containing the IPv6 address 2001:db8::1.
  10. Return the record set to the application.

the redirect in step 7 is the plot twist ๐Ÿ˜ญ๐Ÿ”ฅ


B.3. GNS2DNS Example Resolution ๐ŸŒธ

this one is the DNS handover version. the name lives in GNS, but the actual answer comes from the system DNS resolver ๐Ÿงš same vibe, different ending.

                              Local Host                |   Remote
                                                        |   Storage
                                                        |
                                                        |    +---------+
                                                        |   /         /|
                                                        |  +---------+ |
   +-----------+ (1)      +----------+                  |  |         | |
   |           |          |          |      (4)         |  | Record  | |
   |Application|----------| Resolver |------------------|->| Storage | |
   |           |<---------|          |<-----------------|--|         |/
   +-----------+ (8)      +----------+      (5)         |  +---------+
                             A    A                     |
                             |    |    (6,7)            |
                       (2,3) |    +----------+          |
                             |               |          |
                             |               v          |
                          +---------+    +------------+ |
                         /   v     /|    | System DNS | |
                        +---------+ |    | Resolver   | |
                        |         | |    +------------+ |
                        |  Start  | |                   |
                        |  Zones  | |                   |
                        |         |/                    |
                        +---------+                     |

Figure 26: Example Resolution of an IPv6 Address with DNS Handover

the steps, in order ๐ŸŽ€

  1. Look up the AAAA record for the name "www.example.gnu.gns.alt".
  2. Determine the Start Zone for "www.example.gnu.gns.alt".
  3. The Start Zone is zkey0, and the Remainder is "www.example".
  4. Calculate q0=SHA512(ZKDF(zkey0, "example")) and initiate GET(q0).
  5. Retrieve and decrypt the RRBLOCK, which holds a single GNS2DNS record containing the name "example.com" and the DNS server IPv4 address 192.0.2.1.
  6. Use the system resolver to look up an AAAA record for the DNS name "www.example.com".
  7. Retrieve a DNS reply consisting of a single AAAA record containing the IPv6 address 2001:db8::1.
  8. Return the record set to the application.

Appendix C. Base32GNS ๐Ÿ“

okay, so encoding turns a byte array into a string of symbols, and decoding turns that string back into bytes. if the input string has any symbols outside the defined set, decoding fails ๐Ÿ™ˆ

Table 4 is the boss list. each symbol holds 5 bits. so if you see the symbol "A" or "a" while decoding, it turns into the 5-bit value 10. and when you're encoding, a 5-bit block with the value 18 becomes "J" โœจ if the bit length of your byte string isn't a multiple of 5, you pad it with zeroes up to the next multiple.

also, for extra forgiveness when characters get misread, the letter "U" MUST be decoded to the same value as the letter "V" in Base32GNS. ๐Ÿ’œ

           +==============+=================+=================+
           | Symbol Value | Decoding Symbol | Encoding Symbol |
           +==============+=================+=================+
           | 0            | 0 O o           | 0               |
           +--------------+-----------------+-----------------+
           | 1            | 1 I i L l       | 1               |
           +--------------+-----------------+-----------------+
           | 2            | 2               | 2               |
           +--------------+-----------------+-----------------+
           | 3            | 3               | 3               |
           +--------------+-----------------+-----------------+
           | 4            | 4               | 4               |
           +--------------+-----------------+-----------------+
           | 5            | 5               | 5               |
           +--------------+-----------------+-----------------+
           | 6            | 6               | 6               |
           +--------------+-----------------+-----------------+
           | 7            | 7               | 7               |
           +--------------+-----------------+-----------------+
           | 8            | 8               | 8               |
           +--------------+-----------------+-----------------+
           | 9            | 9               | 9               |
           +--------------+-----------------+-----------------+
           | 10           | A a             | A               |
           +--------------+-----------------+-----------------+
           | 11           | B b             | B               |
           +--------------+-----------------+-----------------+
           | 12           | C c             | C               |
           +--------------+-----------------+-----------------+
           | 13           | D d             | D               |
           +--------------+-----------------+-----------------+
           | 14           | E e             | E               |
           +--------------+-----------------+-----------------+
           | 15           | F f             | F               |
           +--------------+-----------------+-----------------+
           | 16           | G g             | G               |
           +--------------+-----------------+-----------------+
           | 17           | H h             | H               |
           +--------------+-----------------+-----------------+
           | 18           | J j             | J               |
           +--------------+-----------------+-----------------+
           | 19           | K k             | K               |
           +--------------+-----------------+-----------------+
           | 20           | M m             | M               |
           +--------------+-----------------+-----------------+
           | 21           | N n             | N               |
           +--------------+-----------------+-----------------+
           | 22           | P p             | P               |
           +--------------+-----------------+-----------------+
           | 23           | Q q             | Q               |
           +--------------+-----------------+-----------------+
           | 24           | R r             | R               |
           +--------------+-----------------+-----------------+
           | 25           | S s             | S               |
           +--------------+-----------------+-----------------+
           | 26           | T t             | T               |
           +--------------+-----------------+-----------------+
           | 27           | V v U u         | V               |
           +--------------+-----------------+-----------------+
           | 28           | W w             | W               |
           +--------------+-----------------+-----------------+
           | 29           | X x             | X               |
           +--------------+-----------------+-----------------+
           | 30           | Y y             | Y               |
           +--------------+-----------------+-----------------+
           | 31           | Z z             | Z               |
           +--------------+-----------------+-----------------+

Table 4: The Base32GNS Alphabet, Including the Additional Encoding Symbol "U"


Appendix D. Test Vectors ๐Ÿง

these test vectors are your conformance checklist, bestie โœ… implementations can use them to check themselves. unless it says otherwise, the vectors are hexadecimal byte arrays.

D.1. Base32GNS Encoding/Decoding

these are the Base32GNS test vectors for the encoding used by zTLDs. the input strings get encoded without the zero terminator ๐ŸŒˆ

Base32GNS-Encode:
  Input string: "Hello World"
  Output string: "91JPRV3F41BPYWKCCG"

  Input bytes: 474e55204e616d652053797374656d
  Output string: "8X75A82EC5PPA82KF5SQ8SBD"

Base32GNS-Decode:
  Input string: "91JPRV3F41BPYWKCCG"
  Output string: "Hello World"

  Input string: "91JPRU3F41BPYWKCCG"
  Output string: "Hello World"

D.2. Record Sets ๐Ÿ’œ

these vectors cover record sets with a bunch of record types and flags, for both PKEY and EDKEY zones. they even include labels with UTF-8 characters, so the internationalized labels get a moment to shine โœจ

(1) PKEY zone with ASCII label and one delegation record

Zone private key (d, big-endian):
  50 d7 b6 52 a4 ef ea df
  f3 73 96 90 97 85 e5 95
  21 71 a0 21 78 c8 e7 d4
  50 fa 90 79 25 fa fd 98

Zone identifier (ztype|zkey):
  00 01 00 00 67 7c 47 7d
  2d 93 09 7c 85 b1 95 c6
  f9 6d 84 ff 61 f5 98 2c
  2c 4f e0 2d 5a 11 fe df
  b0 c2 90 1f

zTLD:
000G0037FH3QTBCK15Y8BCCNRVWPV17ZC7TSGB1C9ZG2TPGHZVFV1GMG3W

Label:
  74 65 73 74 64 65 6c 65
  67 61 74 69 6f 6e

Number of records (integer): 1

Record #0 := (
  EXPIRATION: 8143584694000000 us
  00 1c ee 8c 10 e2 59 80

  DATA_SIZE:
  00 20

  TYPE:
  00 01 00 00

  FLAGS:   00 01

  DATA:
  21 e3 b3 0f f9 3b c6 d3
  5a c8 c6 e0 e1 3a fd ff
  79 4c b7 b4 4b bb c7 48
  d2 59 d0 a0 28 4d be 84

)

RDATA:
  00 1c ee 8c 10 e2 59 80
  00 20 00 01 00 01 00 00
  21 e3 b3 0f f9 3b c6 d3
  5a c8 c6 e0 e1 3a fd ff
  79 4c b7 b4 4b bb c7 48
  d2 59 d0 a0 28 4d be 84

Okay bestie, the hex is about to get very intense ๐Ÿฆ‹ Buckle up and let the bytes cook ๐Ÿ’…

Encryption NONCE|EXPIRATION|BLOCK COUNTER:
  e9 0a 00 61 00 1c ee 8c
  10 e2 59 80 00 00 00 01

Encryption key (K):
  86 4e 71 38 ea e7 fd 91
  a3 01 36 89 9c 13 2b 23
  ac eb db 2c ef 43 cb 19
  f6 bf 55 b6 7d b9 b3 b3

Storage key (q):
  4a dc 67 c5 ec ee 9f 76
  98 6a bd 71 c2 22 4a 3d
  ce 2e 91 70 26 c9 a0 9d
  fd 44 ce f3 d2 0f 55 a2
  73 32 72 5a 6c 8a fb bb
  b0 f7 ec 9a f1 cc 42 64
  12 99 40 6b 04 fd 9b 5b
  57 91 f8 6c 4b 08 d5 f4

ZKDF(zkey, label):
  18 2b b6 36 ed a7 9f 79
  57 11 bc 27 08 ad bb 24
  2a 60 44 6a d3 c3 08 03
  12 1d 03 d3 48 b7 ce b6

Derived private key (d', big-endian):
  0a 4c 5e 0f 00 63 df ce
  db c8 c7 f2 b2 2c 03 0c
  86 28 b2 c2 cb ac 9f a7
  29 aa e6 1f 89 db 3e 9c

BDATA:
  0c 1e da 5c c0 94 a1 c7
  a8 88 64 9d 25 fa ee bd
  60 da e6 07 3d 57 d8 ae
  8d 45 5f 4f 13 92 c0 74
  e2 6a c6 69 bd ee c2 34
  62 b9 62 95 2c c6 e9 eb

RRBLOCK:
  00 00 00 a0 00 01 00 00
  18 2b b6 36 ed a7 9f 79
  57 11 bc 27 08 ad bb 24
  2a 60 44 6a d3 c3 08 03
  12 1d 03 d3 48 b7 ce b6
  0a d1 0b c1 3b 40 3b 5b
  25 61 26 b2 14 5a 6f 60
  c5 14 f9 51 ff a7 66 f7
  a3 fd 4b ac 4a 4e 19 90
  05 5c b8 7e 8d 1b fd 19
  aa 09 a4 29 f7 29 e9 f5
  c6 ee c2 47 0a ce e2 22
  07 59 e9 e3 6c 88 6f 35
  00 1c ee 8c 10 e2 59 80
  0c 1e da 5c c0 94 a1 c7
  a8 88 64 9d 25 fa ee bd
  60 da e6 07 3d 57 d8 ae
  8d 45 5f 4f 13 92 c0 74
  e2 6a c6 69 bd ee c2 34
  62 b9 62 95 2c c6 e9 eb

(2) PKEY zone with UTF-8 label and three records ๐ŸŒˆ

Zone private key (d, big-endian):
  50 d7 b6 52 a4 ef ea df
  f3 73 96 90 97 85 e5 95
  21 71 a0 21 78 c8 e7 d4
  50 fa 90 79 25 fa fd 98

Zone identifier (ztype|zkey):
  00 01 00 00 67 7c 47 7d
  2d 93 09 7c 85 b1 95 c6
  f9 6d 84 ff 61 f5 98 2c
  2c 4f e0 2d 5a 11 fe df
  b0 c2 90 1f

zTLD:
000G0037FH3QTBCK15Y8BCCNRVWPV17ZC7TSGB1C9ZG2TPGHZVFV1GMG3W

Label:
  e5 a4 a9 e4 b8 8b e7 84
  a1 e6 95 b5

Number of records (integer): 3

Record #0 := (
  EXPIRATION: 8143584694000000 us
  00 1c ee 8c 10 e2 59 80

  DATA_SIZE:
  00 10

  TYPE:
  00 00 00 1c

  FLAGS:   00 00

  DATA:
  00 00 00 00 00 00 00 00
  00 00 00 00 de ad be ef

)

Record #1 := (
  EXPIRATION: 17999736901000000 us
  00 3f f2 aa 54 08 db 40

  DATA_SIZE:
  00 06

  TYPE:
  00 01 00 01

  FLAGS:   00 00

  DATA:
  e6 84 9b e7 a7 b0

)

Record #2 := (
  EXPIRATION: 11464693629000000 us
  00 28 bb 13 ff 37 19 40

  DATA_SIZE:
  00 0b

  TYPE:
  00 00 00 10

  FLAGS:   00 04

  DATA:
  48 65 6c 6c 6f 20 57 6f
  72 6c 64

)

RDATA:
  00 1c ee 8c 10 e2 59 80
  00 10 00 00 00 00 00 1c
  00 00 00 00 00 00 00 00
  00 00 00 00 de ad be ef
  00 3f f2 aa 54 08 db 40
  00 06 00 00 00 01 00 01
  e6 84 9b e7 a7 b0 00 28
  bb 13 ff 37 19 40 00 0b
  00 04 00 00 00 10 48 65
  6c 6c 6f 20 57 6f 72 6c
  64 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00

Encryption NONCE|EXPIRATION|BLOCK COUNTER:
  ee 96 33 c1 00 1c ee 8c
  10 e2 59 80 00 00 00 01

Encryption key (K):
  fb 3a b5 de 23 bd da e1
  99 7a af 7b 92 c2 d2 71
  51 40 8b 77 af 7a 41 ac
  79 05 7c 4d f5 38 3d 01

Storage key (q):
  af f0 ad 6a 44 09 73 68
  42 9a c4 76 df a1 f3 4b
  ee 4c 36 e7 47 6d 07 aa
  64 63 ff 20 91 5b 10 05
  c0 99 1d ef 91 fc 3e 10
  90 9f 87 02 c0 be 40 43
  67 78 c7 11 f2 ca 47 d5
  5c f0 b5 4d 23 5d a9 77

ZKDF(zkey, label):
  a5 12 96 df 75 7e e2 75
  ca 11 8d 4f 07 fa 7a ae
  55 08 bc f5 12 aa 41 12
  14 29 d4 a0 de 9d 05 7e

Derived private key (d', big-endian):
  0a be 56 d6 80 68 ab 40
  e1 44 79 0c de 9a cf 4d
  78 7f 2d 3c 63 b8 53 05
  74 6e 68 03 32 15 f2 ab

BDATA:
  d8 c2 8d 2f d6 96 7d 1a
  b7 22 53 f2 10 98 b8 14
  a4 10 be 1f 59 98 de 03
  f5 8f 7e 7c db 7f 08 a6
  16 51 be 4d 0b 6f 8a 61
  df 15 30 44 0b d7 47 dc
  f0 d7 10 4f 6b 8d 24 c2
  ac 9b c1 3d 9c 6f e8 29
  05 25 d2 a6 d0 f8 84 42
  67 a1 57 0e 8e 29 4d c9
  3a 31 9f cf c0 3e a2 70
  17 d6 fd a3 47 b4 a7 94
  97 d7 f6 b1 42 2d 4e dd
  82 1c 19 93 4e 96 c1 aa
  87 76 57 25 d4 94 c7 64
  b1 55 dc 6d 13 26 91 74

RRBLOCK:
  00 00 00 f0 00 01 00 00
  a5 12 96 df 75 7e e2 75
  ca 11 8d 4f 07 fa 7a ae
  55 08 bc f5 12 aa 41 12
  14 29 d4 a0 de 9d 05 7e
  08 5b d6 5f d4 85 10 51
  ba ce 2a 45 2a fc 8a 7e
  4f 6b 2c 1f 74 f0 20 35
  d9 64 1a cd ba a4 66 e0
  00 ce d6 f2 d2 3b 63 1c
  8e 8a 0b 38 e2 ba e7 9a
  22 ca d8 1d 4c 50 d2 25
  35 8e bc 17 ac 0f 89 9e
  00 1c ee 8c 10 e2 59 80
  d8 c2 8d 2f d6 96 7d 1a
  b7 22 53 f2 10 98 b8 14
  a4 10 be 1f 59 98 de 03
  f5 8f 7e 7c db 7f 08 a6
  16 51 be 4d 0b 6f 8a 61
  df 15 30 44 0b d7 47 dc
  f0 d7 10 4f 6b 8d 24 c2
  ac 9b c1 3d 9c 6f e8 29
  05 25 d2 a6 d0 f8 84 42
  67 a1 57 0e 8e 29 4d c9
  3a 31 9f cf c0 3e a2 70
  17 d6 fd a3 47 b4 a7 94
  97 d7 f6 b1 42 2d 4e dd
  82 1c 19 93 4e 96 c1 aa
  87 76 57 25 d4 94 c7 64
  b1 55 dc 6d 13 26 91 74

(3) EDKEY zone with ASCII label and one delegation record ๐Ÿงš

Zone private key (d):
  5a f7 02 0e e1 91 60 32
  88 32 35 2b bc 6a 68 a8
  d7 1a 7c be 1b 92 99 69
  a7 c6 6d 41 5a 0d 8f 65

Zone identifier (ztype|zkey):
  00 01 00 14 3c f4 b9 24
  03 20 22 f0 dc 50 58 14
  53 b8 5d 93 b0 47 b6 3d
  44 6c 58 45 cb 48 44 5d
  db 96 68 8f

zTLD:
000G051WYJWJ80S04BRDRM2R2H9VGQCKP13VCFA4DHC4BJT88HEXQ5K8HW

Label:
  74 65 73 74 64 65 6c 65
  67 61 74 69 6f 6e

Number of records (integer): 1

Record #0 := (
  EXPIRATION: 8143584694000000 us
  00 1c ee 8c 10 e2 59 80

  DATA_SIZE:
  00 20

  TYPE:
  00 01 00 00

  FLAGS:   00 01

  DATA:
  21 e3 b3 0f f9 3b c6 d3
  5a c8 c6 e0 e1 3a fd ff
  79 4c b7 b4 4b bb c7 48
  d2 59 d0 a0 28 4d be 84

)

RDATA:
  00 1c ee 8c 10 e2 59 80
  00 20 00 01 00 01 00 00
  21 e3 b3 0f f9 3b c6 d3
  5a c8 c6 e0 e1 3a fd ff
  79 4c b7 b4 4b bb c7 48
  d2 59 d0 a0 28 4d be 84

Encryption NONCE|EXPIRATION:
  98 13 2e a8 68 59 d3 5c
  88 bf d3 17 fa 99 1b cb
  00 1c ee 8c 10 e2 59 80

Encryption key (K):
  85 c4 29 a9 56 7a a6 33
  41 1a 96 91 e9 09 4c 45
  28 16 72 be 58 60 34 aa
  e4 a2 a2 cc 71 61 59 e2

Storage key (q):
  ab aa ba c0 e1 24 94 59
  75 98 83 95 aa c0 24 1e
  55 59 c4 1c 40 74 e2 55
  7b 9f e6 d1 54 b6 14 fb
  cd d4 7f c7 f5 1d 78 6d
  c2 e0 b1 ec e7 60 37 c0
  a1 57 8c 38 4e c6 1d 44
  56 36 a9 4e 88 03 29 e9

ZKDF(zkey, label):
  9b f2 33 19 8c 6d 53 bb
  db ac 49 5c ab d9 10 49
  a6 84 af 3f 40 51 ba ca
  b0 dc f2 1c 8c f2 7a 1a

nonce := SHA-256(dh[32..63] || h):
  14 f2 c0 6b ed c3 aa 2d
  f0 71 13 9c 50 39 34 f3
  4b fa 63 11 a8 52 f2 11
  f7 3a df 2e 07 61 ec 35

Derived private key (d', big-endian):
  3b 1b 29 d4 23 0b 10 a8
  ec 4d a3 c8 6e db 88 ea
  cd 54 08 5c 1d db 63 f7
  a9 d7 3f 7c cb 2f c3 98

BDATA:
  57 7c c6 c9 5a 14 e7 04
  09 f2 0b 01 67 e6 36 d0
  10 80 7c 4f 00 37 2d 69
  8c 82 6b d9 2b c2 2b d6
  bb 45 e5 27 7c 01 88 1d
  6a 43 60 68 e4 dd f1 c6
  b7 d1 41 6f af a6 69 7c
  25 ed d9 ea e9 91 67 c3

RRBLOCK:
  00 00 00 b0 00 01 00 14
  9b f2 33 19 8c 6d 53 bb
  db ac 49 5c ab d9 10 49
  a6 84 af 3f 40 51 ba ca
  b0 dc f2 1c 8c f2 7a 1a
  9f 56 a8 86 ea 73 9d 59
  17 50 8f 9b 75 56 39 f3
  a9 ac fa ed ed ca 7f bf
  a7 94 b1 92 e0 8b f9 ed
  4c 7e c8 59 4c 9f 7b 4e
  19 77 4f f8 38 ec 38 7a
  8f 34 23 da ac 44 9f 59
  db 4e 83 94 3f 90 72 00
  00 1c ee 8c 10 e2 59 80
  57 7c c6 c9 5a 14 e7 04
  09 f2 0b 01 67 e6 36 d0
  10 80 7c 4f 00 37 2d 69
  8c 82 6b d9 2b c2 2b d6
  bb 45 e5 27 7c 01 88 1d
  6a 43 60 68 e4 dd f1 c6
  b7 d1 41 6f af a6 69 7c
  25 ed d9 ea e9 91 67 c3

(4) EDKEY zone with UTF-8 label and three records ๐Ÿ’œ

Zone private key (d):
  5a f7 02 0e e1 91 60 32
  88 32 35 2b bc 6a 68 a8
  d7 1a 7c be 1b 92 99 69
  a7 c6 6d 41 5a 0d 8f 65

Zone identifier (ztype|zkey):
  00 01 00 14 3c f4 b9 24
  03 20 22 f0 dc 50 58 14
  53 b8 5d 93 b0 47 b6 3d
  44 6c 58 45 cb 48 44 5d
  db 96 68 8f

zTLD:
000G051WYJWJ80S04BRDRM2R2H9VGQCKP13VCFA4DHC4BJT88HEXQ5K8HW

Label:
  e5 a4 a9 e4 b8 8b e7 84
  a1 e6 95 b5

Number of records (integer): 3

Record #0 := (
  EXPIRATION: 8143584694000000 us
  00 1c ee 8c 10 e2 59 80

  DATA_SIZE:
  00 10

  TYPE:
  00 00 00 1c

  FLAGS:   00 00

  DATA:
  00 00 00 00 00 00 00 00
  00 00 00 00 de ad be ef

)

Record #1 := (
  EXPIRATION: 17999736901000000 us
  00 3f f2 aa 54 08 db 40

  DATA_SIZE:
  00 06

  TYPE:
  00 01 00 01

  FLAGS:   00 00

  DATA:
  e6 84 9b e7 a7 b0

)

Record #2 := (
  EXPIRATION: 11464693629000000 us
  00 28 bb 13 ff 37 19 40

  DATA_SIZE:
  00 0b

  TYPE:
  00 00 00 10

  FLAGS:   00 04

  DATA:
  48 65 6c 6c 6f 20 57 6f
  72 6c 64

)

RDATA:
  00 1c ee 8c 10 e2 59 80
  00 10 00 00 00 00 00 1c
  00 00 00 00 00 00 00 00
  00 00 00 00 de ad be ef
  00 3f f2 aa 54 08 db 40
  00 06 00 00 00 01 00 01
  e6 84 9b e7 a7 b0 00 28
  bb 13 ff 37 19 40 00 0b
  00 04 00 00 00 10 48 65
  6c 6c 6f 20 57 6f 72 6c
  64 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00
  00 00 00 00 00 00 00 00

Encryption NONCE|EXPIRATION:
  bb 0d 3f 0f bd 22 42 77
  50 da 5d 69 12 16 e6 c9
  00 1c ee 8c 10 e2 59 80

Encryption key (K):
  3d f8 05 bd 66 87 aa 14
  20 96 28 c2 44 b1 11 91
  88 c3 92 56 37 a4 1e 5d
  76 49 6c 29 45 dc 37 7b

Storage key (q):
  ba f8 21 77 ee c0 81 e0
  74 a7 da 47 ff c6 48 77
  58 fb 0d f0 1a 6c 7f bb
  52 fc 8a 31 be f0 29 af
  74 aa 0d c1 5a b8 e2 fa
  7a 54 b4 f5 f6 37 f6 15
  8f a7 f0 3c 3f ce be 78
  d3 f9 d6 40 aa c0 d1 ed

ZKDF(zkey, label):
  74 f9 00 68 f1 67 69 53
  52 a8 a6 c2 eb 98 48 98
  c5 3a cc a0 98 04 70 c6
  c8 12 64 cb dd 78 ad 11

nonce := SHA-256(dh[32..63] || h):
  f8 6a b5 33 8a 74 d7 a1
  d2 77 ea 11 ff 95 cb e8
  3a cf d3 97 3b b4 ab ca
  0a 1b 60 62 c3 7a b3 9c

Derived private key (d', big-endian):
  17 c0 68 a6 c3 f7 20 de
  0e 1b 69 ff 3f 53 e0 5d
  3f e5 c5 b0 51 25 7a 89
  a6 3c 1a d3 5a c4 35 58

BDATA:
  4e b3 5a 50 d4 0f e1 a4
  29 c7 f4 b2 67 a0 59 de
  4e 2c 8a 89 a5 ed 53 d3
  d4 92 58 59 d2 94 9f 7f
  30 d8 a2 0c aa 96 f8 81
  45 05 2d 1c da 04 12 49
  8f f2 5f f2 81 6e f0 ce
  61 fe 69 9b fa c7 2c 15
  dc 83 0e a9 b0 36 17 1c
  cf ca bb dd a8 de 3c 86
  ed e2 95 70 d0 17 4b 82
  82 09 48 a9 28 b7 f0 0e
  fb 40 1c 10 fe 80 bb bb
  02 76 33 1b f7 f5 1b 8d
  74 57 9c 14 14 f2 2d 50
  1a d2 5a e2 49 f5 bb f2
  a6 c3 72 59 d1 75 e4 40
  b2 94 39 c6 05 19 cb b1

RRBLOCK:

  00 00 01 00 00 01 00 14
  74 f9 00 68 f1 67 69 53
  52 a8 a6 c2 eb 98 48 98
  c5 3a cc a0 98 04 70 c6
  c8 12 64 cb dd 78 ad 11
  75 6d 2c 15 7a d2 ea 4f
  c0 b1 b9 1c 08 03 79 44
  61 d3 de f2 0d d1 63 6c
  fe dc 03 89 c5 49 d1 43
  6c c3 5b 4e 1b f8 89 5a
  64 6b d9 a6 f4 6b 83 48
  1d 9c 0e 91 d4 e1 be bb
  6a 83 52 6f b7 25 2a 06
  00 1c ee 8c 10 e2 59 80
  4e b3 5a 50 d4 0f e1 a4
  29 c7 f4 b2 67 a0 59 de
  4e 2c 8a 89 a5 ed 53 d3
  d4 92 58 59 d2 94 9f 7f
  30 d8 a2 0c aa 96 f8 81
  45 05 2d 1c da 04 12 49
  8f f2 5f f2 81 6e f0 ce
  61 fe 69 9b fa c7 2c 15
  dc 83 0e a9 b0 36 17 1c
  cf ca bb dd a8 de 3c 86
  ed e2 95 70 d0 17 4b 82
  82 09 48 a9 28 b7 f0 0e
  fb 40 1c 10 fe 80 bb bb
  02 76 33 1b f7 f5 1b 8d
  74 57 9c 14 14 f2 2d 50
  1a d2 5a e2 49 f5 bb f2
  a6 c3 72 59 d1 75 e4 40
  b2 94 39 c6 05 19 cb b1

D.3. Zone Revocation ๐Ÿฆ‹

okay so here's an example revocation for a PKEY zone ๐Ÿ’…โœจ

Zone private key (d, big-endian):

  6f ea 32 c0 5a f5 8b fa
  97 95 53 d1 88 60 5f d5
  7d 8b f9 cc 26 3b 78 d5
  f7 47 8c 07 b9 98 ed 70

Zone identifier (ztype|zkey):

  00 01 00 00 2c a2 23 e8
  79 ec c4 bb de b5 da 17
  31 92 81 d6 3b 2e 3b 69
  55 f1 c3 77 5c 80 4a 98
  d5 f8 dd aa

zTLD: 000G001CM8HYGYFCRJXXXDET2WRS50EP7CQ3PTANY71QEQ409ACDBY6XN8 ๐ŸŽ€

Difficulty (5 base difficulty + 2 epochs): 7

Signed message:

  00 00 00 34 00 00 00 03
  00 05 ff 1c 56 e4 b2 68
  00 01 00 00 2c a2 23 e8
  79 ec c4 bb de b5 da 17
  31 92 81 d6 3b 2e 3b 69
  55 f1 c3 77 5c 80 4a 98
  d5 f8 dd aa

Proof:

  00 05 ff 1c 56 e4 b2 68
  00 00 39 5d 18 27 c0 00
  38 0b 54 aa 70 16 ac a2
  38 0b 54 aa 70 16 ad 62
  38 0b 54 aa 70 16 af 3e
  38 0b 54 aa 70 16 af 93
  38 0b 54 aa 70 16 b0 bf
  38 0b 54 aa 70 16 b0 ee
  38 0b 54 aa 70 16 b1 c9
  38 0b 54 aa 70 16 b1 e5
  38 0b 54 aa 70 16 b2 78
  38 0b 54 aa 70 16 b2 b2
  38 0b 54 aa 70 16 b2 d6
  38 0b 54 aa 70 16 b2 e4
  38 0b 54 aa 70 16 b3 2c
  38 0b 54 aa 70 16 b3 5a
  38 0b 54 aa 70 16 b3 9d
  38 0b 54 aa 70 16 b3 c0
  38 0b 54 aa 70 16 b3 dd
  38 0b 54 aa 70 16 b3 f4
  38 0b 54 aa 70 16 b4 42
  38 0b 54 aa 70 16 b4 76
  38 0b 54 aa 70 16 b4 8c
  38 0b 54 aa 70 16 b4 a4
  38 0b 54 aa 70 16 b4 c9
  38 0b 54 aa 70 16 b4 f0
  38 0b 54 aa 70 16 b4 f7
  38 0b 54 aa 70 16 b5 79
  38 0b 54 aa 70 16 b6 34
  38 0b 54 aa 70 16 b6 8e
  38 0b 54 aa 70 16 b7 b4
  38 0b 54 aa 70 16 b8 7e
  38 0b 54 aa 70 16 b8 f8
  38 0b 54 aa 70 16 b9 2a
  00 01 00 00 2c a2 23 e8
  79 ec c4 bb de b5 da 17
  31 92 81 d6 3b 2e 3b 69
  55 f1 c3 77 5c 80 4a 98
  d5 f8 dd aa 08 ca ff de
  3c 6d f1 45 f7 e0 79 81
  15 37 b2 b0 42 2d 5e 1f
  b2 01 97 81 ec a2 61 d1
  f9 d8 ea 81 0a bc 2f 33
  47 7f 04 e3 64 81 11 be
  71 c2 48 82 1a d6 04 f4
  94 e7 4d 0b f5 11 d2 c1
  62 77 2e 81

and now the EDKEY one, same energy but a different zone type ๐ŸŒˆโœจ

Zone private key (d):

  5a f7 02 0e e1 91 60 32
  88 32 35 2b bc 6a 68 a8
  d7 1a 7c be 1b 92 99 69
  a7 c6 6d 41 5a 0d 8f 65

Zone identifier (ztype|zkey):

  00 01 00 14 3c f4 b9 24
  03 20 22 f0 dc 50 58 14
  53 b8 5d 93 b0 47 b6 3d
  44 6c 58 45 cb 48 44 5d
  db 96 68 8f

zTLD: 000G051WYJWJ80S04BRDRM2R2H9VGQCKP13VCFA4DHC4BJT88HEXQ5K8HW ๐Ÿงš

Difficulty (5 base difficulty + 2 epochs): 7

Signed message:

  00 00 00 34 00 00 00 03
  00 05 ff 1c 57 35 42 bd
  00 01 00 14 3c f4 b9 24
  03 20 22 f0 dc 50 58 14
  53 b8 5d 93 b0 47 b6 3d
  44 6c 58 45 cb 48 44 5d
  db 96 68 8f

Proof:

  00 05 ff 1c 57 35 42 bd
  00 00 39 5d 18 27 c0 00
  58 4c 93 3c b0 99 2a 08
  58 4c 93 3c b0 99 2d f7
  58 4c 93 3c b0 99 2e 21
  58 4c 93 3c b0 99 2e 2a
  58 4c 93 3c b0 99 2e 53
  58 4c 93 3c b0 99 2e 8e
  58 4c 93 3c b0 99 2f 13
  58 4c 93 3c b0 99 2f 2d
  58 4c 93 3c b0 99 2f 3c
  58 4c 93 3c b0 99 2f 41
  58 4c 93 3c b0 99 2f fd
  58 4c 93 3c b0 99 30 33
  58 4c 93 3c b0 99 30 82
  58 4c 93 3c b0 99 30 a2
  58 4c 93 3c b0 99 30 e1
  58 4c 93 3c b0 99 31 ce
  58 4c 93 3c b0 99 31 de
  58 4c 93 3c b0 99 32 12
  58 4c 93 3c b0 99 32 4e
  58 4c 93 3c b0 99 32 9f
  58 4c 93 3c b0 99 33 31
  58 4c 93 3c b0 99 33 87
  58 4c 93 3c b0 99 33 8c
  58 4c 93 3c b0 99 33 e5
  58 4c 93 3c b0 99 33 f3
  58 4c 93 3c b0 99 34 26
  58 4c 93 3c b0 99 34 30
  58 4c 93 3c b0 99 34 68
  58 4c 93 3c b0 99 34 88
  58 4c 93 3c b0 99 34 8a
  58 4c 93 3c b0 99 35 4c
  58 4c 93 3c b0 99 35 bd
  00 01 00 14 3c f4 b9 24
  03 20 22 f0 dc 50 58 14
  53 b8 5d 93 b0 47 b6 3d
  44 6c 58 45 cb 48 44 5d
  db 96 68 8f 04 ae 26 f7
  63 56 5a b7 aa ab 01 71
  72 4f 3c a8 bc c5 1a 98
  b7 d4 c9 2e a3 3c d9 34
  4c a8 b6 3e 04 53 3a bf
  1a 3c 05 49 16 b3 68 2c
  5c a8 cb 4d d0 f8 4c 3b
  77 48 7a ac 6e ce 38 48
  0b a9 d5 00

Acknowledgements

the authors wanna thank everyone who reviewed this ๐Ÿซถ for real, the reviews were so detailed and so smart. special shoutouts to D. J. Bernstein, S. Bortzmeyer, A. Farrel, E. Lear, and R. Salz for their insightful and detailed technical reviews ๐Ÿ”ฅ. thank you also to J. Yao and J. Klensin for the internationalization reviews ๐ŸŒธ. thanks to Dr. J. Appelbaum for suggesting the name "GNU Name System" ๐Ÿ‘‘, and to Dr. Richard Stallman for approving its use ๐Ÿ’œ. T. Lange and M. Wachs get a big thank you for their earlier contributions to the design and implementation of GNS โœจ. and finally, NLnet and NGI DISCOVERY for funding work on the GNU Name System, you're literally the best ๐Ÿฆ‹

Authors' Addresses

Martin Schanzenbach ๐Ÿ’– Fraunhofer AISEC Lichtenbergstrasse 11 85748 Garching Germany Email: martin.schanzenbach@aisec.fraunhofer.de

Christian Grothoff ๐Ÿงš Berner Fachhochschule Hoeheweg 80 CH-2501 Biel/Bienne Switzerland Email: christian.grothoff@bfh.ch

Bernd Fix ๐Ÿ“ GNUnet e.V. Boltzmannstrasse 3 85748 Garching Germany Email: fix@gnunet.org

๐Ÿ“ฆ where this page comes from