did:me Method Specification (v1)

Status: Beta
Specification URI: https://did-me.org/spec/v1/ JSON-LD Context: https://did-me.org/ns/did-me/v1


1. Introduction

did:me is a DID method designed for:

The authoritative DID state is represented by a core object, encoded using canonical DAG-CBOR, hashed to a CID, and signed by the DID controller. The public DID Document is a JSON projection derived from this signed core.

did:me identifiers are fundamentally self-hosted DIDs whose authoritative state lives on the controller’s wallet, device, or agent. No central registry is required for validity or resolution. Decentralization is enabled by the method’s cryptographic update structure, including:


2. DID Format

did:me identifiers are not derived from keys or core CIDs.
This ensures DID stability even as keys rotate or services change.

2.1 DID Syntax

A did:me identifier MUST conform to:

did:me:<identifier>

Where <identifier> is the full Bech32-encoded string, including: - the HRP "me"
- the separator "1"
- the 5-bit data payload
- the Bech32 checksum

Identifiers are generated by:

  1. Generating 16 bytes (128 bits) of cryptographically secure entropy
  2. Converting the entropy into 5-bit groups (8→5 conversion, padded)
  3. Encoding the result via Bech32 with HRP "me"

Formal representation:

identifier = Bech32.encode(hrp="me", data=convertBits(entropy[16], 8→5))

The checksum included in the Bech32 output MUST be preserved, as it provides error-detection and guards against accidental corruption.

2.2 Allowed characters

The data portion of the Bech32 identifier (after “me1”) MUST match Bech32’s lowercase character set:

^[023456789acdefghjklmnpqrstuvwxyz]+$

(Excludes: 1, b, i, o.)

2.3 Length

Given 16 bytes of entropy: - 16 bytes × 8 bits = 128 bits - Converted to ~26 five-bit groups - Bech32 encoding produces ~26–35 characters, including checksum

2.4 Example

did:me:me1q90w7wd0qpsl6rh6tsg4y0e0a60p3f60g

3. DID Resolution

3.1 Optional Directory-Based Resolution

Controllers MAY publish their DID Document to one or more public directories (e.g., reallyme.directory). If published, a DID Document can be retrieved via:

GET https://reallyme.directory/dids/<id>

This endpoint is optional and not required for DID validity or resolution. Local resolvers MAY reconstruct DID state using only the signed core chain.

3.2 HTTP Status Codes


4. Data Model Overview

A did:me DID Document is a standard DID Document projected from a signed core object and: - Uses verificationMethod, authentication, assertionMethod, capabilityInvocation, keyAgreement, and service as defined in DID Core. - Adds the following method-specific fields: - sequence — monotonic per-DID update counter
- prev — CID of the previous core (or null)
- currentCore — CID of the current DAG-CBOR core object
- keyHistory — ordered list of prior core CIDs - updatePolicy — rules defining which verification methods may authorize updates
- attestations — signatures over the core object by the DID controller
- proof — optional Data Integrity Proof over currentCore
- domainVerification — optional DNS/HTTP binding the DID to a domain

4.1 Method-Specific Extension Properties

did:me supports optional, method-specific properties that extend the base DID Document data model. These properties are defined in the did:me JSON-LD context:

https://did-me.org/ns/did-me/v1

The context defines terms such as: - currentCore - keyHistory - attestations - updatePolicy - domainVerification - and additional optional metadata fields (e.g., hardwareBound, biometricProtected, deviceModel)

All method-specific terms: - MAY appear in a DID Document - MUST NOT affect the validity of the core snapshot or signature - MUST be ignored by processors that do not understand them, per DID Core rules - MUST NOT change the canonical core object unless explicitly listed in the core schema

These extensions allow did:me to support richer metadata while preserving DID Core compatibility and forward extensibility.

4.2 Encoding Preferences

Did:me should use base64url encoding for keys.

4.3 Protocol buffers

Due to the size of post-quantum keys, did:me documents MAY use Protocol Buffers as an optional (and preferred) transport/storage encoding.

The canonical authoritative state is always the signed canonical DAG-CBOR core: - CID derivation MUST be performed from canonical DAG-CBOR core bytes - authoritative signature verification MUST be performed over canonical DAG-CBOR core bytes

The DID Document JSON is a projection output derived from the core. Protocol Buffers bytes MUST NOT be used for CID derivation or authoritative signature verification.


5. Core Object

5.1 Purpose

The core object is the canonical representation of DID state. It is:

Although the DID string never changes, all mutable cryptographic state is reflected through successive, signed core snapshots.

currentCore contains the CID of the latest snapshot. keyHistory contains only the CIDs of prior core snapshots, in ascending sequence order. prev references the immediately preceding core CID and enforces canonical update ordering.

prev enables: - rollback prevention (reject older snapshots) - replay protection (reject repeated snapshots) - fork detection (reject alternative update branches)

This design provides: - deterministic state integrity - tamper-evident version history - key rotation without changing the DID - future support for decentralized or mirrored resolvers

The keyHistory array MUST contain only the CIDs of all prior core snapshots and MUST NOT include the currentCore CID. The CIDs in keyHistory MUST be ordered in strict ascending sequence order, representing the canonical update history from the first snapshot to the most recent prior snapshot.

5.2 Core Schema (Conceptual)

Core = {
  id: string,                       // "did:me:<id>"
  sequence: uint64,                 // monotonic update counter.  This always starts at 1.
  prev: CID | null,                 // CID of previous core.   If null, then prev is omitted.
  controller: string | string[],    // one or more controllers
  controllerKeys: [CoreKey],        // declared keys
  authenticationKeys: [string],     // references into controllerKeys
  assertionKeys: [string],
  keyAgreementKeys: [string],
  services: [CoreService],          // service endpoints
  updatePolicy: CoreUpdatePolicy,   // defines which verification methods may authorize updates
}

This schema represents exactly the content protected by the signature. Anything not included here (e.g., proof, domainVerification) is not part of the core and does not affect DID validity.

A did:me DID MAY have one or more controllers. If only one controller is present, it is typically the DID subject itself.

5.3 CoreKey Schema

All of the following are required values:

CoreKey = {
  id: string,                     // e.g., "#ed25519"
  type: string,                   // e.g., "Multikey", "MLDSA87Key2024"
  algorithm: string,              // e.g., "ES256", "Ed25519", "ML-DSA-87"
  publicKeyMultibase: string
}

Keys listed here define: - which verification methods exist - which methods can sign updates (via updatePolicy) - which methods serve authentication, assertion, invocation, or key agreement

All key relationship references (authenticationKeys, assertionKeys, keyAgreementKeys, and allowedVerificationMethods in updatePolicy) MUST refer to a CoreKey.id present in controllerKeys. Section 14 defines a stricter, normative default profile for public did:me v1 interoperability; those profile requirements may constrain this base model further.

5.4 CoreUpdatePolicy

The update policy is part of the canonical core object and defines which verification methods are authorized to sign core updates.

CoreUpdatePolicy = {
  allowedVerificationMethods: [string]   // references into controllerKeys by id.  These strings MUST match a CoreKey.id.
}

5.5 CoreService Schema

CoreService = {
  id: string,                     // "#hub", "#openid", "#wallet"
  type: string,                   // DID Core service type or did:me extension
  serviceEndpoint: any,           // URI or structured JSON
  version?: string
}

Service endpoints are part of the core snapshot and therefore immutable within each version.

5.6 Canonical CBOR Encoding

The core object MUST be encoded using canonical CBOR: - Map keys sorted lexicographically by UTF-8 bytes - Only definite-length arrays/maps - UTF-8 text keys - No undefined or extraneous fields - Deterministic encoding per RFC 8949 / DAG-CBOR restrictions

This ensures: - identical encoding across languages - identical CIDs across implementations - provable state integrity

Implementations MUST reject cores containing indefinite-length items or map keys not in strictly sorted order.

5.7 CID Derivation

The CID is computed as follows:

This CID is published as: ~ “currentCore”: “~

and used to verify signatures over the core.

5.8 Payment and Crypto Address Services

did:me supports chain-agnostic crypto payment addresses through standard DID Core service entries. These addresses are non-authoritative metadata and are not part of the core update authorization model unless the corresponding public keys also appear in controllerKeys.

A DID MAY include one or more payment-related services such as: • Bitcoin (bech32) • Ethereum and EVM chains (0x-prefixed addresses) • Solana (base58) • Avalanche (X-Chain, C-Chain, or P-Chain formats) • Any other blockchain or digital payment network

Payment addresses MUST be expressed as a structured JSON serviceEndpoint object, for example:

{
  "id": "#wallet",
  "type": "PaymentService",
  "serviceEndpoint": {
    "btc": "bc1q...",
    "eth": "0x1234...",
    "sol": "So1111...",
    "avax": "0xabc..."
  }
}

5.9 EU Digital Identity Wallet Interoperability

did:me is designed to interoperate cleanly with the European Digital Identity Wallet (EUDI Wallet) architecture, including PID, ARF, and EBSI profiles. DID Documents MAY include service endpoints and proof formats that support credential issuance, presentation, and trust-chain interoperability.

5.9.1 EUDI Wallet Subject Compatibility

did:me identifiers: • are stable, non-key-derived identifiers • support rekeying without subject identifier changes • are fully compatible as subject_id values in PID / ARF data models • remain resolvable even when controller cryptographic material rotates

5.9.2 OIDC4VCI and OIDC4VP Service Endpoints

did:me supports EUDI wallet credential flows via standard DID Core service entries:

{
  "id": "#openid-credential-offer",
  "type": "OpenID4VCI",
  "serviceEndpoint": "<issuer-endpoint>"
}

{
  "id": "#oid4vp",
  "type": "OpenID4VP",
  "serviceEndpoint": "<presentation-endpoint>"
}

Resolvers MAY treat these endpoints as wallet-compatible credential interfaces.

5.9.3 Optional Service Type for EUDI Integration

Implementations MAY define a dedicated service entry for EUDI wallet interactions:

{
  "id": "#eudi",
  "type": "EudiCredentialService",
  "serviceEndpoint": "<eudi-service-url>"
}

This is functionally equivalent to using OpenID4VCI and OpenID4VP, but provides clearer semantic typing for wallets that recognize EUDI-specific services.

5.10 Wallet Binding and Domain Verification

DID Documents MAY include domainVerification entries used for: • binding a DID to a legally recognized domain • proving issuer authenticity • supporting EUDI trust chain requirements

These domain bindings are optional metadata and do not alter core state.


6. Data Integrity Proofs (Optional P-256 Anchor)

6.1 Purpose and Motivation

did:me supports optional DataIntegrityProof objects using ES256 (P-256).

These proofs provide a classical-cryptography signature anchor suitable for:

These proofs are non-authoritative: the authoritative cryptographic rail is the signature over the canonical DAG-CBOR core snapshot.

DI proofs: - MAY appear in a DID Document - MUST NOT influence update authorization or determine DID validity

6.2 Proof Object Schema

A did:me DataIntegrityProof using the es256-jws-cid-2025 cryptosuite appears as follows:

"proof": {
  "type": "DataIntegrityProof",
  "cryptosuite": "es256-jws-cid-2025",
  "proofPurpose": "assertionMethod",
  "verificationMethod": "#p256",
  "created": "<ISO8601Z>",
  "jws": "<compact-jws-with-currentCore-as-payload>"
}

es256-jws-cid-2025 is a did:me-defined custom Data Integrity cryptosuite profile. Implementations MUST apply the verification algorithm defined in this specification for this cryptosuite value.

The proof MUST:

6.3 Cryptosuite: es256-jws-cid-2025

The cryptosuite identifier:

"cryptosuite": "es256-jws-cid-2025"

The es256-jws-cid-2025 suite defines a compact ES256 JWS signature over the currentCore CID string. This cryptosuite is a did:me custom profile and is not required to be supported by generic Data Integrity processors unless they implement this suite definition.

Components:

Verification Steps: 1. Parse the compact JWS into header, payload, signature. 2. Confirm header.alg === “ES256”. 3. Decode payload and confirm it equals currentCore. 4. Recompute signingInput. 5. Verify ECDSA P-256 over SHA-256(signingInput) using the referenced P-256 key.

This proof MUST NOT be used to authorize DID updates. If a verifier does not support es256-jws-cid-2025, it MUST treat this proof as unsupported and MUST NOT treat it as valid.

6.4 ECDSA S-Value Canonicality

ES256 signatures MAY use either the “low-S” or “high-S” form. Both are cryptographically valid and MUST be accepted.

Implementations: - MAY normalize to low-S (s ≤ n/2) - MUST NOT reject high-S signatures - MAY apply normalization internally (s := min(s, n − s))

This rule ensures full interoperability across platforms such as Secure Enclave, WebCrypto, and noble-curves.

6.5 Interoperability and Usage Notes


7. Signatures and Attestations

7.1 Core Signature

Each core snapshot MUST be signed by the DID controller using one of the verification methods listed in:

updatePolicy.allowedVerificationMethods

The signature covers the raw canonical DAG-CBOR bytes of the core object.

These signatures are the authoritative root of trust for did:me and determine: - whether an update is valid - whether rollback, replay, or fork attempts are rejected - whether the currentCore CID matches its signed content

Core signatures appear in:

"attestations": [
  {
    "alg": "ML-DSA-87",
    "vm": "#mldsa87-root",
    "sig": "<base64url(signature-over-core-cbor)>"
  }
]

Multiple signatures MAY be present (e.g., Ed25519 and ML-DSA-87) to support multi-suite cryptography. For attestations.sig, implementations MUST use base64url-encoded signature bytes.

7.2 Additional Signatures

A DID Document MAY include an optional W3C DataIntegrityProof using ES256 (P-256). This proof is not authoritative for update validation. See Section 6 for the full definition of the DataIntegrityProof and the es256-jws-cid-2025 cryptosuite.


8. Operations

8.1 Create

A new did:me identifier starts with:

sequence = 1
prev = null

Creation steps:

  1. Construct the initial core object
  2. Encode the core using canonical DAG-CBOR
  3. Compute currentCore as CIDv1 (dag-cbor, sha2-256)
  4. Sign the core bytes using an allowed verification method
  5. Publish the resulting DID Document at the registry endpoint

8.2 Update

To update a DID, the registry MUST enforce all of the following:

new.id == old.id
new.sequence == old.sequence + 1
new.prev == old.currentCore
signature(new-core-cbor) verifies under new.updatePolicy.allowedVerificationMethods

If any check fails, the update MUST be rejected.

A successful update produces: - a new core snapshot - a new currentCore CID - an appended entry in keyHistory - an updated DID Document projection

8.2.1 Multiple Controllers

A did:me DID MAY list one or more controllers.

An update is valid if and only if its signature verifies under a verification method that:

  1. is listed in updatePolicy.allowedVerificationMethods, and
  2. belongs to at least one controller.

Any single such verification method is sufficient.

8.3 Deactivate

To deactivate: - Publish a DID Document with completely empty verification relationships (e.g., empty verificationMethod, authentication, assertionMethod, and capabilityInvocation arrays). - Include a valid core signature from the controller or authorized recovery key.

After deactivation: - The resolver returns 404 Not Found for the DID. - A stored deactivated DID Document MAY still be published in a separate archival namespace for audit or compliance, but does not participate in resolution.


9. DID Document Projection

The DID Document is a JSON projection derived from the signed core. Validation MUST be performed against the core and its signatures, not the DID Document.

9.1 Field Mapping from Core

The following DID Document fields MUST be derived directly from the core: - id → core.id - controller → core.controller - sequence → core.sequence - prev → core.prev - currentCore → CID of the canonical DAG-CBOR core snapshot - coreCbor → base64url-encoded canonical DAG-CBOR bytes of the current core snapshot - verificationMethod → derived from core.controllerKeys - authentication → derived from core.authenticationKeys - assertionMethod → derived from core.assertionKeys - updatePolicy → core.updatePolicy - capabilityInvocation → derived from the appropriate core keys - keyAgreement → derived from core.keyAgreementKeys - service → derived from core.services. If the core has no services, the service property MUST be omitted from the DID Document. - keyHistory → ordered list of prior core CIDs

These fields MUST reflect the core exactly, and MUST NOT introduce information not present in the core snapshot.

9.2 Method-Specific Extensions (Non-Core Metadata)

The DID Document MAY include additional non-authoritative metadata that does not affect the core state: - attestations — signatures over the core object - proof — optional Data Integrity Proof (P-256) over currentCore - domainVerification — optional DNS/HTTP domain-binding - any other optional terms defined in the JSON-LD context at: https://did-me.org/ns/did-me/v1

Processors that do not recognize these fields MUST ignore them, per DID Core rules. When projecting from core to DID Document JSON, prev MUST be omitted when core.prev is null (genesis state) and MUST be present as a non-null CID value when sequence > 1. proof remains optional metadata in v1; however, profiles that require ZK anchoring SHOULD include it.

9.3 Domain Verification Objects

Each optional domainVerification entry MUST include:

Resolvers MUST accept at least one valid domain-verification method. Support for both is RECOMMENDED.

9.4 Requirements


10. JSON-LD Context

did:me JSON-LD context provides optional metadata extensions. Implementations MUST ignore any unrecognized terms, consistent with DID Core processing rules.

The did:me JSON-LD context is published at https://did-me.org/ns/did-me/v1.

This context defines: - method-specific terms (sequence, prev, currentCore, coreCbor, keyHistory) - metadata terms (updatePolicy, attestations, domainVerification) - service types (e.g., ReallyMeDirectoryService) - optional device- or persona-related extensions (e.g., hardwareBound, biometricProtected, deviceModel)

All terms defined in the context: - MAY appear in DID Documents - MUST NOT influence the authoritative core state unless explicitly part of the core schema - MUST be ignored by processors that do not understand them, per DID Core rules

The JSON-LD context MUST be included in all did:me DID Documents to guarantee consistent interpretation of method-specific terms. The first three @context entries MUST be the canonical did:me context tuple, in this exact order: 1. https://www.w3.org/ns/did/v1 2. https://w3id.org/security/multikey/v1 3. https://did-me.org/ns/did-me/v1 Additional contexts MAY follow and MUST NOT redefine terms from the canonical tuple. Conformance checkers and validators SHOULD reject DID Documents whose additional contexts redefine terms from the canonical tuple.

10.1 alsoKnownAs (Optional Correlation Identifiers)

alsoKnownAs is an optional DID Core property that MAY appear in a did:me DID Document. It provides human-readable or system-assigned alternate identifiers, such as short profile URLs, usernames, handles, or legacy identifiers. These values: • do not participate in update authorization • do not affect core validity • do not alter the canonical core snapshot • MAY be ignored by resolvers or relying parties


  "alsoKnownAs": [
  "https://domain/<short-id>"
]

alsoKnownAs is strictly non-authoritative metadata and serves only as an optional correlation convenience.

10.2 Hardware Bound and Biometric Protected

hardwareBound and biometricProtected are optional metadata fields that describe protection characteristics of the controller’s authentication environment. These fields are not authoritative, do not affect core state, and MAY be ignored by relying parties.

10.3 User Verification Method

userVerificationMethod is optional metadata describing how a user authenticates locally (face, fingerprint, pin, passcode, password, iris, voice, pattern, none). This field is non-authoritative and MUST NOT influence the validity of a core snapshot.

10.4 Device and Model

deviceModel is optional metadata identifying the user’s device model or hardware platform. It is purely informational and does not affect DID state.


11. Security Considerations


12. Decentralization and Federation

did:me identifiers are fundamentally self-hosted and do not rely on any central registry. Optional public directories may mirror published DID Documents for discovery. The method’s structure supports decentralized and federated deployments without breaking existing identifiers.

The method supports: - Multi-directory federation – multiple independent operators may host equivalent projections of the same DID state for discovery. - Verifiable replay – any resolver can reconstruct canonical DID state by validating the chain of signed core snapshots. - Independent resolution – resolvers do not need to trust any directory, host, or service; all validation derives from the signed core chain.

This is enabled by: - sequence – enforces strict update ordering
- prev – links each core snapshot to the previous CID
- currentCore – cryptographic addressing of core snapshots
- signed canonical cores – guarantee tamper-evident integrity

These features allow did:me to evolve toward decentralized, distributed, or mirrored resolution models in the future.


13. Illustrative did:me JSON member order (non-normative)

JSON member order is non-normative. Producers MAY emit members in any order, and processors MUST NOT rely on JSON key order for validity. ~ @context id controller alsoKnownAs sequence prev

hardwareBound biometricProtected userVerificationMethod deviceModel

coreCbor currentCore keyHistory

verificationMethod authentication assertionMethod capabilityInvocation keyAgreement

service(s) updatePolicy attestations proof ~

14. Default Profile Requirements Matrix (did:me v1)

This section is normative for the did:me v1 default interoperability profile. The base method model is defined in Sections 5 through 9; this profile adds stricter required key sets and relationship requirements for public did:me v1 deployments.

This table defines for every DID Document field:

14.1 DID Document Field Matrix

Field Required Nullable Emit When Empty Notes
@context Yes No N/A The first 3 entries MUST be, in order: https://www.w3.org/ns/did/v1, https://w3id.org/security/multikey/v1, https://did-me.org/ns/did-me/v1. Additional contexts MAY follow and MUST NOT redefine terms from the canonical tuple.
id Yes No N/A MUST be a valid did:me: identifier.
controller Yes No N/A MUST be either: (a) a did:me: string, or (b) a non-empty array of did:me: strings.
alsoKnownAs No No Omit if empty Optional. MUST be an array when present.
sequence Yes No N/A MUST equal keyHistory.count + 1.
prev Conditional No Omit when sequence=1 MUST be omitted when sequence=1; otherwise MUST equal last keyHistory entry.
hardwareBound No Yes Omit if null/false Optional metadata. False treated as absent.
biometricProtected No Yes Omit if null/false Optional metadata. False treated as absent.
userVerificationMethod No Yes Omit if null Optional (“face”, “pin”, etc.).
deviceModel No Yes Omit if null/empty Optional metadata.
coreCbor Yes No N/A Base64url-encoded canonical DAG-CBOR bytes of the current core snapshot; decoded bytes MUST hash to currentCore.
currentCore Yes No N/A MUST be CIDv1 of the core snapshot.
keyHistory Yes No Emit empty array MUST contain only past CIDs; MUST NOT include currentCore.
verificationMethod Yes No N/A MUST contain all required key types.
authentication Yes No N/A MUST contain at least #ed25519 and #mldsa87-auth.
assertionMethod Yes No N/A MUST include #p256.
capabilityInvocation Yes No N/A MUST include #mldsa87-root.
keyAgreement Yes No N/A MUST include #x25519 and at least one of #mlkem768 or #mlkem1024.
service No No Omit if empty Include only when one or more services exist.
updatePolicy Yes No N/A MUST include allowedVerificationMethods containing #mldsa87-root.
attestations Yes No N/A MUST have ≥1 ML-DSA-87 core signature.
proof No No Omit if absent Optional in v1; strongly recommended for profiles requiring ZK anchoring.
domainVerification No No Omit if empty Optional DNS/HTTP domain-bindings.

14.2 Null vs Omission Rules Summary

NEVER emit explicit null in the JSON DID Document.

14.3 Required Arrays (non-null)

These MUST always be present in the JSON and MUST NOT be null:

14.4 Optional Arrays

These MAY be omitted entirely:

{
  "domainVerification": [
    {
      "method": "dns",
      "domain": "example.com",
      "dns": {
        "recordName": "_did",
        "txtValue": "did=me:123..."
      }
    }
  ]
}

or

{
  "domainVerification": [
    {
      "method": "wellknown",
      "domain": "example.com",
      "wellknown": {
        "uri": "/.well-known/did-configuration.json",
        "content": "eyAidHlwZSI6ICJkaWQtY29uZmlnIiB9" 
      }
    }
  ]
}

domainVerification entries are self-asserted claims added by the DID controller. Resolvers and relying parties MUST NOT assume these claims are accurate. Independent verification MUST be performed by the verifier.

DID Document Relationship Definitions

verificationMethod

Definition:
A list of all public keys the DID controls.

Meaning:
These keys exist and can be referenced by other DID Document sections.
This list does not define how the keys are used; roles appear below.

Used for:
- Declaring available keys
- Referencing keys in authentication, assertionMethod, etc.
- Interoperability with DID Core processors


authentication

Definition:
Keys used to prove control of the DID in interactive protocols.

Used for:
- Logging in
- Pairwise authentication
- Messaging identity proofs
- Presentations that require DID control verification

Key types:
- Ed25519
- ML-DSA-87
- P-256
(Never X25519 or ML-KEM; they cannot sign.)


assertionMethod

Definition:
Keys used to sign statements made by the DID, including VCs, public claims, and ZK-friendly proofs.

Used for:
- Verifiable Credential issuance
- Identity claims
- Public profile statements
- ZK-friendly attestations (P-256)

Key types:
- Ed25519
- ML-DSA-87
- P-256
(Never X25519 or ML-KEM.)


keyAgreement

Definition:
Keys used to derive shared secrets for encrypted channels.

Used for:
- Secure messaging
- Encrypted VC presentation
- Session establishment
- Hybrid encryption (X25519 + ML-KEM-768 + ML-KEM-1024)

Key types:
- X25519
- ML-KEM-768
- ML-KEM-1024
(Never Ed25519 or P-256; those are signing keys.)


capabilityInvocation

Definition:
Keys authorized to change or update DID state. These are the root control keys.

Used for:
- DID Document updates
- Key rotation
- Recovery operations
- Deactivation

Key types:
- ML-DSA-87 (recommended primary root)
- Ed25519 (optional second root for hybrid AND-control)
(Never X25519 or ML-KEM. P-256 should only be used if Secure Enclave must sign updates.)


attestations

Definition:
Signatures over the canonical core snapshot (DAG-CBOR) that validate DID state.
Used for hybrid AND-security.

Used for:
- Proving core snapshot authenticity
- True hybrid root control (Ed25519 AND ML-DSA-87)
- Long-term survivability across cryptographic eras

Key types:
- Ed25519
- ML-DSA-87


proof

Definition:
A non-authoritative P-256 Data Integrity Proof for compatibility with ZK systems, Apple Secp256r1 flows, and DI verifiers.

Used for:
- ZK proof integrations
- Apple Secure Enclave-backed identities
- EUDI Wallet compatibility
- JWS-based verifiers

Key types:
- P-256 only
(Does not control DID updates.)

DID Type Authentication Assertion / Proofs Verification Methods (VM Set) Key Agreement Capability Invocation (Root Control) Attestations (Core Update)
Core Identity (private wallet, root identity) Ed25519 + ML-DSA-87 + P-256 ML-DSA-87 + Ed25519 + P-256 (ZK-friendly) Ed25519, ML-DSA-87, P-256, X25519, ML-KEM-768, ML-KEM-1024 X25519 + ML-KEM-768 and/or ML-KEM-1024 ML-DSA-87 AND Ed25519 (dual required) Required dual (ML-DSA + Ed25519)
Public Profile (persona; receives ZK proofs) Ed25519 + P-256 (+ optional ML-DSA-87) Ed25519 + P-256 (+ optional ML-DSA-87) Ed25519, ML-DSA-87, P-256, X25519, ML-KEM-768, ML-KEM-1024 X25519 + ML-KEM-768 and/or ML-KEM-1024 ML-DSA-87 only Optional (P-256 DI proof recommended)
Public Profile + Issuer (VC issuer persona) Ed25519 + ML-DSA-87 + P-256 ML-DSA-87 (primary) + Ed25519 + P-256 Ed25519, ML-DSA-87, P-256, X25519, ML-KEM-768, ML-KEM-1024 X25519 + ML-KEM-768 and/or ML-KEM-1024 ML-DSA-87 AND Ed25519 Optional dual or PQ-only
Issuer DID (Harvard, banks, orgs) Ed25519 + ML-DSA-87 + P-256 ML-DSA-87 (primary) + Ed25519 + P-256 Ed25519, ML-DSA-87, P-256 Optional ML-DSA-87 AND Ed25519 Optional dual or PQ-only
Messaging DID (fast, throwaway, persona-tied) Ed25519 (+ optional P-256) None or P-256 if ZK required Ed25519, P-256, X25519, ML-KEM-768, ML-KEM-1024 X25519 + ML-KEM-768 and/or ML-KEM-1024 Ed25519 None
Payment / Wallet DID (optional specialization) secp256k1 + optional P-256 Optional secp256k1, P-256 Rare secp256k1 Optional

15. Conformance Test Vectors (Informative)

This section provides implementation-oriented conformance vectors. It is informative and does not replace normative requirements in Sections 5 through 14.

15.1 @context Canonical Prefix

15.1.1 Valid

The first three @context entries match the canonical tuple in order:

"@context": [
  "https://www.w3.org/ns/did/v1",
  "https://w3id.org/security/multikey/v1",
  "https://did-me.org/ns/did-me/v1",
  "https://example.org/extra-context"
]

Expected result: ACCEPT

15.1.2 Invalid

Wrong order in first three entries:

"@context": [
  "https://w3id.org/security/multikey/v1",
  "https://www.w3.org/ns/did/v1",
  "https://did-me.org/ns/did-me/v1"
]

Expected result: REJECT

15.1.3 Invalid (Term Redefinition in Additional Context)

Additional context attempts to redefine a canonical term:

"@context": [
  "https://www.w3.org/ns/did/v1",
  "https://w3id.org/security/multikey/v1",
  "https://did-me.org/ns/did-me/v1",
  {
    "currentCore": "https://example.org/redefinedCurrentCore"
  }
]

Expected result: REJECT

15.2 coreCbor and currentCore Consistency

15.2.1 Valid

Expected result: ACCEPT

15.2.2 Invalid

Expected result: REJECT

15.3 sequence, prev, and keyHistory

15.3.1 Valid Genesis

"sequence": 1,
"keyHistory": []

prev is omitted in the DID Document projection for genesis.

Expected result: ACCEPT

15.3.2 Invalid Non-Genesis

"sequence": 3,
"keyHistory": ["cidA", "cidB"],
"prev": "cidA"

Expected result: REJECT (prev MUST equal last keyHistory entry for sequence > 1)

15.4 Core Attestation Validation

15.4.1 Valid

"attestations": [
  {
    "alg": "ML-DSA-87",
    "vm": "#mldsa87-root",
    "sig": "<valid-base64url-signature-over-coreCbor-bytes>"
  }
]

Expected result: ACCEPT when: - vm exists in verificationMethod - alg matches verification method algorithm - decoded sig verifies over decoded coreCbor bytes

15.4.2 Invalid

"attestations": [
  {
    "alg": "ML-DSA-87",
    "vm": "#mldsa87-root",
    "sig": "!!!not-base64url!!!"
  }
]

Expected result: REJECT

15.5 Data Integrity Proof Behavior

15.5.1 Valid (Supported Suite)

"proof": {
  "type": "DataIntegrityProof",
  "cryptosuite": "es256-jws-cid-2025",
  "proofPurpose": "assertionMethod",
  "verificationMethod": "#p256",
  "created": "2026-01-01T00:00:00Z",
  "jws": "<valid-compact-jws>"
}

Expected result: - ACCEPT only if all cryptosuite checks pass, including: - type is DataIntegrityProof - cryptosuite is es256-jws-cid-2025 - protected JWS header is exactly {"alg":"ES256"} - payload equals currentCore - ES256 signature verifies with the referenced P-256 verification method - proof remains non-authoritative for update validity

15.5.2 Unsupported Suite Handling

"proof": {
  "type": "DataIntegrityProof",
  "cryptosuite": "unsupported-suite",
  "jws": "header.payload.signature"
}

Expected result: - proof treated as unsupported - proof MUST NOT be treated as valid - core-based DID validity processing continues