§ 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:
- It has a proven track record of 15 years.
- It is the biggest DHT in existence with an estimated 10 million servers.
- It retains data for multiple hours at no cost.
- 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 |
-
The Root Record serves as a “map” to reconstruct a DID Document from a DNS packet. This record contains a version number indicating the version of this specification against which it is created.
-
Additional records like
svc
(services),vm
(Verification Methods), and Verification Relationships (e.g., authentication, assertion, etc.) are represented as additional records in the format<ID>._did.
. These records contain the zero-indexed value of eachkey
orservice
as attributes. -
All resource record names, aside from the Root Record and optional Authoritative Gateway Records, MUST end in
_did.
. -
The DNS packet MUST set the Authoritative Answer flag since this is always an Authoritative packet.
-
TXT
records MAY exceed 255 characters as per [RFC1035]. Records exceeding 255 characters are represented as multiple strings, which can be concatenated to a single value upon DID Document reconstruction. -
DNS packets MUST be compressed as per [RFC1035] section 4.1.4 before transmission.
§ 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.
-
The root record’s name MUST be of the form,
_did.<ID>.
, whereID
is the Mainline identifier associated with the DID (i.e.did:dht:<ID>
becomes_did.<ID>.
). -
The root record’s type is
TXT
indicating a Text record. -
The root record’s rdata is represented by the form
v=M;vm=N;auth=O;asm=P;inv=Q;del=R;svc=S
whereM
is the version of the DNS packet representation defined by this specification.N
is the set Verification Method identifiers (e.g.,k0,k1
) present in the document, always containing at leastk0
.O
,P
,Q
, andR
contain the set of Verification Method resource aliases (e.g.,k0
) for each Verification Relationship.S
contains the set of Service resource aliases (e.g.,s0
) for each Service.
Additionally:
-
A version number MUST be present. The version number for this specification version is 0 (e.g.,
v=0
). The version number is not present in the corresponding DID Document. -
The
vm
property MUST always contain at least the Identity Key represented byk0
. -
Verification Relationships (
auth
,asm
,agm
,inv
,del
) without any members MUST be omitted. -
If there are no Services, the
svc
property MUST be omitted.
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.
-
Resource names are aliased with zero-indexed values (e.g.,
k0
,k1
,s0
,s1
). -
Verification Methods, Verification Relationships, and Services are separated by a semicolon (
;
), while values within each property are separated by a comma (,
). -
Across all properties, distinct elements are separated by semicolons (
;
) while array elements are separated by commas (,
). -
Additional properties not defined by this specification MAY be represented in a DID Document and its corresponding DNS packet if the properties are registered in the additional properties registry.
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.
-
The Controller record’s name is represented as a
_cnt._did.
. -
The Controller record’s type is
TXT
indicating a Text record. -
The Controller record’s data is represented as a comma-separated list of controller DID identifiers.
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.
-
The Also Known As record’s name is represented as a
_aka._did.
. -
The Also Known As record’s type is
TXT
indicating a Text record. -
The Also Known As record’s data is represented as a comma-separated list of DID identifiers.
Example AKA Record:
Name | Type | TTL | Rdata |
---|---|---|---|
_aka._did. | TXT | 7200 | did:example:efgh,did:example:ijkl |
§ Verification Methods
-
Each Verification Method record’s name is represented as a
_kN._did.
record whereN
is the zero-indexed positional index of a given Verification Method (e.g.,_k0
,_k1
). -
Each Verification Method record’s type is
TXT
, indicating a Text record. -
Each Verification Method record’s rdata is represented by the form
id=M;t=N;k=O;a=P
whereM
is an optional Verification Method Identifier,N
is the index of the key’s type from the key type index,O
is the unpadded base64URL [RFC4648] representation of the public key, andP
is theJWK
alg
identifier of the key. It is important to note that the value ofO
represents the byte representation of the public key itself rather than an encoded JWK.-
The Identity Key MUST always be at index
_k0
. -
It is RECOMMENDED to omit Verification Method ID values from the DNS packet representation, as they can be deterministically computed according to the rules specified in the representing keys section. Additionally:
-
For the Identity Key, the
id
value MUST be set to0
. -
For all other keys, if an
id
value is present in the record, it is used as theid
value for the Verification Method. If there is noid
value set, the JWK Thumbprint [RFC7638] is used as the Verification Method ID.
-
-
The algorithm identifier (
a
property) MUST be omitted from the record if it is assigned to the default value specified in the key type index. If it differs from the default value, it MUST be present.
-
-
Verification Methods MAY have an optional controller property represented by
c=C
whereC
is the identifier of the verification method’s controller (e.g.,t=N;k=O;c=C
). If omitted, it is assumed that the controller of the Verification Method is the Identity Key.
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
- Each Verification Relationship is represented as a part
of the root
_did.<ID>.
record (see: Root Record).
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
-
Each Service record’s name is represented as a
_sN._did.
record whereN
is the zero-indexed positional index of the Service (e.g.,_s0
,_s1
). -
Each Service record’s type is
TXT
indicating a Text record. -
Each Service record’s data is represented with the form
id=M;t=N;se=O
whereM
is the Service’s ID,N
is the Service’stype
andO
is the Service’s URI.-
Multiple service endpoints MAY be present. If present, they MUST be represented as an array (e.g.,
id=dwn;t=DecentralizedWebNode;se=https://dwn.org/dwn1,https://dwn.org/dwn2
). -
Additional properties MAY be present (e.g.,
id=dwn;t=DecentralizedWebNode;se=https://dwn.org/dwn1;sig=1;enc=2
) if the properties are registered in the additional properties registry.
-
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:
-
Generate an Ed25519 key pair and encode the public key using the format provided in the format section.
-
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 be0
and the type ofJsonWebKey
as defined by VC-JOSE-COSE. The key MUST be represented as apublicKeyJwk
as per [RFC7517] with akid
of0
.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 theJWK
specification, thealg
property MUST always be present in the DID Document representation. The indexed types registry defines default algorithm values per key type. -
Map the output DID Document to a DNS packet as outlined in property mapping.
-
Compress the DNS packet as per [RFC1035] section 4.1.4.
-
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. -
Submit the result of to the DHT via a Mainline node, or a Gateway, with the identifier created in step 1.
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:
-
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.
-
Decode the resulting BEP44 response’s
v
value using bencode. -
Uncompress the DNS packet according to [RFC1035] section 4.1.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 JWKkid
to0
.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 JWKkid
.ii. If no
id
value is set, the JWK Thumbprint [RFC7638] is used as the Verification Method ID and JWKkid
.c. Expand all identifiers (i.e. Verification Methods, Services, etc.
id
s ) to their fully-qualified form (e.g.,did:dht:uodqi99wuzxsz6yx445zxkp8ddwj9q54ocbcg8yifsqru45x63kj#0
as opposed to0
or#0
,did:dht:uodqi99wuzxsz6yx445zxkp8ddwj9q54ocbcg8yifsqru45x63kj#service-1
as opposed to#service-1
). -
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.
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:
-
Let the DHT record expire and cease to publish it.
-
Publish a new DHT record where the
rdata
of the root DNS record is the stringdeactivated
.
Name | Type | TTL | Rdata |
---|---|---|---|
_did.<ID> . |
TXT | 7200 | deactivated |
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:
-
Using the old Identity Key, sign over the new Identity Key using the Ed25519 variant of the EdDSA algorithm [RFC8032].
-
Encode the resulting signature data using the unpadded base64URL [RFC4648] scheme.
-
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:
-
The Previous record’s name is represented as a
_prv._did.
record. -
The Previous record’s type is
TXT
indicating a Text record. -
The Previous record’s data is represented with the form
id=M;s=N
whereM
is the identifier of the previous DID, andN
is the unpadded base64URL signature from step (3) above.
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:
-
Each Gateway record’s name is represented as
_did.<ID>.
record, whereID
represents the suffix of thedid:dht
identifier. -
Each Gateway record’s type is
NS
indicating a Name Server record. -
Each Gateway record’s data is represented as a Fully Qualified Domain Name (FQDN).
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:
-
The Type Index record’s name is represented as a
_typ._did.
record. -
The Type Index record’s type is
TXT
indicating a Text record. -
The Type Index record’s data is represented with the form
id=H,I,J,...N
where the value is a comma-separated list of integer types from the indexed types registry.
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.
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.
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:
-
Obtain a DID identifier and set it to
DID
. -
Get the
difficulty
andhash
value from the server set toDIFFICULTY
andHASH
respectively. -
Generate a random 32-bit integer nonce value set to
NONCE
. -
Set
RETENTION
equal to the result of (DID
+HASH
+NONCE
). -
Compute the SHA-256 hash over
RETENTION
whereATTEMPT
= SHA256(RETENTION
). -
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.
-
Set
RETENTION_SOLUTION
equal to the concatenation ofATTEMPT
andNONCE
separated by a colon (e.g.,ATTEMPT
:NONCE
). -
Submit the
RETENTION_SOLUTION
to the Gateway API for write operations.
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:
-
Extract the
RETENTION_SOLUTION
value from the write request. -
Retrieve the
DID
identifier associated with the write request. -
Obtain the current
HASH
andDIFFICULTY
values used by the Gateway. -
Construct the
RETENTION_VALUE
by concatenating theDID
,HASH
, and theNONCE
(extracted from theRETENTION_SOLUTION
). -
Compute the SHA-256 hash of the
RETENTION_VALUE
and set it toCOMPUTED_HASH
. -
Compare the
COMPUTED_HASH
with theRETENTION_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.
- 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:
-
To guarantee a sensible minimum retention period, it is RECOMMENDED that Gateways retain DIDs for at least 1 week starting from the acceptance of Retention Solution.
-
Gateways MAY choose to offer an extended grace period before evicting DIDs, particularly for those with a substantial history with the Gateway, such as DIDs exposed through the Historical Resolution API.
-
Gateways MAY choose to include the
expiry
value as a part of the DID Resolution Metadata, during DID Resolution, to aid Clients in being able to assess whether further proof of work is required. -
Gateways SHOULD treat each new valid Retention Solution as extending a DID’s retention period. When a Client submits a fresh Retention Solution for a DID already in the Retained DID Set, the Gateway SHOULD update the DID’s expiry timestamp, effectively resetting the expiry window and granting a renewed retention period.
-
When a Gateway reaches its storage capacity or experiences high load, it is RECOMMENDED that it significantly increases the
difficulty
parameter for Retention Challenges. By raising thedifficulty
the Gateway can effectively limit the acceptance of new DIDs into its Retained DID Set, ensuring the stability and performance of the server under resource constraints.
§ 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:
Access-Control-Allow-Origin
:*
Access-Control-Allow-Methods
:GET
,PUT
,OPTIONS
§ Put
On receiving a PUT
request the server verifiers the sig
and submits a mutable put to Mainline as per
BEP44.
- Method:
PUT
- Path:
/:id
id
- string - REQUIRED - The z-base-32 encoded Identity Key, equivalent to the suffix of the DID DHT identifier.
- Request Body:
application/octet-stream
- Returns:
application/json
200
- Success.400
- Bad request if thesig
is not valid.500
- Internal server error.
§ Get
When it receives a GET
request the server submits a mutable get query to Mainline as per BEP44.
- Method:
GET
- Path:
/:id
id
- string - REQUIRED - The z-base-32 encoded Identity Key, equivalent to the suffix of the DID DHT identifier.
- Returns:
application/octet-stream
200
- Success. The binary representation of<sig><seq>[<v>]
where:404
- Record not found.
§ Get the Current Challenge
Challenge is exposed as an endpoint to facilitate functionality pertaining to the Retained DID Set, surfacing a Retention Challenge.
- Method:
GET
- Path:
/challenge
- Returns:
application/json
200
- Success.hash
- string - REQUIRED - The current hash which is to be used as input for computing a Retention Solution.hash_source
- string - REQUIRED - The source of the hash as defined by the Hash Source Registry.difficulty
- integer - REQUIRED - The challenge’s current difficulty represents the number of bits of leading zeros the resulting hash must contain.expiry
- integer - An approximate expiry date-time value, if a valid Retention Solution is submitted against this challenge, which MUST be a Unix Timestamp in seconds. The precise expiry date-time value is returned as a part of a PUT operation.
501
- Retention Sets are not supported by this gateway.503
- Retention Sets have been temporarily disabled.
Example Challenge Response:
{
"hash": "000000000000000000022be0c55caae4152d023dd57e8d63dc1a55c1f6de46e7",
"hash_source": "bitcoin",
"difficulty": 26,
"expiry": 1715578600
}
§ Register or Update a DID
- Method:
PUT
- Path:
/did/:id
id
- string - REQUIRED - ID of the DID to publish.
- Request Body: – application/json
did
- string - REQUIRED - The DID to register or update.sig
- string - REQUIRED - An unpadded base64URL-encoded signature of the BEP44 payload.seq
- integer - REQUIRED - A sequence number for the request. This number MUST be unique for each DID operation, which MUST be a Unix Timestamp in seconds.v
- string - REQUIRED - An unpadded base64URL-encoded bencoded compressed DNS packet containing the DID Document.retention_solution
- string - OPTIONAL - A retention solution calculated according to the retention solution algorithm.
- Returns:
application/json
202
- Accepted. The server has accepted the request as valid and will publish to the DHT.expiry
- string - OPTIONAL – The Unix Timestamp in seconds indicating when the DID will be evicted from the Gateway's Retained DID Set.
400
- Invalid request, including an invalid retention solution.401
- Invalid signature.409
- DID already exists with a higher sequence number. DID may be accepted if the Gateway supports historical resolution.503
- Retention Sets have been temporarily disabled.
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:
-
Verify the signature of the request and, if valid, publish the BEP44 payload to the DHT.
-
If one is provided, validate the
retention_solution
and, if valid, add the DID to the Gateway's Retained DID Set. -
If the DNS packet contain a
_typ._did.
record, update the specified indexes with the DID.
Requests without a retention_solution
have no retention guarantees.
§ Resolving a DID
- Method:
GET
- Path:
/did/:id
id
- string - REQUIRED - ID of the DID to resolve.
- Returns:
application/json
200
- Success.did
- object - REQUIRED - A JSON object representing the DID Document.dht
- string - REQUIRED - An unpadded base64URL-encoded representation of the full BEP44 payload, represented as 64 bytes sig, 8 bytes u64 big-endian seq, and 0-1000 bytes of v concatenated, enabling independent verification.types
- array - OPTIONAL - An array of type integers for the DID.sequence_numbers
- array - OPTIONAL - An sorted array of integers representing seen sequence numbers, used with historical resolution.expiry
- integer - OPTIONAL - The Unix Timestamp in seconds indicating when the DID will be evicted from the Gateway's Retained DID Set.400
- Invalid request.
404
- DID not found.
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:
-
Query local storage for the DID record set, and if the Gateway is authoritative for the DID, return the stored DIDs.
-
If the Gateway is not authoritative for the DID, the Gateway MUST query the DHT for the DID Document, and if found, return the record set. If the records are not found in the DHT, the Gateway MAY fall back to its local storage.
-
If the DNS Packet contains a
_typ._did.
record, the Gateway MUST return the associatedtypes
value. -
If the Gateway supports historical resolution and has multiple stored Sequence Numbers for the DID, the Gateway MUST return the associated
sequence_number
value(s). -
If the DID is in the Gateway's Retained DID Set, the Gateway MUST return the associated
expiry
value.
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:
- Method:
GET
- Path:
/did/:id?seq=:sequence_number
id
- string - REQUIRED - ID of the DID to resolveseq
- integer - OPTIONAL - Sequence number of the DID to resolve
- Returns:
application/json
200
- Success.did
- object - REQUIRED - A JSON object representing the DID Document.dht
- string - REQUIRED - An unpadded base64URL-encoded representation of the full BEP44 payload, represented as 64 bytes sig, 8 bytes u64 big-endian seq, and 0-1000 bytes of v concatenated, enabling independent verification.types
- array - OPTIONAL - An array of type integers for the DID.expiry
- integer - OPTIONAL - The Unix Timestamp in seconds indicating when the DID will be evicted from the Gateway's Retained DID Set.
400
- Invalid request.404
- DID not found for the given sequence number.501
- Historical resolution not supported by this gateway.
§ 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
- Method:
GET
- Path:
/did/types
- Returns:
application/json
Example Type Index Response:
[
{
"type": 1,
"description": "Organization"
},
{
"type": 7,
"description": "Financial Institution"
}
]
Get a Specific Type
- Method:
GET
- Path:
/did/types/:id
id
- integer - REQUIRED - The type to query from the index.offset
- integer - OPTIONAL - Specifies the starting position from where the type records should be retrieved (Default:0
).limit
- integer - OPTIONAL - Specifies the maximum number of type records to retrieve (Default:100
).
- Returns:
application/json
200
- Success.- array - REQUIRED - An array of DID Identifiers matching the associated type.
400
- Invalid request.404
- Type not found.501
- Types not supported by this gateway.
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:
-
For the Identity Key, the Verification Method
id
and JWKid
properties MUST be set to0
. -
For all keys besides the Identity Key, the Verification Method
id
and the JWKkid
are set to the providedid
value, if present. If noid
value is specified, the Verification Method’sid
value and the JWKkid
values are set to the key’s JWK Thumbprint calculated according to [RFC7638]. -
DID Document representations of elliptic curve (EC) keys MUST include the x- and y-coordinate pair. To conserve space in the DNS packet representation, compressed point encoding MUST be used to transmit the x-coordinate and a sign bit for the y-coordinate. This practice reduces each public key’s size from 65 to 33 bytes.
-
DID Document representations MUST always use fully-qualified identifiers when referring to Verification Methods (e.g.,
did:dht:uodqi99wuzxsz6yx445zxkp8ddwj9q54ocbcg8yifsqru45x63kj#0
as opposed to0
or#0
).
§ 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:
Register types
, gateway
, and expiry
types in the DID Specification Registry.
§ DID Document Metadata
-
The metadata
versionId
property MUST be set to the DID Document packet’s current sequence number. -
The metadata
created
property MUST be set to XML Datetime representation of the earliest known Sequence Number for the DID. -
The metadata
updated
property MUST be set to the XML Datetime representation of the last known Sequence Number for the DID. -
If the DID Document has been deactivated the
deactivated
property MUST be set totrue
. -
The metadata
types
property MUST be set to the array of strings representing type values if type data is present in the DID Document's packet. -
The metadata
expiry
property MUST be set to the integer representing the expiry date-time value for the DID in the Gateway's Retained DID Set.
§ DID Resolution Metadata
- The metadata
gateway
property MUST be set to the string representing the Gateway's URI from which the DID was resolved. This property is useful in cases where a DID Resolvers performs resolution against an Authoritative Gateway.
§ 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:
-
Low Sequence Number - If a Gateway has yet to see Sequence Numbers for a given record it MUST query its peers to see if they have encountered the record. If a peer is found who has encountered the record, the record with the latest sequence number must be selected. If the server has encountered greater sequence numbers before, the server MAY reject the record set. If the server supports historical resolution it MAY choose to accept the request and insert the record into its historically ordered state.
-
Conflicting Sequence Number - When a malicious actor publishes valid but conflicting records to two different Mainline Servers or Gateways. Implementers are encouraged to follow the guidance outlined in conflict resolution.
-
High Sequence Number - Since Sequence Numbers MUST be second representations of a Unix Timestamp, it is RECOMMENDED that Gateways reject Sequence Numbers that represent timestamps greater than 2 hours into the future to mitigate timing attack risks.
§ 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:
- ID:
did:dht:x3heus3ke8fhgb5pbecday9wtbfynd6m19q4pm6gcf5j356qhjzo
. - Signature:
Tt9DRT6J32v7O2lzbfasW63_FfagiMHTHxtaEOD7p85zHE0r_EfiNleyL6BZGyB1P-oQ5p6_7KONaHAjr2K6Bw
.
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.