Skip to main content
info
IOTA Identity for Rebased is currently in alpha and may still be subject to significant changes

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.

  1. Conflicts among nodes are resolved and dealt with by the ledger.
  2. Replay attacks are mitigated since transactions need to be confirmed by the ledger.
  3. 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:

NameTypeDescription
Document TypeByteArray[3]Set to value DID to denote a DID Document.
Versionuint8Set value 1 to denote the version number of this method
Encodinguint8Set to value to 0 to denote JSON encoding without compression.
Payload(uint16)ByteArrayA 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, and updated 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. The id and controller is specified by did: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:

  1. An Address for which the private key is available.
  2. Enough funds to cover for the creation of a new Identity object.

Creation steps:

  1. Create the content of the DID Document like verification methods, services, etc.
  2. Create the payload and the headers as described in the Anatomy of the encoded DID document.
  3. 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.

  1. Obtain the Object ID from the DID by extracting the iota-tag from the DID, see DID Format.
  2. Obtain the network of the DID by extracting the iota-network from the DID, see DID Format.
  3. 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.
  4. Assert that the Object ID of the returned Object matches the Object ID extracted from the DID. Return an error otherwise.
  5. Parse the retrieved object into an Identity object.
  6. Decode the DID Document from its byte packed encoding stored in the Identity Object.
  7. 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:

  1. Create a copy of the encoded DID document with the Object ID set explicitly.
  2. 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.
  3. 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.
  4. 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.