§ Peer DID Method Specification

Specification Status: v1.0 Draft

Latest Draft:

https://github.com/decentralized-identity/peer-did-method-spec

Editors:

Authors

§ Abstract

This document defines a “peer” DID Method that conforms to the DID Spec. The method can be used independent of any central source of truth, and is intended to be cheap, fast, scalable, and secure. It is suitable for most private relationships between people, organizations, and things. We expect that peer-to-peer relationships in every blockchain ecosystem can benefit by offloading pairwise and n-wise relationships to peer DIDs.

There are reasonable, tested did:peer libraries for python and java. It is convenient to use with DIDComm v2.

§ Introduction

§ Overview

This section is non-normative.

Most documentation about decentralized identifiers (DIDs) describes them as identifiers that are rooted in a public source of truth like a blockchain, a database, a distributed filesystem, or similar. This publicness lets arbitrary parties resolve the DIDs to an endpoint and keys. It is an important feature for many use cases.

However, the vast majority of relationships between people, organizations, and things have simpler requirements. When Alice (Corp|Device) and Bob want to interact, there are exactly and only 2 parties in the world who should care: Alice and Bob. Instead of arbitrary parties needing to resolve their DIDs, only Alice and Bob do. Peer DIDs are perfect in these cases. In many ways, peer DIDs are to public, blockchain-based DIDs what Ethereum Plasma or state channels are to on-chain smart contracts— or what Bitcoin’s Lightning Network is to on-chain cryptopayments. They move the bulk of interactions off-chain, but offer options to connect back to a chain-based ecosystem as needed. Peer DIDs create the conditions for people, organizations and things to have full control of their end of the digital relationships they sustain.

Some formal terminology may make the application of this insight to DIDs clearer:

Anywise DID
A DID intended for use with an unknowable number of parties (e.g., the global public or some subset thereof).
Pairwise DID
A DID intended to be known by its subject and exactly one other party (e.g., one usable in the Alice and Bob example just above).
N-wise DID
A DID intended to be known by exactly N enumerated parties including its subject. A business partnership with 3 members might be a modeled with n-wise DIDs. Pairwise DIDs are just a special case of an N-wise DID (N = 2).

Generally, an anywise DID needs to be resolvable by strangers (i.e. publicly anchored DID). These strangers can use the DID to reference its subject (usually by resolving it on a public ledger) without establishing a relationship. On the other hand, pairwise and n-wise DIDs only need to be resolvable by the parties in the relationship, and each party in the relationship has to contribute a DID to make the relationship work. Because of the reciprocal nature of DID usage in enumerated relationships like this, we call the parties “peers”, and it is this dynamic that gives our DID method its name.

§ Benefits

This section is non-normative.

Peer DIDs are not suitable for anywise use cases, which are usually public by intent. However, peer DIDs have certain virtues that make them desirable for private relationships between a small number of enumerable parties:

For more on when peer DIDs do and do not make sense, see Comparison to Other DID Methods in the Appendices.

§ Core Characteristics

§ Method Name

The method name that identifies this DID method SHALL be: peer

A DID that uses this method MUST begin with the following prefix: did:peer:. Per the DID specification, this string MUST be in lowercase. The remainder of the DID, after the prefix, is the method specific identifier (MSI) described below.

§ Target System(s)

This DID method applies to any identity management implementation that meets the following requirement:

§ Method Specific Identifier

The peer DID scheme is defined by the following ABNF (see RFC5234 for syntax):

EXAMPLE
peer-did = "did:peer:" numalgo transform encnumbasis
numalgo = "0" / "1" / "2"
transform = "z"
encnumbasis = 46*BASE58BTC

Peer DIDs use an underlying number with high entropy, called the numeric basis, as the source of their uniqueness. There are two methods for generating this number, as described in the next section of this spec. These methods are represented in the DID value with numalgo == 0 or numalgo == 1.

To build the full MSI, the raw bytes of the numeric basis are prefixed with a multicodec descriptor that makes those bytes self-describing. This descriptor plus the raw bytes are then transformed to text in the manner associated with transform. This yields encnumbasis in the ABNF.

composition of a peer DID value

Composition of a peer DID value

In this version of the spec, the multicodec descriptor for numalgo == 0 is dependent on key type and exactly matches the descriptor that would be used for the same value in did:key. The multicodec descriptor for numalgo == 1 is byte pair 0x12 0x20, which says that what follows is a SHA2-256 hash, 32 bytes long. (The size is included because, although SHA-256 is known to produce 32-byte digests, other hash algorithms have variable-length output, and we could change the hash algorithm in a future version of the spec.) The transform is base58, represented by the multibase prefix z. BASE58BTC in the ABNF means the Bitcoin base58 character inventory; for brevity, we omit the expansion–but see the matching regex for details.

The format of the DID value is intended to be future-proof, offering three expandable self-describing choices. Future versions of the spec may describe additional methods of generating the numeric basis; each new method should be associated with the next unused numalgo decimal digit when it is defined. Likewise, future versions of the spec may choose a different way to transform raw bytes to text, or a different format for the raw bytes of the numeric basis; these should be reflected in updated values of transform or of the multicodec descriptor at the front of the transformed bytes, respectively.

NOTE

Base58 is case-sensitive; in this version of the spec, peer DIDs MUST be compared with a case-sensitive algorithm and MUST NOT be normalized in case. The more general rule is that case sensitivity derives from transform, so routines that process multiple versions of peer DIDs MUST derive their case sensitivity rules from the corresponding properties of whatever transform a particular peer DID uses.

§ Generation Method

The unique numeric basis underlying a Peer DID MUST be generated in one of the following ways:

§ Method 0: inception key without doc

If numalgo == 0, a single keypair is chosen, having all possible privileges with respect to the DID. The public key value for this pair is the numeric basis of the DID. The genesis version of the DID doc is considered to be empty, granting all privileges to this key (and algorithmic derivations thereof, to provide key agreement versus signing and so forth). The DID doc offers no endpoint. This makes the DID functionally equivalent to a did:key value, and visually similar, except that a peer DID will have the numeric algorithm as a prefix, before the multibase encoded, multicodec-encoded public key. For example, did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH is equivalent to did:peer:0z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH.

§ Method 1: genesis doc

By hashing the stored variant, we avoid the circular problem of including the DID in the data that’s being hashed. This means that a peer DID doc must be resolved by converting a stored variant of DID doc data into a resolved variant by inserting the value of the DID being resolved.

The root of trust for peer DIDs is the entropy in the inception key. The inception key MUST be new for each DID; it MUST NOT ever be reused–and it must be the case that anyone observing the public half of the inception key cannot somehow derive or steal the private half. This guarantees that nobody other than the holder of the inception key could have created the genesis version of the DID doc. Because only the inception key has the privilege of sharing the DID doc with a peer, no other key holder can establish the relationship contrary to the intent of the inception key holder. This gives peer DIDs a self-certifying property that is vital to cybersecurity of all DIDs. Any DID method that does not guarantee the chain of custody of the DID between when it is created and when it is shared (e.g., written to a ledger or given to a peer) lacks this quality and is susceptible to attacks early in the DID’s lifecycle. See github for more discussion.

§ Method 2: multiple inception key without doc

If numalgo == 2, the generation mode is similar to Method 0 (and therefore also did:key) with the ability to specify additional keys in the generated DID Document. This method is necessary when both an encryption key and a signing key are required. This method also enables including services in the generated DID Document.

NOTE

The first iteration of this method left some elements of the encoding and decoding process underspecified. Clarifications have been made to this specification to resolve this. These clarifications will be noted by appending “(clarified)” to the relevant statements.

EXAMPLE
peer-did-method-2 = "did:peer:2" 1*element 
element = "." ( purposecode transform encnumbasis / service )
purposecode = "A" / "E" / "V" / "I" / "D" / "S" 
keypurpose = 
transform = "z"
encnumbasis = 46*BASE58BTC
service = 1*B64URL
§ Generating a did:peer:2

When generating a did:peer:2, take as inputs a set of keys and their purpose. Each key’s purpose corresponds to the Verification Relationship it will hold in the DID Document generated from the DID.

Abstractly, these inputs may look like the following (in this example, the keys are already multibase, multicodec encoded values):

[
  {
    "purpose": "verification",
    "publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc"
  },
  {
    "purpose": "encryption",
    "publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR"
  }
]

To encode the input keys:

In addition to keys, did:peer:2 can encode one or more services.

The service SHOULD follow the DID Core specification for services.

For use with did:peer:2, service id attributes MUST be relative. The service MAY omit the id; however, this is NOT RECOMMEDED (clarified).

Consider the following service as input:

{
  "type": "DIDCommMessaging",
  "serviceEndpoint": {
    "uri": "http://example.com/didcomm",
    "accept": [
      "didcomm/v2"
    ],
    "routingKeys": [
      "did:example:123456789abcdefghi#key-1"
    ]
  }
}

To encode a service:

WARNING

Do not use the dm common string as the service type for DIDComm v1 did:peer:2 DIDs. Instead, use the full DIDComm v1 service type, did-communication.

The dm common string is the service type for the DIDComm v2 DID service. It should NOT be used for a DIDComm v1 DID service. If you are defining a did:peer:2 DID Doc to be used with DIDComm v1, make sure you use a DIDComm v1 service, and DO NOT use the dm common string, but rather use the proper DIDComm v1 service type of did-communication. There is no common string defined for did-communication so it MUST be spelled out in full.

Finally, to create the DID, concatenate the following values:

This concatenation will result in a value like the following:

did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ
§ Lookup Tables
§ Common String Abbreviations
Common String Abbreviation
type t
DIDCommMessaging dm
serviceEndpoint s
routingKeys r
accept a
§ Purpose Codes
Purpose Code Verification Relationship
A Assertion
E Key Agreement (Encryption)
V Authentication (Verification)
I Capability Invocation
D Capability Delegation
S Service
§ Resolving a did:peer:2
NOTE

Below is the normative approach to resolving did:peer:2 DIDs. However, it is often the case that the resolved value is only used within a particular component. In this case, some of these rules may be relaxed. For instance, the verification material may be transformed into a JWK or other representation if the resolving component is more accustomed to working with those key representations. It is not strictly necessary to first represent the document as described here only to immediately transform it into the more familiar representation. Shortcuts like these are not problematic unless they impact the function of the DID Document.

The id value of the Document, verification method, and service objects MUST be set as outlined below. These values are used to reference elements of the document and must be consistent across implementations regardless of shortcuts taken within the resolver.

When Resolving the peer DID into a DID Document, the process is reversed:

NOTE

It is not possible to express a verification method not controlled by the controller of the DID Document with did:peer:2.

EXAMPLE
{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/multikey/v1",
  ],
  "id": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ",
  "verificationMethod": [
    {
      "id": "#key-1",
      "controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ",
      "type": "Multikey",
      "publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc"
    },
    {
      "id": "#key-2",
      "controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9kaWRjb21tIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0xIl19fQ.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9leGFtcGxlLmNvbS9hbm90aGVyIiwiYSI6WyJkaWRjb21tL3YyIl0sInIiOlsiZGlkOmV4YW1wbGU6MTIzNDU2Nzg5YWJjZGVmZ2hpI2tleS0yIl19fQ",
      "type": "Multikey",
      "publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR"
    }
  ],
  "authentication": [
    "#key-1"
  ],
  "keyAgreement": [
    "#key-2"
  ],
  "service": [
    {
      "type": "DIDCommMessaging",
      "serviceEndpoint": {
        "uri": "http://example.com/didcomm",
        "accept": [
          "didcomm/v2"
        ],
        "routingKeys": [
          "did:example:123456789abcdefghi#key-1"
        ]
      },
      "id": "#service"
    },
    {
      "type": "DIDCommMessaging",
      "serviceEndpoint": {
        "uri": "http://example.com/another",
        "accept": [
          "didcomm/v2"
        ],
        "routingKeys": [
          "did:example:123456789abcdefghi#key-2"
        ]
      },
      "id": "#service-1"
    }
  ],
  "alsoKnownAs": ["did:peer:3zQmd6RdU6e2nDrLn1rjwdA5Buzq7wJwsv3WJ1AgrwKYJoLE"]
}

§ Method 3: DID Shortening with SHA-256 Hash

If numalgo == 3, the generation mode is similar to Method 2, but with a shorter DID identifier derived from a SHA-256 hash of the original identifier. The benefit of using Method 3 over Method 2 is the ability to have smaller size didcomm messages as did:peer:2. dids tend to be verbose in nature. Method 3 peer dids can only be used after a peer did method 2 has been exchange with the other party and thus can map the shortened did to the longform one. In order to send a message encrypted with method 3 you first MUST send a discover-feature message (using the method 2 as the to field) to make sure that the receiving agent is capable of resolving method 3 dids.

EXAMPLE
peer-did-method-3 = "did:peer:3" transform encnumbasis
transform = "z"
encnumbasis = 46*BASE58BTC

For example, if the Method 2 DID is:

did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0

First, remove the prefix “did:peer:2”:

.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0

Take the SHA-256 hash of the remaining string and represent as a multi-hash, multi-base encoded(base58btc) string:

zQmS19jtYDvGtKVrJhQnRFpBQAx3pJ9omx2HpNrcXFuRCz9

Finally, concatenate the prefix “did:peer:3” with the computed and encoded hash:

did:peer:3zQmS19jtYDvGtKVrJhQnRFpBQAx3pJ9omx2HpNrcXFuRCz9

§ Method 4: Short Form and Long Form

DID Peer Numalgo 4 is a statically resolvable DID Method with a short form and a long form. The short form is the hash over the long form. The combined use of short and long forms allows for fully peer shared DID Documents, with efficient use of the short form after initial exchange.

§ Creating a DID

To create a did:peer:4 DID, you must start with a document which is very similar in structure to DID Documents. This document is referred to as the “Input Document.” This document should look almost exactly like the final resolved DID Document you desire but with a few key differences:

For this tutorial, consider an Input Document like the following:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/x25519-2020/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1"
  ],
  "verificationMethod": [
    {
      "id": "#6LSqPZfn",
      "type": "X25519KeyAgreementKey2020",
      "publicKeyMultibase": "z6LSqPZfn9krvgXma2icTMKf2uVcYhKXsudCmPoUzqGYW24U"
    },
    {
      "id": "#6MkrCD1c",
      "type": "Ed25519VerificationKey2020",
      "publicKeyMultibase": "z6MkrCD1csqtgdj8sjrsu8jxcbeyP6m7LiK87NzhfWqio5yr"
    }
  ],
  "authentication": [
    "#6MkrCD1c"
  ],
  "assertionMethod": [
    "#6MkrCD1c"
  ],
  "keyAgreement": [
    "#6LSqPZfn"
  ],
  "capabilityInvocation": [
    "#6MkrCD1c"
  ],
  "capabilityDelegation": [
    "#6MkrCD1c"
  ],
  "service": [
    {
      "id": "#didcommmessaging-0",
      "type": "DIDCommMessaging",
      "serviceEndpoint": {
        "uri": "didcomm://queue",
        "accept": ["didcomm/v2"],
        "routingKeys": [],
      }
    }
  ]
}

To encode this value into a did:peer:4:

  1. Encode the document:

    1. JSON stringify the object without whitespace
    2. Encode the string as utf-8 bytes
    3. Prefix the bytes with the multicodec prefix for json (varint 0x0200)
    4. Multibase encode the bytes as base58btc (base58 encode the value and prefix with a z)
    5. Consider this value the encoded document
  2. Hash the document:

    1. Take SHA2-256 digest of the encoded document (encode the bytes as utf-8)
    2. Prefix these bytes with the multihash prefix for SHA2-256 and the hash length (varint 0x12 for prefix, varint 0x20 for 32 bytes in length)
    3. Multibase encode the bytes as base58btc (base58 encode the value and prefix with a z)
    4. Consider this value the hash
  3. Construct the did by concatenating the values as follows:

     did:peer:4{{hash}}:{{encoded document}}
    

Here is an example long form DID made from the input example above:

did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd:z2M1k7h4psgp4CmJcnQn2Ljp7Pz7ktsd7oBhMU3dWY5s4fhFNj17qcRTQ427C7QHNT6cQ7T3XfRh35Q2GhaNFZmWHVFq4vL7F8nm36PA9Y96DvdrUiRUaiCuXnBFrn1o7mxFZAx14JL4t8vUWpuDPwQuddVo1T8myRiVH7wdxuoYbsva5x6idEpCQydJdFjiHGCpNc2UtjzPQ8awSXkctGCnBmgkhrj5gto3D4i3EREXYq4Z8r2cWGBr2UzbSmnxW2BuYddFo9Yfm6mKjtJyLpF74ytqrF5xtf84MnGFg1hMBmh1xVx1JwjZ2BeMJs7mNS8DTZhKC7KH38EgqDtUZzfjhpjmmUfkXg2KFEA3EGbbVm1DPqQXayPYKAsYPS9AyKkcQ3fzWafLPP93UfNhtUPL8JW5pMcSV3P8v6j3vPXqnnGknNyBprD6YGUVtgLiAqDBDUF3LSxFQJCVYYtghMTv8WuSw9h1a1SRFrDQLGHE4UrkgoRvwaGWr64aM87T1eVGkP5Dt4L1AbboeK2ceLArPScrdYGTpi3BpTkLwZCdjdiFSfTy9okL1YNRARqUf2wm8DvkVGUU7u5nQA3ZMaXWJAewk6k1YUxKd7LvofGUK4YEDtoxN5vb6r1Q2godrGqaPkjfL3RoYPpDYymf9XhcgG8Kx3DZaA6cyTs24t45KxYAfeCw4wqUpCH9HbpD78TbEUr9PPAsJgXBvBj2VVsxnr7FKbK4KykGcg1W8M1JPz21Z4Y72LWgGQCmixovrkHktcTX1uNHjAvKBqVD5C7XmVfHgXCHj7djCh3vzLNuVLtEED8J1hhqsB1oCBGiuh3xXr7fZ9wUjJCQ1HYHqxLJKdYKtoCiPmgKM7etVftXkmTFETZmpM19aRyih3bao76LdpQtbw636r7a3qt8v4WfxsXJetSL8c7t24SqQBcAY89FBsbEnFNrQCMK3JEseKHVaU388ctvRD45uQfe5GndFxthj4iSDomk4uRFd1uRbywoP1tRuabHTDX42UxPjz

To construct the short form, simply omit the :{{encoded document}} from the end.

Here is an example short form DID for the long form above:

did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd
§ Resolving a DID
§ Long form

Resolving a long form did:peer:4 document is done by decoding the document from the DID and “contextualizing” the restored Input Document with the DID.

To decode the document:

  1. Extract the encoded document portion of the DID
  2. Verify the hash over the encoded document by extracting the hash portion of the DID and comparing it against the result of following step 2 (“Hash the document”) above to recreate the hash.
  3. Perform the inverse of step 1 (“Encode the document”) to get the decoded document

To “contextualize” a document:

  1. Take the decoded document (which should look identical to the input example above)
  2. Add id at the root of the document and set it to the DID
  3. Add alsoKnownAs at the root of the document and set it to a list, if not already present, and append the short form of the DID
  4. For each verification method (declared in the verificationMethod section or embedded in a verification relationship like authentication):
    • If controller is not set, set controller to the DID

Note: Implementations may turn relative references in the document into absolute references by prepending the reference with the DID. This is not recommended due to length but this is an implementation detail that should not affect usage of the resolved document. Both relative and absolute references are valid within DID Documents.

Here is an example long form DID Document:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/x25519-2020/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1"
  ],
  "verificationMethod": [
    {
      "id": "#6LSqPZfn",
      "type": "X25519KeyAgreementKey2020",
      "publicKeyMultibase": "z6LSqPZfn9krvgXma2icTMKf2uVcYhKXsudCmPoUzqGYW24U",
      "controller": "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd:z2M1k7h4psgp4CmJcnQn2Ljp7Pz7ktsd7oBhMU3dWY5s4fhFNj17qcRTQ427C7QHNT6cQ7T3XfRh35Q2GhaNFZmWHVFq4vL7F8nm36PA9Y96DvdrUiRUaiCuXnBFrn1o7mxFZAx14JL4t8vUWpuDPwQuddVo1T8myRiVH7wdxuoYbsva5x6idEpCQydJdFjiHGCpNc2UtjzPQ8awSXkctGCnBmgkhrj5gto3D4i3EREXYq4Z8r2cWGBr2UzbSmnxW2BuYddFo9Yfm6mKjtJyLpF74ytqrF5xtf84MnGFg1hMBmh1xVx1JwjZ2BeMJs7mNS8DTZhKC7KH38EgqDtUZzfjhpjmmUfkXg2KFEA3EGbbVm1DPqQXayPYKAsYPS9AyKkcQ3fzWafLPP93UfNhtUPL8JW5pMcSV3P8v6j3vPXqnnGknNyBprD6YGUVtgLiAqDBDUF3LSxFQJCVYYtghMTv8WuSw9h1a1SRFrDQLGHE4UrkgoRvwaGWr64aM87T1eVGkP5Dt4L1AbboeK2ceLArPScrdYGTpi3BpTkLwZCdjdiFSfTy9okL1YNRARqUf2wm8DvkVGUU7u5nQA3ZMaXWJAewk6k1YUxKd7LvofGUK4YEDtoxN5vb6r1Q2godrGqaPkjfL3RoYPpDYymf9XhcgG8Kx3DZaA6cyTs24t45KxYAfeCw4wqUpCH9HbpD78TbEUr9PPAsJgXBvBj2VVsxnr7FKbK4KykGcg1W8M1JPz21Z4Y72LWgGQCmixovrkHktcTX1uNHjAvKBqVD5C7XmVfHgXCHj7djCh3vzLNuVLtEED8J1hhqsB1oCBGiuh3xXr7fZ9wUjJCQ1HYHqxLJKdYKtoCiPmgKM7etVftXkmTFETZmpM19aRyih3bao76LdpQtbw636r7a3qt8v4WfxsXJetSL8c7t24SqQBcAY89FBsbEnFNrQCMK3JEseKHVaU388ctvRD45uQfe5GndFxthj4iSDomk4uRFd1uRbywoP1tRuabHTDX42UxPjz"
    },
    {
      "id": "#6MkrCD1c",
      "type": "Ed25519VerificationKey2020",
      "publicKeyMultibase": "z6MkrCD1csqtgdj8sjrsu8jxcbeyP6m7LiK87NzhfWqio5yr",
      "controller": "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd:z2M1k7h4psgp4CmJcnQn2Ljp7Pz7ktsd7oBhMU3dWY5s4fhFNj17qcRTQ427C7QHNT6cQ7T3XfRh35Q2GhaNFZmWHVFq4vL7F8nm36PA9Y96DvdrUiRUaiCuXnBFrn1o7mxFZAx14JL4t8vUWpuDPwQuddVo1T8myRiVH7wdxuoYbsva5x6idEpCQydJdFjiHGCpNc2UtjzPQ8awSXkctGCnBmgkhrj5gto3D4i3EREXYq4Z8r2cWGBr2UzbSmnxW2BuYddFo9Yfm6mKjtJyLpF74ytqrF5xtf84MnGFg1hMBmh1xVx1JwjZ2BeMJs7mNS8DTZhKC7KH38EgqDtUZzfjhpjmmUfkXg2KFEA3EGbbVm1DPqQXayPYKAsYPS9AyKkcQ3fzWafLPP93UfNhtUPL8JW5pMcSV3P8v6j3vPXqnnGknNyBprD6YGUVtgLiAqDBDUF3LSxFQJCVYYtghMTv8WuSw9h1a1SRFrDQLGHE4UrkgoRvwaGWr64aM87T1eVGkP5Dt4L1AbboeK2ceLArPScrdYGTpi3BpTkLwZCdjdiFSfTy9okL1YNRARqUf2wm8DvkVGUU7u5nQA3ZMaXWJAewk6k1YUxKd7LvofGUK4YEDtoxN5vb6r1Q2godrGqaPkjfL3RoYPpDYymf9XhcgG8Kx3DZaA6cyTs24t45KxYAfeCw4wqUpCH9HbpD78TbEUr9PPAsJgXBvBj2VVsxnr7FKbK4KykGcg1W8M1JPz21Z4Y72LWgGQCmixovrkHktcTX1uNHjAvKBqVD5C7XmVfHgXCHj7djCh3vzLNuVLtEED8J1hhqsB1oCBGiuh3xXr7fZ9wUjJCQ1HYHqxLJKdYKtoCiPmgKM7etVftXkmTFETZmpM19aRyih3bao76LdpQtbw636r7a3qt8v4WfxsXJetSL8c7t24SqQBcAY89FBsbEnFNrQCMK3JEseKHVaU388ctvRD45uQfe5GndFxthj4iSDomk4uRFd1uRbywoP1tRuabHTDX42UxPjz"
    }
  ],
  "service": [
    {
      "id": "#didcommmessaging-0",
      "type": "DIDCommMessaging",
      "serviceEndpoint": {
        "uri": "didcomm:transport/queue",
        "accept": [
          "didcomm/v2"
        ],
        "routingKeys": []
      }
    }
  ],
  "authentication": [
    "#6MkrCD1c"
  ],
  "keyAgreement": [
    "#6LSqPZfn"
  ],
  "assertionMethod": [
    "#6MkrCD1c"
  ],
  "capabilityDelegation": [
    "#6MkrCD1c"
  ],
  "capabilityInvocation": [
    "#6MkrCD1c"
  ],
  "alsoKnownAs": [
    "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd"
  ],
  "id": "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd:z2M1k7h4psgp4CmJcnQn2Ljp7Pz7ktsd7oBhMU3dWY5s4fhFNj17qcRTQ427C7QHNT6cQ7T3XfRh35Q2GhaNFZmWHVFq4vL7F8nm36PA9Y96DvdrUiRUaiCuXnBFrn1o7mxFZAx14JL4t8vUWpuDPwQuddVo1T8myRiVH7wdxuoYbsva5x6idEpCQydJdFjiHGCpNc2UtjzPQ8awSXkctGCnBmgkhrj5gto3D4i3EREXYq4Z8r2cWGBr2UzbSmnxW2BuYddFo9Yfm6mKjtJyLpF74ytqrF5xtf84MnGFg1hMBmh1xVx1JwjZ2BeMJs7mNS8DTZhKC7KH38EgqDtUZzfjhpjmmUfkXg2KFEA3EGbbVm1DPqQXayPYKAsYPS9AyKkcQ3fzWafLPP93UfNhtUPL8JW5pMcSV3P8v6j3vPXqnnGknNyBprD6YGUVtgLiAqDBDUF3LSxFQJCVYYtghMTv8WuSw9h1a1SRFrDQLGHE4UrkgoRvwaGWr64aM87T1eVGkP5Dt4L1AbboeK2ceLArPScrdYGTpi3BpTkLwZCdjdiFSfTy9okL1YNRARqUf2wm8DvkVGUU7u5nQA3ZMaXWJAewk6k1YUxKd7LvofGUK4YEDtoxN5vb6r1Q2godrGqaPkjfL3RoYPpDYymf9XhcgG8Kx3DZaA6cyTs24t45KxYAfeCw4wqUpCH9HbpD78TbEUr9PPAsJgXBvBj2VVsxnr7FKbK4KykGcg1W8M1JPz21Z4Y72LWgGQCmixovrkHktcTX1uNHjAvKBqVD5C7XmVfHgXCHj7djCh3vzLNuVLtEED8J1hhqsB1oCBGiuh3xXr7fZ9wUjJCQ1HYHqxLJKdYKtoCiPmgKM7etVftXkmTFETZmpM19aRyih3bao76LdpQtbw636r7a3qt8v4WfxsXJetSL8c7t24SqQBcAY89FBsbEnFNrQCMK3JEseKHVaU388ctvRD45uQfe5GndFxthj4iSDomk4uRFd1uRbywoP1tRuabHTDX42UxPjz"
}
§ Short form

To resolve a short form did:peer:4 DID, you must know the corresponding long form DID. It is not possible to resolve a short form did:peer:4 without first seeing and storing it’s long form counterpart.

To resolve a short form DID, retrieve the saved long form DID or decoded document (like the Input Document such as in the example above) and follow the same rules described in the long form section to “contextualize” the document but using the short form DID instead of the long form DID.

Here is an example short form DID Document:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/x25519-2020/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1"
  ],
  "verificationMethod": [
    {
      "id": "#6LSqPZfn",
      "type": "X25519KeyAgreementKey2020",
      "publicKeyMultibase": "z6LSqPZfn9krvgXma2icTMKf2uVcYhKXsudCmPoUzqGYW24U",
      "controller": "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd"
    },
    {
      "id": "#6MkrCD1c",
      "type": "Ed25519VerificationKey2020",
      "publicKeyMultibase": "z6MkrCD1csqtgdj8sjrsu8jxcbeyP6m7LiK87NzhfWqio5yr",
      "controller": "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd"
    }
  ],
  "service": [
    {
      "id": "#didcommmessaging-0",
      "type": "DIDCommMessaging",
      "serviceEndpoint": {
        "uri": "didcomm:transport/queue",
        "accept": [
          "didcomm/v2"
        ],
        "routingKeys": []
      }
    }
  ],
  "authentication": [
    "#6MkrCD1c"
  ],
  "keyAgreement": [
    "#6LSqPZfn"
  ],
  "assertionMethod": [
    "#6MkrCD1c"
  ],
  "capabilityDelegation": [
    "#6MkrCD1c"
  ],
  "capabilityInvocation": [
    "#6MkrCD1c"
  ],
  "alsoKnownAs": [
    "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd:z2M1k7h4psgp4CmJcnQn2Ljp7Pz7ktsd7oBhMU3dWY5s4fhFNj17qcRTQ427C7QHNT6cQ7T3XfRh35Q2GhaNFZmWHVFq4vL7F8nm36PA9Y96DvdrUiRUaiCuXnBFrn1o7mxFZAx14JL4t8vUWpuDPwQuddVo1T8myRiVH7wdxuoYbsva5x6idEpCQydJdFjiHGCpNc2UtjzPQ8awSXkctGCnBmgkhrj5gto3D4i3EREXYq4Z8r2cWGBr2UzbSmnxW2BuYddFo9Yfm6mKjtJyLpF74ytqrF5xtf84MnGFg1hMBmh1xVx1JwjZ2BeMJs7mNS8DTZhKC7KH38EgqDtUZzfjhpjmmUfkXg2KFEA3EGbbVm1DPqQXayPYKAsYPS9AyKkcQ3fzWafLPP93UfNhtUPL8JW5pMcSV3P8v6j3vPXqnnGknNyBprD6YGUVtgLiAqDBDUF3LSxFQJCVYYtghMTv8WuSw9h1a1SRFrDQLGHE4UrkgoRvwaGWr64aM87T1eVGkP5Dt4L1AbboeK2ceLArPScrdYGTpi3BpTkLwZCdjdiFSfTy9okL1YNRARqUf2wm8DvkVGUU7u5nQA3ZMaXWJAewk6k1YUxKd7LvofGUK4YEDtoxN5vb6r1Q2godrGqaPkjfL3RoYPpDYymf9XhcgG8Kx3DZaA6cyTs24t45KxYAfeCw4wqUpCH9HbpD78TbEUr9PPAsJgXBvBj2VVsxnr7FKbK4KykGcg1W8M1JPz21Z4Y72LWgGQCmixovrkHktcTX1uNHjAvKBqVD5C7XmVfHgXCHj7djCh3vzLNuVLtEED8J1hhqsB1oCBGiuh3xXr7fZ9wUjJCQ1HYHqxLJKdYKtoCiPmgKM7etVftXkmTFETZmpM19aRyih3bao76LdpQtbw636r7a3qt8v4WfxsXJetSL8c7t24SqQBcAY89FBsbEnFNrQCMK3JEseKHVaU388ctvRD45uQfe5GndFxthj4iSDomk4uRFd1uRbywoP1tRuabHTDX42UxPjz"
  ],
  "id": "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd"
}
§ Reference implementation

https://github.com/dbluhm/did-peer-4

§ Recognizing and handling peer DIDs

This section is non-normative.

EXAMPLE
did:peer:1zQmZMygzYqNwU6Uhmewx5Xepf2VLp5S4HLSwwgf2aiKZuwa

Peer DIDs consist entirely of printable ASCII characters and in this version of the spec are exactly 57 or 58 characters long. They have no whitespace, and the only punctuation they use is the : character. When rendering in columns with a constrained width, they could be hyphenated one or more times as needed; the hyphens would not be confused with meaningful delimiters, and the final character of the DID would be easy to find. They could also be rendered in a short form with the middle of the long base58 section elided, if it is not necessary to compare them with precision: did:peer:1z6Tx...WzJJq. The ellipsis should not obscure the prefix or the initial or final few characters of encnumbasis, to preserve enough info for casual distinction. This might be a useful rendering in log files, for example.

A convenient regex to match peer DIDs is:

EXAMPLE
^did:peer:(([01](z)([1-9a-km-zA-HJ-NP-Z]{46,47}))|(2((\.[AEVID](z)([1-9a-km-zA-HJ-NP-Z]{46,47}))+(\.(S)[0-9a-zA-Z=]*)*)))$

A match against this regex places numalgo (the algorithm for choosing a numeric basis) in capture group 1, transform in capture group 2, and encnumbasis in capture group 3.

§ CRUD Operations

peer DIDs implement the following CRUD (Create, Read, Update, and Delete) operations:

§ Appendix

§ Security Considerations

This section is non-normative.

§ Guarantees

This section is non-normative.

This spec uses a protocol, rather than a public oracle, as the root of trust. This protocol reliably communicates data about peer DIDs and peer DID docs; peers must persist that data into a local cache or database that functions as the Decentralized Identifier Registry for the method. The method is worthy of trust because it guarantees the following properties:

DIDs are associated with exactly one inception key pair at the moment of creation.
This prevents a category of man-in-the-middle attacks where an attacker could rotate a DID’s keys at the outset of a relationship, unbeknownst to peers. It also prevents any party other than the holder of the inception key from using the DID in an unintended context.
DIDs have an acceptable level of uniqueness.
This is NOT a guarantee that DIDs will never be improperly reused by their owner, NOR is it a guarantee that collusion cannot subvert uniqueness. Thus, it is not a uniqueness upon which deep trust can be based. Rather, it is a guarantee that good behavior will not produce accidental collisions. In this sense, it is a bit like the uniqueness offered by NATing mechanisms in IPv4. It provides enough uniqueness that a DID can be used as an index in a database or as a routing target in DID communication. It also makes it possible for blockchains to graft a peer DID by mapping it into their namespace, without incurring the risk of ambiguity. Any time a peer DID is discovered to be less than unique, a true problem exists and systems can fairly raise an exception.
The values of DIDs are securely random.
This prevents attackers from discovering patterns in DIDs that might undermine privacy.

§ Enforcement

This section is non-normative.

In centralized systems, security is enforced at the center. This is so obvious that we take it for granted—you can’t access a database unless you log in first, and it’s the database that enforces this.

Despite their other decentralized features, blockchains are no different in this respect. If a blockchain accepts updates to a DID doc, then the blockchain must guarantee that those updates are only made by authorized parties. Thus, most DID methods imagine a blockchain parsing the authorization section of a DID doc, and rejecting mischief from hackers.

However, in a peer relationship, there IS no centralized authority. This leads to an interesting inversion of responsibility that must be understood: Bob enforces Alice’s authorization policy, and Alice enforces Bob’s.

This might seem wrong—shouldn’t Alice enforce her own security? But it is quite rational. Who cares whether the agents he is dealing with truly belong to Alice and are authorized by her? Bob does. And if one of Alice’s agents gets hacked and attempts to subvert the Alice:Bob relationship, who is the uncontaminated party that can refuse to cooperate with the rogue agent? Bob is.

Another way to think about this is that, within the Alice:Bob relationship, Bob acts as a substitute for a centralized resource that Alice’s agents try to access. In such a mental model, of course, Bob would be a logical place to enforce access rules for Alice.

§ Secure communication

All the messages in this protocol (except for a connection invitation that requires no security, by design) must be sent encrypted, using the encryption format specified in DIDComm’s encryption envelope. This gives strong guarantees about the confidentiality and integrity of exchanged data, regardless of the transport mechanism used to transmit the messages.

§ Proof of Control

Because peer DIDs are generated from an algorithm that includes the values of their initial public key(s) as input, they cannot be created without the creator controlling them. As mentioned earlier, this prevents man-in-the-middle attacks at the time of creation. A man-in-the-middle attacker might still try to exchange the public key(s) in a DID Doc, while keeping the DID the same. If unnoticed, this would bind a DID generated by an honest party to the attacker’s public key(s). To prevent this, the receiver of a freshly generated peer DID and DID Doc must verify that the DID was properly generated using the algorithm. This check is required when the received (DID, DID Doc) pair was not otherwise authenticated, which is the case for the exchange request during peer DID Exchange.

§ Entropy

Since keys must be created from keys generated by a secure random number generator, they are guaranteed to be unpredictable and globally unique at creation time.

§ Key Management

Keys used to control peer DIDs, or keys authorized to communicate and update the DID docs for peer DIDs, should be managed according to best practices for DKMS, as described in the DKMS spec.

§ Handling the trust-on-first-use (TOFU) problem

The trust-on-first-use is described in detail in its Wikipedia article. In brief, the TOFU problem occurs because it’s not possible to verify on receipt of a public key, who is the owner of the corresponding private key. This lack of knowledge enables Man in the Middle (MITM) attacks, where an attempt to establish a connection between two participants is compromised by a third party. With peer:did, the interaction most vulnerable to MITM attacks is when an invitation is sent in plaintext to start the establishment of a connection. Recall that a plaintext invitation (a URL, a QR code, etc.) is needed when there is no way for two parties that want to connect to send an encrypted message. A relatively simple MITM attack using an intercepted invitation is for the MITM to respond to the invitation and establish a connection with the inviter, pretending to be the invitee. In a more sophisticated attack, the MITM sends a second, replacement MITM-generated invitation to the intended invitee, establishes a connection with that party, responds to the original invitation, and establishes a connection with the inviter. That second attack example could allow the MITM to remain between the two communicating parties, proxying messages between them, and intervening when it is advantageous. Since it is such a complex attack, it is viewed as extremely unlikely (arguably, impossible) to occur in practice.

There are two common approaches to handling the TOFU problem with connections established using the peer DID method specification. One is to verify the connection using a trusted third party channel, and the second is through the use of verifiable credentials.

Note that in many use cases, an entity might not care who responds to an invitation. In that case an “intercepted” invitation is OK, and might even be encouraged as a way to get more connections. For example a service where users only put in data for their own use (for example, a time tracking app) would not care who establishes a connection, just that the service has a reliable way to know whenever an entity returns to the service. In that case, neither verification method is necessary. It might only be when the user becomes a paying client that the service needs stronger credentials from whomever it is that is using the service.

§ Verification Using a Trusted Third Party Channel

Verifying that the established connection is with the intended party using a trusted third party channel is done by sending a request by some means other than the newly established connection, and having the response returned on (or about) the established connection. For example, after establishing the connection, the inviter might telephone the invitee and verbally confirm the public key the invitee is using for the connection. Of course, such an approach is neither user friendly, nor does it scale. The challenge is finding approaches that are reliable, easy and that scale. Another approach might be to email a message to the invitee and have them respond via the new connection with a phrase from the email. While that approach would detect the first example MITM attack (described above), it would not detect the second.

The user experience can be improved as well using a randomart image generated from a public key while being able to detect both the first and second MITM attack examples. This image could be sent in numerous ways such as embedding it in a qr code, sending it over a email, or text message would also work.

§ Using Verifiable Credentials

The use of verifiable credentials is another way to verify a connection. With the connection in place, one party requests from the other a verifiable presentation of third party claims made about them. The requested claims should be sufficient to mitigate the risk for the transactions to be carried out using the connection, possibly including (but not just) the detection of a MITM attack. Note that such risk mitigation should be done by both connected parties. For example, a company might need to know some identity information about a new client, and the new client might want to be certain that the company is who they claim to be as attested to by an authorized entity.

The presentation of verifiable claims is sufficient to handle the first example MITM attack—the presentation provides sufficient information about the other entity to continue the relationship. However, because in the second example, the MITM can proxy the presentation request and presentation between the parties, a verifiable presentation might not be sufficient to detect the second MITM example. In that case, we also want proof that the entity that delivered the presentation is the same entity that constructed the presentation. Since in the case of did:peer the delivery is by definition through a did:peer enabled connection, that extra proof involves linking the construction of the presentation to the connection through which it will be delivered.

This extra proof can be achieved by having the entity constructing the presentation include a self-attested claim that is the did:peer public key of the prover. When the presentation is received, the verifier can compare the signed, self-attested claim with the one they are holding in the did:peer DIDDoc for the connection. If they do not match it is possible there has been a MITM attack and the connection is suspect.

§ Privacy Considerations

This section is non-normative.

Peer DIDs should remain pairwise or n-wise, not be reused across relationships. This allows proper isolation to defeat correlation. It also enables granular exercise of sovereignty in a robust, multidimensional identity.

many pairwise DIDs

Alice maintains different pairwise DIDs for each relationship, and discloses different aspects and quantities about herself in each one.

§ Fingerprinting

The names of roles and the arrangement of rules in a peer DID doc could conceivably be used to create a sort of fingerprint of a sovereign domain, in much the same way that browser fingerprinting keys off individual uniqueness in combinations of browser+plugin+hardware configuration. To combat this problem, the following best practices are recommended:

§ Comparison to Other DID Methods

This section is non-normative.

§ Ledger-oriented Methods

We could certainly build peer relationships with anywise DIDs based on a public ledger or a similar source of truth. However, in the same way that a company doesn’t want the public to resolve private host names inside its corporate intranet, letting others resolve pairwise and n-wise DIDs is unnecessary, and it represents a privacy and security risk as well as a problem of cost, scale, and performance. We strongly recommend that peer DIDs be used for peer relationships.

In a similar vein, peer DIDs could be used, hypothetically, for anywise scenarios. The main disadvantage would be the lack of a formal publication mechanism. Nothing would prevent a user from publishing a peer DID and its associated DID document on a website. However, information published in this way would be hard to discover, maintain as DID docs evolved, and integrate into interoperable applications. DID methods that use a public ledger or a similar source of truth are a better choice here, because they have authoritative answers to the publication problem.

§ did:key

The did:key method encodes a public key directly as a DID value, and generates a very simple DID Doc in a deterministic way from that key. The only material that has to be generated or stored when using this method is the public key or DID itself; either can derive the other and the DID Doc. Using a did:key is very similar to sharing and then using a public SSH key.

The benefit of the did:key method is its simplicity. Like peer DIDs, it has no dependence on an external source of truth, and can be implemented in code with little effort. Like peer DIDs, they are cheap to create and use.

However, did:key are not direct equivalent of peer DIDs. Here are some features of peer DIDs that they do not provide:

Peer DIDs use a layering approach so the complexity of key rotation and updates need not be supported if only static, ephemeral use cases matter. This is the main complexity difference between peer DIDs and these other two methods, and is optional with peer DIDs. Peer DIDs also use multicodec to encode keys in the same way that did:key does. The hope is that these two methods will remain as similar as possible, and that Peer DIDs will be a logical upgrade choice when use cases go beyond those that did:key and did:nacl are designed to handle.

§ Resources

Developers maintaining this spec and its reference implementations are often found on the Aries channel of Hyperledger’s Discord Server. You might also connect with them via the Hyperledger Aries mailing list, in Hyperledger working groups, in DIF and W3C meetings, or at the semi-annual Internet Identity Workshop or Rebooting Web of Trust conferences. They sometimes answer questions on stackoverflow tagged with decentralized-identifiers, decentralized-identity, hyperledger-aries, or hyperledger-indy.

§ References

§ Normative references

Table of Contents