diff --git a/impl/internal/did/pow.go b/impl/internal/did/pow.go index 3f5a7a47..6e6f38dd 100644 --- a/impl/internal/did/pow.go +++ b/impl/internal/did/pow.go @@ -29,10 +29,10 @@ func hasLeadingZeros(hash string, difficulty int) bool { return strings.HasPrefix(binaryHash, target) } -// computeRetentionProof generates the Retention Proof Hash and checks if it meets the criteria. -func computeRetentionProof(didIdentifier, bitcoinBlockHash string, difficulty, nonce int) (string, bool) { +// solveRetentionChallenge generates the Retention Challenge Hash and checks if it meets the criteria. +func solveRetentionChallenge(didIdentifier, inputHash string, difficulty, nonce int) (string, bool) { // Concatenating the DID identifier with the retention value - retentionValue := didIdentifier + (bitcoinBlockHash + fmt.Sprintf("%d", nonce)) + retentionValue := didIdentifier + (inputHash + fmt.Sprintf("%d", nonce)) // Computing the SHA-256 hash hash := computeSHA256Hash(retentionValue) diff --git a/impl/internal/did/pow_test.go b/impl/internal/did/pow_test.go index 39e6dd26..2a072786 100644 --- a/impl/internal/did/pow_test.go +++ b/impl/internal/did/pow_test.go @@ -8,22 +8,23 @@ import ( ) func TestPOW(t *testing.T) { - // Example usage of computeRetentionProof + // Example usage of solveRetentionChallenge didIdentifier := "did:dht:test" - bitcoinBlockHash := "000000000000000000022be0c55caae4152d023dd57e8d63dc1a55c1f6de46e7" + inputHash := "000000000000000000022be0c55caae4152d023dd57e8d63dc1a55c1f6de46e7" // 26 leading zeros difficulty := 26 timer := time.Now() for nonce := 0; nonce < math.MaxInt; nonce++ { - hash, isValid := computeRetentionProof(didIdentifier, bitcoinBlockHash, difficulty, nonce) + hash, isValid := solveRetentionChallenge(didIdentifier, inputHash, difficulty, nonce) if isValid { fmt.Printf("Hash: %s\n", hash) - fmt.Printf("Valid Retention Proof: %v\n", isValid) + fmt.Printf("Valid Retention Challenge: %v\n", isValid) fmt.Printf("Nonce: %d\n", nonce) break } } + fmt.Printf("Time taken: %s\n", time.Since(timer)) } diff --git a/spec/spec.md b/spec/spec.md index ba5909ff..93532add 100644 --- a/spec/spec.md +++ b/spec/spec.md @@ -9,7 +9,7 @@ The DID DHT Method Specification 1.0 **Draft Created:** October 20, 2023 -**Last Updated:** May 9, 2024 +**Last Updated:** May 13, 2024 **Editors:** ~ [Gabe Cohen](https://github.com/decentralgabe) @@ -91,10 +91,10 @@ services, and other properties outlined in the specification. ~ The unique identifier string within a DID URI (e.g. the part after `did:dht:`). For DID DHT the suffix is the [[ref:z-base-32]] encoded public key portion of the [[ref:Identity Key]]. -[[def:Identity Key]] -~ An [Identity Key](#identity-key) is an [[ref:Ed25519]] key-pair required to authenticate all records in +[[def:Identity Key Pair, Identity Key]] +~ An [Identity Key Pair](#identity-key-pair) is an [[ref:Ed25519]] key pair required to authenticate all records in [[ref:Mainline DHT]]. The public key portion is encoded using [[ref:z-base-32]] and represented in the [[ref:DID Suffix]]. -This key is guaranteed to be present in each `did:dht` document. +The public key, also known as the [[ref:Identity Key]] is guaranteed to be present in each `did:dht` document. [[def:DNS Resource Records, DNS Resource Record]] ~ An efficient format for representing [[ref:DID Documents]] and providing semantics pertinent to DID DHT, @@ -125,15 +125,17 @@ for retaining records in the DHT. See [Republishing Data](#republishing-data). [[def:Client, Clients]] ~ A client is a piece of software that is responsible for generating a `did:dht` and submitting it to a [[ref:Mainline Server]] or [[ref:Gateway]]. Notably, a client has the ability to sign messages with the -private key associated with an [[ref:Identity Key]]. +private-key portion of an [[ref:Identity Key Pair]]. -[[def:Retained DID Set, Retained Set, Retention Set]] +[[def:Retained DID Set, Retained Set, Retention Set, Retention Sets]] ~ The set of DIDs that a [[ref:Gateway]] is retaining and thus is responsible for [[ref:republishing]]. +See [Retained DID Set](#retained-did-set). -[[def:Retention Proof, Retention Proofs]] -~ A proof provided by the [[ref:DID]] controller to a [[ref:Gateway]] which attests that (1) they control the -DID and (2) have done sufficient work to have a [[ref:Gateway]] retain their DID for a set period of time. See -[Retained DID Set](#retained-did-set). +[[def:Retention Challenge, Retention Challenges, Retention Solution, Retention Solutions]] +~ A _Retention Challenge_ refers to a computational cost associated with a set of guarantees to be provided to a +DID controller by a [[ref:Gateway]], who submits a corresponding _Retention Solution_. A solution provided by the [[ref:DID]] +controller to a [[ref:Gateway]] which attests both that (1) they control the DID and (2) have done sufficient work to +have a [[ref:Gateway]] retain their DID for a set period of time as a part of its [[ref:Retention Set]]. [[def:Sequence Number, Sequence Numbers, Sequence]] ~ A sequence number, or `seq`, is a property of a mutable item as defined in [[ref:BEP44]]. It is a 64-bit integer that @@ -163,10 +165,11 @@ Alternatively, one can interpret the encoding rules as a series of transformatio did-dht-format := did:dht:Z-BASE-32(raw-public-key-bytes) ``` -### Identity Key +### Identity Key Pair -A unique property of DID DHT is its dependence on an a single non-rotatable key which we refer to as an _Identity Key_. -This requirement stems from [[ref:BEP44]], particularly within the _Mutable Items_ section: +A unique property of DID DHT is its dependence on an 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 [[ref: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 @@ -175,19 +178,19 @@ stored under is the SHA-1 hash of the public key (as it appears in the put messa This mechanism, as detailed in [[ref: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 [[ref:Mainline]] or [[ref:Gateway]] server -for providing unaltered messages is unnecessary. Instead, all clients can, and should, verify messages themselves. This +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](https://www.w3.org/TR/did-core/#choosing-did-resolvers) might tamper with a [[ref:DID Document]] -which would be undetectable by a client. +[DID resolver](https://www.w3.org/TR/did-core/#choosing-did-resolvers) has the ability tamper with a [[ref:DID Document]], +in a manner which could be undetectable by a client. -Currently, [[ref:Mainline]] exclusively supports the [[ref:Ed25519]] signature system. In turn, [[ref:Ed25519]]-based +At present, [[ref:Mainline]] exclusively supports the [[ref:Ed25519]] signature system. In turn, [[ref: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 [[ref:z-base-32]] encoded public key, which acts as its [[ref:suffix]]. -Identity Keys ****MUST**** have the identifier `0` as both its Verification Method `id` and JWK `kid` [[spec:RFC7517]]. -Identity Keys ****MUST**** have the [Verification Relationships](#verification-relationships) _Authentication_, _Assertion_, -_Capability Invocation_, and _Capability Delegation_. +concatenating the `did:dht:` prefix with a [[ref:z-base-32]] encoded public key (the [[ref:Identity Key]], which acts as +its [[ref:suffix]]. Identity Keys ****MUST**** have the identifier `0` as both its Verification Method `id` and JWK `kid` +[[spec:RFC7517]]. Identity Keys ****MUST**** have the [Verification Relationships](#verification-relationships) +_Authentication_, _Assertion_, _Capability Invocation_, and _Capability Delegation_. -While the system requires at least one [[ref:Ed25519]], a DID DHT Document can include any number of additional keys. +While DID DHT requires at least one [[ref: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](registry/index.html##key-type-index). As a unique consequence of the requirement of the Identity Key, DID DHT Documents are able to be partially-resolved @@ -199,7 +202,7 @@ resolution is only used as a fallback mechanism. Similarly, the requirement of a In this scheme, we encode the [[ref:DID Document]] as [DNS Resource Records](https://en.wikipedia.org/wiki/Domain_Name_System#Resource_records). These resource records make -up a DNS packet [[spec:RFC1034]] [[spec:RFC1035]], which is then stored in the [[ref:DHT]]. +up a DNS packet [[spec:RFC1034]] [[spec:RFC1035]], which is then stored in the [[ref:DHT]] encoded as a [[ref:BEP44]] payload. | Name | Type | TTL | Rdata | | ------------ | ---- | ------ | ------------------------------------------------------------ | @@ -311,8 +314,7 @@ To ensure that the DID controller is authorized to make changes to the DID Docum ##### Also Known As -A `did:dht` document ****MAY**** have multiple identifiers using the -[alsoKnownAs](https://www.w3.org/TR/did-core/#also-known-as) property. +A `did:dht` document ****MAY**** have multiple identifiers using the [alsoKnownAs](https://www.w3.org/TR/did-core/#also-known-as) property. - The [Also Known As](https://www.w3.org/TR/did-core/#also-known-as) record's **name** is represented as a `_aka._did.`. @@ -487,14 +489,14 @@ A sample transformation of a fully-featured DID Document to a DNS packet is exem ### Operations -Entries to the [[ref:DHT]] require a signed record as per [[ref:BEP44]]. As such, the keypair used for the [[ref:Mainline]] +Entries to the [[ref:DHT]] require a signed record as per [[ref:BEP44]]. As such, the key pair used for the [[ref:Mainline]] identifier is also used to sign the [[ref:DHT]] record. #### Create To create a `did:dht` document, the process is as follows: -1. Generate an [[ref:Ed25519]] keypair and encode the public key using the format provided in the [format section](#format). +1. Generate an [[ref:Ed25519]] key pair and encode the public key using the format provided in the [format section](#format). 2. Construct a conformant JSON representation of a [[ref:DID Document]]. @@ -564,7 +566,7 @@ Any valid [[ref:BEP44]] record written to the DHT is an update. As long as contr [[ref:Identity Key]] is retained any update is made possibly by signing and writing records with a unique incremental [[ref:sequence number]] with [mutable items](https://www.bittorrent.org/beps/bep_0044.html). -It is ****RECOMMENDED**** that updates are infrequent, as caching of the DHT is highly encouraged. +It is ****RECOMMENDED**** that updates are infrequent — at least every 2 hours — as DHT caching is highly encouraged. #### Deactivate @@ -615,7 +617,6 @@ and `N` is the the unpadded base64URL signature from step (3) above. | ---------- | ---- | ----- | -------------------------------------------------------------------------------------- | | _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 [[ref:DID Document]] indicating the rotation to the new identifier, by setting the [controller property](#controller) to the new DID. Without the previous record present in the new DID's record set, the linkage ****MUST NOT**** be considered legitimate. @@ -702,64 +703,79 @@ One such registry is [provided by this specification](registry/index.html#gatewa A [[ref:Retained DID Set]] refers to the set of DIDs a [[ref:Gateway]] retains and [[ref:republishes]] to the DHT. A [[ref:Gateway]] may choose to surface additional [APIs](#gateway-api) based on this set, such as providing a -[type index](#type-indexing). +[type index](#type-indexing) or supporting [historical resolution](#historical-resolution). To safeguard equitable access to the resources of [[ref:Gateways]], which are publicly accessible and potentially -subject to [a high volume of requests](#rate-limiting), we suggest an ****OPTIONAL**** mechanism aimed at upholding +subject to [a high volume of requests](#rate-limiting), we provie an _optional_ mechanism aimed at upholding fairness in the retention and [[ref:republishing]] of record sets by [[ref:Gateways]]. This mechanism, referred to as a -[[ref:Retention Proof]], requires clients to generate a proof value for write requests that attests to to an amount of work -completed in exchange for a retention guarantee provided by a [[ref:Gateway]]. This process aims to fairly guarnatee that -the amount of work done by a client is proportional to the duration of data retention and [[ref:republishing]] a [[ref:Gateway]] -performs. This mechanism enhances the overall reliability and effectiveness of [[ref:Gateways]] in managing requests. - -#### Generating a Retention Proof - -A [[ref:Retention Proof]] is a form of [Proof of Work](https://en.bitcoin.it/wiki/Proof_of_work) performed over a DID -identifier concatenated with the `retention` value of a given DID operation. The `retention` value is composed of a -hash value specified [by the gateway](registry/index.html#gateways), and a random -[nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) using the [SHA-256 hashing algorithm](https://en.wikipedia.org/wiki/SHA-2). -The resulting _Retention Proof Hash_ is used to determine the retention duration based on the number of leading zeros -of the hash, referred to as the _difficulty_, which ****MUST**** be no less than 26 bits of the 256-bit hash value. -The algorithm, in detail, is as follows: +[[ref:Retention Challenge]], requires clients to generate a solution for the challenge — a [[ref:Retention Solution]] — for +write requests, which attest to an amount of work completed in exchange for a retention guarantee provided by a [[ref:Gateway]]. -1. Obtain a DID identifier and set it to `DID`. +This process aims to provide a fair mechanism which provides numerous benefits for clients while giving [[ref:Gateway]] operators +anti-spam prevention, and control over the rate at which they accept new DIDs, thus enhancing the overall +reliability and effectiveness of [[ref:Gateways]] in managing DIDs. -2. Get the difficulty and recent hash from the server set to `DIFFICULTY` and `HASH`, respectively. +#### Managing the Retained DID Set -3. Generate a random 32-bit integer nonce value set to `NONCE`. +[[ref:Gateways]] supporting [[ref:Retention Set]] guidelines ****MUST**** provide an `expiry` value represented as a +[[ref:Unix Timestamp]]. This timestamp precisely indicates when the [[ref:Gateway]] will cease republishing a particular DID, +thus evicting the DID from the [[ref:Gateway]]'s Retained DID Set. This timestamp establishes a binding agreement between the +[[ref:Client]] and the [[ref:Gateway]], and it ****MUST NOT**** be modified once set. -4. Compute the [SHA-256](https://en.wikipedia.org/wiki/SHA-2) hash over `ATTEMPT` where `ATTEMPT` = (`DID` + `HASH` + `NONCE`). +To guarantee a sensible minimum retention period, it is ****RECOMMENDED**** that [[ref:Gateways]] retain DIDs for at least **1 week** +starting from the acceptance of [[ref:Retention Solution]]. -5. Inspect the result of `ATTEMPT`, and ensure it has >= `DIFFICULTY` bits of leading zeroes. +[[ref:Gateways]] ****MAY**** choose to offer an extended grace period before evicting DIDs, particularly for those with a substantial history +with the [[ref:Gateway]], such as DIDs exposed through the [historical resolution API](#historical-resolution). - a. If so, `ATTEMPT` = `RETENTION_PROOF`. +[[ref:Gateways]] ****MAY**** choose to include the `expiry` value as a part of the +[DID Resolution Metadata](https://www.w3.org/TR/did-core/#did-resolution-metadata), during [DID Resolution](#did-resolution), +to aid [[ref:Clients]] in being able to assess whether further proof of work is required. - b. Otherwise, regenerate `NONCE` and go to step 3. +#### Generating a Retention Solution -6. Submit the `RETENTION_PROOF` to the [Gateway API](#register=or-update-a-did). +A [[ref:Retention Solution]] is a form of [proof of work](https://en.bitcoin.it/wiki/Proof_of_work) bound to a specific +DID identifier, using input values supplied by given [gateway](registry/index.html#gateways). The proof of work is performed using +the [SHA-256 hashing algorithm](https://en.wikipedia.org/wiki/SHA-2) over the concatenation of a the `did` identifier and random +[`nonce`](https://en.wikipedia.org/wiki/Cryptographic_nonce) supplied by the user, and a `hash` value +[supplied by the gateway](#get-the-current-difficulty). The result of a given proof of work attempt is referred to as the +`retention` value. -#### Managing the Retained DID Set +The resulting `retention` value is determined to be a valid [[ref:Retention Solution]] based on whether it has the requisite +number of leading zeros defined by the `difficulty`. Difficulty values ****MUST**** be no less than 26 bits of the 256-bit hash value. + +The algorithm, in detail, 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`. -[[ref:Gateways]] adhering to the [[ref:Retention Set]] rules ****SHOULD**** sort DIDs they are retaining by the number of -_leading 0s_ in their [[ref:Retention Proofs]] in descending order, followed by the block hash's index number in -descending order. When a [[ref:Gateway]] needs to reduce its [[ref:retained set]] of DID entries, it ****SHOULD**** -remove entries from the bottom of the list following this sort. +4. Set `RETENTION` equal to the result of (`DID` + `HASH` + `NONCE`). -#### Reporting on Retention Status +5. Compute the [SHA-256](https://en.wikipedia.org/wiki/SHA-2) hash over `ATTEMPT` where `ATTEMPT` = SHA256(`RETENTION_VALUE`). -[[ref:Gateways]] ****MUST**** include the approximate time until retention fall-off in the -[DID Resolution Metadata](https://www.w3.org/TR/did-core/#did-resolution-metadata) of a resolved -[[ref:DID Document]], to aid [[ref:clients]] in being able to assess whether resubmission is required. +6. Inspect the result of `ATTEMPT`, and ensure it has >= `DIFFICULTY` bits of leading zeroes. -:::todo -[](https://github.com/TBD54566975/did-dht-method/issues/74) -Specify how gateways can report on retention guarantees and provide guidance for clients to work with these guarantees. + a. If it does, set `RETENTION_SOLUTION` = `ATTEMPT`. + + b. Otherwise, return to step 3. + +7. Submit the `RETENTION_SOLUTION` to the [Gateway API](#register=or-update-a-did) for write operations. + +:::note +When a [[ref:Client]] submits a valid [[ref:Retention Solution]], compliant [[ref:Gateways]] respond with an `expiry` timestamp. +This timestamp indicates when DID will be evicted from the [[ref:Gateway]]'s [Retained DID Set](#retained-did-set). [[ref:Clients]] +are advised to take note of this `expiry` timestamp and ensure they complete a new [[ref:Retention Challenge]] before the expiration +is reached. By doing so, [[ref:Clients]] can maintain the continuity of their DID's retention and prevent unintended eviction +of their identifier. ::: ### Gateway API -At a minimum, a [[ref:Gateway]] ****MUST**** support the [Relay API](#relay) inspired by [[ref:Pkarr]], which is specified in the subsequent -section. +At a minimum, a [[ref:Gateway]] ****MUST**** support the [Relay API](#relay) inspired by [[ref:Pkarr]], which is specified +in the subsequent section. Expanding on this API, a fully conformant [[ref:Gateway]] ****MUST**** support the following API, which is made available via an [OpenAPI document](#open-api-definition). @@ -807,7 +823,7 @@ On receiving a `GET` request the server submits a mutable get query to [[ref:Mai #### Get the Current Difficulty -Difficulty is exposed as an **OPTIONAL** endpoint based on support of [retention proofs](#retained-did-set). +Difficulty is exposed as an **OPTIONAL** endpoint based on support of the [Retained DID Set](#retained-did-set) feature. - **Method:** `GET` - **Path:** `/difficulty` @@ -815,12 +831,15 @@ Difficulty is exposed as an **OPTIONAL** endpoint based on support of [retention - `200` - Success. - `hash` - **string** - **REQUIRED** - The current hash. - `difficulty` - **integer** - **REQUIRED** - The current difficulty. - - `501` - Retention proofs not supported by this gateway. + - `expiry` - **integer** - An _approximate_ expiry date-time value which ****MUST**** be a [[ref:Unix Timestamp]] + in seconds. The _precise_ expiry date-time value is returned as a part of an [update operation](#register-or-update-a-did). + - `501` - [[ref:Retention Sets]] are not supported by this gateway. ```json { "hash": "000000000000000000022be0c55caae4152d023dd57e8d63dc1a55c1f6de46e7", - "difficulty": 26 + "difficulty": 26, + "expiry": 1715578600 } ``` @@ -836,12 +855,14 @@ Difficulty is exposed as an **OPTIONAL** endpoint based on support of [retention for each DID operation, which ****MUST**** be a [[ref:Unix Timestamp]] in seconds. - `v` - **string** - **REQUIRED** - An unpadded base64URL-encoded [[ref:bencoded]] compressed DNS packet containing the DID Document. - - `retention_proof` - **string** - **OPTIONAL** - A retention proof calculated according to the - [retention proof algorithm](#generating-a-retention-proof). + - `retention_solution` - **string** - **OPTIONAL** - A retention solution calculated according to the + [retention solution algorithm](#generating-a-retention-solution). - **Returns:** `application/json` - `202` - Accepted. The server has accepted the request as valid and will publish to the DHT. + - `expiry` - **string** - **OPTIONAL** – The [[ref:Unix Timestamp]] in seconds indicating when the DID will be evicted + from the [[ref:Gateway]]'s' [[ref:Retained DID Set]]. - `400` - Invalid request. - - `401` - Invalid signature. + - `401` - Invalid signature or retention solution. - `409` - DID already exists with a higher [[ref:sequence number]]. DID may be accepted if the [[ref:Gateway]] supports [historical resolution](#historical-resolution). @@ -850,13 +871,18 @@ Difficulty is exposed as an **OPTIONAL** endpoint based on support of [retention "did": "did:dht:example", "sig": "", "seq": 1234, - "v": "" + "v": "", + "retention_solution": "000000270b7c547aff552f302aad08200b3db815b69bc11ec3f263b7ef755a52" } ``` -Upon receiving a request to register a DID, the Gateway ****MUST**** verify the signature of the request and if valid -publish the DID Document to the DHT. If the DNS Packets contain a `_typ._did.` record, the [[ref:Gateway]] ****MUST**** -index the DID by its type. +Upon receiving a request to register a DID the [[ref:Gateway]] ****MUST**** perform the following steps: + +* Verify the signature of the request and, if valid, publish the [[ref:BEP44]] payload to the DHT. + +* If one is provided, validate the `retention_solution` and, if valid, add the DID to the [[ref:Gateway]]'s [[ref:Retained DID Set]]. + +* If the DNS packet contain a `_typ._did.` record, update the specified indexes with the DID. #### Resolving a DID @@ -872,6 +898,8 @@ index the DID by its type. - `types` - **array** - **OPTIONAL** - An array of [type integers](#type-indexing) for the DID. - `sequence_numbers` - **array** - **OPTIONAL** - An sorted array of integers representing seen [[ref:sequence numbers]], used with [historical resolution](#historical-resolution). + - `expiry` - **integer** - **OPTIONAL** - The [[ref:Unix Timestamp]] in seconds indicating when the DID will be evicted + from the [[ref:Gateway]]'s' [[ref:Retained DID Set]]. - `400` - Invalid request. - `404` - DID not found. @@ -902,28 +930,44 @@ index the DID by its type. }, "dht": "", "types": [1, 4], - "sequence_numbers": [1700356854, 1700461736] + "sequence_numbers": [1700356854, 1700461736], + "expiry": 1715579444 } ``` -Upon receiving a request to resolve a DID, the [[ref:Gateway]] ****MUST**** query the DHT for the [[ref:DID Document]], -and if found, return the document. If the records are not found in the DHT, the [[ref:Gateway]] ****MAY**** fall back -to its local storage. If the DNS Packets contain a `_typ._did.` record, the [[ref:Gateway]] ****MUST**** return the -type index. +Upon receiving a request to resolve a DID, the [[ref:Gateway]] ****MUST**** perform the following steps: -This API is returns a `dht` property which matches the payload of a [Relay GET Request](#relay), +* Query local storage for the [[ref:DID]] record set, and if the [[ref:Gateway]] [is authoritative](#designating-authoritative-gateways) +for the DID, return the stored DIDs. + +* If the [[ref:Gateway]] is not authoritative for the DID, the [[ref:Gateway]] ****MUST**** query the DHT for the +[[ref:DID Document]], and if found, return the record set. If the records are not found in the DHT, the [[ref:Gateway]] +****MAY**** fall back to its local storage. + +* If the DNS Packet contains a `_typ._did.` record, the [[ref:Gateway]] ****MUST**** return the +associated `types` value. + +* If the [[ref:Gateway]] supports [historical resolution](#historical-resolution) and has multiple stored [[ref:Sequence Numbers]] +for the DID, the [[ref:Gateway]] ****MUST**** return the associated `sequence_number` value(s). + +* If the DID is in the [[ref:Gateway]]'s [[ref:Retained DID Set]], the [[ref:Gateway]] ****MUST**** return the +associated `expiry` value. + +:::note +This API returns a `dht` property which matches the payload of a [Relay GET Request](#relay), 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 -[[ref:Gateways]] ****MAY**** choose to support historical resolution, which is to surface different versions of the -same [[ref:DID Document]], sorted by [[ref:sequence number]], according to the rules set out in the section on +[[ref:Gateways]] ****MAY**** choose to support _historical resolution_, which is to surface different versions of the +same [[ref:DID Document]], sorted by [[ref:Sequence Number]], according to the rules set out in the section on [conflict resolution](#conflict-resolution). -Upon [resolving a DID](#resolving-a-did), the Gateway will return the parameter `sequence_numbers` if there exists -historical state for a given [[ref:DID]]. The following API can be used with specific [[ref:sequence numbers]] to fetch +Upon [resolving a DID](#resolving-a-did), the [[ref:Gateway]] will return the value `sequence_numbers` if there exists +historical state for a given [[ref:DID]]. The following API can be used with specific [[ref:Sequence Numbers]] to fetch historical state: - **Method:** `GET` @@ -937,6 +981,8 @@ historical state: 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](#type-indexing) for the DID. + - `expiry` - **integer** - **OPTIONAL** - The [[ref:Unix Timestamp]] in seconds indicating when the DID will be evicted + from the [[ref:Gateway]]'s' [[ref:Retained DID Set]]. - `400` - Invalid request. - `404` - DID not found for the given [[ref:sequence number]]. - `501` - Historical resolution not supported by this gateway. @@ -1017,13 +1063,13 @@ Interoperable DID methods ****MUST**** be registered in ### Conflict Resolution -Per [[ref:BEP44]], [[ref:Gateway]] servers can leverage the `seq` [[ref:sequence number]] to handle conflicts: +Per [[ref:BEP44]], [[ref:Gateway]] servers can leverage the `seq` [[ref:Sequence Number]] to handle conflicts: -> [[ref:Gateways]] receiving a put request where `seq` is lower than or equal to what's already stored on the server, -****MUST**** reject the request. If the [[ref:sequence number]] is equal, and the value is also the same, the server +> [[ref:Gateways]] receiving a put request where `seq` is lower than or equal to what's already stored on the [[ref:Gateway]], +****MUST**** reject the request. If the [[ref:Sequence Number]] is equal, and the value is also the same, the [[ref:Gateway]] ****SHOULD**** reset its timeout counter. -When the [[ref:sequence number]] is equal, but the value is different, servers need to decide which value to accept +When the [[ref:Sequence Number]] is equal, but the value is different, [[ref:Gateways]] need to decide which value to accept and which to reject. To make this determination [[ref:Gateways]] ****MUST**** compare the payloads lexicographically to determine a [lexicographical order](https://en.wikipedia.org/wiki/Lexicographic_order), and reject the payload with a **lower** lexicographical order. @@ -1067,13 +1113,13 @@ the [[ref:DID Document]] more concise. [[ref:Mainline]] offers a limited duration (approximately 2 hours) for retaining records in the DHT. To ensure the verifiability of data signed by a [[ref:DID]], consistent republishing of [[ref:DID Document]] records is crucial. To -address this, it is ****RECOMMENDED**** to use [[ref:Gateways]] equipped with [[ref:Retention Proofs]] support. +address this, it is ****RECOMMENDED**** to use [[ref:Gateways]] with support for a [Retained DID Set](#retained-did-set). ### Rate Limiting To reduce the risk of [Denial of Service Attacks](https://www.cisa.gov/news-events/news/understanding-denial-service-attacks), -spam, and other unwanted traffic, it is ****RECOMMENDED**** that [[ref:Gateways]] require [[ref:Retention Proofs]]. The -use of [[ref:Retention Proofs]] can act as an attack prevention measure, as it would be costly to scale retention proof +spam, and other unwanted traffic, it is ****RECOMMENDED**** that [[ref:Gateways]] require [[ref:Retention Challenges]]. The +use of [[ref:Retention Challenges]] can act as an attack prevention measure, as it would be costly to scale retention proof calculations. [[ref:Gateways]] ****MAY**** choose to explore other rate limiting techniques, such as IP-limiting, or an access-token-based approach.