did:uuid Method Specification v0.1did: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.
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.
did:uuid FormatA 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:
10).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.
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.
The four DID operations defined by DID Core [[DID-CORE]] map onto RUUID concepts as follows.
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:
(network, type) tuple._uuid.<domain>, optionally an HTTP/HTTPS-served
JSON document at the well-known URL). A working PTR record alone is
sufficient for an RUUID to be resolvable to a default referent URL;
a UUID document is what makes the DID document informative.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.
A did:uuid DID resolver MUST perform the following
steps:
invalidDid.invalidDid.notFound.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):
did:uuid:<controller-RUUID>.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.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.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.
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:
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.
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.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:
data: URI in the URI
record at _uuid.<domain>, publish a new URI
record value.did:web:, did:plc:), the update mechanism
is that method's update mechanism.Caching follows ordinary HTTP semantics: the registry endpoint and
the document host SHOULD set appropriate Cache-Control
headers, and resolvers MUST respect them.
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.
The trust model of did:uuid is identical to the trust
model of the underlying RUUID resolution pipeline, summarised here for
convenience:
did:uuid
DID asserts that the holder of the encoded network prefix controls
the DID. The effective trust gate is not "owns an IP allocation"
but "holds reverse-DNS authority over that allocation" — the two
are separable services. Most residential customers receive IP
space (a /60 or /56 from many home ISPs) without a reverse-DNS
zone delegation; obtaining the delegation (NS records in the
parent's in-addr.arpa / ip6.arpa zone
pointed at one's own nameservers) generally requires a business
contract, a BGP-announced allocation, or a cloud-provider tier
that explicitly supports it. The population of entities that can
generate did:uuid: DIDs is therefore bounded by the
RIR / LIR / ISP allocation-and-delegation chain — a more
accountable gradient than e.g. domain-name registration. Two
residual risks worth naming: smaller allocations (per-customer
/64s, cloud-instance prefixes) carry weaker vetting at the bottom
of the chain; and BGP hijacking can give an attacker temporary
de-facto control of a network prefix, mitigated but not
eliminated by RPKI. Within this population, no further
good-faith guarantee is made.http:,
data:, or file: schemes have no
transport-layer authentication; resolvers SHOULD restrict the schemes
they will dereference based on operator policy.did:uuid does not define cryptographic verification of
the DID document. An attacker who can substitute the document (by
compromising DNS, the hosting server, or the network path) controls
the DID document. Future revisions of RUUID may add an optional
document-signing scheme; see the editor's note in
RUUID
§6.did:uuid
DIDs generated under the transferred prefix.did:uuid syntax accepts any variant-1 version-8 UUID,
but version 8 is custom/experimental in [[RFC9562]] with no
inherent subtype discriminator. A v8 UUID generated by some other
scheme is therefore syntactically a valid
did:uuid: DID even though its bit layout was not
chosen with RUUID semantics in mind. The accidental case is
self-mitigating: resolution of a
non-RUUID v8 UUID requires the reverse-DNS PTR for its 64-bit
network field to point at a domain that publishes either a
_uuid.<domain> URI/TXT record or a
/.well-known/uuid-document.json; neither is
something an unrelated third party publishes by accident. The
realistic failure modes are therefore (a) a legitimate RUUID
generator whose network prefix happens to overlap with someone
else's v8 UUID bits — the resolver fetches that generator's UUID
document, substitutes the random identifier into a template, and
the consumer almost always sees a 404; and (b) an adversary who
deliberately stands
up RUUID infrastructure to harvest collisions, bounded by the
reverse-DNS-authority gradient above (the attacker can only
claim prefixes they actually control reverse-DNS for, and only
"catches" v8 UUIDs whose network-field bits happen to fall in
those prefixes). The structural fix — applying for a dedicated
UUID version so that "this is an RUUID" is signalled in the
UUID bits themselves — would close the namespace claim
entirely but is out of scope for this revision.id is the resolved DID, the service array contains a
single entry wrapping the Phase 2 referent URI, and the
controller is the controller DID derived deterministically from
the RUUID's bits. The authorisation for this synthesis is the
reverse-DNS path that Phase 1 followed: only the entity
controlling the prefix's reverse-DNS zone can stand up the
registry endpoint that the resolver consulted, so only that
entity can have caused the referent URI template to be served.
Standard DID-Core alsoKnownAs reciprocation
guidance — resolving the other DID and checking it links back —
adds no information for intra-did:uuid: links, which
all route through the same network prefix (resolving them again
returns to the same UUID document).
Cross-method alsoKnownAs entries
(did:web:, did:plc:, etc.) resolve via
independent infrastructure and the standard guidance applies
normally.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.
did:uuid
resolution emits one or more DNS queries (PTR, URI/TXT) followed by an
HTTP fetch, each addressed to infrastructure the resolver did not
choose. Both the DNS path and the HTTPS path are visible to the
relevant network operators and to the operators of the registry
endpoint and document host. Resolvers that require resolution
confidentiality SHOULD use DNS-over-HTTPS or DNS-over-TLS, and
SHOULD consider HTTPS-fronted DID resolver gateways.did:uuid DIDs sharing a network prefix reach the same
registry endpoint and (in the default deployment) the same UUID
document host. An observer can correlate per-prefix traffic even
when the individual DIDs are unrelated. When per-DID
unlinkability matters, partition network prefixes per logical
group of subjects.did:uuid involves no public ledger or registry. A DID's
existence is visible only to parties who possess it or who
successfully resolve it.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.