§ The DID DHT Method Specification 1.0

Specification Status: Implementer’s Draft

Latest Draft: https://did-dht.com

Registry: https://did-dht.com/registry

Draft Created: October 20, 2023

Last Updated: July 25, 2024

Editors:
Gabe Cohen
Daniel Buchner
Contributors:
Moe Jangda
Frank Hinek
Henry Tsai
Kendall Weihe
Participate:
GitHub repo
File a bug
Commit history

§ Abstract

A DID Method [DID-CORE] based on DNS Resource Records and Mainline DHT, identified by the prefix did:dht.

DID DHT
DNS RRs
Mainline DHT

DID DHT makes use of Mainline DHT, specifically BEP44 to store signed mutable records. This DID method uses DNS Resource Records to efficiently represent DID Documents.

Mainline is in use for the following reasons:

  1. It has a proven track record of 15 years.
  2. It is the biggest DHT in existence with an estimated 10 million servers.
  3. It retains data for multiple hours at no cost.
  4. It has been implemented in most languages and is stable.

The syntax of the identifier and accompanying data model used by the protocol is conformant with the [DID-CORE] specification and shall be registered with the [DID-SPEC-REGISTRIES].

§ Conformance

The keywords MAY, MUST, MUST NOT, RECOMMENDED, SHOULD, and SHOULD NOT 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.

§ Terminology

Decentralized Identifier
A W3C specification describing an identifier that enables verifiable, decentralized digital identity. A DID identifier is associated with a JSON document containing cryptographic keys, services, and other properties outlined in the specification.
DID Suffix
The unique identifier string within a DID URI (e.g., the part after did:dht:). For DID DHT the suffix is the z-base-32 encoded public key portion of the Identity Key.
Identity Key Pair
An Identity Key Pair is an Ed25519 key pair required to authenticate all records in Mainline DHT. The public key portion is encoded using z-base-32 and represented in the DID Suffix. The public key, also known as the Identity Key is guaranteed to be present in each did:dht document.
DNS Resource Records
An efficient format for representing DID Documents and providing semantics pertinent to DID DHT, such as TTLs, caching, and different record types (e.g., NS, TXT). Follows [RFC1035].
Mainline DHT
Mainline DHT is the name given to the Distributed Hash Table used by the BitTorrent protocol. It is a distributed system for storing and finding data on a peer-to-peer network. It is based on Kademlia and is primarily used to store and retrieve peer data. It is estimated to have tens of millions of concurrent active users consistently.
Gateway
A server that that facilitates Mainline and DID DHT operations. The gateway may offer a set of APIs to interact with the DID DHT method features such as providing guaranteed retention, historical resolution, and other features. Gateways can make themselves discoverable via a Gateway Registry.
Gateway Registry
A system used to aid in the discovery of Gateways. One such system is the registry provided by this specification.
Republish
The action that keeps a record alive in Mainline, which offers a limited duration (approximately 2 hours) for retaining records in the DHT. See Republishing Data.
Client
A client is a piece of software that is responsible for generating a did:dht and submitting it to a Mainline Server or Gateway. Notably, a client has the ability to sign messages with the private-key portion of an Identity Key Pair.
Retained DID Set
The set of DIDs that a Gateway is retaining and thus is responsible for republishing. See Retained DID Set.
Retention Challenge
A Retention Challenge refers to a computational cost associated with a set of guarantees to be provided to a DID controller by a Gateway, who submits a corresponding Retention Solution. A solution provided by the DID controller to a Gateway which attests both that (1) they control the DID and (2) have done sufficient work to have a Gateway retain their DID for a set period of time as a part of its Retention Set.
Sequence Number
A sequence number, or seq, is a property of a mutable item as defined in BEP44. It is a 64-bit integer that increases in a consistent, unidirectional manner, ensuring that items are ordered sequentially. This specification requires that sequence numbers are Unix Timestamps represented in seconds.
Unix Timestamp
A value that measures time by the number of non-leap seconds that have elapsed since 00:00:00 UTC on 1 January 1970, the Unix epoch.

§ DID DHT Method Specification

§ Format

The format for did:dht conforms to the [DID-CORE] specification. It consists of the did:dht prefix followed by the Mainline identifier. The Mainline identifier is a z-base-32-encoded Ed25519 public key, which we refer to as an Identity Key.

did-dht-format := did:dht:<z-base-32-value>
z-base-32-value := [a-km-uw-z13-9]+

Alternatively, one can interpret the encoding rules as a series of transformation functions on the raw public key bytes:

did-dht-format := did:dht:Z-BASE-32(raw-public-key-bytes)

§ Identity Key Pair

A unique property of DID DHT is its dependence on a single non-rotatable key, which we refer to as an Identity Key Pair, whose public key is referred to as the Identity Key. This requirement stems from BEP44, particularly within the section on Mutable Items:

Mutable items can be updated, without changing their DHT keys. To authenticate that only the original publisher can update an item, it is signed by a private key generated by the original publisher. The target ID mutable items are stored under the SHA-1 hash of the public key (as it appears in the put message).

This mechanism, as detailed in BEP44, ensures that all entries in the DHT are authenticated through a private key unique to the initial publisher. Consequently, DHT records, including DID DHT Documents, are independently verifiable. This independence implies that trust in a specific Mainline or Gateway server for providing unaltered messages is unnecessary. Instead, all clients have the ability to verify messages themselves. This approach significantly mitigates risks associated with other DID methods, where a compromised server or DID resolver has the ability to tamper with a DID Document, in a manner that could be undetectable by a client.

At present, Mainline exclusively supports the Ed25519 signature system. In turn, Ed25519-based keys are required by DID DHT and used to uniquely identify DID DHT Documents. DID DHT identifiers are formed by concatenating the did:dht: prefix with a z-base-32 encoded public key (the Identity Key, which acts as its suffix. Identity Keys MUST have the identifier 0 as both its Verification Method id and JWK kid [RFC7517]. Identity Keys MUST have the Verification Relationships Authentication, Assertion, Capability Invocation, and Capability Delegation.

While DID DHT requires at least one Ed25519 key pair, a DID DHT Document can include any number of additional keys. Additional key types MUST be registered in the Key Type Index.

As a unique consequence of the requirement of the Identity Key, DID DHT Documents are able to be partially-resolved without contacting Mainline or Gateway servers, though it is RECOMMENDED that deterministic resolution is only used as a fallback mechanism. Similarly, the requirement of an Identity Key enables interoperability with other DID methods.

§ DIDs as DNS Records

In this scheme, we encode the DID Document as DNS Resource Records. These resource records make up a DNS packet [RFC1034] [RFC1035], which is then stored in the DHT encoded as a BEP44 payload.

Name Type TTL Rdata
_did.<ID>. TXT 7200 v=0;vm=k0,k1,k2;auth=k0;asm=k1;inv=k2;del=k2;svc=s0,s1,s2
_k0._did. TXT 7200 id=0;t=0;k=<unpadded-b64url>
_k1._did. TXT 7200 id=abcd;t=1;k=<unpadded-b64url>
_k2._did. TXT 7200 t=1;k=<unpadded-b64url>
_s0._did. TXT 7200 id=domain;t=LinkedDomains;se=https://foo.com
_s1._did. TXT 7200 id=dwn;t=DecentralizedWebNode;se=https://dwn.tbddev.org/dwn5
NOTE

The RECOMMENDED TTL value is 7200 seconds (2 hours), the default TTL for Mainline records.

§ Root Record

The root record is a special record which serves as instructions on how to reconstruct a DID Document, by providing a property mapping for a DID Document, along with containing pertinent metadata such as a version identifier.

Additionally:

Example Root Record:

Name Type TTL Rdata
_did.o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy. TXT 7200 v=0;vm=k0,k1,k2;auth=k0;asm=k1;inv=k2;del=k2;svc=s0,s1,s2

§ Property Mapping

The following section describes mapping a DID Document to a DNS packet’s rdata.

The subsequent instructions serve as a reference for mapping DID Document properties to DNS Resource Records:

§ Identifiers

§ Controller

A DID controller MAY be present in a did:dht document.

To ensure that the DID controller is authorized to make changes to the DID Document, the controller for the Identity Key Verification Method MUST be contained within the controller property.

Example Controller Record:

Name Type TTL Rdata
_cnt._did. TXT 7200 did:example:abcd
§ Also Known As

A did:dht document MAY have multiple identifiers using the alsoKnownAs property.

Example AKA Record:

Name Type TTL Rdata
_aka._did. TXT 7200 did:example:efgh,did:example:ijkl

§ Verification Methods

NOTE

Controllers are not cryptographically verified by Gateways or this DID method. This means any DID may choose to list a controller, even if there is no relationship between the identifiers. As such, DID controllers should be interrogated to assert the integrity of their relations.

§ Verification Relationships

The following table acts as a map between Verification Relationship types and their record name:

§ Verification Relationship Index
Verification Relationship Record Name
Authentication auth
Assertion asm
Key Agreement agm
Capability Invocation inv
Capability Delegation del

The record data is uniform across Verification Relationships, represented as a comma-separated list of key references.

Example Verification Relationship Records:

Verification Relationship Rdata in the Root Record
“authentication”: [“did:dht:example#0”, “did:dht:example#HTsY9aMkoDomPBhGcUxSOGP40F-W4Q9XCJV1ab8anTQ”] auth=0,HTsY9aMkoDomPBhGcUxSOGP40F-W4Q9XCJV1ab8anTQ
“assertionMethod”: [“did:dht:example#0”, “did:dht:example#HTsY9aMkoDomPBhGcUxSOGP40F-W4Q9XCJV1ab8anTQ”] asm=0,HTsY9aMkoDomPBhGcUxSOGP40F-W4Q9XCJV1ab8anTQ
“keyAgreement”: [“did:dht:example#1”] agm=1
“capabilityInvocation”: [“did:dht:example#0”] inv=0
“capabilityDelegation”: [“did:dht:example#0”] del=0

§ Services

Example Service Record:

Name Type TTL Rdata
_s0._did. TXT 7200 id=dwn;t=DecentralizedWebNode;se=https://example.com/dwn

Each Service is represented as part of the root record (_did.<ID>.) as a list under the key svc=<ids> where ids is a comma-separated list of all IDs for each Service.

§ Example

A sample transformation of a fully-featured DID Document to a DNS packet is exemplified as follows:

DID Document:

{
  "id": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y",
  "controller": "did:example:abcd",
  "alsoKnownAs": ["did:example:efgh", "did:example:ijkl"],
  "verificationMethod": [
    {
      "id": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#0",
      "type": "JsonWebKey",
      "controller": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y",
      "publicKeyJwk": {
        "kid": "0",
        "alg": "EdDSA",
        "crv": "Ed25519",
        "kty": "OKP",
        "x": "r96mnGNgWGOmjt6g_3_0nd4Kls5-kknrd4DdPW8qtfw"
      }
    },
    {
      "id": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#HTsY9aMkoDomPBhGcUxSOGP40F-W4Q9XCJV1ab8anTQ",
      "type": "JsonWebKey",
      "controller": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y",
      "publicKeyJwk": {
        "kid": "HTsY9aMkoDomPBhGcUxSOGP40F-W4Q9XCJV1ab8anTQ",
        "alg": "ES256K",
        "crv": "secp256k1",
        "kty": "EC",
        "x": "KI0DPvL5cGvznc8EDOAA5T9zQfLDQZvr0ev2NMLcxDw",
        "y": "0iSbXxZo0jIFLtW8vVnoWd8tEzUV2o22BVc_IjVTIt8"
      }
    }
  ],
  "authentication": [
    "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#0",
    "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#HTsY9aMkoDomPBhGcUxSOGP40F-W4Q9XCJV1ab8anTQ"
  ],
  "assertionMethod": [
    "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#0",
    "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#HTsY9aMkoDomPBhGcUxSOGP40F-W4Q9XCJV1ab8anTQ"
  ],
  "capabilityInvocation": [
    "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#0"
  ],
  "capabilityDelegation": [
    "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#0"
  ],
  "service": [
    {
      "id": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#dwn",
      "type": "DecentralizedWebNode",
      "serviceEndpoint": ["https://example.com/dwn1", "https://example/dwn2"]
    }
  ]
}

DNS Resource Records:

Name Type TTL Rdata
_did.<ID>. TXT 7200 v=0;vm=k0,k1;auth=k0,k1;asm=k0,k1;inv=k0;del=k0;svc=s0
_cnt._did. TXT 7200 did:example:abcd
_aka._did. TXT 7200 did:example:efgh,did:example:ijkl
_k0._did. TXT 7200 t=0;k=afdea69c63605863a68edea0ff7ff49dde0a96ce7e9249eb7780dd3d6f2ab5fc
_k1._did. TXT 7200 t=1;k=AyiNAz7y-XBr853PBAzgAOU_c0Hyw0Gb69Hr9jTC3MQ8
_s0._did. TXT 7200 id=dwn;t=DecentralizedWebNode;se=https://example.com/dwn1,https://example.com/dwn2

§ Operations

Entries to the DHT require a signed record as per BEP44. As such, the key pair used for the Mainline identifier is also used to sign the DHT record.

§ Create

To create a did:dht document, the process is as follows:

  1. Generate an Ed25519 key pair and encode the public key using the format provided in the format section.

  2. Construct a conformant JSON representation of a DID Document.

    a. The document MUST include a Verification Method with the Identity Key. The id property of this Verification Method MUST be 0 and the type of JsonWebKey as defined by VC-JOSE-COSE. The key MUST be represented as a publicKeyJwk as per [RFC7517] with a kid of 0.

    b. The Identity Key MUST have the Verification Relationships Authentication, Assertion, Capability Invocation, and Capability Delegation.

    c. The document can include any number of other core properties; always representing key material as a JWK as per [RFC7517]. In addition to the properties required by the JWK specification, the alg property MUST always be present in the DID Document representation. The indexed types registry defines default algorithm values per key type.

  3. Map the output DID Document to a DNS packet as outlined in property mapping.

  4. Compress the DNS packet as per [RFC1035] section 4.1.4.

  5. Construct a BEP44 conformant mutable put message.

    a. v MUST be set to a bencoded compressed DNS packet from the prior step.

    b. seq MUST be set to the current Unix Timestamp in seconds.

  6. Submit the result of to the DHT via a Mainline node, or a Gateway, with the identifier created in step 1.

NOTE

This specification does not make use of JSON-LD. As such, DID DHT Documents MUST NOT include the @context property.

§ Read

To read a did:dht document, the process is as follows:

  1. Take the suffix of the DID, that is, the z-base-32 encoded identifier key, and submit it to a Mainline node or a Gateway.

  2. Decode the resulting BEP44 response’s v value using bencode.

  3. Uncompress the DNS packet according to [RFC1035] section 4.1.4.

  4. Reverse the DNS property mapping process and re-construct a conformant DID Document.

    a. Identify the Identity Key using the suffix of the did:dht identifier, with record name _k0._did, and set it’s Verification Method ID and JWK kid to 0.

    b. For all other keys, assign the Verification Method ID as follows:

    i. If an id value is provided, use that value as the Verification Method ID and JWK kid.

    ii. If no id value is set, the JWK Thumbprint [RFC7638] is used as the Verification Method ID and JWK kid.

    c. Expand all identifiers (i.e. Verification Methods, Services, etc. ids ) to their fully-qualified form (e.g., did:dht:uodqi99wuzxsz6yx445zxkp8ddwj9q54ocbcg8yifsqru45x63kj#0 as opposed to 0 or #0, did:dht:uodqi99wuzxsz6yx445zxkp8ddwj9q54ocbcg8yifsqru45x63kj#service-1 as opposed to #service-1).

  5. If NS records are present this process should be repeated, making the initial request against the given Gateway. The document with the highest sequence number is to be treated as authoritative.

NOTE

As a fallback, if a did:dht value cannot be resolved via the network, it can be expanded to a conformant DID Document containing just the Identity Key.

§ Update

Any valid BEP44 record written to the DHT is an update. As long as control of the Identity Key is retained any update is made possible by signing and writing records with a unique incremental sequence number with mutable items.

It is RECOMMENDED that updates be infrequent — at least every 2 hours — as DHT caching is highly encouraged.

§ Deactivate

To deactivate a did:dht document controllers have multiple options:

  1. Let the DHT record expire and cease to publish it.

  2. Publish a new DHT record where the rdata of the root DNS record is the string deactivated.

Name Type TTL Rdata
_did.<ID>. TXT 7200 deactivated
NOTE

If you have published your DID through a Gateway, you can contact the operator to have them remove the record from their Retained DID Set via the DID Deactivation API.

§ Rotation

Verification Method Rotation is a recommended practice for avoiding the risks associated with key compromise. Rotating Verification Methods is straightforward using the update functionality enabled by this specification; however, rotation of the Identity Key is not possible given the constraints imposed by Mainline. To mitigate this limitation, DID DHT controllers have the option to rotate to a new DID, and thus a new Identity Key, while maintaining a cryptographic linkage between the two documents. This linkage can be useful in providing an auditable history of a controller’s activity as they move between root Verification Methods and identifiers.

To establish a cryptographic linkage between the old and new DID Documents, adhere to the following steps:

  1. Using the old Identity Key, sign over the new Identity Key using the Ed25519 variant of the EdDSA algorithm [RFC8032].

  2. Encode the resulting signature data using the unpadded base64URL [RFC4648] scheme.

  3. Set the resulting string as the data for a new DNS Resource Record, called a Previous record, in the new DID’s record set.

A did:dht Document MUST NOT have more than one Previous record. The Previous record is defined as follows:

Name Type TTL Rdata
_prv._did. TXT 7200 id=did:dht:pxoem5sfzxxxrnrwfgiu5i5wc7epouy1jk9zb7ad159dsxbxy8io;s=ol5LbUydL3_PdChE8tVYH-z_NhyFDQlop0agYtjyYbKz_-CYrj_3JGLiFne1e7PruOwf-b91uEFq9R_PgBn-Bg

The DID controller MAY include a statement in the old DID Document indicating the rotation to the new identifier by setting the controller property to the new DID. Without the previous record present in the new DID’s record set, the linkage MUST NOT be considered legitimate.

§ Designating Authoritative Gateways

Gateways provide additional benefits to did:dht, such as the ability to resolve historical DID Documents or support type indexing. To enable these additional features, did:dht documents need to be published to Gateway(s) that with the necessary capabilities. Whether it’s accessing historical states, engaging with type indexes, or utilizing other specialized features, the resolution process must be directed towards a Gateway that maintains this supplementary data.

To facilitate the discovery of authoritative Gateways for a did:dht and to ensure consistent access to a DID’s state across different Gateways, DID controllers may designate one or more Gateways as authoritative sources for their DID. This designation is accomplished by incorporating DNS NS records within the DNS packet destined for storage in the DHT. A DID MAY have multiple NS records, enhancing redundancy and reliability. The format for these records is outlined as follows:

Name Type TTL Rdata
_did.<ID>. NS 7200 gateway1.example-did-dht-gateway.com.
_did.<ID>. NS 7200 gateway2.example-did-dht-gateway.com.

§ Type Indexing

Type indexing is an optional feature that enables DIDs to become discoverable, by flagging themselves as being of a particular type. Types are not included as part of the DID Document, but rather as part of the DNS packet. This allows for DIDs to be indexed by type by Gateways, and for DIDs to be resolved by type.

DIDs can be indexed by type by adding a _typ._did. record to the DNS packet. A DID MAY have at most one type index record. This record is of the following format:

Example Type Index Record:

Name Type TTL Rdata
_typ._did. TXT 7200 id=0,1,2

Types can be discovered and registered in the indexed types registry.

NOTE

Identifying entities through type-based indexing is a relatively unreliable practice. It serves as an initial step in recognizing the identity linked to a DID. To validate identity assertions in a more robust manner, it is essential to delve deeper, employing tools like verifiable credentials and the interrogation of related data.

§ Gateways

Gateways serve as specialized servers, providing a range of DID-centric functionalities that extend beyond the capabilities of a standard Mainline DHT servers. This section elaborates on these unique features, outlines the operational prerequisites for managing a gateway, and discusses various other facets, including the optional integration of these gateways into a registry system.

NOTE

Gateways may choose to support interoperable methods in addition to did:dht as outlined in the section on interoperability.

§ Discovering Gateways

As an optional feature of the DID DHT Method, operators of a Gateway MAY choose to make their server discoverable through a Gateway Registry. This feature allows for easy location through various internet-based discovery mechanisms. Gateway Registries can vary in nature, encompassing a spectrum from centrally managed directories to diverse decentralized systems including databases, ledgers, or other structures.

As a convenience, one such registry is provided by this specification.

§ Retained DID Set

As a feature of the DID DHT Method, operators of a Gateway MUST support retaining DIDs for extended periods of time to reduce the burden on DID controllers and Clients in needing to republish their records to Mainline.

A Retained DID Set refers to the set of DIDs a Gateway retains and republishes to the DHT. This feature aims to safeguard equitable access to the resources of Gateways, which are publicly accessible and potentially subject to a high volume of requests. The Retained DID Set is facilitated by a Retention Challenge, which requires clients to generate a solution for the challenge — a Retention Solution — in order to have their write requests accepted. Retention Solutions act as proof of an amount of work completed in exchange for a retention guarantee provided by a Gateway (via the expiry property).

The Retained DID Set aims to provide a fair mechanism that provides numerous benefits for clients while giving Gateway operators anti-spam prevention, and control over the rate at which they accept new DIDs, thus enhancing the overall reliability and effectiveness of Gateways in managing DIDs.

§ Generating a Retention Solution

A Retention Solution is a form of proof of work bound to a specific DID identifier, using input values supplied by a given gateway. The proof of work is performed using the SHA-256 hashing algorithm over the concatenation of the did identifier and random nonce supplied by the user, and a hash value supplied by the gateway. The source of a given hash referred to as a hash_source MUST be one of the values specified in the Hash Source Registry. The result of a given proof of work attempt is referred to as the retention value.

The resulting retention value is determined to be a valid Retention Solution based on whether it has the requisite number of leading zeros defined by the difficulty. Difficulty values are supplied by the gateway, and MUST be no less than 26 bits of the 256-bit hash value.

The algorithm for generating a Retention Solution is as follows:

  1. Obtain a DID identifier and set it to DID.

  2. Get the difficulty and hash value from the server set to DIFFICULTY and HASH respectively.

  3. Generate a random 32-bit integer nonce value set to NONCE.

  4. Set RETENTION equal to the result of (DID + HASH + NONCE).

  5. Compute the SHA-256 hash over RETENTION where ATTEMPT = SHA256(RETENTION).

  6. Inspect the result of ATTEMPT, and ensure it has >= DIFFICULTY bits of leading zeroes.

    a. If it does, set RETENTION_SOLUTION = ATTEMPT.

    b. Otherwise, return to step 3.

  7. Set RETENTION_SOLUTION equal to the concatenation of ATTEMPT and NONCE separated by a colon (e.g., ATTEMPT:NONCE).

  8. Submit the RETENTION_SOLUTION to the Gateway API for write operations.

NOTE

When a Client submits a valid Retention Solution, conformant Gateways respond with an expiry timestamp. This timestamp indicates when DID will be evicted from the Gateway's Retained DID Set. Clients are advised to take note of this expiry timestamp and ensure they solve a new Retention Challenge before the expiration is reached. By doing so, Clients can maintain the continuity of their DID’s retention and prevent unintended eviction of their identifier.

§ Validating a Retention Solution

When a Gateway receives a Retention Solution as part of a write operation, it MUST validate the solution to ensure it meets the required criteria before accepting the write request and providing a retention guarantee.

The algorithm for validating a Retention Solution is as follows:

  1. Extract the RETENTION_SOLUTION value from the write request.

  2. Retrieve the DID identifier associated with the write request.

  3. Obtain the current HASH and DIFFICULTY values used by the Gateway.

  4. Construct the RETENTION_VALUE by concatenating the DID, HASH, and the NONCE (extracted from the RETENTION_SOLUTION).

  5. Compute the SHA-256 hash of the RETENTION_VALUE and set it to COMPUTED_HASH.

  6. Compare the COMPUTED_HASH with the RETENTION_SOLUTION:

a. If the COMPUTED_HASH matches the RETENTION_SOLUTION, proceed to step 7.

b. If the COMPUTED_HASH does not match the RETENTION_SOLUTION, the validation fails, and the write request is rejected.

  1. Check if the COMPUTED_HASH has the required number of leading zeros specified by the difficulty value:

a. If the COMPUTED_HASH has the required number of leading zeros, the Retention Solution is considered valid.

b. If the COMPUTED_HASH does not have the required number of leading zeros, the validation fails, and the write request is rejected.

If the Retention Solution is deemed valid, the Gateway accepts the write request and proceeds to store the DID document in its Retained DID Set. The Gateway generates an expiry timestamp based on its retention policy and includes it in the response to the Client.

By validating the Retention Solution, the Gateway ensures that the Client has performed the necessary proof of work and is eligible for the retention guarantee. This validation process helps maintain the integrity and fairness of the Retained DID Set system. It is important for Gateways to consistently apply the validation logic and reject any write requests that do not include a valid Retention Solution. Retention solutions help prevent abuse and ensures that only Clients who have invested the required computational effort can benefit from the retention feature. Gateways SHOULD regularly update their hash value to prevent pre-computation attacks and ensure the uniqueness and freshness of the Retention Solutions. The recommended hash refresh window is 10 minutes.

§ Managing the Retained DID Set

Gateways supporting Retention Set feature MUST provide an expiry value represented as a Unix Timestamp as a part of the Gateway API. This timestamp precisely indicates when the Gateway will cease republishing a particular DID, thus evicting the DID from the Gateway's Retained DID Set. This timestamp establishes a binding agreement between the Client and the Gateway, and it MUST NOT be modified once set.

Further, it is RECOMMENDED that Gateway's adhere to the following guidance:

§ Gateway API

A conformant Gateway MUST support the API defined in the following sections.

As a convenience, this API is made available via an OpenAPI document.

§ DHT

The DHT API, drawing inspiration from Pkarr, is built as an abstraction layer over Mainline DHT which enables the storage of DNS Resource Records within BEP44 payloads. It is important to exercise caution when utilizing the DHT API, as it does not offer any assurances regarding data retention.

For this API, Gateways will need to set up Cross-origin resource sharing (CORS) headers as follows:

§ Put

On receiving a PUT request the server verifiers the sig and submits a mutable put to Mainline as per BEP44.

§ Get

When it receives a GET request the server submits a mutable get query to Mainline as per BEP44.

§ Get the Current Challenge

Challenge is exposed as an endpoint to facilitate functionality pertaining to the Retained DID Set, surfacing a Retention Challenge.

Example Challenge Response:

{
  "hash": "000000000000000000022be0c55caae4152d023dd57e8d63dc1a55c1f6de46e7",
  "hash_source": "bitcoin",
  "difficulty": 26,
  "expiry": 1715578600
}

§ Register or Update a DID

Example DID Registration Request:

{
  "did": "did:dht:example",
  "sig": "<unpadded-base64URL-encoded-signature>",
  "seq": 1234,
  "v": "<unpadded-base64URL-encoded bencoded DNS packet>",
  "retention_solution": "000000270b7c547aff552f302aad08200b3db815b69bc11ec3f263b7ef755a52"
}

Upon receiving a request to register a DID the Gateway MUST perform the following steps:

NOTE

Requests without a retention_solution have no retention guarantees.

§ Resolving a DID

Example DID Resolution Response:

{
  "did": {
    "id": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y",
    "verificationMethod": [
      {
        "id": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#0",
        "type": "JsonWebKey",
        "controller": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y",
        "publicKeyJwk": {
          "kid": "0",
          "alg": "EdDSA",
          "crv": "Ed25519",
          "kty": "OKP",
          "x": "r96mnGNgWGOmjt6g_3_0nd4Kls5-kknrd4DdPW8qtfw"
        }
      }
    ],
    "authentication": [
      "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#0"
    ],
    "assertionMethod": [
      "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#0"
    ]
  },
  "dht": "<unpadded-base64URL-encoded BEP44 payload as [sig][seq][v]>",
  "types": [1, 4],
  "sequence_numbers": [1700356854, 1700461736],
  "expiry": 1715579444
}

Upon receiving a request to resolve a DID, the Gateway MUST perform the following steps:

NOTE

This API returns a dht property which matches the payload of a DHT GET Request, when encoded as an unpadded base64URL string. Implementers are RECOMMENDED to verify the integrity of the response using the dht data and reconstruct the DID Document themselves. The did property is provided as a utility which, without independent verification, MUST NOT be trusted.

§ Historical Resolution

Gateways MAY choose to support historical resolution, which is to surface different versions of the same DID Document, sorted by Sequence Number, according to the rules set out in the section on conflict resolution.

Upon resolving a DID, the Gateway will return the value sequence_numbers if there exists historical state for a given DID. The following API can be used with specific Sequence Numbers to fetch historical state:

§ Deactivating a DID

To intentionally deactivate a DID, as opposed to letting the record cease being published to the DHT, a DID controller follows the same process as updating a DID, but with a record format outlined in the section on deactivation.

Upon receiving a request to deactivate a DID, the Gateway MUST verify the signature of the request, and if valid, stop republishing the DHT. If the DNS Packets contain a _typ._did. record, the Gateway MUST stop indexing the type(s) for the DID.

§ Type Indexing

Get Info

Example Type Index Response:

[
  {
    "type": 1,
    "description": "Organization"
  },
  {
    "type": 7,
    "description": "Financial Institution"
  }
]

Get a Specific Type

Example Type Response:

[
  "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y",
  "did:dht:uodqi99wuzxsz6yx445zxkp8ddwj9q54ocbcg8yifsqru45x63kj"
]

A query to the type index returns an array of DIDs matching the associated type. If the type is not found, a 404 is returned. If no DIDs match the type, an empty array is returned.

§ Interoperability With Other DID Methods

As an optional extension, some existing DID methods can leverage did:dht to expand their feature set. This enhancement is most useful for DID methods that operate based on a single key and are compatible with the Ed25519 key format. Users can maintain their current DIDs without any changes by adopting this optional extension. Additionally, they gain the ability to add extra information to their DIDs by either publishing or retrieving data from Mainline.

Interoperable DID methods MUST be registered in this specification’s registry.

§ Implementation Considerations

§ Conflict Resolution

Per BEP44, Gateway servers can leverage the seq Sequence Number to handle conflicts:

Gateways receiving a put request where seq is lower than or equal to what’s already stored on the Gateway, MUST reject the request. If the Sequence Number is equal, and the value is also the same, the Gateway SHOULD reset its timeout counter.

When the Sequence Number is equal, but the value is different, Gateways need to decide which value to accept and which to reject. To make this determination Gateways MUST compare the payloads lexicographically to determine a lexicographical order, and reject the payload with a lower lexicographical order.

§ Size Constraints

BEP44 payload sizes are limited to 1000 bytes. Accordingly, we specify an efficient representation of a DID Document and leveraged DNS packet encoding to optimize our payload sizes. With this encoding format, we recommend additional considerations to minimize payload sizes:

§ Representing Keys

The following guidance on representations of keys and their identifiers using the JsonWebKey type defined by VC-JOSE-COSE are REQUIRED:

§ Historical Key State

Rotating keys is a widely recommended security practice. However, if you frequently rotate keys in a DID Document, this increases the document’s size due to the accumulation of old keys. Storage of old keys, in turn, increases the size of the corresponding DNS packet. To manage this overhead while still distinguishing between currently active keys and those that are no longer in use (but were valid in the past), users MAY utilize the service property. This property allows for the specification of services that are dedicated to storing signed records of the historical key states. Following this practice helps to keep the DID Document more concise.

§ Republishing Data

Mainline offers a limited duration (approximately 2 hours) for retaining records in the DHT. To ensure the verifiability of data signed by a DID, consistent republishing of DID Document records is crucial. To address this, it is RECOMMENDED for Clients to use Retention Challenges when interfacing with Gateways.

§ Rate Limiting

To reduce the risk of Denial of Service Attacks, spam, and other unwanted traffic, it is RECOMMENDED that Gateways require Retention Challenges for all requests. The use of Retention Challenges can act as an attack prevention measure, as it would be costly to scale retention challenge calculations. Gateways MAY choose to explore other rate-limiting techniques, such as IP limiting, or access-token-based approaches.

§ DID Resolution

The process for resolving a DID DHT Document via a Gateway is outlined in the read section above. However, we provide additional guidance for DID Resolvers, supplying DID Document Metadata and DID Resolution Metadata as follows:

TODO

Register types, gateway, and expiry types in the DID Specification Registry.

§ DID Document Metadata

§ DID Resolution Metadata

§ Security and Privacy Considerations

When implementing and using the did:dht method, there are several security and privacy considerations to be aware of to ensure expected and legitimate behavior.

§ Data Conflicts

Malicious actors may try to force Gateways into uncertain states by manipulating the Sequence Number associated with a record set. There are three such cases to be aware of:

§ Data Availability

Given the nature of decentralized distributed systems, there are no firm guarantees that all Gateways have access to the same state. To reduce such risks, it is RECOMMENDED to publish and read from multiple Gateways. As an optional enhancement Gateways MAY choose to share state amongst themselves via mechanisms such as a gossip protocol.

§ Data Authenticity

To enter into the DHT using BEP44 records MUST be signed by an Ed25519 private key, known as the Identity Key. When retrieving records either through a Mainline Server or a Gateway is it RECOMMENDED that one verifies the cryptographic integrity of the record themselves instead of trusting a server to have done the validation. Implementers MUST NOT trust servers that do not return a signature value.

§ Key Compromise

Since the did:dht uses a single, un-rotatable root key, there is are significant consequences associated with root key compromise. Such a compromise may be tough to detect without external assurances of identity. Implementers are encouraged to be aware of this possibility and devise strategies that support entities transitioning to new DIDs regularly, such as the mechanism for rotation noted in this specification.

§ Public Data

Mainline is a public network. As such, there is a risk in storing private, sensitive, or personally identifying information (PII) on such a network. Storing such sensitive information on the network or in the contents of a did:dht document is strongly discouraged.

§ Data Retention

It is RECOMMENDED that Gateways implement measures supporting the “Right to be Forgotten,” enabling precise control over the data retention duration.

§ Cryptographic Risk

The security of data within the Mainline DHT which relies on mutable records using Ed25519 keys—is intrinsically tied to the strength of these keys and their underlying algorithms, as outlined in [RFC8032]. Should vulnerabilities be discovered in Ed25519 or if advancements in quantum computing compromise its cryptographic foundations, the Mainline method could become obsolete.

§ Appendix

§ Test Vectors

§ Vector 1

A minimal DID Document.

Identity Public Key JWK:

{
  "kid": "0",
  "alg": "EdDSA",
  "crv": "Ed25519",
  "kty": "OKP",
  "x": "YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE"
}

DID Document:

{
  "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo",
  "verificationMethod": [
    {
      "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0",
      "type": "JsonWebKey",
      "controller": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo",
      "publicKeyJwk": {
        "kid": "0",
        "alg": "EdDSA",
        "crv": "Ed25519",
        "kty": "OKP",
        "x": "YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE"
      }
    }
  ],
  "authentication": [
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
  ],
  "assertionMethod": [
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
  ],
  "capabilityInvocation": [
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
  ],
  "capabilityDelegation": [
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
  ]
}

DNS Resource Records:

Name Type TTL Rdata
_did.cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo. TXT 7200 v=0;vm=k0;auth=k0;asm=k0;inv=k0;del=k0
_k0._did. TXT 7200 t=0;k=YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE

§ Vector 2

A DID Document with two keys (Identity Key and an uncompressed secp256k1 key with a custom id value), a service with multiple endpoints, a gateway, two types to index, an aka, and controller properties.

Identity Public Key JWK:

{
  "kid": "0",
  "alg": "EdDSA",
  "crv": "Ed25519",
  "kty": "OKP",
  "x": "YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE"
}

secp256k1 Public Key JWK:

With controller: did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y and id value sig.

{
  "kid": "sig",
  "alg": "ES256K",
  "crv": "secp256k1",
  "kty": "EC",
  "x": "1_o0IKHGNamet8-3VYNUTiKlhVK-LilcKrhJSPHSNP0",
  "y": "qzU8qqh0wKB6JC_9HCu8pHE-ZPkDpw4AdJ-MsV2InVY"
}

Key Purposes: Assertion Method, Capability Invocation.

Service:

{
  "id": "service-1",
  "type": "TestService",
  "serviceEndpoint": ["https://test-service.com/1", "https://test-service.com/2"]
}

Gateway: gateway1.example-did-dht-gateway.com.

Types: 1, 2, 3.

DID Document:

{
  "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo",
  "controller": "did:example:abcd",
  "alsoKnownAs": ["did:example:efgh", "did:example:ijkl"],
  "verificationMethod": [
    {
      "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0",
      "type": "JsonWebKey",
      "controller": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo",
      "publicKeyJwk": {
        "kid": "0",
        "alg": "EdDSA",
        "crv": "Ed25519",
        "kty": "OKP",
        "x": "YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE"
      }
    },
    {
      "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#sig",
      "type": "JsonWebKey",
      "controller": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y",
      "publicKeyJwk": {
        "kid": "sig",
        "alg": "ES256K",
        "crv": "secp256k1",
        "kty": "EC",
        "x": "1_o0IKHGNamet8-3VYNUTiKlhVK-LilcKrhJSPHSNP0",
        "y": "qzU8qqh0wKB6JC_9HCu8pHE-ZPkDpw4AdJ-MsV2InVY"
      }
    }
  ],
  "authentication": [
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
  ],
  "assertionMethod": [
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0",
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw"
  ],
  "capabilityInvocation": [
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0",
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw"
  ],
  "capabilityDelegation": [
    "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
  ],
  "service": [
    {
      "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#service-1",
      "type": "TestService",
      "serviceEndpoint": ["https://test-service.com/1", "https://test-service.com/2"]
    }
  ]
}

DNS Resource Records:

Name Type TTL Rdata
_did.cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo. NS 7200 gateway1.example-did-dht-gateway.com.
_did.cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo. TXT 7200 v=0;vm=k0,k1;auth=k0;asm=k0,k1;inv=k0,k1;del=k0;svc=s0
_cnt._did. TXT 7200 did:example:abcd
_aka._did. TXT 7200 did:example:efgh,did:example:ijkl
_k0._did. TXT 7200 t=0;k=YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE
_k1._did. TXT 7200 id=sig;t=1;k=Atf6NCChxjWpnrfPt1WDVE4ipYVSvi4pXCq4SUjx0jT9;c=did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y
_s0._did. TXT 7200 id=service-1;t=TestService;se=https://test-service.com/1,https://test-service.com/2
_typ._did. TXT 7200 id=1,2,3

§ Vector 3

A DID Document with two keys — the Identity Key and an X25519 key used with a different alg value than what is specified in the registry. The DID also has two gateway records and a service with an endpoint greater than 255 characters, and a previous record.

Identity Public Key JWK:

{
  "kid": "0",
  "alg": "EdDSA",
  "crv": "Ed25519",
  "kty": "OKP",
  "x": "sTyTLYw-n1NI9X-84NaCuis1wZjAA8lku6f6Et5201g"
}

X25519 Public Key JWK:

{
  "kid": "WVy5IWMa36AoyAXZDvPd5j9zxt2t-GjifDEV-DwgIdQ",
  "alg": "ECDH-ES+A128KW",
  "crv": "X25519",
  "kty": "OKP",
  "x": "3POE0_i2mGeZ2qiQCA3KcLfi1fZo0311CXFSIwt1nB4"
}

Key Purposes: Key Agreement.

Service:

{
  "id": "service-1",
  "type": "TestLongService",
  "serviceEndpoint": ["https://test-lllllllllllllllllllllllllllllllllllooooooooooooooooooooonnnnnnnnnnnnnnnnnnngggggggggggggggggggggggggggggggggggggsssssssssssssssssssssssssseeeeeeeeeeeeeeeeeeerrrrrrrrrrrrrrrvvvvvvvvvvvvvvvvvvvviiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiccccccccccccccccccccccccccccccceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.com/1"]
}

Gateways: gateway1.example-did-dht-gateway.com, gateway2.example-did-dht-gateway.com.

Previous DID:

DID Document:

{
  "id": "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy",
  "verificationMethod": [
    {
      "id": "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy#0",
      "type": "JsonWebKey",
      "controller": "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy",
      "publicKeyJwk": {
        "kid": "0",
        "alg": "EdDSA",
        "crv": "Ed25519",
        "kty": "OKP",
        "x": "sTyTLYw-n1NI9X-84NaCuis1wZjAA8lku6f6Et5201g"
      }
    },
    {
      "id": "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy#WVy5IWMa36AoyAXZDvPd5j9zxt2t-GjifDEV-DwgIdQ",
      "type": "JsonWebKey",
      "controller": "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy",
      "publicKeyJwk": {
        "kid": "WVy5IWMa36AoyAXZDvPd5j9zxt2t-GjifDEV-DwgIdQ",
        "alg": "ECDH-ES+A128KW",
        "crv": "X25519",
        "kty": "OKP",
        "x": "3POE0_i2mGeZ2qiQCA3KcLfi1fZo0311CXFSIwt1nB4"
      }
    }
  ],
  "authentication": [
    "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy#0"
  ],
  "assertionMethod": [
    "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy#0"
  ],
  "keyAgreement": [
    "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy#WVy5IWMa36AoyAXZDvPd5j9zxt2t-GjifDEV-DwgIdQ"
  ],
  "capabilityInvocation": [
    "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy#0"
  ],
  "capabilityDelegation": [
    "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy#0"
  ],
  "service": [
    {
      "id": "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy#service-1",
      "type": "TestLongService",
      "serviceEndpoint": ["https://test-lllllllllllllllllllllllllllllllllllooooooooooooooooooooonnnnnnnnnnnnnnnnnnngggggggggggggggggggggggggggggggggggggsssssssssssssssssssssssssseeeeeeeeeeeeeeeeeeerrrrrrrrrrrrrrrvvvvvvvvvvvvvvvvvvvviiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiccccccccccccccccccccccccccccccceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.com/1"]
    }
  ]
}

DNS Resource Records:

Name Type TTL Rdata
_prv._did. TXT 7200 id=did:dht:x3heus3ke8fhgb5pbecday9wtbfynd6m19q4pm6gcf5j356qhjzo;s=Tt9DRT6J32v7O2lzbfasW63_FfagiMHTHxtaEOD7p85zHE0r_EfiNleyL6BZGyB1P-oQ5p6_7KONaHAjr2K6Bw
_did.sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy. NS 7200 gateway1.example-did-dht-gateway.com.
_did.sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy. NS 7200 gateway2.example-did-dht-gateway.com.
_did.sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy. TXT 7200 v=0;vm=k0,k1;auth=k0;asm=k0;agm=k1;inv=k0;del=k0;svc=s0
_k0._did. TXT 7200 t=0;k=sTyTLYw-n1NI9X-84NaCuis1wZjAA8lku6f6Et5201g
_k1._did. TXT 7200 t=3;k=3POE0_i2mGeZ2qiQCA3KcLfi1fZo0311CXFSIwt1nB4;a=ECDH-ES+A128KW
_s0._did. TXT 7200 id=service-1;t=TestLongService;se=https://test-lllllllllllllllllllllllllllllllllllooooooooooooooooooooonnnnnnnnnnnnnnnnnnngggggggggggggggggggggggggggggggggggggsssssssssssssssssssssssssseeeeeeeeeeeeeeeeeeerrrrrrrrrrrrrrrvvvvvvvvvvvvvvvvvvvviiiiiiiiiiiiiiii iiiiiiiiiiiiiiiccccccccccccccccccccccccccccccceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.com/1

§ Open API Definition

openapi: 3.0.1
info:
  title: DID DHT Gateway API
  description: "The [DID DHT API](https://did-dht.com)"
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
  version: v1.0
paths:
  /{id}:
    get:
      tags:
        - DHT
      summary: Get DNS-encoded BEP44 records from the DHT
      description: Get a DNS-encoded BEP44 record set from the DHT
      parameters:
        - name: id
          in: path
          description: ID to get
          required: true
          schema:
            type: string
      responses:
        "200":
          description: 64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v
          content:
            application/octet-stream:
              schema:
                type: array
                items:
                  type: integer
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                type: string
        "404":
          description: Not found
          content:
            application/json:
              schema:
                type: string
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                type: string
    put:
      tags:
        - DHT
      summary: Put a DNS-encoded BEP44 record set into the DHT
      description: Put a DNS-encoded BEP44 record set into the DHT
      parameters:
        - name: id
          in: path
          description: ID to put
          required: true
          schema:
            type: string
      requestBody:
        description: 64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v
        content:
          application/octet-stream:
            schema:
              type: array
              items:
                type: integer
        required: true
      responses:
        "200":
          description: OK
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                type: string
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                type: string
  /dids/{id}:
    put:
      tags:
        - DID
      summary: Publish a DID
      description: Register or Update a DID in the DHT
      parameters:
        - name: id
          in: path
          description: DID to publish.
          required: true
          schema:
            type: string
      requestBody:
        description: A deconstructed DNS-encoded BEP44 request object
        content:
          application/json:
            schema:
              type: object
              properties:
                sig:
                  type: string
                  description: A base64URL-encoded signature of the BEP44 payload
                seq:
                  type: integer
                  description: A sequence number for the request, recommended to be a unix timestamp in seconds
                v:
                  type: string
                  description: A base64URL-encoded bencoded DNS packet containing the DID Document
                retention_solution:
                  type: string
                  description: A retention solution calculated according to the spec-defined retention solution algorithm
              required: [ did, sig, seq, v ]
      responses:
        "202":
          description: The server has accepted the request as valid and will publish it to the DHT
          content:
            application/json:
              schema:
                type: object
                properties:
                  expiry:
                    type: number
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                type: string
        "401":
          description: Invalid signature or retention solution
          content:
            application/json:
              schema:
                type: string
        "409":
          description: DID already exists with a higher sequence number. May still be accepted if the Gateway supports historical resolution.
          content:
            application/json:
              schema:
                type: string
        "503":
          description: Retention sets have been temporarily disabled.
          content:
            application/json:
              schema:
                type: string
    get:
      tags:
        - DID
      summary: Resolve a DID
      description: Resolve a DID from the DHT first, with a fallback to local storage
      parameters:
        - name: id
          in: path
          description: The DID to resolve
          required: true
          schema:
            type: string
        - name: seq
          in: query
          description: The sequence number of the DID to resolve
          required: false
          schema:
            type: integer
      responses:
        "200":
          description: The resolved DID Document
          content:
            application/json:
              schema:
                type: object
                properties: 
                  did:
                    type: object
                    description: The DID Document
                  dht:
                    type: string
                    description: An unpadded base64URL-encoded representation of a full DNS-encoded BEP44 payload, represented as 64 bytes sig, 8 bytes u64 big-endian seq, 0-1000 bytes of v concatenated; enabling independent verification
                  types:
                    type: array
                    items:
                      type: integer
                    description: The types associated with the DID
                  sequence_numbers:
                    type: array
                    items:
                      type: integer
                    description: The sequence numbers available for querying for this node
                  expiry:
                    type: number
                    description: The Unix Timestamp in seconds indicating when the DID will be evicted from the Gateway's Retained DID Set
                required: [ did, dht ]
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                type: string
        "404":
          description: The requested DID could not be resolved
          content:
            application/json:
              schema:
                type: string
  /dids/types:
    get:
      tags:
        - DID
      summary: Retrieve a list of supported types for indexing
      description: Retrieve a list of supported indexing types, according to the spec-defined type list
      responses:
        "200":
          description: A list of types support, alongside their human-readable description
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    type:
                      type: integer
                    description:
                      type: string
                  required: [ type, description ]
        "404":
          description: Type indexing not supported by this gateway
          content:
            application/json:
              schema:
                type: string
  /dids/types/{id}:
    get:
      tags:
        - DID
      summary: Retrieve a list of DIDs indexed under a given type
      description: Retrieve a list of DIDs indexed under a given type, according to the spec-defined type index
      parameters:
        - name: id
          in: path
          description: Type to query.
          required: true
          schema:
            type: integer
        - name: offset
          in: query
          description: Specifies the starting position from where the type records should be retrieved. Default is 0
          schema:
            type: integer
        - name: limit
          in: query
          description: Specifies the maximum number of type records to retrieve. The default is 100.
          schema:
            type: integer
      responses:
        "200":
          description: A list of DIDs indexed under the given type
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
        "404":
          description: Type not found
          content:
            application/json:
              schema:
                type: string
  /challenge:
    get:
      tags:
        - DID
      summary: Get information necessary to solve a retention challenge
      description: Get information needed to calculate a retention solution for DID PUT operations
      responses:
        "200":
          description: The current hash and difficulty to calculate a retention solution against, along with an estimated retention guarantee represented by the expiry property
          content:
            application/json:
              schema:
                type: object
                properties:
                  hash:
                    type: string
                    description: The current hash which is to be used as input for computing a retention solution
                  hash_source:
                    type: string
                    description: The source of the hash as defined by the Hash Source Registry.
                  difficulty:
                    type: integer
                    description: The current difficulty of the challenge representing the number of bits of leading zeros the resulting hash must contain
                  expiry:
                    type: integer
                    description: An approximate expiry date-time value, if a valid Retention Solution is submitted against this challenge, represented as a Unix Timestamp in seconds. The precise expiry date-time value is returned as a part of a PUT operation
                required: [ hash, difficult, expiry ]
        "501":
          description: Retention challenges are not supported
          content:
            application/json:
              schema:
                type: string     
        "503":
          description: Retention sets have been temporarily disabled
          content:
            application/json:
              schema:
                type: string

§ References

Ed25519
Ed25519. D. J. Bernstein, N. Duif, T. Lange, P. Schwabe, B.-Y. Yang; 26 September 2011. ed25519.cr.yp.to.
BEP44
BEP44. Storing arbitrary data in the DHT. A. Norberg, S. Siloti; 19 December 2014. Bittorrent.org.
Bencode
Bencode. A way to specify and organize data in a terse format. Bittorrent.org.
z-base-32
z-base-32. Human-oriented base-32 encoding. Z. O’Whielacronx; November 2002.
Pkarr
Pkarr. Public-Key Addressable Resource Records. Nuhvi.
VC-JOSE-COSE
Securing Verifiable Credentials using JOSE and COSE. O. Steele, M. Jones, M. Prorock, G. Cohen; 25 April 2024. W3C.

DID-CORE
Decentralized Identifiers (DIDs) v1.0. Drummond Reed; Manu Sporny; Markus Sabadello; Dave Longley; Christopher Allen; Jonathan Holt; 2020-09-07. Status: WD.
DID-SPEC-REGISTRIES
DID Specification Registries. Orie Steele; Manu Sporny; 2020-06-18. Status: NOTE.
RFC1034
Domain names - concepts and facilities. P.V. Mockapetris; 1987-11. Status: Internet Standard.
RFC1035
Domain names - implementation and specification. P.V. Mockapetris; 1987-11. Status: Internet Standard.
RFC2119
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner; 1997-03. Status: Best Current Practice.
RFC4648
The Base16, Base32, and Base64 Data Encodings. S. Josefsson; 2006-10. Status: Proposed Standard.
RFC7517
JSON Web Key (JWK). M. Jones; 2015-05. Status: Proposed Standard.
RFC7638
JSON Web Key (JWK) Thumbprint. M. Jones; N. Sakimura; 2015-09. Status: Proposed Standard.
RFC8032
Edwards-Curve Digital Signature Algorithm (EdDSA). S. Josefsson; I. Liusvaara; 2017-01. Status: Informational.
RFC8174
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba; 2017-05. Status: Best Current Practice.

Table of Contents