From e120703741f744216b74d6477b6e072f25ef75c5 Mon Sep 17 00:00:00 2001 From: Gabe <7622243+decentralgabe@users.noreply.github.com> Date: Fri, 24 May 2024 08:28:07 -0700 Subject: [PATCH] Allow for setting custom Verification Method IDs (#226) * tmp * fix test * simple * consistency --- impl/internal/did/did.go | 54 ++- impl/internal/did/did_vectors_test.go | 2 +- .../did/testdata/vector-2-did-document.json | 8 +- .../did/testdata/vector-2-dns-records.json | 2 +- .../testdata/vector-2-public-key-jwk-2.json | 2 +- spec/spec.md | 357 +++++++++--------- 6 files changed, 235 insertions(+), 190 deletions(-) diff --git a/impl/internal/did/did.go b/impl/internal/did/did.go index 797a53a9..72dc9464 100644 --- a/impl/internal/did/did.go +++ b/impl/internal/did/did.go @@ -169,18 +169,25 @@ func CreateDIDDHTDID(pubKey ed25519.PublicKey, opts CreateDIDDHTOpts) (*did.Docu // mark as seen seenIDs[vm.VerificationMethod.ID] = true - // make sure the verification method JWK KID is set to its thumbprint - vm.VerificationMethod.ID = id + "#" + vm.VerificationMethod.PublicKeyJWK.KID - - // e.g. #key-1 -> did:dht:123456789abcdefghi#key-1 - if strings.HasPrefix(vm.VerificationMethod.ID, "#") { - vm.VerificationMethod.ID = id + vm.VerificationMethod.ID + // if verification method ID is set, make sure it's fully qualified + if vm.VerificationMethod.ID != "" { + if strings.HasPrefix(vm.VerificationMethod.ID, "#") { + vm.VerificationMethod.ID = id + vm.VerificationMethod.ID + } else if !strings.Contains(vm.VerificationMethod.ID, "#") { + vm.VerificationMethod.ID = id + "#" + vm.VerificationMethod.ID + } + } else { + // if no verification method ID is set, set it to the JWK thumbprint + thumbprint, err := vm.VerificationMethod.PublicKeyJWK.Thumbprint() + if err != nil { + return nil, fmt.Errorf("failed to calculate JWK thumbprint: %v", err) + } + vm.VerificationMethod.ID = id + "#" + thumbprint + vm.VerificationMethod.PublicKeyJWK.KID = thumbprint } - // e.g. key-1 -> did:dht:123456789abcdefghi#key-1 - if !strings.Contains(vm.VerificationMethod.ID, "#") { - vm.VerificationMethod.ID = id + "#" + vm.VerificationMethod.ID - } + // make sure the JWK KID matches the unqualified VM ID + vm.VerificationMethod.PublicKeyJWK.KID = strings.TrimPrefix(vm.VerificationMethod.ID, id+"#") // if there's no controller, set it to the DID itself if vm.VerificationMethod.Controller == "" { @@ -365,8 +372,20 @@ func (d DHT) ToDNSPacket(doc did.Document, types []TypeIndex, gateways []Authori return nil, err } - keyBase64URL := base64.RawURLEncoding.EncodeToString(pubKeyBytes) - txtRecord := fmt.Sprintf("t=%d;k=%s", keyType, keyBase64URL) + txtRecord := "" + + // calculate the JWK thumbprint + thumbprint, err := vm.PublicKeyJWK.Thumbprint() + if err != nil { + return nil, fmt.Errorf("failed to calculate JWK thumbprint: %v", err) + } + + // only include the id if it's not the JWK thumbprint + unqualifiedVMID := strings.TrimPrefix(vm.ID, doc.ID+"#") + if unqualifiedVMID != thumbprint { + txtRecord += fmt.Sprintf("id=%s;", unqualifiedVMID) + } + txtRecord += fmt.Sprintf("t=%d;k=%s", keyType, base64.RawURLEncoding.EncodeToString(pubKeyBytes)) // only include the alg if it's not the default alg for the key type forKeyType := algIsDefaultForJWK(*vm.PublicKeyJWK) @@ -595,6 +614,7 @@ func (d DHT) FromDNSPacket(msg *dns.Msg) (*DIDDHTDocument, error) { if strings.HasPrefix(record.Hdr.Name, "_k") { unchunkedTextRecord := unchunkTextRecord(record.Txt) data := parseTxtData(unchunkedTextRecord) + vmID := data["id"] keyType := keyTypeLookUp(data["t"]) keyBase64URL := data["k"] controller := data["c"] @@ -634,7 +654,6 @@ func (d DHT) FromDNSPacket(msg *dns.Msg) (*DIDDHTDocument, error) { } // compare pubkey to identity key to see if they're equal, and if they are set the vmID and kid to 0 - var vmID string if identityKey.Equal(pubKey) { vmID = "0" pubKeyJWK.KID = "0" @@ -642,7 +661,14 @@ func (d DHT) FromDNSPacket(msg *dns.Msg) (*DIDDHTDocument, error) { // if the verification method ID is not set, set it to the thumbprint if vmID == "" { - vmID = pubKeyJWK.KID + thumbprint, err := pubKeyJWK.Thumbprint() + if err != nil { + return nil, fmt.Errorf("failed to calculate JWK thumbprint: %v", err) + } + vmID = thumbprint + pubKeyJWK.KID = thumbprint + } else { + pubKeyJWK.KID = vmID } vm := did.VerificationMethod{ diff --git a/impl/internal/did/did_vectors_test.go b/impl/internal/did/did_vectors_test.go index d5d1da9d..1e92e833 100644 --- a/impl/internal/did/did_vectors_test.go +++ b/impl/internal/did/did_vectors_test.go @@ -110,7 +110,7 @@ func TestVectors(t *testing.T) { VerificationMethods: []VerificationMethod{ { VerificationMethod: did.VerificationMethod{ - ID: secpJWK.KID, + ID: "sig", Type: cryptosuite.JSONWebKeyType, Controller: "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y", PublicKeyJWK: &secpJWK, diff --git a/impl/internal/did/testdata/vector-2-did-document.json b/impl/internal/did/testdata/vector-2-did-document.json index 5d82b7eb..7936e86b 100644 --- a/impl/internal/did/testdata/vector-2-did-document.json +++ b/impl/internal/did/testdata/vector-2-did-document.json @@ -16,7 +16,7 @@ } }, { - "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw", + "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#sig", "type": "JsonWebKey", "controller": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y", "publicKeyJwk": { @@ -25,13 +25,13 @@ "x": "1_o0IKHGNamet8-3VYNUTiKlhVK-LilcKrhJSPHSNP0", "y": "qzU8qqh0wKB6JC_9HCu8pHE-ZPkDpw4AdJ-MsV2InVY", "alg": "ES256K", - "kid": "0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw" + "kid": "sig" } } ], "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"], + "assertionMethod": ["did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0", "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#sig"], + "capabilityInvocation": ["did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0", "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#sig"], "capabilityDelegation": ["did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"], "service": [ { diff --git a/impl/internal/did/testdata/vector-2-dns-records.json b/impl/internal/did/testdata/vector-2-dns-records.json index 4b6436ae..67ca934b 100644 --- a/impl/internal/did/testdata/vector-2-dns-records.json +++ b/impl/internal/did/testdata/vector-2-dns-records.json @@ -39,7 +39,7 @@ "name": "_k1._did.", "type": "TXT", "ttl": 7200, - "rdata": ["t=1;k=Atf6NCChxjWpnrfPt1WDVE4ipYVSvi4pXCq4SUjx0jT9;c=did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y"] + "rdata": ["id=sig;t=1;k=Atf6NCChxjWpnrfPt1WDVE4ipYVSvi4pXCq4SUjx0jT9;c=did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y"] }, { "name": "_s0._did.", diff --git a/impl/internal/did/testdata/vector-2-public-key-jwk-2.json b/impl/internal/did/testdata/vector-2-public-key-jwk-2.json index 35dcf9fa..a55416c9 100644 --- a/impl/internal/did/testdata/vector-2-public-key-jwk-2.json +++ b/impl/internal/did/testdata/vector-2-public-key-jwk-2.json @@ -4,5 +4,5 @@ "x": "1_o0IKHGNamet8-3VYNUTiKlhVK-LilcKrhJSPHSNP0", "y": "qzU8qqh0wKB6JC_9HCu8pHE-ZPkDpw4AdJ-MsV2InVY", "alg": "ES256K", - "kid": "0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw" + "kid": "sig" } \ No newline at end of file diff --git a/spec/spec.md b/spec/spec.md index 76371e60..1f71631f 100644 --- a/spec/spec.md +++ b/spec/spec.md @@ -1,27 +1,27 @@ The DID DHT Method Specification 1.0 ================== -**Specification Status**: Working Draft +**Specification Status**: Implementer's Draft -**Latest Draft:** [https://did-dht.com](https://did-dht.com) +**Latest Draft**: [https://did-dht.com](https://did-dht.com) -**Registry:** [https://did-dht.com/registry](https://did-dht.com/registry) +**Registry**: [https://did-dht.com/registry](https://did-dht.com/registry) -**Draft Created:** October 20, 2023 +**Draft Created**: October 20, 2023 -**Last Updated:** May 14, 2024 +**Last Updated**: May 22, 2024 -**Editors:** +**Editors**: ~ [Gabe Cohen](https://github.com/decentralgabe) ~ [Daniel Buchner](https://github.com/csuwildcat) -**Contributors:** +**Contributors**: ~ [Moe Jangda](https://github.com/mistermoe) ~ [Frank Hinek](https://github.com/frankhinek) ~ [Henry Tsai](https://github.com/thehenrytsai) ~ [Kendall Weihe](https://github.com/KendallWeihe) -**Participate:** +**Participate**: ~ [GitHub repo](https://github.com/TBD54566975/did-dht) ~ [File a bug](https://github.com/TBD54566975/did-dht/issues) ~ [Commit history](https://github.com/TBD54566975/did-dht/commits/main) @@ -96,7 +96,7 @@ the [[ref:z-base-32]] encoded public key portion of the [[ref:Identity Key]]. [[ref:Mainline DHT]]. The public key portion is encoded using [[ref:z-base-32]] and represented in the [[ref:DID Suffix]]. 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]] +[[def:DNS Resource Records, DNS Resource Record, DNS Packet]] ~ An efficient format for representing [[ref:DID Documents]] and providing semantics pertinent to DID DHT, such as TTLs, caching, and different record types (e.g. `NS`, `TXT`). Follows [[spec:RFC1035]]. @@ -208,13 +208,13 @@ up a DNS packet [[spec:RFC1034]] [[spec:RFC1035]], which is then stored in the [ | ------------ | ---- | ------ | ------------------------------------------------------------ | | _did.``. | 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=`` | -| _k1._did. | TXT | 7200 | t=1;k=`` | +| _k1._did. | TXT | 7200 | id=abcd;t=1;k=`` | | _k2._did. | TXT | 7200 | t=1;k=`` | | _s0._did. | TXT | 7200 | id=domain;t=LinkedDomains;se=https://foo.com | | _s1._did. | TXT | 7200 | id=dwn;t=DecentralizedWebNode;se=https://dwn.tbddev.org/dwn5 | ::: note -The recommended TTL value is 7200 seconds (2 hours), the default TTL for [[ref:Mainline]] records. +The ****RECOMMENDED**** TTL value is 7200 seconds (2 hours), the default TTL for [[ref:Mainline]] records. ::: - The [Root Record](#root-record) serves as a "map" to reconstruct a [[ref:DID Document]] from a DNS packet. @@ -233,7 +233,8 @@ each `key` or `service` as attributes. - `TXT` records ****MAY**** exceed 255 characters as per [[spec:RFC1035]]. Records exceeding 255 characters are represented as multiple strings, which upon DID Document reconstruction, can be concatenated to a single value. -- DNS packets ****MUST**** be compressed as per [[spec:RFC1035]] section 4.1.4 before transmission. +- DNS packets ****MUST**** be compressed as per [[spec:RFC1035]] +[section 4.1.4](https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4) before transmission. #### Root Record @@ -262,13 +263,13 @@ Additionally: - Verification Relationships (`auth`, `asm`, `agm`, `inv`, `del`) without any members ****MUST**** be omitted. -- If there are no [Services](#services) the `svc` property ****MUST**** be omitted. +- If there are no [Services](#services), the `svc` property ****MUST**** be omitted. -**Example Root Record** +**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 +| 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 @@ -282,8 +283,8 @@ 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 [[ref:DID Document]] and -its corresponding DNS packet if the properties are registered in the +- Additional properties not defined by this specification ****MAY**** be represented in a [[ref:DID Document]] +and its corresponding DNS packet if the properties are registered in the [additional properties registry](registry/index.html#additional-properties). The subsequent instructions serve as a reference for mapping DID Document properties to @@ -305,7 +306,7 @@ list of controller DID identifiers. To ensure that the DID controller is authorized to make changes to the DID Document, the controller for the [[ref:Identity Key]] Verification Method ****MUST**** be contained within the controller property. -**Example Controller Record** +**Example Controller Record**: | Name | Type | TTL | Rdata | | ---------- | ---- | ---- | ---------------- | @@ -322,7 +323,7 @@ A `did:dht` document ****MAY**** have multiple identifiers using the [alsoKnownA - The [Also Known As](https://www.w3.org/TR/did-core/#also-known-as) record's **data** is represented as a comma-separated list of DID identifiers. -**Example AKA Record** +**Example AKA Record**: | Name | Type | TTL | Rdata | | ---------- | ---- | ---- | ---------------------------------- | @@ -337,18 +338,25 @@ as a `_kN._did.` record where `N` is the zero-indexed positional index of a give indicating a Text record. - Each [Verification Method](https://www.w3.org/TR/did-core/#verification-methods) record's **rdata** is represented by the form -`t=M;k=N;a=O` `M` is the index of the key's type from the [key type index](registry/index.html#key-type-index), `N` is the unpadded -base64URL [[spec:RFC4648]] representation of the public key, and `O` is the `JWK` `alg` identifier of the key. +`id=M;t=N;k=O;a=P` where `M` is an **optional** Verification Method Identifier, `N` is the index of the key's type from the +[key type index](registry/index.html#key-type-index), `O` is the unpadded base64URL [[spec:RFC4648]] representation of the public +key, and `P` is the `JWK` `alg` identifier of the key. It is important to note that the value of `O` represents the byte +representation of the public key itself, rather than an encoded JWK. - The [[ref:Identity Key]] ****MUST**** always be at index `_k0`. - - Verification Method `id`s ****MUST**** be omitted as they can be computed deterministically according to the - rules specified in the section on [representing keys](#representing-keys). When reconstructing the DID Document from - it's DNS Packet representation the `id` is used `0` for the [[ref:Identity Key]], and the JWK Thumbprint - [[spec:RFC7638]] for all other keys. + - 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](#representing-keys). + Additionally: - - The `a` property ****MUST**** be omitted if it is assigned to the default value specified in the - [key type index](registry/index.html#key-type-index). If it differs from the default value, it ****MUST**** be present. + - For the [[ref:Identity Key]], the `id` value ****MUST**** be set to `0`. + + - For all other keys, if an `id` value is present in the record, it is used as the `id` value for the Verification + Method. If there is no `id` value set, the JWK Thumbprint [[spec: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](registry/index.html#key-type-index). If it differs from the default value, it + ****MUST**** be present. - [Verification Methods](https://www.w3.org/TR/did-core/#verification-methods) ****MAY**** have an _optional_ **controller** property represented by `c=C` where `C` is the identifier of the verification method's controller (e.g. `t=N;k=O;c=C`). If @@ -380,7 +388,7 @@ The following table acts as a map between Verification Relationship types and th The record data is uniform across [Verification Relationships](https://www.w3.org/TR/did-core/#verification-relationships), represented as a comma-separated list of key references. -**Example Verification Relationship Records** +**Example Verification Relationship Records**: | Verification Relationship | Rdata in the Root Record | |----------------------------------------------------|----------------------------------------------| @@ -398,13 +406,15 @@ the zero-indexed positional index of the Service (e.g. `_s0`, `_s1`). - Each [Service](https://www.w3.org/TR/did-core/#services) record's **type** is `TXT`, indicating a Text record. - Each [Service](https://www.w3.org/TR/did-core/#services) record's **data** is represented with the form `id=M;t=N;se=O` -where `M` is the Service's ID, `N` is the Service's Type and `O` is the Service's URI. +where `M` is the Service's ID, `N` is the Service's `type` and `O` is the Service's URI. - - Multiple service endpoints can be represented as an array (e.g. `id=dwn;t=DecentralizedWebNode;se=https://dwn.org/dwn1,https://dwn.org/dwn2`) + - 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`) + - 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](registry/index.html#additional-properties). -**Example Service Record** +**Example Service Record**: | Name | Type | TTL | Rdata | | --------- | ---- | ---- | -------------------------------------------------------- | @@ -417,7 +427,7 @@ is a comma-separated list of all IDs for each Service. A sample transformation of a fully-featured DID Document to a DNS packet is exemplified as follows: -**DID Document** +**DID Document**: ```json { @@ -475,7 +485,7 @@ A sample transformation of a fully-featured DID Document to a DNS packet is exem } ``` -**DNS Resource Records** +**DNS Resource Records**: | Name | Type | TTL | Rdata | | ------------ | ---- | ----- | ---------------------------------------------------------------------------------- | @@ -500,26 +510,27 @@ To create a `did:dht` document, the process is as follows: 2. Construct a conformant JSON representation of a [[ref:DID Document]]. a. The document ****MUST**** include a [Verification Method](https://www.w3.org/TR/did-core/#verification-methods) with - the [[ref:Identity Key]]. The `id` property of this Verification Method ****MUST**** be `0` and type of `JsonWebKey` as defined - by [[ref:VC-JOSE-COSE]]. The key ****MUST**** be represented as a `publicKeyJwk` as per [[spec:RFC7517]] with a `kid` of `0`. + the [[ref:Identity Key]]. The `id` property of this Verification Method ****MUST**** be `0` and type of `JsonWebKey` + as defined by [[ref:VC-JOSE-COSE]]. The key ****MUST**** be represented as a `publicKeyJwk` as per [[spec:RFC7517]] + with a `kid` of `0`. b. The [[ref:Identity Key]] ****MUST**** have the [Verification Relationships](#verification-relationships) _Authentication_, _Assertion_, _Capability Invocation_, and _Capability Delegation_. c. The document can include any number of other [core properties](https://www.w3.org/TR/did-core/#core-properties); always representing key material as a `JWK` as per [[spec:RFC7517]]. In addition to the properties required by - the `JWK` specification, the `alg` property ****MUST**** always be present. Default algorithms are defined per key - type in the [indexed types registry](registry/index.html#indexed-types). + the `JWK` specification, the `alg` property ****MUST**** always be present in the DID Document representation. + Default algorithm values are defined per key type in the [indexed types registry](registry/index.html#indexed-types). 3. Map the output [[ref:DID Document]] to a DNS packet as outlined in [property mapping](#property-mapping). -4. Compress the DNS packet as per [[spec:RFC1035]] section 4.1.4. +4. Compress the DNS packet as per [[spec:RFC1035]] [section 4.1.4](https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4). 5. Construct a [[ref:BEP44]] conformant mutable put message. a. `v` ****MUST**** be set to a [[ref:bencoded]] compressed DNS packet from the prior step. - b. `seq` ****MUST**** be set to the current [[ref:Unix Timestamp]] in seconds. + b. `seq` ****MUST**** be set to the current [[ref:Unix Timestamp]] in **seconds**. 6. Submit the result of to the [[ref:DHT]] via a [[ref:Mainline]] node, or a [[ref:Gateway]], with the identifier created in step 1. @@ -538,14 +549,19 @@ To read a `did:dht` document, the process is as follows: 2. Decode the resulting [[ref:BEP44]] response's `v` value using [[ref:bencode]]. -3. Uncompress the DNS packet according to [[spec:RFC1035]] section 4.1.4. +3. Uncompress the DNS packet according to [[spec:RFC1035]] [section 4.1.4](https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4). 4. Reverse the DNS [property mapping](#property-mapping) process and re-construct a conformant [[ref:DID Document]]. a. Identify the [[ref:Identity Key]] using the [[ref:suffix]] of the `did:dht` identifier, with record name `_k0._did`, - and set it's Verification Method ID to `0`. + and set it's Verification Method ID and JWK `kid` to `0`. + + b. For all other keys, assign the Verification Method ID as follows: + + i. If an `id` value is provided, use that value as the Verification Method ID and JWK `kid`. - b. Set all other key Verification Method ID values to their JWK Thumbprint as per [[spec:RFC7638]] + ii. If no `id` value is specified, calculate the key's JWK Thumbprint according to [[spec:RFC7638]] + and use it as the Verification Method ID and JWK `kid`. c. Expand all identifiers (i.e. Verification Methods, Services, etc. `id`s ) to their fully-qualified form (e.g. `did:dht:uodqi99wuzxsz6yx445zxkp8ddwj9q54ocbcg8yifsqru45x63kj#0` @@ -599,20 +615,21 @@ root Verification Methods and identifiers. To establish a cryptographic linkage between the old and new [[ref:DID Documents]], adhere to the following steps: -1. Using the old [[ref:Identity Key]], sign over the new [[ref:Identity Key]] using EdDSA [[spec:RFC8032]]. +1. Using the old [[ref:Identity Key]], sign over the new [[ref:Identity Key]] using the [[ref:Ed25519]] variant of the +EdDSA algorithm [[spec:RFC8032]]. 2. Encode the resulting signature data using the unpadded base64URL [[spec:RFC4648]] scheme. -3. Set the resulting string as the data for a new [[ref:DNS Resource Record]], called a _previous record_, in +3. Set the resulting string as the data for a new [[ref: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: +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` where `M` is the identifier of the previous DID, +- The Previous record's **data** is represented with the form `id=M;s=N` where `M` is the identifier of the previous DID, and `N` is the the unpadded base64URL signature from step (3) above. | Name | Type | TTL | Rdata | @@ -652,11 +669,11 @@ records is outlined as follows: ### Type Indexing -Type indexing is an **OPTIONAL** feature that enables DIDs to become **discoverable**, by flagging themselves as being +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 a part of the DID Document, but rather as part of the DNS packet. This allows for DIDs to be indexed by type by [[ref: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 +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. @@ -666,18 +683,18 @@ type index record. This record is of the following format: - 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](registry/index.html#indexed-types). -**Example Type Index Record** +**Example Type Index Record**: | Name | Type | TTL | Rdata | | ---------- | ---- | ---- | --------- | | _typ._did. | TXT | 7200 | id=0,1,2 | -Types can be found and registered in the [indexed types registry](registry/index.html#indexed-types). +Types can be discovered, and registered, in the [indexed types registry](registry/index.html#indexed-types). ::: note Identifying entities through type-based indexing is a relatively unreliable practice. It serves -as an initial step in recognizing the identity linked to a [[ref:DID]]. To validate identity assertions more robustly, -it is essential to delve deeper, employing tools like verifiable credentials and the examination of related data. +as an initial step in recognizing the identity linked to a [[ref: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 @@ -694,7 +711,7 @@ optional integration of these gateways into a registry system. ### Discovering Gateways -As an **OPTIONAL** feature of the DID DHT Method, operators of a [[ref:Gateway]] ****MAY**** choose to make their server +As an **optional** feature of the DID DHT Method, operators of a [[ref:Gateway]] ****MAY**** choose to make their server discoverable through a [[ref:Gateway Registry]]. This feature allows for easy location through various internet-based discovery mechanisms. [[ref:Gateway Registries]] can vary in nature, encompassing a spectrum from centrally managed directories to diverse decentralized systems including databases, ledgers, or other structures. @@ -789,26 +806,29 @@ The algorithm for validating a [[ref:Retention Solution]] is as follows: a. If the `COMPUTED_HASH` has the required number of leading zeros, the [[ref: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. + 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 [[ref:Retention Solution]] is deemed valid, the [[ref:Gateway]] accepts the write request and proceeds to store the DID document -in its [[ref:Retained DID Set]]. The [[ref:Gateway]] generates an `expiry` timestamp based on its retention policy and includes it in the -response to the [[ref:Client]]. +If the [[ref:Retention Solution]] is deemed valid, the [[ref:Gateway]] accepts the write request and proceeds to store +the DID document in its [[ref:Retained DID Set]]. The [[ref:Gateway]] generates an `expiry` timestamp based on its +retention policy and includes it in the response to the [[ref:Client]]. -By validating the [[ref:Retention Solution]], the [[ref:Gateway]] ensures that the [[ref: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 [[ref:Retained DID Set]] -system. It is important for [[ref:Gateways]] to consistently apply the validation logic and reject any write requests that do not include a valid -[[ref:Retention Solution]]. This helps prevent abuse and ensures that only [[ref:Clients]] who have invested the required computational effort can -benefit from the retention feature. [[ref:Gateways]] ****SHOULD**** regularly update their hash value to prevent pre-computation attacks and ensure -the uniqueness and freshness of the [[ref:Retention Solutions]]. The recommended hash refresh window is **10 minutes**. +By validating the [[ref:Retention Solution]], the [[ref:Gateway]] ensures that the [[ref: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 [[ref:Retained DID Set]] system. It is important for [[ref:Gateways]] to consistently +apply the validation logic and reject any write requests that do not include a valid [[ref:Retention Solution]]. This +helps prevent abuse and ensures that only [[ref:Clients]] who have invested the required computational effort can benefit +from the retention feature. [[ref:Gateways]] ****SHOULD**** regularly update their hash value to prevent pre-computation +attacks and ensure the uniqueness and freshness of the [[ref:Retention Solutions]]. The recommended hash refresh window +is **10 minutes**. #### Managing the Retained DID Set [[ref:Gateways]] supporting [[ref:Retention Set]] feature ****MUST**** provide an `expiry` value represented as a [[ref:Unix Timestamp]] as a part of the [Gateway API](#gateway-api). 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. +[[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. Further, it is ****RECOMMENDED**** that [[ref:Gateway]]'s adhere to the following guidance: @@ -827,10 +847,10 @@ When a [[ref:Client]] submits a fresh [[ref:Retention Solution]] for a DID alrea [[ref:Gateway]] ****SHOULD**** update the DID's expiry timestamp, effectively resetting the expiry window and granting a renewed retention period. -* When a [[ref:Gateway]] reaches its storage capacity or experiences high load, it is ****RECOMMENDED**** that it significantly -increases the `difficulty` parameter for [[ref:Retention Challenges]]. By raising the `difficulty`, the [[ref:Gateway]] can -effectively limit the acceptance of new DIDs into its [[ref:Retained DID Set]], ensuring the stability and performance of the -server under resource constraints. +* When a [[ref:Gateway]] reaches its storage capacity or experiences high load, it is ****RECOMMENDED**** that it +significantly increases the `difficulty` parameter for [[ref:Retention Challenges]]. By raising the `difficulty`, the +[[ref:Gateway]] can effectively limit the acceptance of new DIDs into its [[ref:Retained DID Set]], ensuring the +stability and performance of the server under resource constraints. ### Gateway API @@ -855,16 +875,16 @@ headers as follows: On receiving a `PUT` request the server verifiers the `sig` and submits a mutable put to [[ref:Mainline]] as per [[ref:BEP44]]. -- **Method:** `PUT` -- **Path:** `/:id` +- **Method**: `PUT` +- **Path**: `/:id` - `id` - **string** - **REQUIRED** - The [[ref:z-base-32]] encoded [[ref:Identity Key]], equivalent to the suffix of the DID DHT identifier. -- **Request Body:** `application/octet-stream` +- **Request Body**: `application/octet-stream` - The binary representation of `[]` where: - `sig` - represents the 64-byte [[ref:BEP44]] payload signature. - `seq` - represents the 8-byte unsigned 64-bit integer big-endian representation of a [[ref:BEP44]] sequence number. - `v` - represents between 0-1000 bytes of a [[ref:bencoded]] compressed DNS packet. -- **Returns:** `application/json` +- **Returns**: `application/json` - `200` - Success. - `400` - Bad request if the `sig` is not valid. - `500` - Internal server error. @@ -873,11 +893,11 @@ On receiving a `PUT` request the server verifiers the `sig` and submits a mutabl On receiving a `GET` request the server submits a mutable get query to [[ref:Mainline]] as per [[ref:BEP44]]. -- **Method:** `GET` -- **Path:** `/:id` +- **Method**: `GET` +- **Path**: `/:id` - `id` - **string** - **REQUIRED** - The [[ref:z-base-32]] encoded [[ref:Identity Key]], equivalent to the suffix of the DID DHT identifier. -- **Returns:** `application/octet-stream` +- **Returns**: `application/octet-stream` - `200` - Success. The binary representation of `[]` where: - `sig` - represents the 64-byte [[ref:BEP44]] payload signature. - `seq` - represents the 8-byte unsigned 64-bit integer big-endian representation of a [[ref:BEP44]] sequence number. @@ -889,9 +909,9 @@ On receiving a `GET` request the server submits a mutable get query to [[ref:Mai Challenge is exposed as an endpoint to facilitate functionality pertaining to the [Retained DID Set](#retained-did-set), surfacing a [[ref:Retention Challenge]]. -- **Method:** `GET` -- **Path:** `/challenge` -- **Returns:** `application/json` +- **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 [[ref:Retention Solution]]. - `hash_source` - **string** - **REQUIRED** - The source of the hash as defined by the [Hash Source Registry](registry/index.html#hash-source). @@ -903,7 +923,7 @@ surfacing a [[ref:Retention Challenge]]. - `501` - [[ref:Retention Sets]] are not supported by this gateway. - `503` - [[ref:Retention Sets]] have been temporarily disabled. -**Example Challenge Response** +**Example Challenge Response**: ```json { @@ -916,10 +936,10 @@ surfacing a [[ref:Retention Challenge]]. #### Register or Update a DID -- **Method:** `PUT` -- **Path:** `/did/:id` +- **Method**: `PUT` +- **Path**: `/did/:id` - `id` - **string** - **REQUIRED** - ID of the DID to publish. -- **Request Body:** – application/json +- **Request Body**: – application/json - `did` - **string** - **REQUIRED** - The DID to register or update. - `sig` - **string** - **REQUIRED** - An unpadded base64URL-encoded signature of the [[ref:BEP44]] payload. - `seq` - **integer** - **REQUIRED** - A [[ref:sequence number]] for the request. This number ****MUST**** be unique @@ -928,7 +948,7 @@ surfacing a [[ref:Retention Challenge]]. the DID Document. - `retention_solution` - **string** - **OPTIONAL** - A retention solution calculated according to the [retention solution algorithm](#generating-a-retention-solution). -- **Returns:** `application/json` +- **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]]. @@ -938,7 +958,7 @@ surfacing a [[ref:Retention Challenge]]. supports [historical resolution](#historical-resolution). - `503` - [[ref:Retention Sets]] have been temporarily disabled. -**Example DID Registration Request** +**Example DID Registration Request**: ```json { @@ -965,10 +985,10 @@ Requests without a `retention_solution` have **no retention guarantees**. #### Resolving a DID -- **Method:** `GET` -- **Path:** `/did/:id` +- **Method**: `GET` +- **Path**: `/did/:id` - `id` - **string** - **REQUIRED** - ID of the DID to resolve. -- **Returns:** `application/json` +- **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 [[ref:BEP44]] @@ -982,7 +1002,7 @@ Requests without a `retention_solution` have **no retention guarantees**. - `400` - Invalid request. - `404` - DID not found. -**Example DID Resolution Response** +**Example DID Resolution Response**: ```json { @@ -1028,8 +1048,8 @@ for the DID, return the stored DIDs. * 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 [[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. @@ -1051,19 +1071,19 @@ Upon [resolving a DID](#resolving-a-did), the [[ref:Gateway]] will return the va historical state for a given [[ref:DID]]. The following API can be used with specific [[ref:Sequence Numbers]] to fetch historical state: -- **Method:** `GET` -- **Path:** `/did/:id?seq=:sequence_number` +- **Method**: `GET` +- **Path**: `/did/:id?seq=:sequence_number` - `id` - **string** - **REQUIRED** - ID of the DID to resolve - `seq` - **integer** - **OPTIONAL** - [[ref:Sequence number]] of the DID to resolve -- **Returns:** `application/json` +- **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 [[ref: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](#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]]. + - `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. @@ -1075,24 +1095,24 @@ follows the same process as [updating a DID](#register-or-update-a-did), but wit [section on deactivation](#deactivate). Upon receiving a request to deactivate a DID, the Gateway ****MUST**** verify the signature of the request, and if valid, -stop [[ref:republishing]] the DHT. If the DNS Packets contain a `_typ._did.` record, the Gateway ****MUST**** stop indexing the -type(s) for the DID. +stop [[ref: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` +- **Method**: `GET` +- **Path**: `/did/types` +- **Returns**: `application/json` - `200` - Success. - **array** - An array of objects describing the known types of the following form: - `type` - **integer** - **REQUIRED** - An integer representing the [type](#type-indexing). - `description` - **string** - **REQUIRED** - A string describing the [type](#type-indexing). - `404` - Type indexing not supported. +**Example Type Index Response**: -**Example Type Index Response** ```json [ { @@ -1108,20 +1128,20 @@ type(s) for the DID. **Get a Specific Type** -- **Method:** `GET` -- **Path:** `/did/types/:id` +- **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` +- **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** +**Example Type Response**: ```json [ @@ -1135,7 +1155,7 @@ 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 +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 [[ref:Ed25519]] key format. By adopting this optional extension, users can maintain their current DIDs without any changes. Additionally, they gain the ability to add extra information to their DIDs. This is achieved by either publishing or retrieving @@ -1150,14 +1170,14 @@ Interoperable DID methods ****MUST**** be registered in 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 [[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. +> [[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, [[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. +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. ### Size Constraints @@ -1172,10 +1192,9 @@ The following guidance on representations of keys and their identifiers using th - For the [[ref:Identity Key]], both the Verification Method `id` and JWK `id` ****MUST**** be set to `0`. -- For all other Verification Methods, JWK identifiers (`kid`s) ****MUST**** be set to the key's JWK Thumbprint -as per [[spec:RFC7638]]. - -- For all keys besides the [[ref:Identity Key]], the Verification Method `id` is set to the JWK's `kid` value. +- For all keys besides the [[ref:Identity Key]], the Verification Method `id` and the JWK `kid` is set to the +provided `id` value, if present. If no `id` value is specified, the Verification Method's `id` value and the JWK +`kid` values are set to the key's JWK Thumbprint calculated according to [[spec:RFC7638]]. - [[ref: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 @@ -1187,12 +1206,12 @@ to Verification Methods (e.g. `did:dht:uodqi99wuzxsz6yx445zxkp8ddwj9q54ocbcg8yif #### Historical Key State Rotating keys is a widely recommended security practice. However, if you frequently rotate keys in a -[[ref:DID Document]], this can lead to an increase in the document's size due to the accumulation of old keys. -This, in turn, can enlarge the size of the corresponding DNS packet. To manage this issue, while still distinguishing +[[ref:DID Document]], this leads to an increase in the document's size due to the accumulation of old keys. +This, 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](https://www.w3.org/TR/did-core/#services). This property allows for the specification -of services that are dedicated to storing signed records of the historical key states. By doing this, it helps to keep -the [[ref:DID Document]] more concise. +of services that are dedicated to storing signed records of the historical key states. Following this practice helps +to keep the [[ref:DID Document]] more concise. ### Republishing Data @@ -1204,10 +1223,10 @@ with [[ref:Gateways]]. ### 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 Challenges]] for -all requests. The use of [[ref:Retention Challenges]] can act as an attack prevention measure, as it would be costly to scale -retention challenge calculations. [[ref:Gateways]] ****MAY**** choose to explore other rate limiting techniques, such as -IP-limiting, or an access-token-based approaches. +spam, and other unwanted traffic, it is ****RECOMMENDED**** that [[ref:Gateways]] require [[ref:Retention Challenges]] +for all requests. The use of [[ref:Retention Challenges]] can act as an attack prevention measure, as it would be +costly to scale retention challenge calculations. [[ref:Gateways]] ****MAY**** choose to explore other rate limiting +techniques, such as IP-limiting, or an access-token-based approaches. ### DID Resolution @@ -1270,9 +1289,9 @@ its historical ordered state. [[ref:Mainline Servers]] or [[ref:Gateways]]. Implementers are encouraged to follow the guidance outlined in [conflict resolution](#conflict-resolution). -- **High Sequence Number** - Since [[ref:Sequence Numbers]] ****MUST**** be second representations of a [[ref:Unix Timestamp]], -it is ****RECOMMENDED**** that [[ref:Gateways]] reject [[ref:Sequence Numbers]] that represent timestamps greater than -**2 hours** into the future to mitigate [timing attack](#data-conflicts) risks. +- **High Sequence Number** - Since [[ref:Sequence Numbers]] ****MUST**** be second representations of a +[[ref:Unix Timestamp]], it is ****RECOMMENDED**** that [[ref:Gateways]] reject [[ref:Sequence Numbers]] that represent +timestamps greater than **2 hours** into the future to mitigate [timing attack](#data-conflicts) risks. ### Data Availability @@ -1321,7 +1340,7 @@ cryptographic foundations, the [[ref:Mainline]] method could become obsolete. A minimal DID Document. -**Identity Public Key JWK:** +**Identity Public Key JWK**: ```json { @@ -1333,7 +1352,7 @@ A minimal DID Document. } ``` -**DID Document:** +**DID Document**: ```json { @@ -1367,7 +1386,7 @@ A minimal DID Document. } ``` -**DNS Resource Records:** +**DNS Resource Records**: | Name | Type | TTL | Rdata | | --------- | ---- | ---- | --------------------------------------------------------------------------------------- | @@ -1376,10 +1395,10 @@ A minimal DID Document. #### Vector 2 -A DID Document with two keys ([[ref:Identity Key]] and an uncompressed secp256k1 key), a service with multiple -endpoints, a gateway, two types to index, an aka, and controller properties. +A DID Document with two keys ([[ref: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:** +**Identity Public Key JWK**: ```json { @@ -1391,13 +1410,13 @@ endpoints, a gateway, two types to index, an aka, and controller properties. } ``` -**secp256k1 Public Key JWK:** +**secp256k1 Public Key JWK**: -With controller: `did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y`. +With controller: `did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y` and `id` value `sig`. ```json { - "kid": "0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw", + "kid": "sig", "alg": "ES256K", "crv": "secp256k1", "kty": "EC", @@ -1406,9 +1425,9 @@ With controller: `did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y`. } ``` -**Key Purposes:** `Assertion Method`, `Capability Invocation`. +**Key Purposes**: `Assertion Method`, `Capability Invocation`. -**Service:** +**Service**: ```json { @@ -1418,11 +1437,11 @@ With controller: `did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y`. } ``` -**Gateway:**: `gateway1.example-did-dht-gateway.com`. +**Gateway**: `gateway1.example-did-dht-gateway.com`. -**Types:** `1`, `2`, `3`. +**Types**: `1`, `2`, `3`. -**DID Document:** +**DID Document**: ```json { @@ -1443,11 +1462,11 @@ With controller: `did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y`. } }, { - "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw", + "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#sig", "type": "JsonWebKey", "controller": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y", "publicKeyJwk": { - "kid": "0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw", + "kid": "sig", "alg": "ES256K", "crv": "secp256k1", "kty": "EC", @@ -1480,18 +1499,18 @@ With controller: `did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y`. } ``` -**DNS Resource Records:** +**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 | 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 | +| 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 @@ -1499,7 +1518,7 @@ A DID Document with two keys — the [[ref:Identity Key]] and an X25519 key used 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:** +**Identity Public Key JWK**: ```json { @@ -1511,7 +1530,7 @@ what is specified in the registry. The DID also has two gateway records and a se } ``` -**X25519 Public Key JWK:** +**X25519 Public Key JWK**: ```json { @@ -1523,9 +1542,9 @@ what is specified in the registry. The DID also has two gateway records and a se } ``` -**Key Purposes:** `Key Agreement`. +**Key Purposes**: `Key Agreement`. -**Service:** +**Service**: ```json { @@ -1535,13 +1554,13 @@ what is specified in the registry. The DID also has two gateway records and a se } ``` -**Gateways:** `gateway1.example-did-dht-gateway.com`, `gateway2.example-did-dht-gateway.com`. +**Gateways**: `gateway1.example-did-dht-gateway.com`, `gateway2.example-did-dht-gateway.com`. -**Previous DID:** - - ID: `did:dht:pxoem5sfzxxxrnrwfgiu5i5wc7epouy1jk9zb7ad159dsxbxy8io`. +**Previous DID**: + - ID: `did:dht:x3heus3ke8fhgb5pbecday9wtbfynd6m19q4pm6gcf5j356qhjzo`. - Signature: `Tt9DRT6J32v7O2lzbfasW63_FfagiMHTHxtaEOD7p85zHE0r_EfiNleyL6BZGyB1P-oQ5p6_7KONaHAjr2K6Bw`. -**DID Document:** +**DID Document**: ```json { @@ -1597,7 +1616,7 @@ what is specified in the registry. The DID also has two gateway records and a se } ``` -**DNS Resource Records:** +**DNS Resource Records**: | Name | Type | TTL | Rdata | | ---------- | ---- | ---- | ----------- |