The did:uuid Method Specification v0.1

did:uuid is a W3C Decentralized Identifier (DID) [[DID-CORE]] method whose method-specific identifier is a Resolvable UUID (RUUID). Resolution of a did:uuid DID runs the two-phase RUUID resolution pipeline to obtain a Phase 2 referent URI, then synthesises a per-RUUID DID document that wraps that URI as a service entry. The RUUID UUID document (a W3C Controlled Identifiers document, [[CID]]) provides type information and optional verification fields consumed during synthesis. No infrastructure beyond what the RUUID specification already requires is needed.

This is an unofficial editor's draft. It has no standing within the W3C Process and is published to invite review while the companion Internet-Draft, Resolvable Universally Unique Identifiers (RUUID) (draft-motters-ruuid), is in progress.

Introduction

The RUUID specification defines a UUID format that encodes a 64-bit network prefix, a 48-bit identifier, and a 10-bit type index, resolvable via DNS and various URI infrastructure. RUUID resolution is two-phase: Phase 1 walks from the RUUID's network prefix to a JSON-LD UUID document (a W3C Controlled Identifiers document, [[CID]]) carrying id, controller, alsoKnownAs, and per-type service templates; Phase 2 applies the matching service template to the 48-bit identifier to produce the referent URI. The RUUID spec's normative output is that URI.

This document specifies a DID method, did:uuid:X, that encapsulates an RUUID as a DID. The DID document for a did:uuid DID is synthesised by this method on top of the RUUID resolution pipeline's output: the resolved Phase 2 URI becomes the synthesised document's single service endpoint, and the controller is the controller DID derived from the RUUID's bits. The synthesis lives in this method, not in the RUUID spec, so RUUID can serve consumers that have no DID requirement at all.

The did:uuid Format

A did:uuid DID has the form:

did-uuid        = "did:uuid:" canonical-ruuid
canonical-ruuid = 8HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 12HEXDIG
HEXDIG          = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7"
                / "8" / "9" / "a" / "b" / "c" / "d" / "e" / "f"

The method-specific identifier is the canonical textual form of an RUUID, as defined in the RUUID specification §3 (equivalent to the standard UUID 8-4-4-4-12 lowercase hexadecimal form). Implementations MUST treat hexadecimal characters as lowercase; an identifier containing uppercase hexadecimal is not a conformant did:uuid DID.

Within the RUUID bit layout:

A DID whose method-specific identifier parses as a UUID but does not satisfy both constraints is not a did:uuid DID — for example, a version-4 random UUID encoded as did:uuid:... is syntactically not conformant, even though the textual form matches. Resolvers MUST reject such inputs.

Version 8 UUIDs are for custom/experimental use-cases, and [[RFC9562]] does not provide a means to distinguish subtypes of this version. A version 8 UUID may therefore not be a Resolvable UUID. If an attempt is made to resolve such a UUID, this will most likely fail early; namely, at the DNS PTR lookup on the low 64-bits of the UUID.

Example

did:uuid:abcdef01-2345-8200-8012-c000022a0000

This DID's method-specific identifier decodes to an RUUID with network prefix IPv4 192.0.2.42 (6to4-encoded into the network field), type 1, identifier 0xabcdef012345. Group 4 reads 8012: variant 10 at bits 63..62, type 0000000001 at bits 61..52, and the top nibble of network_lo (2) at bits 51..48.

DID Method Operations

The four DID operations defined by DID Core [[DID-CORE]] map onto RUUID concepts as follows.

Create

A did:uuid DID is created by the act of generating an RUUID and publishing a UUID document that an RUUID resolver can fetch for it. The generation and publication rules are out of scope for this method and are normatively specified by the RUUID specification:

The resulting DID is did:uuid:<canonical-RUUID>. No registration with any central authority is required: anyone who controls a network prefix can generate and publish a did:uuid DID under that network prefix.

Read (Resolve)

A did:uuid DID resolver MUST perform the following steps:

  1. Parse the method-specific identifier as an RUUID per RUUID §3. If parsing fails, return invalidDid.
  2. Verify that the RUUID's version is 8 and its variant is the [[RFC9562]] variant. If either check fails, return invalidDid.
  3. Run the two-phase RUUID resolution pipeline defined in RUUID §4 to obtain a Phase 2 referent URI for this RUUID, and (when Phase 1 succeeds) the UUID document fetched along the way. If Phase 1 fails altogether — no document, and no usable default-template fallback — return notFound.
  4. Synthesise the DID document for the resolved DID per §3.2.1 Synthesis, using the Phase 2 URI as the service endpoint and the UUID document (when present) for type propagation and cross-checks.

Synthesis

The RUUID pipeline's normative output is a referent URI, not a DID document. This method synthesises the DID document on top of that URI so the resolver can satisfy DID-Core §3.1 (the returned document's id MUST equal the resolved DID):

  1. Derive the controller RUUID deterministically from the resolved RUUID by zeroing the type and identifier fields. The controller DID is did:uuid:<controller-RUUID>.
  2. Construct the per-RUUID DID document:
    • id = the resolved DID.
    • controller = the controller DID.
    • service = a single entry wrapping the Phase 2 referent URI: id = the fragment #<type> under the resolved DID; serviceEndpoint = the Phase 2 URI; type is propagated from the matching service entry in the UUID document (RUUID §6.7 fallback ladder: type-specific entry, then #0 default), or a generic placeholder when no UUID-document entry matched (or no UUID document was fetched).
    • @context = the DID-Core context https://www.w3.org/ns/did/v1; an additional entry MAY be appended when the UUID document's context carries material the synthesised document needs.
  3. If the UUID document lists the controller DID in alsoKnownAs or as its own id, that is an explicit confirmation; mismatch (the UUID document claims a different controller DID) SHOULD be logged, and operators MAY configure the resolver to return notFound on mismatch.
  4. Return the synthesised document as the DID document.

The reverse-DNS routing performed during Phase 1 is what authorises the synthesis: only the controller of the prefix's reverse-DNS zone can stand up the DNS path that the resolver follows back to a registry endpoint and on to the UUID document. The controller DID is fully determined by the resolved RUUID's bits, so the resolver does not depend on the UUID document to learn it; the document's optional alsoKnownAs entry is a cross-check, not the root of trust.

Equivalence with the bare RUUID pipeline

The synthesis is a pure function of the resolved RUUID's bits and the UUID document's contents. As a result, resolving did:uuid:<X> via this method and resolving the bare RUUID X through the RUUID pipeline (with the post-Phase-2 synthesis applied) return the same DID document, byte-for-byte, against the same registry and UUID document. The second path is just the first path with a "parse the RUUID out of the DID method-specific id" prefix.

The practical consequence is that a consumer chooses the interface that suits their tooling:

  • A consumer that only needs the referent URI uses the RUUID pipeline directly and reads its Phase 2 output.
  • A DID-aware consumer presents did:uuid:<canonical-RUUID> to a DID resolver and receives the synthesised DID document.

Both paths exercise the same UUID document; they differ only in whether the synthesis wrapper is applied to the result. Demo case #1 of the reference implementation shows both: the verbose mode prints the Phase 2 referent URI and, separately, the DID Document for equivalent DID-encapsulated RUUID --- the latter is what a DID resolver would return for did:uuid:<canonical-RUUID>.

When the UUID document carries the optional verification fields prefixes and domains (RUUID §6.4), the resolver SHOULD cross-check the resolved RUUID's network prefix against prefixes and the domain returned by Phase 1 against domains. A mismatch SHOULD be logged; whether to fail resolution is operator policy.

Resolution Metadata

The resolver MAY include the following entries in the DID-resolution metadata it returns:

  • contentType: "application/did+json" (or "application/did+ld+json" if the document carries @context, which a conformant RUUID UUID document should).
  • error: present only on failure; one of invalidDid, notFound, or internalError.

Update

A did:uuid DID is updated by changing the UUID document that the RUUID resolution pipeline returns for it. The mechanism depends on where the document is hosted:

Caching follows ordinary HTTP semantics: the registry endpoint and the document host SHOULD set appropriate Cache-Control headers, and resolvers MUST respect them.

Deactivate

A did:uuid DID is deactivated by removing the published UUID document and the supporting registry-endpoint records, leaving the default resolution path to return notFound. The RUUID itself MUST NOT be reused for a different referent after deactivation (RUUID §7.2): the binding is one-way.

A resolver that fetches a previously-resolvable did:uuid and now receives notFound SHOULD treat the DID as deactivated.

Security Considerations

The trust model of did:uuid is identical to the trust model of the underlying RUUID resolution pipeline, summarised here for convenience:

A resolver SHOULD log resolution-time TLS validation failures and DNS anomalies in a way that lets the operator distinguish transient failures from probable compromise.

Privacy Considerations

Reference Implementation

A reference resolver is implemented in ruuid-tools (Python). The handler lives at ruuid-tools/ruuid/did.py and delegates resolution to ruuid.resolve.resolve_ruuid. End-to-end behaviour is exercised by demo case #9c in ruuid-tools/demo/demo.sh.