IOTA DID Method Specification v2.0
2024-08-23
Abstract
The IOTA DID Method Specification describes a method of implementing the Decentralized Identifiers (DID) standard on IOTA, a Distributed Ledger Technology (DLT). It conforms to the DID specification v1.0 and describes how to perform Create, Read, Update and Delete (CRUD) operations for IOTA DID Documents using shared Move objects on the IOTA network.
Introduction
Identity Object
Identity
is a shared Move object that contains a DID document along other metadata used for access-control.
Although Identity
's instances are shared, and therefore publicly accessible by anyone, only a well-defined per-instance set of
actors - called controllers - are allowed to make changes to an Identity
.
Ledger and DID
Storing DID Documents in the ledger state means they inherently benefit from the guarantees the ledger provides.
- Conflicts among nodes are resolved and dealt with by the ledger.
- Replay attacks are mitigated since transactions need to be confirmed by the ledger.
- Through the
State Index
a linear history for updates of a DID Document is provided.
DID Method Name
The method-name
to identify this DID method is: iota
.
A DID that uses this method MUST begin with the following prefix: did:iota
. Following the generic DID specification, this string MUST be lowercase.
DID Format
The DIDs that follow this method have the following ABNF syntax. It uses the syntax in RFC5234 and the corresponding definition for digit
.
iota-did = "did:iota:" iota-specific-idstring
iota-specific-idstring = [ iota-network ":" ] iota-tag
iota-network = 8lowercase-hex
iota-tag = "0x" 64lowercase-hex
lowercase-hex = digit / "a" / "b" / "c" / "d" / "e" / "f"
It starts with the string "did:iota:", followed by an optional network name (8 lowercase hexadecimal digits) and a colon, then the tag.
The tag starts with "0x" followed by a lowercase hex-encoded Object ID
.
IOTA-Network
The iota-network is an identifier of the network where the DID is stored. This network must be an IOTA Ledger, but can either be a public or private network, permissionless or permissioned.
When no IOTA network is specified, it is assumed that the DID is located on IOTA main network, having id PUT IOTA CHAIN ID HERE. This means that the following DIDs will resolve to the same DID Document:
did:iota:IOTA CHAIN ID:0xe4edef97da1257e83cbeb49159cfdd2da6ac971ac447f233f8439cf29376ebfe
did:iota:0xe4edef97da1257e83cbeb49159cfdd2da6ac971ac447f233f8439cf29376ebfe
IOTA-Tag
An IOTA-tag is a lowercase hex-encoded Object ID
. The Object ID
itself is a unique identifier for Move objects and is derived from the digest of the trasanction that created the object it identifies.
This tag identifies the Identity
where the DID Document is stored, and it will not be known before the generation of the DID since it will be assigned when the Identity
object is created.
Anatomy of the encoded DID Document
The DID Document stored within an Identity
must be encoded as the payload of a byte packed structure with fields as follows:
Name | Type | Description |
---|---|---|
Document Type | ByteArray[3] | Set to value DID to denote a DID Document. |
Version | uint8 | Set value 1 to denote the version number of this method |
Encoding | uint8 | Set to value to 0 to denote JSON encoding without compression. |
Payload | (uint16)ByteArray | A DID Document and its metadata, where every occurrence of the DID in the document is replaced by did:0:0 . It must be encoded according to Encoding . |
The types are defined in TIP-21.
Payload
The payload must contain the following fields:
meta
: contains metadata about the DID Document. For example,created
to indicate the time of creation, andupdated
to indicate the time of the last update to the document. It may also include other properties.doc
: contains the DID Document. In the example below, the document only contains one verification method. Theid
andcontroller
is specified bydid:0:0
which references the DID of the document itself, since the DID is unknown at the time of publishing. It also deduplicates the DID of the document to reduce the size of the state metadata, in turn reducing the required storage deposit.
Example State Metadata Document:
{
"doc": {
"id": "did:0:0",
"verificationMethod": [
{
"id": "did:0:0#jkGOGVO3Te7ADpvlplr47eP9ucLt41zm",
"controller": "did:0:0",
"type": "JsonWebKey",
"publicKeyJwk": {
"kty": "OKP",
"alg": "EdDSA",
"kid": "jkGOGVO3Te7ADpvlplr47eP9ucLt41zm",
"crv": "Ed25519",
"x": "D5w8vG6tKEnpBAia5J4vNgLID8k0BspHz-cVMBCC3RQ"
}
}
],
"authentication": ["did:0:0#jkGOGVO3Te7ADpvlplr47eP9ucLt41zm"]
},
"meta": {
"created": "2023-08-28T14:49:37Z",
"updated": "2023-08-28T14:50:27Z"
}
}
Multiple controllers and voting power
An Identity
may be owned by more than one controller and each controller may have a different voting power - i.e. a quantificable level of control over a given Identity
represented with an unsigned integer.
Whenever control over an Identity
is shared among multiple controllers an access control (AC) policy - in the form of an unsigned positive integer threshold - must be defined. Any operation a controller performs that might modify the interested Identity
isn't carried out right away. Instead, a proposal to perform such an operation is created, and controllers are required to approve it, before it may be executed. The number of approvals needed in order to execute the proposal depends on the threshold and controllers' voting power.
CRUD Operations
Create, Read, Update and Delete (CRUD) operations that change the DID Documents are performed by invoking Identity
's APIs in a transaction.
These operations require funds to cover the gas cost. Transactions must be carefully done in order to avoid fund loss - e.g. executing a transaction that is bound to fail wastefully consumes funds for gas. Additionally, private keys of controllers must be stored securely.
Create
In order to create a simple self controlled DID two things are required:
- An Address for which the private key is available.
- Enough funds to cover for the creation of a new
Identity
object.
Creation steps:
- Create the content of the DID Document like verification methods, services, etc.
- Create the payload and the headers as described in the Anatomy of the encoded DID document.
- Execute
Identity::new
in a transaction, providing the encoded DID document as its parameter.
Once the transaction is confirmed, the DID is published and can be formatted by using the Object ID
as the tag in DID Format.
Read
The following steps can be used to read the latest DID Document associated with a DID.
- Obtain the
Object ID
from the DID by extracting theiota-tag
from the DID, see DID Format. - Obtain the network of the DID by extracting the
iota-network
from the DID, see DID Format. - Query the Object corresponding to the
Object ID
using a node running the indexer, asserting that the network the node is connected to matches the previously extracted network ID. - Assert that the
Object ID
of the returned Object matches theObject ID
extracted from the DID. Return an error otherwise. - Parse the retrieved object into an
Identity
object. - Decode the DID Document from its byte packed encoding stored in the
Identity
Object. - Replace the placeholder
did:0:0
with the DID given as input.
Update
Updating a DID Document can be achieved by invoking the Identity::propose_update
API passing the updated encoded DID Document as its parameter, followed by executing the generated proposal after enough approvals from the Identity
's controllers are obtained.
In a more detailed step-by-step description:
- Create a copy of the encoded DID document with the
Object ID
set explicitly. - Pack the updated DID Document, as described in the Anatomy of the encoded DID Document, and use it as the parameter to a call to
Identity::propose_update
API. - Query the generated
Proposal
object, and check if the threshold has been reached. If that's not the case wait for enough controllers to approve the proposal. - Execute the approved proposal by invoking
Identity::execute_update
.
Delete
Deactivate
Temporarily deactivating a DID can be done by deleting the contents of the encoded DID Document in the Identity
object, setting it to an empty byte array, and publishing an update.
Another option is to update the DID Document and set the deactivated
property in its metadata
to true. In both cases, the deactivated DID Document will be marked as deactivated
when resolved.
Destroy
To permanently destroy a DID Document controllers need to go through a process similar to that of updating the document. First, a proposal for destroying the corresponding Identity
is created, which can be executed after the AC policy has been met.
Note that this operation irreversibly and irrecoverably deletes the DID. This is because the Object ID
from which an IOTA DID is derived (see IOTA-Tag) is generated from the hash of the input transaction that created it, which cannot generally be replicated.
IOTA Identity standards
The did:iota
method is implemented in the IOTA Identity framework. This framework supports a number of operations that are standardized, some are standardized across the SSI community, and some are the invention of the IOTA Foundation.
Revocation
Revocation of verifiable credentials and signatures can be achieved using the Revocation Bitmap 2022 where issuers store a bitmap of indices in the DID Document. These indices correspond to verifiable credentials they have issued. If the binary value of the index in the bitmap is 1 (one), the verifiable credential is revoked, if it is 0 (zero) it is not revoked.
Standardized Services
The IOTA Identity framework also standardized certain services
that are embedded in the DID Document. It is RECOMMENDED to implement these when implementing the did:iota
method.
Currently standardized services
:
Security Considerations
Private Key Management
All private keys or seeds used for the did:iota
method should be equally well protected by the users. Private keys of the state controller and the governor are especially important as they control how keys are added or removed, providing full control over the identity.
Privacy Considerations
Personal Identifiable Information
IOTA networks are immutable. This means that once something is included, it can never be completely removed. For example, destroying an Identity
will remove it from the ledger state, but it can still be stored in permanodes or by any party that records historical ledger states.
That directly conflicts with certain privacy laws such as GDPR, which have a 'right-to-be-forgotten' for Personal Identifiable Information (PII). As such, users should NEVER upload any PII, including inside DID Documents. While verifiable credentials can be made public, this should only be utilized by Identity for Organisations and Identity for Things.
Correlation Risks
As with any DID method, identities can be linked if they are used too often and their usage somehow becomes public. See DID Correlation Risks. Additionally, a DID can be correlated with funds if the Alias Output used to store the DID Document or any of its controllers is used for holding, transferring or controlling coins or NFTs.