W3C DID
DID stands for Decentralized IDentifiers. DIDs are meant to be globally unique identifiers that allow their owner to
prove cryptographic control over them. The owner(s) of the DID is called the controller
. The identifiers are not just assignable
to humans but to anything. Quoting the DID spec,
A DID identifies any subject (e.g., a person, organization, thing, data model, abstract entity, etc.) that the controller of the DID decides that it identifies.
DIDs differ from public keys in that DIDs are persistent, i.e. a public key has to be changed if the private key is stolen/lost or the cryptographic scheme of the public key is no longer considered safe. This is not the case with DIDs, they can remain unchanged even when the associated cryptographic material changes. Moreover, a DID can have multiple keys and any of its keys can be rotated. Additionally, depending on the scheme, public keys can be quite large (several hundred bytes in RSA) whereas a unique identifier can be much smaller.
Each DID is associated with a DID Document
that specifies the subject, the public keys, the authentication mechanisms usable
by the subject, authorizations the subject has given to others, service endpoints to communicate with the subject, etc,
for all properties that can be put in the DID Document, refer this section of the spec.
DIDs and their associated DID Documents are stored on the DID registry which is a term used for the centralized on decentralized
database persisting the DID and its Document.
The process of discovering the DID Document for a DID is called DID resolution and the tool (library or a service) is called DID
resolver. To resolve the DID, the resolver first needs to check on which registry the DID is hosted and then decide whether it
is capable or willing to lookup that registry. The registry is indicated by the DID method
of that DID. In addition to the
registry, the method also specifies other details of that DID like the supported operations, crypto, etc. Each DID method
defines its own specification, Docks's DID method spec is here.
In case of Dock, the registry is the Dock blockchain, and the method is dock
.
We support 2 kinds of DIDs, on-chain and off-chain.
With off-chain DIDs, only a reference to the DID Document is kept on chain and this reference can be an CID (for IPFS) or a URL or any
custom format.
With on-chain DIDs, the keys, controllers and service endpoints of the DID are stored on chain. A DID key can have 1 or more verification
methods which indicates what that key can be used for. Only a DID key with verification
relationship capabilityInvocation
can update the DID document, i.e. add/remove keys, add/remove controllers,
add/remove service endpoints and remove the DID. Also a DID can have 1 or more controllers and these controllers can also
update its DID document. A DID with a key with capabilityInvocation
verification relationship is its own controller.
An example on-chain Dock DID.
did:dock:5CEdyZkZnALDdCAp7crTRiaCq6KViprTM6kHUQCD8X6VqGPW
Above DID has method dock
and the DID identifier is 5CEdyZkZnALDdCAp7crTRiaCq6KViprTM6kHUQCD8X6VqGPW
. Dock DID identifiers
are 32 bytes in size.
An example DID Document
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"controller": ["did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn"],
"verificationMethod": [
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1",
"type": "Sr25519VerificationKey2020",
"controller": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"publicKeyBase58": "7d3QsaW6kP7bGiJtRZBxdyZsbJqp6HXv1owwr8aYBjbg"
},
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-2",
"type": "Ed25519VerificationKey2018",
"controller": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"publicKeyBase58": "p6gb7WNh9SWC4hkye4VV5epo1LYpLXKH21ojfwJLayg"
}
],
"authentication": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1",
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-2"
],
"assertionMethod": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1"
],
"capabilityInvocation": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1"
]
}
Dock DIDs support multiple keys. The keys are present in the publicKey
section. As per the above DID document, the DID did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn
has 2 public keys and 1 controller which is itself.
Note how that public key is referred to using its id
in authentication
, assertionMethod
and capabilityInvocation
sections.
The above document states that the DID did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn
can authenticate with 2 public keys
whose id is specified under authentication
. When it attests to some fact (becomes issuer), it can only use 1 key, which is under assertionMethod
.
The keys specified under capabilityInvocation
can be used to update the DID document, i.e. add/remove keys, etc.
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"controller": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"did:dock:5Hc3RZyfJd98QbFENrDP57Lga8mSofDFwKQpodN2g2ZcYscz"
],
"verificationMethod": [
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1",
"type": "Sr25519VerificationKey2020",
"controller": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"publicKeyBase58": "7d3QsaW6kP7bGiJtRZBxdyZsbJqp6HXv1owwr8aYBjbg"
},
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-2",
"type": "Ed25519VerificationKey2018",
"controller": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"publicKeyBase58": "p6gb7WNh9SWC4hkye4VV5epo1LYpLXKH21ojfwJLayg"
}
],
"authentication": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1",
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-2"
],
"assertionMethod": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1"
],
"capabilityInvocation": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1"
]
}
In the above DID document, there are controllers, 1 is the DID did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn
itself
and the other is did:dock:5Hc3RZyfJd98QbFENrDP57Lga8mSofDFwKQpodN2g2ZcYscz
. This means that DID did:dock:5Hc3RZyfJd98QbFENrDP57Lga8mSofDFwKQpodN2g2ZcYscz
can also modify above DID document, i.e. add/remove keys, add/remove controller, etc.
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"controller": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"did:dock:5Hc3RZyfJd98QbFENrDP57Lga8mSofDFwKQpodN2g2ZcYscz"
],
"verificationMethod": [
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1",
"type": "Sr25519VerificationKey2020",
"controller": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"publicKeyBase58": "7d3QsaW6kP7bGiJtRZBxdyZsbJqp6HXv1owwr8aYBjbg"
},
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-2",
"type": "Ed25519VerificationKey2018",
"controller": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"publicKeyBase58": "p6gb7WNh9SWC4hkye4VV5epo1LYpLXKH21ojfwJLayg"
}
],
"authentication": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1",
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-2"
],
"assertionMethod": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1"
],
"capabilityInvocation": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1"
],
"service": [
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#linked-domain-1",
"type": "LinkedDomains",
"serviceEndpoint": ["https://foo.example.com"]
}
]
}
In the above document, there is also a service endpoint for the DID.
DIDs can also be keyless, i.e. not have any keys of its own. In this case the DID is not self-controlled by controlled by another DID(s) and the other DID could add/remove keys, controllers or remove the DID. An example keyless DID is shown below
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"controller": ["did:dock:5Hc3RZyfJd98QbFENrDP57Lga8mSofDFwKQpodN2g2ZcYscz"],
"verificationMethod": [],
"authentication": [],
"assertionMethod": [],
"capabilityInvocation": [],
"service": [
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#linked-domain-1",
"type": "LinkedDomains",
"serviceEndpoint": ["https://bar.example.com"]
}
]
}
In the above DID Doc, DID did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn
is controlled by did:dock:5Hc3RZyfJd98QbFENrDP57Lga8mSofDFwKQpodN2g2ZcYscz
. Now
did:dock:5Hc3RZyfJd98QbFENrDP57Lga8mSofDFwKQpodN2g2ZcYscz
add a key, say for authentication to did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn
and the
DID Doc will look like below
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"controller": ["did:dock:5Hc3RZyfJd98QbFENrDP57Lga8mSofDFwKQpodN2g2ZcYscz"],
"verificationMethod": [
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1",
"type": "Ed25519VerificationKey2018",
"controller": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn",
"publicKeyBase58": "p6gb7WNh9SWC4hkye4VV5epo1LYpLXKH21ojfwJLayg"
}
],
"authentication": [
"did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#keys-1"
],
"assertionMethod": [],
"capabilityInvocation": [],
"service": [
{
"id": "did:dock:5Hhnorjqd7vXPKdT7Y1ZpHksMBHsVRNewntZjMF2NHm3PoFn#linked-domain-1",
"type": "LinkedDomains",
"serviceEndpoint": ["https://bar.example.com"]
}
]
}
Another thing to keep in mind is that the keys associated with the Dock DID are independent of the keys used to send the transaction on chain and pay fees. Eg. Alice might not have any tokens to write anything on chain but can still create a DID and corresponding key and ask Bob who has tokens to register the DID on chain. Even though Bob wrote the DID on chain, he cannot update or remove it since only Alice has the keys associated with that DID. Similarly, when Alice wants to update the DID , it can create the update, sign it and send it to Carol this time to send the update on chain. Similar to blockchain accounts, DIDs also have their own nonce which increments by 1 on each action of a DID. On DID creation, its nonce is set to the block number on which its created and the DID is expected to send signed payloads, each with nonce 1 more than the previous nonce.