§ The Hedera DID Method v2.0 / Editor’s Draft

Specification Status: EDITORS DRAFT

Current Specification: Editor’s Draft

Specification Version: v2.0 (see Changelog)

Source of Latest Draft: https://github.com/Swiss-Digital-Assets-Institute/did-method/blob/master/hedera-did-method-specification.md

Previous Versions:
v1.0
Authors:
Jakub Sydor
Pablo Buitrago
Participate:
GitHub repo
File an issue
Commit history
Implementations:
PoC Repository

§ Abstract

The Hedera DID method specification conforms to the requirements specified in the [DID-CORE] W3C Recommendation.

The hedera DID Method is registered in the W3C DID Method Registry.

This document defines version 2.0 of the Hedera DID Method, which adopts the standard W3C controller pattern for authorization. This change provides enhanced flexibility, security, and interoperability while maintaining compatibility with the established v1.0 identifier format.

§ Status of This Document

This document is published as a Draft for feedback. Comments and contributions are welcome.

§ Definitions

::: term DID Controller [DID-CORE]~ The entity that controls (creates, updates, deactivates) a given DID, as defined in [DID-CORE]. In the Hedera DID Method v2.0, control is explicitly defined by the controller property within the DID document. :::

::: term HCS Topic ~ An entity created in the Hedera Consensus Service (HCS) to manage a stream of messages. Each message receives a consensus timestamp and sequence number, providing ordered, immutable records. :::

::: term Hedera Consensus Service (HCS) ~ A service provided by the Hedera network that provides functionality for publishing arbitrary messages (organized by topics) for consensus, giving each message a trusted timestamp and ordering. HCS offers high throughput, scalability, and low cost. :::

::: term Namespace Specific Identifier (NSI) ~ The unique identifier portion of a DID that follows the method name. For Hedera DIDs, this includes the network identifier, base58-encoded key component, and HCS topic ID. :::

::: term did-topic-id ~ A mandatory parameter in the Hedera DID identifier that specifies the HCS Topic ID where messages related to the DID are submitted. Format: shard.realm.num (e.g., 0.0.3474905). :::

::: term Hedera Mirror Node ~ A public node that provides historical access to HCS messages and other Hedera network data through REST APIs. Used by DID resolvers to retrieve the message history needed to reconstruct DID document state. :::

§ Hedera Hashgraph DID Method Specification

§ About Hedera Hashgraph

Hedera Hashgraph is a public, open-source, proof-of-stake network that utilizes the hashgraph consensus algorithm. It offers high throughput, low fees, and finality in seconds for various services, including the Hedera Consensus Service (HCS) leveraged by this DID method.

§ Motivation

Version 1.0 of the Hedera DID Method established a functional DID method on Hedera using HCS but tied DID control rigidly to the key embedded in the identifier (referred to as #did-root-key logic). This deviated from the standard W3C controller model, creating significant limitations:

Hedera DID Method v2.0 aims to rectify these issues by fully adopting the standard W3C controller pattern for authorization. This change occurs while retaining the established v1.0 identifier format to ensure naming continuity for existing DID concepts on Hedera. The result is a more flexible, robust, secure, and interoperable DID method aligned with global standards.

NOTE

This specification defines a new ruleset (v2.0). Existing v1.0 DIDs remain under v1.0 rules; new DIDs must be created under v2.0 rules to benefit from the W3C-aligned control mechanism. There is no in-place upgrade path from v1.0 to v2.0 for an existing DID identifier.

§ Method Name

The namestring that shall identify this DID method is: hedera

A DID that uses this method must begin with the following prefix: did:hedera:. Per the [DID-CORE] specification, this string must be in lowercase. The remainder of the DID, after the prefix, is the Namespace Specific Identifier (NSI) specified below. This section defines the identifier format, which remains consistent between v1.0 and v2.0 of this method.

§ Namespace Specific Identifier (NSI)

The did:hedera NSI is defined by the following ABNF grammar:

hedera-did = "did:hedera:" hedera-specific-idstring "_" hedera-specific-parameters
hedera-specific-idstring = hedera-network ":" hedera-base58btc-key
hedera-specific-parameters = did-topic-id
did-topic-id = 1*DIGIT "." 1*DIGIT "." 1*DIGIT

hedera-network = "mainnet" / "testnet"
hedera-base58btc-key = 32*44(base58btc) ; Using the Bitcoin Base58 alphabet
base58btc = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "A" / "B" /
            "C" / "D" / "E" / "F" / "G" / "H" / "J" / "K" / "L" / "M" / "N" /
            "P" / "Q" / "R" / "S" / "T" / "U" / "V" / "W" / "X" / "Y" / "Z" /
            "a" / "b" / "c" / "d" / "e" / "f" / "g" / "h" / "i" / "j" / "k" /
            "m" / "n" / "o" / "p" / "q" / "r" / "s" / "t" / "u" / "v" / "w" /
            "x" / "y" / "z"
EXAMPLE
did:hedera:mainnet:z52k2w6rFF9xxzvmSiuyqwJS8b7oFnDtk8S3bhY4YbnJq_0.0.3474905

The method-specific identifier (hedera-specific-idstring combined with hedera-specific-parameters) consists of:

Control and authorization for managing the DID under v2.0 are determined solely by the controller property within the DID document and verified via cryptographic proof mechanisms submitted in HCS messages (detailed in the CRUD Operations section), aligning with the [DID-CORE] specification. The v1.0 concept of a mandatory #did-root-key intrinsically linked to the identifier for control is superseded in v2.0.

EXAMPLE

The following example illustrates the structure of a DID document under v2.0 rules. The controller property defines authority. While a verification method like #key-1 might use a key related to the identifier’s <base58btc-key> component, this method holds no special control privileges granted by this DID method specification itself. Authorization relies on proofs generated by keys authorized by the controller(s) for specific capabilities (like capabilityInvocation).

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/multikey/v1",
    "https://w3id.org/security/suites/jws-2020/v1"
  ],
  "id": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
  "controller": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
  "verificationMethod": [
    {
      "id": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-1",
      "type": "Multikey",
      "controller": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
      "publicKeyMultibase": "z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd"
    },
    {
      "id": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-2",
      "type": "JsonWebKey2020",
      "controller": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
      "publicKeyJwk": {
        "kty": "OKP",
        "crv": "Ed25519",
        "x": "iaRFURYLA-QTlCYjFo_8UfMScPZgYTCpJzVEiJmQ_50"
      }
    }
  ],
  "capabilityInvocation": [
    "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-1"
  ],
  "authentication": [
    "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-1"
  ],
  "service": [
    {
      "id": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#service-1",
      "type": "LinkedDomains",
      "serviceEndpoint": "https://test.com/did"
    }
  ]
}

§ Method-Specific DID URL Parameters

§ Mandatory Identifier Parameter

There is one method-specific parameter that is a mandatory component of the NSI:

A Hedera TopicID is a triplet of numbers (shard.realm.num), e.g., 0.0.29656231, represents topic identifier 29656231 within realm 0 and shard 0. Realms and shards are Hedera network constructs; currently, all topics reside in shard 0 and realm 0.

§ Optional Version Resolution Parameters

The Hedera DID method supports two optional DID URL query parameters for version-specific resolution, conforming to the [DID-RESOLUTION] specification:

Version Resolution Behavior:

When either versionId or versionTime is specified in a DID URL, resolvers must return the DID document state as it existed at that specific point in the DID’s history. If neither parameter is present, the resolver returns the latest version of the DID document.

Version Parameter Precedence:

If both versionId and versionTime are specified in the same DID URL, the versionId parameter must take precedence.

EXAMPLE
# Resolve to a specific sequence number
did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701?versionId=5

# Resolve to a specific point in time
did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701?versionTime=2025-07-14T22:10:00Z

§ Topic Association Models

The did-topic-id parameter allows for flexibility in how DID operations are logged on HCS. The choice between these models is left to the implementer or DID controller, and involves trade-offs between cost and performance.

§ Dedicated Topic Model (One Topic per DID)

§ Shared Topic Model (Many DIDs per Topic)

§ CRUD Operations

Create, Update, and Deactivate operations against a DID Document under the v2.0 ruleset are performed by submitting authorized messages to the DID’s associated Hedera Consensus Service (HCS) topic. Authorization must be achieved via cryptographic proofs linked to the DID’s designated controller(s), as detailed below.

CRUD Flow

The Read operation (resolution) of a DID document must occur by querying a Hedera mirror node for the HCS topic history and reconstructing the state based on the ordered, authorized messages.

Read Flow

§ Message Structure

A valid v2.0 HCS message payload for Create, Update, or Deactivate operations must be a JSON object containing at least the following top-level fields:

NOTE

Including a mandatory, top-level did field provides an unambiguous subject for every operation at the message envelope level. While this information is redundant for create and update operations (where it must match the id in the didDocument), it is essential for operations like deactivate, where the message payload does not contain a didDocument. This ensures the target of a deactivation is always explicit within the message itself.

The mandatory did property also significantly improves resolver efficiency, particularly in a Shared Topic Model. When multiple DIDs log their operations to the same HCS topic, a resolver must filter through all messages to find those relevant to the specific DID it is resolving. The top-level did field allows a resolver to perform this filtering by checking a simple string value first. If the did does not match the target DID being resolved, the resolver can immediately discard the message without needing to parse the potentially large and complex didDocument object within the payload. This acts as an efficient “fast-lane” filter, reducing computational overhead.

EXAMPLE

The following example is illustrative. Specific values like DIDs, keys, timestamps, and proof values will vary.

{
  "version": "2.0",
  "did": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
  "operation": "create",
  "didDocument": {
    "@context": [
      "https://www.w3.org/ns/did/v1",
      "https://w3id.org/security/multikey/v1",
      "https://w3id.org/security/suites/jws-2020/v1"
    ],
    "id": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
    "controller": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
    "verificationMethod": [
      {
        "id": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-1",
        "type": "Multikey",
        "controller": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
        "publicKeyMultibase": "z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd"
      },
      {
        "id": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-2",
        "type": "JsonWebKey2020",
        "controller": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701",
        "publicKeyJwk": {
          "kty": "OKP",
          "crv": "Ed25519",
          "x": "iaRFURYLA-QTlCYjFo_8UfMScPZgYTCpJzVEiJmQ_50"
        }
      }
    ],
    "capabilityInvocation": [
      "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-1"
    ],
    "authentication": [
      "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-1"
    ],
    "service": [
      {
        "id": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#service-1",
        "type": "LinkedDomains",
        "serviceEndpoint": "https://test.com/did"
      }
    ]
  },
  "proof": {
    "type": "Ed25519Signature2020",
    "created": "2025-04-30T12:00:00Z",
    "verificationMethod": "did:hedera:testnet:z6MkipomYgdGz1MXBm5ZJNVNVqTgumeMboAy3fCpd_0.0.645701#key-1",
    "proofPurpose": "capabilityInvocation",
    "proofValue": "z5uJVg3hJn5fL8gK1fG5hV6fK8gL3kH7jR9wQ4bD5pT2mN1rS7yZ3xW"
  }
}

§ Validation and Authorization

Neither Hedera network nodes nor standard mirror nodes validate the semantics of DID documents or the cryptographic proofs within HCS messages against the DID logic. This validation must be performed by DID resolvers and client applications according to the v2.0 specification rules. Specifically, resolvers must:

§ HCS Topic Access Control vs. DID Control

It is the responsibility of the entity managing the DID (the controller or their delegate) to manage access to the associated HCS topic. Access control for submitting messages to the HCS topic is defined by the topic’s submitKey property, managed via Hedera’s ConsensusUpdateTopicTransaction.

NOTE

Hedera Consensus Service messages have a size limit per transaction. However, the official Hedera SDKs automatically handle segmentation (chunking) of messages larger than the single transaction limit, allowing for the submission of typical DID documents and proofs without manual chunking in most cases. Developers should generally use the standard SDK functions for message submission.

§ Operations

§ Create

A DID is created under the v2.0 ruleset by sending a ConsensusSubmitMessage transaction to a Hedera network node containing the initial DID document and an authorization proof from the designated controller. This is executed by sending a submitMessage RPC call (or equivalent SDK function) to the HCS API with the ConsensusSubmitMessageTransactionBody containing:

§ Read (Resolve)

Resolving a did:hedera DID under v2.0 rules involves querying the HCS topic history associated with the DID’s did-topic-id and reconstructing the DID document’s state by processing authorized messages in consensus order. The process must follow these steps:

  1. Parse DID URL Parameters: Extract any optional version resolution parameters (versionId or versionTime) from the DID URL if present.
  2. Fetch History: Retrieve all messages from the specified HCS topicID via a Hedera mirror node.
  3. Order Messages: Sort the retrieved messages strictly according to their consensus timestamp and sequence number (lower sequence number first for messages within the same second).
  4. Determine Resolution Point: Based on the version parameters:
    • If versionId is specified, identify the message with that sequence number as the resolution endpoint.
    • If versionTime is specified, identify the last message with a consensus timestamp less than or equal to the specified time as the resolution endpoint.
    • If neither parameter is present, the resolution endpoint is the last message in the topic.
    • If both parameters are specified, versionId must take precedence.
  5. Process Sequentially: Iterate through the ordered messages up to the determined resolution point, maintaining the current known state of the DID document (initially null) and the current authorized controller(s) (initially null). For each message:
    1. Check Version: Verify if the message payload is a JSON object with a version field equal to "2.0". If not, or if the message is malformed, ignore it.
    2. Filter by DID: If the message has a top-level did property, verify that it matches the DID being resolved. If it does not, ignore this message.
    3. Validate Proof:
      • If the operation is create, the proof must be validated against a verification method associated with the controller specified within the didDocument payload of this create message itself.
      • If the operation is update or deactivate, the proof must be validated against a verification method associated with the current known controller(s) established by prior valid messages in the sequence.
      • If the proof field is missing, malformed, or fails validation, the message must be considered invalid and ignored.
    4. Apply Operation (if proof is valid):
      • create: If the current state is null, parse the didDocument from the payload. This becomes the initial valid state. Record the controller(s) defined within this document. If a state already exists, this subsequent create message should be ignored.
      • update: Replace the entire current known state of the DID document with the didDocument provided in the message payload. Update the record of the current controller(s) based on the controller property in this new document state.
      • deactivate: Mark the DID as deactivated. Subsequent update operations must be ignored.
    5. Check Resolution Endpoint: If the current message reaches the resolution endpoint, stop processing.
  6. Return Result: After processing messages:
    • If the DID was marked as deactivated, the resolver must return a result indicating the deactivated status.
    • Otherwise, return the final reconstructed state of the DID document.
    • If no valid create message was found within the resolution scope, the resolver must return an error (e.g., notFound).
    • Include version metadata in the resolution result (the actual sequence number and timestamp of the resolved state).

§ Update

An existing DID document is updated under the v2.0 ruleset by submitting a ConsensusSubmitMessage transaction containing the complete new state of the document and an authorization proof from the current controller. This is executed by sending a submitMessage RPC call (or equivalent SDK function) to the HCS API with the ConsensusSubmitMessageTransactionBody containing:

§ Deactivate

A DID document is deactivated under the v2.0 ruleset (marking it as no longer valid or resolvable to a current state) by submitting a ConsensusSubmitMessage transaction authorized by the current controller. This is executed by sending a submitMessage RPC call (or equivalent SDK function) to the HCS API with the ConsensusSubmitMessageTransactionBody containing:

§ Security Considerations

The security model for Hedera DID Method v2.0 relies on the inherent security properties of the Hedera network (specifically HCS consensus and finality) combined with the robustness of the W3C controller model and cryptographic proofs. Key considerations include:

§ Identifier Component Roles (v2.0 Rule)

Crucial Distinction: The <base58btc-key> component within the DID identifier string (did:hedera:<network>:<base58btc-key>_<topic-id>) serves only as part of the unique identifier after the initial create operation under v2.0 rules. It must not be interpreted as granting ongoing control authority or authorization privileges for managing the DID document. Control is solely determined by the controller property within the DID document state and verified via the proof mechanism in HCS messages. Misunderstanding this distinction presents a significant security risk, potentially leading to incorrect implementation of authorization logic.

§ Controller Authority & Compromise

§ HCS Topic Interaction & Access Control

§ SubmitKey Mitigation Strategies

To mitigate DoS risks associated with open topics or compromised submitKeys, operators should consider:

§ Validation Responsibility (Resolvers & Clients)

As stated previously, neither Hedera network nodes nor standard mirror nodes validate DID document semantics or controller proofs against the DID logic. This validation must be performed by DID resolvers and client applications according to the v2.0 specification rules. Failure to perform these validations correctly breaks the security model.

§ Resolver Validation Requirements

Resolvers must:

§ Privacy Considerations

DID Documents should not include Personally Identifiable Information (PII) directly. Information included in a DID document is typically public.

§ Correlation Risks

The use of identifiers, particularly public and persistent identifiers like DIDs, can create risks of correlation. When the same DID is used across multiple contexts or interactions, it allows observing parties (including websites, applications, and resolvers) to link those activities together. This correlation can potentially reveal sensitive information about the DID subject’s behavior or relationships without their consent.

§ Resolution Privacy

The DID resolution process itself can leak information. When a party (the verifier) resolves a DID presented by the DID subject, the resolver learns that the subject is interacting with that specific verifier at that time.

§ Mitigation Strategies

To mitigate correlation risks, DID controllers should consider using pairwise DIDs – creating a unique DID for each distinct relationship or interaction. Correspondingly, the DID Documents for these pairwise DIDs should contain unique public keys and service endpoints specific to that relationship, further compartmentalizing interactions.

§ Reference Implementations and Testing

§ Production SDK

Reference SDK packages implementing the Hedera DID Method v2.0 are available through npm:

These packages are used in the PoC repository and demonstrate how to create, resolve, update, and deactivate DIDs according to this specification.

§ Proof of Concept Repository

A comprehensive set of runnable Proof of Concept (PoC) implementations demonstrating all v2.0 features is available at: hedera-did-method-v2-poc.

The PoC repository validates the following specification features:

Controller Operations:

Key Management:

Verification Methods:

Historical Resolution:

Each PoC can be run independently after setting up a Hedera Testnet account:

# Install dependencies
npm install

# Configure environment
cp .env.template .env
# Edit .env with your Hedera Testnet credentials

# Run specific PoCs
npm run poc:create-did-with-controller
npm run poc:did-key-rotation
npm run poc:resolution-with-version-id
npm run poc:did-transfer-controller
# See repository README for complete list of 15 available PoCs

The PoC repository includes a detailed PoC Plan that outlines objectives, scope, success criteria, and validation methodology for each feature.

§ Test Vectors

To ensure interoperability and compliance with this specification, implementers (of SDKs, resolvers, or applications interacting with did:hedera) should validate their implementations against standardized test vectors. These test vectors should cover various scenarios, including:

NOTE

Test vectors and JSON Schema definitions for v2.0 are planned for inclusion in the PoC repository.

§ References

§ Normative References

§ Informative References

§ Hedera DID Method Version Changelog

Lists of substantive changes in each version of the specification.

§ Version 2.0

§ Version 1.0

Table of Contents