The did:vh DID Method
v0.1 / Editors Draft§
Specification Status: Editors Draft
Specification Version: v0.1 (see Changelog)
Source of Latest Draft: https://github.com/swcurran/didvh
- Editors:
- Stephen Curran
- Participate:
- GitHub repo
- File a bug
- Commit history
- Related Specifications:
- VH-Log — the log mechanism
did:vhspecialises - did:webvh — the web-located sibling of
did:vh
Abstract§
did:vh (DID + Verifiable History) is a DID Method defined as a
specialisation of the VH-Log specification. It is the
location-independent sibling of did:webvh: a did:vh DID is simply
did:vh:<SCID>
where <SCID> is the self-certifying identifier derived from the DID’s
first DID log entry. Unlike did:webvh, a did:vh DID contains no
domain name or path, and so is not bound to any location where its
DID Log is published.
did:vh constrains VH-Log by specifying:
- The state object is a W3C DID Document (DIDDoc).
- The log file is named
did.jsonl, and the witness proofs filedid-witness.json, as indid:webvh. - The DID identifier is the method prefix and the SCID, nothing else.
Because the DID carries no location, sourcing the DID Log is
separated from resolving the DID. A did:vh Resolver implements the
standard DID Resolution resolve(did, resolutionOptions) function: the client
passes the DID Log and witness proofs directly, or by reference in the
src option, as resolution
options, and the Resolver verifies the log
and returns the DIDDoc. How a client sources the DID Log
beforehand — getting the log itself or a reference to it, because it is
known in context, from a watcher, exchanged
peer-to-peer, or from a web location — is described
non-normatively, and a DID Log sourced in any of these ways is verified in
exactly the same way. The
SCID guarantees that the log is the authentic history of the DID,
wherever it came from.
Through VH-Log, did:vh provides the same verifiable-history features as
did:webvh:
- A self-certifying identifier (SCID), globally unique and derived from the initial DID log entry, binding the DID to its full history.
- The ability to resolve the full history of the DID using a verifiable chain of updates to the DIDDoc, from creation to deactivation.
- DIDDoc updates containing a proof signed by a DID Controller-authorized key.
- An optional mechanism for publishing pre-rotation key hashes to prevent loss of control of a DID when an active private key is compromised.
- An optional mechanism for having collaborating witnesses approve updates to the DID before publication.
- Support for cryptographic agility through versioned specification upgrades and algorithm-identifying formats.
- An optional mechanism for listing watchers that archive and re-serve the DID’s history.
Separating the identifier from the location of its history gives did:vh
properties that a web-located DID cannot have:
- Permanence. The DID never has to change because the place its history is kept changes. There is no need for a portability mechanism.
- Location independence. The DID Log can be kept on a web server, with a watcher, in a database, on a distributed ledger, or only in the wallets of the parties to a relationship — and in several such places at once.
- Peer-to-peer use. A
did:vhDID can be used between two parties who exchange their DID Logs directly, in the manner ofdid:peer[DID-PEER], while still supporting key rotation, pre-rotation and the other VH-Log features.
did:vh is comparable to the did:scid:vh format of the proposed
did:scid
metamethod, and adopts its src parameter.
Overview§
did:webvh added a verifiable history to did:web: a self-certifying identifier
(SCID), a hash-chained log of every version of the DIDDoc,
signed updates, pre-rotation, witnesses and watchers. It kept
the domain name from did:web in the DID, so that a Resolver can turn
the DID into an HTTPS URL and fetch the DID Log.
The domain name does two jobs in did:webvh: it tells a Resolver
where to find the log, and it makes the DID a web identifier. It is not needed
for security — the SCID and the verifiable history provide that on
their own. But it does tie the DID to one location. When that location
changes, the DID changes, which did:webvh handles with its optional
portability mechanism, at the cost of a DID that is no longer the same string.
Many uses of DIDs need an identifier that never changes: as a permanent
account identifier, embedded in content-addressed data, or held in long-lived
credentials. Others have no web location at all: DIDs exchanged between two
parties, DIDs kept in an organisation’s database, or DIDs anchored on a
ledger. did:vh serves those uses by removing the location from the DID:
did:webvh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ:example.com:dids:issuer
did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ
Everything else is kept as close to did:webvh as makes sense. The DID format, parameters, SCID and entry-hash algorithms,
key authorisation and pre-rotation, witnesses, watchers, and
DID URL query parameters are those of VH-Log as used by did:webvh.
Implementations of did:webvh should be able to support did:vh by replacing
the DID-to-HTTPS transformation with the DID Log
sources defined here and dropping the
web-location-specific features.
The following is a tl;dr summary of how did:vh works:
- A DID Controller creates the first DID log entry exactly as
in
did:webvh, using the DID stringdid:vh:{SCID}with the{SCID}placeholder, calculates the SCID and replaces the placeholders. - The DID Log (
did.jsonl) is a JSON Lines file of DID log entries, each containing aversionId,versionTime,parameters,state(the DIDDoc) and a Data Integrity proof, as defined in VH-Log. - The DID Controller makes the DID Log available wherever it is needed: to the other party in a relationship, to one or more watchers, at one or more web locations, or in any other store. There is no single authoritative location.
- A client that needs to resolve
did:vh:<SCID>first sources the DID Log: it gets the log itself from context, a watcher or a peer, or a reference to it, such as the web location given indid:vh:<SCID>?src=https://example.com/dids/issuer. - The client calls the Resolver, passing
the DID Log (and witness proofs) directly, or by reference in the
srcoption. The Resolver verifies the log with the VH-Log algorithm and returns the DIDDoc. The SCID check ensures the log is the history of that DID, regardless of where it came from. - Updates append entries to the log, which the DID Controller re-distributes to the places the log is kept.
Because a did:vh DID Log has no single authoritative location, a
Resolver cannot always be sure it holds the latest version of the
log, and a DID Controller could give different parties different
extensions of the same log. Watchers and witnesses are the
tools did:vh uses to manage those risks; see Log Freshness and
Duplicity.
Relationship to did:scid§
The proposed
did:scid
metamethod defines a family of location-independent DIDs, each using the
verification data format of an existing SCID-based DID method. Its
did:scid:vh format uses the did:webvh format, and so is comparable to
did:vh:
did:scid:vh:1:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ
did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ
did:vh shares the design goals of did:scid — a permanent, portable,
self-certifying DID whose history can be kept in any number of locations — and
adopts its src parameter for passing the log by reference, as both a resolution
option and a DID URL query parameter. The
differences are:
did:vhis a standalone DID method rather than a format of a metamethod.- The version of the specification in use is carried in the
methodparameter of the DID Log, as indid:webvh, rather than in the DID string. - In this version of
did:vh, thesrcparameter carries only a URL: anhttpsURL, a URL with another scheme the Resolver supports (such asipns), or, as a resolution option to a local Resolver, a loopbackhttpURL or afile:URL for a local directory.did:scidalso allows it to name a DID method that stores the log.
Because the DID string is part of the first DID log entry, and so of
the input to the SCID, a did:vh, a did:scid:vh and a did:webvh
DID can never share a DID Log or an SCID. A
DID Controller can link such DIDs using alsoKnownAs.
did:vh DID Method Specification§
Conformance§
As well as sections marked as non-normative, all examples, notes, and informative checklists in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, MUST NOT, NOT REQUIRED, RECOMMENDED, REQUIRED, SHOULD, and SHOULD NOT in this specification are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
Relationship to VH-Log and did:webvh§
did:vh is a specialisation of the VH-Log specification.
VH-Log defines the log mechanism underlying did:vh — the log entry structure,
cryptographic chaining, SCID, parameters, witnesses,
watchers, and the resolution algorithm. This specification defines
only what is specific to did:vh, and implementers MUST consult
VH-Log for the normative definition of the log mechanism.
did:vh constrains VH-Log by:
- Specifying the state object as a W3C DID Document (DIDDoc).
- Naming the log file
did.jsonland the witness proofs filedid-witness.json. - Defining the DID as
did:vh:<SCID>, with no location component. - Defining how the DID Log is sourced and
passed to a Resolver as
did:vhresolution options, including thesrcoption. - Using
method(e.g.,did:vh:1.0) as thedid:vh-specific form of the VH-LoglogVersionparameter. - Defining the DID method identifier, CRUD operations and DID URL handling.
did:vh is deliberately as close to
did:webvh as its lack of a location allows.
The differences are:
did:webvh |
did:vh |
|
|---|---|---|
| DID | did:webvh:<SCID>:<domain>[:<path>] |
did:vh:<SCID> |
| Locating the DID Log | DID-to-HTTPS transformation | Passed to the Resolver in resolution options, after the client sources it |
method values |
did:webvh:1.0 |
did:vh:1.0 |
portable parameter |
Optional | Not used — the DID never changes |
Implicit #files and #whois services |
Derived from the HTTPS location | None |
Parallel did:web |
Optional | Not applicable |
The log format, SCID and entry hash algorithms, key
authorisation, pre-rotation, witness identifiers (did:key), witness file
format, and the versionId, versionTime and versionNumber DID URL query
parameters are the same in both methods.
Target System§
did:vh does not have a single target system. A did:vh DID Log can
be held by any system that can store and return a file: a web server, a
watcher, a database or registry, a distributed ledger, or the wallets
of the parties that use the DID. The SCID and the verifiable history
make the DID Log verifiable no matter which of those systems it was
obtained from.
Method Name§
The namestring that identifies this DID method is: vh. A DID that uses this
method MUST begin with the prefix did:vh:. Per the DID specification, the
prefix MUST be in lowercase. The remainder of the DID, after the prefix, is
the method-specific identifier.
Method-Specific Identifier§
The did:vh method-specific identifier is the SCID of the DID, and
nothing else. The SCID MUST be
generated during the creation of the DID
from its initial content.
A did:vh DID MUST conform to the following ABNF [RFC5234]:
vh-did = "did:vh:" scid
scid = 46base58-char
base58-char = %x31-39 / %x41-48 / %x4A-4E / %x50-5A / %x61-6B / %x6D-7A
; the base58btc alphabet: 1-9, A-Z except I and O,
; a-z except l
A did:vh DID URL follows the generic DID URL syntax of [DID-CORE],
with the addition of the optional src query
parameter.
A did:vh DID, and DID URLs using the src and versionNumber query
parameters and a fragment:
did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ
did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ?src=https://example.com/dids/issuer
did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ?versionNumber=3
did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ#key-1
The DID Log File§
The did:vh DID Log is a VH-Log log file. The log entry
structure, JSON Lines serialisation, cryptographic chaining, and
verification algorithm are all as defined in VH-Log. This includes
VH-Log’s requirement that versionTime values are in whole seconds, with no
fractional seconds, as in did:webvh.
The did:vh-specific constraints are:
- When the log is stored as a file, it SHOULD be named
did.jsonl, and MUST be nameddid.jsonlwhen stored at a location named by asrcreference. Its media type SHOULD betext/jsonl. - The witness proofs file, when stored as a file, SHOULD be named
did-witness.json, and MUST be nameddid-witness.jsonwhen stored at a location named by asrcreference. - The
stateproperty of each entry MUST contain the DIDDoc for that version of the DID. - The
parametersproperty MUST followdid:vhDID Method Parameters.
did:vh-specific examples of log entries that fail verification, in
addition to the general examples in VH-Log. Illustrative and
non-exhaustive.
-
state.idis not the DID. The first entry hasparameters.scid: "Qm111...", and an entry hasstate.id: "did:vh:Qm111...?src=https://example.com"or"did:webvh:Qm111...:example.com". Every entry’sstate.idmust be exactlydid:vh:Qm111.... -
portableparameter present. An entry includes"portable": true.portableis not adid:vhparameter. -
did:webvhmethod value. The first entry hasparameters.method: "did:webvh:1.0". Adid:vhlog must use adid:vhmethodvalue.
DID Method Operations§
Create (Register)§
Creating a did:vh DID follows the Create algorithm defined in
VH-Log, with the following did:vh-specific constraints:
-
The DID string (VH-Log Create step 1) is the literal
did:vh:{SCID}, where{SCID}is the placeholder for the SCID calculated later. -
The initial state object MUST be a DIDDoc (VH-Log Create step 3). Its top-level
idMUST bedid:vh:{SCID}. All other absolute references to the DID within the DIDDoc MUST likewise use the placeholder form (e.g.,did:vh:{SCID}#key-1). The DIDDoc MAY contain any other content the DID Controller requires. -
The parameters (VH-Log Create step 4) MUST follow
did:vhDID Method Parameters, including adid:vhmethodvalue. -
Witnesses. If witnesses are used, the witness proofs MUST be collected into the witness proofs file before the DID Log is distributed.
-
Distribution (VH-Log Create step 7). Instead of publishing the log at a location derived from the DID, the DID Controller makes the DID Log (and witness proofs file) available through the DID Log sources (see Sourcing the DID Log) that the parties who will resolve the DID will use: giving it to a peer, sending it to watchers, publishing it at one or more web locations, or storing it where the ecosystem expects to find it. A DID Controller MUST make the log available through at least one source that those parties can use.
Read (Resolve)§
A did:vh Resolver implements the resolve function defined in
[DID-RESOLUTION]:
resolve(did, resolutionOptions) →
« didResolutionMetadata, didDocument, didDocumentMetadata »
The did input is the DID itself, did:vh:<SCID>, which says nothing about
where the DID Log is. The client of the Resolver therefore
passes the DID Log — and, if witnesses are in use, the
witness proofs — in resolutionOptions, in one of the two
ways defined below: directly, or by reference, in
which case the Resolver first retrieves the files. The
Resolver then verifies the DID Log and returns the requested
version of the DIDDoc.
The Resolver does not discover the DID Log. How a client
sources the DID Log — gets the log itself, or a reference to it —
before calling resolve is described in the non-normative Sourcing the DID
Log section. Once it has the DID Log the
client passed, the Resolver retrieves further copies only when the
client asks it to, with the checkWatchers and extraWatchers options, to
check that the client’s copy is current and has not been forked.
did:vh Resolution Options§
A did:vh Resolver MUST recognise the following options, which
pass the DID Log to it. They are did:vh-specific, and are to be
registered in [DID-EXTENSION-RESOLUTION].
| Option | Value | Purpose |
|---|---|---|
didLog |
String | The complete DID Log, in JSON Lines format. |
didWitness |
JSON array | The witness proofs file content, as defined in VH-Log’s Witness Proofs File section. |
src |
String | A reference to the location where did.jsonl (and did-witness.json) are stored. See The src Option. |
A did:vh Resolver also supports the options defined in VH-Log’s
Resolution
Options
section, passed in resolutionOptions. versionId and versionTime are
defined in [DID-RESOLUTION]; versionNumber, checkWatchers,
extraWatchers and minCopies are did:vh-specific, and are to be
registered in [DID-EXTENSION-RESOLUTION]. The DID Log passed
directly or by reference is the copy from the location defined by the
specialisation (VH-Log Resolution Options step 1), and counts
towards minCopies.
The options support two ways of giving the Resolver the DID Log:
- Passing the log directly. The client passes the content of the
DID Log in
didLog, and of the witness proofs file (if any) indidWitness. - Passing the log by reference. The client passes, in
src, a reference to the location from which the Resolver retrievesdid.jsonlanddid-witness.json, as defined in ThesrcOption. In this version ofdid:vh, a reference is a web location, a location using another URL scheme the Resolver supports, or, for a Resolver local to its client, a local directory or loopback web location.
In addition to VH-Log’s requirements for its options:
- Exactly one of
didLogandsrcMUST be given. didWitnessMAY be given only withdidLog.- A malformed option, a value that does not conform to the rules for
src, or more than one ofversionId,versionTimeandversionNumber, MUST cause theinvalidOptionserror. - A Resolver MUST support logs passed directly. It MAY decline to
retrieve from a
srcreference, based on its policy (for example, a Resolver that never retrieves from locations chosen by its callers), and then MUST return thefeatureNotSupportederror, except as defined in Web Locations and Local Directories. - A VH-Log option the Resolver does not support MUST cause the
featureNotSupportederror. A Resolver SHOULD supportcheckWatchers,extraWatchersandminCopies. - Each
extraWatchersvalue MUST be anhttpsURL.
Passing the log directly, resolving version 2:
{
"did": "did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ",
"resolutionOptions": {
"didLog": "{\"versionId\":\"1-Qm...\",...}\n{\"versionId\":\"2-Qm...\",...}\n",
"didWitness": [ { "versionId": "2-Qm...", "proof": [ ... ] } ],
"versionNumber": 2
}
}
Passing the log by reference to a web location:
{
"did": "did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ",
"resolutionOptions": {
"src": "https://example.com/dids/issuer"
}
}
Passing the log by reference to a local directory, using a local Resolver:
{
"did": "did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ",
"resolutionOptions": {
"src": "file:///var/lib/wallet/dids/QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ"
}
}
The src Option§
The src (“source”) option is a reference to the location where
did.jsonl and, if witnesses are active, did-witness.json are
stored. A src value MUST be an absolute URL [RFC3986], and its
scheme determines the kind of reference:
https, orhttpwith a loopback host: a web location, such ashttps://example.com/dids/issuerorhttp://localhost:8000/dids/issuer.file: a local directory [RFC8089], such asfile:///var/lib/wallet/dids/QmfGEU....- Any other scheme: an other scheme reference, such as
ipns://k51qzi5uqu5d.../dids/issuer.
A value that is not an absolute URL, or that is not valid for its kind,
MUST cause the invalidOptions error.
Whatever the kind of reference, the Resolver MUST retrieve the
files the same way: did.jsonl from the location, and, if the active
parameters require witnesses, did-witness.json from the
same location (for a web location, as defined in Web
Locations). If did.jsonl is not found, the Resolver MUST
return the notFound error.
Because a location can hold only one did.jsonl, a DID Controller
or client storing several did:vh DID Logs in one place SHOULD
give each its own location (a URL path or a directory). Using the
SCID as the last path segment is a simple way to do so.
A src reference is not authoritative: a DID Controller MAY stop
publishing at a web location at any time, and the DID Log found
through any src reference may not be the latest. Because src is not part
of the DID, the DID does not change when the log is stored elsewhere.
A src reference also says nothing about who controls the DID: a
DID Controller can publish a log at any location it can write to,
and anyone can put any src value in a DID URL. Resolvers and their
clients MUST NOT treat a src reference as evidence of an association
between the DID and the owner of the location.
The did:scid src parameter can also name a DID method that stores the
verification data (for example, a DID-Linked Resource on a ledger). This
version of did:vh supports only URL references. Other kinds of reference,
such as DID values or references to other ways of storing a
DID Log, may be added in a later version.
Web Locations§
A web location reference is the base URL under which the files are
published on a web server, such as https://example.com/dids/issuer.
The following requirements apply to a web location reference:
- The value MUST be an absolute URL with the
httpsorhttpscheme, and MUST NOT include a query or fragment component. - The value MAY include a port, such as
https://example.com:3000/dids. - For
https, the host MUST be a domain name, not an IP address. A host containing non-ASCII characters (an internationalised domain name) MUST be converted to its ASCII form (A-labels) as defined in IDNA2008 [RFC5891] before retrieval; a host that cannot be converted MUST cause theinvalidOptionserror. - For
http, the host MUST be a loopback host:localhost, an IPv4 address in127.0.0.0/8, or[::1]. Anhttpreference with any other host MUST cause theinvalidOptionserror. Anhttpreference is a loopback reference, intended for development and testing. - After any trailing
/is removed, each path segment, once percent-decoded, MUST be non-empty, MUST NOT be.or.., MUST NOT contain/,\or NUL, and MUST NOT begin or end with whitespace. The checks apply to the decoded form because percent-encoded variants such as%2E%2E,%2F,%5Cand%00would otherwise pass unnoticed. A segment that fails a check MUST cause theinvalidOptionserror. - A loopback reference is subject to the same restrictions as a local
directory reference: a Resolver that accepts
requests from other systems MUST NOT retrieve from it and MUST
return the
invalidOptionserror, and it MUST NOT be taken from a DID URL. A loopback reference would otherwise let a caller make a Resolver send requests to services on its own host.
To retrieve the DID Log from a web location, the Resolver MUST:
- Take the
srcvalue, removing any trailing/. - If the URL has no path, append
/.well-known/did.jsonl. Otherwise, append/did.jsonl. - Retrieve the DID Log with an HTTP
GET(HTTPS for anhttpsreference), following the transport requirements below. - If the active parameters require witnesses, retrieve the
witness proofs file from the same URL with the final
did.jsonlreplaced bydid-witness.json.
When retrieving from a web location, a Resolver MUST meet the requirements of VH-Log’s Retrieving Log Resources section, which include HTTPS with server authentication, no automatic redirects, and rejection of IP literals and private addresses. The only exception is a loopback reference, for which the requirements to use HTTPS and to reject loopback hosts do not apply.
This is the same layout as did:webvh, so a web location reference names the
same location as the domain and path of a did:webvh DID:
Web location src values and the corresponding DID Log URLs:
https://example.com --> https://example.com/.well-known/did.jsonl
https://example.com/dids/issuer --> https://example.com/dids/issuer/did.jsonl
https://example.com:3000/dids/issuer --> https://example.com:3000/dids/issuer/did.jsonl
https://example.com/users/{SCID} --> https://example.com/users/{SCID}/did.jsonl
http://localhost:8000/dids/issuer --> http://localhost:8000/dids/issuer/did.jsonl
Local Directories§
A local directory reference identifies a directory on the system where the Resolver runs. It is for a Resolver used by a client on the same system — for example, a Resolver used as a library or command-line tool — such as a wallet that keeps the DID Logs it holds in local storage.
- A local directory reference MUST be a
file:URL [RFC8089] with an absolute path, an empty host or the hostlocalhost, and no query or fragment component. - To retrieve the files, the Resolver MUST remove any trailing
/from the path, and append/did.jsonlfor the DID Log and/did-witness.jsonfor the witness proofs file. A file that does not exist or cannot be read is treated as not found. - A Resolver MUST treat the content of the files exactly as if it had been passed directly.
- A Resolver that accepts requests from other systems — for example,
over HTTP — MUST NOT read local files, and MUST return the
invalidOptionserror for a local directory reference. - A local directory reference MUST NOT be taken from a DID URL, as
defined in Reading
did:vhDID URLs. A DID URL can come from an untrusted party; allowing it to name local directories would let such a party make a Resolver read files on its host.
Local directory src values and the corresponding DID Log files:
file:///var/lib/wallet/dids/QmfGEU... --> /var/lib/wallet/dids/QmfGEU.../did.jsonl
file://localhost/home/alice/dids/QmfGEU.../ --> /home/alice/dids/QmfGEU.../did.jsonl
Other Schemes§
A Resolver MAY support src references using other URL schemes,
provided the scheme has hierarchical paths through which a base URL names a
location holding did.jsonl and did-witness.json — for example, ipns
and ipfs URLs naming an IPFS directory. For such a reference:
- The value MUST NOT include a query or fragment component.
- The Resolver MUST remove any trailing
/, and append/did.jsonlfor the DID Log and/did-witness.jsonfor the witness proofs file. The/.well-known/form used by web locations does not apply. - A Resolver that does not support the scheme MUST return the
featureNotSupportederror. - A Resolver MUST apply to the retrieval protections equivalent to those required for web locations, including to any gateway it uses to reach the scheme’s network.
Other scheme src values and the corresponding DID Log locations:
ipns://k51qzi5uqu5d.../dids/issuer --> ipns://k51qzi5uqu5d.../dids/issuer/did.jsonl
ipfs://bafybei.../ --> ipfs://bafybei.../did.jsonl
Some schemes name immutable content. An ipfs URL names a directory by the
hash of its content, so any change to did.jsonl or did-witness.json —
including witness proofs added after an entry — gives the directory a new
identifier. An ipfs reference is therefore a snapshot of the
DID Log, useful for archiving but never updated; an ipns name,
which the DID Controller repoints to each new directory, can serve
the latest log. See Log Freshness and
Duplicity.
Resolution Algorithm§
A did:vh Resolver MUST apply VH-Log’s Read
(Resolve)
algorithm, including its Comparing Copies of a
Log
and Selecting a
Version
sections, with the following did:vh-specific rules:
-
The DID. The
didinput MUST conform to the ABNF in Method-Specific Identifier; if it does not, return theinvalidDiderror. -
The options. Validate the
resolutionOptionsas defined indid:vhResolution Options. If they are invalid, return theinvalidOptionserror. -
Getting the log (VH-Log Read step 1). Get the DID Log according to how it was passed:
- Directly: the
didLogvalue. - By reference: retrieve it as defined in The
srcOption. If the DID Log is not found, return thenotFounderror.
The witness proofs file is needed only if the active parameters require witnesses. When it is, use the
didWitnessvalue if the log was passed directly, or retrieve the file from the samesrcreference as defined in ThesrcOption. - Directly: the
-
Parameters (VH-Log Read step 1).
parametersMUST adhere todid:vhDID Method Parameters. -
Witnesses (VH-Log Read step 2.1). Witness proofs MUST be verified as defined in Witnesses.
-
State (VH-Log Read step 6). For every entry,
state.idMUST be exactlydid:vh:followed by thescidparameter of the first entry, and that SCID MUST equal the SCID of thedidinput. This check applies to every entry verified, including those of further copies retrieved withcheckWatchersorextraWatchers. -
Result. Return the DIDDoc (unless the DID is deactivated, as defined in Deactivate (Revoke)) with the metadata defined in DID Resolution Metadata. A failure that VH-Log defines returns the corresponding
errorlisted there.
DID Resolution Metadata§
As defined in [DID-RESOLUTION], a did:vh Resolver
SHOULD return the following DID Document Metadata:
{
"versionId": "1-QmRRaLXwc6BjBuBPosSupJwEQ8w9f3znP7yfbpGfwcnLr6",
"versionTime": "2025-01-23T04:12:36Z",
"created": "2025-01-23T04:12:36Z",
"updated": "2025-01-23T04:12:36Z",
"scid": "QmPEQVM1JPTyrvEgBcDXwjK4TeyLGSX1PxjgyeAisdWM1p",
"deactivated": false,
"ttl": "3600",
"witness": { ... },
"watchers": [ ... ]
}
The items are taken from the VH-Log Resolution Result, as follows:
versionId— TheversionIdof the DID log entry of the resolved DIDDoc version.versionTime— TheversionTimeof the DID log entry of the resolved DIDDoc version, as an ISO8601 timestamp.created— TheversionTimeof the first DID log entry, as an ISO8601 timestamp: when, according to the DID Controller, the DID was created.updated— TheversionTimeof the last valid DID log entry, as an ISO8601 timestamp.scid— The SCID of the DID.deactivated— A boolean that istrueif the DID has been deactivated, as defined in Deactivate (Revoke).ttl— A string containing the unsigned integer value, in seconds, of the activettlparameter: guidance from the DID Controller on how long to cache the resolution result.witness— The activewitnessparameter object, as defined in VH-Log’s ThewitnessParameter section, if witnesses are active. Itsthresholdvalue is a string containing the integer value.watchers— The active list of watcher URLs from thewatchersparameter.
“Active” means as set by the last valid DID log entry. That is the last entry in the DID Log unless later entries fail verification, in which case it is the last entry before the first failure.
ttl and the witness threshold are strings, not integers, because
[DID-RESOLUTION] does not permit integers in DID metadata; a client
converts them to integers before use. updated, and the values marked
active, reflect the DID Log passed to the Resolver, which
may not be the latest (see Log Freshness and
Duplicity).
The copies and warnings items of the VH-Log Resolution
Result describe the resolution
rather than the DID, so they are returned in the didResolutionMetadata, not
the DID Document Metadata. A Resolver given checkWatchers,
extraWatchers or minCopies MUST include copies, and SHOULD
include warnings when there are any, with the structure and values defined
in VH-Log:
{
"contentType": "application/did+json",
"copies": [
{
"source": "https://example.com/dids/issuer",
"versionId": "3-QmRRaLXwc6BjBuBPosSupJwEQ8w9f3znP7yfbpGfwcnLr6",
"status": "current"
},
{
"source": "https://watcher.example.org",
"versionId": "2-QmPEQVM1JPTyrvEgBcDXwjK4TeyLGSX1PxjgyeAisdWM1p",
"status": "behind"
},
{
"source": "https://watcher.example.net",
"status": "unavailable"
}
],
"warnings": [
{
"code": "copy-behind",
"source": "https://watcher.example.org",
"message": "Copy is 1 entry behind the reference copy."
},
{
"code": "copy-unavailable",
"source": "https://watcher.example.net",
"message": "Watcher did not respond."
}
]
}
When a DID resolution error occurs, the error field MUST be included in
the didResolutionMetadata, as defined in [DID-RESOLUTION], and
Resolvers SHOULD include problemDetails following
[RFC9457]. The following error values MUST be used. The first
four are from [DID-EXTENSION-RESOLUTION]; logForked and
insufficientCopies are did:vh-specific, and are to be registered there.
invalidDid— The DID is malformed, or the DID Log passed to the Resolver (or the requested version) fails verification.invalidOptions— A resolution option is malformed or not permitted, including a local directory or loopback reference passed to a Resolver that accepts requests from other systems.notFound— The DID Log was not found through thesrcreference, the requested version does not exist, or the resource referenced by a DID URL was not found.featureNotSupported— The Resolver declined to retrieve from asrcreference, does not support the scheme of asrcreference, or does not supportversionNumber,checkWatchers,extraWatchersorminCopies.logForked— Two copies of the DID Log both pass verification but diverge, as defined in VH-Log’s Comparing Copies of a Log section. TheproblemDetailsMUST include the fork report that section requires.insufficientCopies— Fewer thanminCopiescopies of the DID Log were retrieved and matched.
Reading did:vh DID URLs§
The src, versionId, versionTime and versionNumber options can also be
given as DID URL query parameters, such as
did:vh:<SCID>?src=https://example.com/dids/issuer&versionNumber=2. didLog and
didWitness are resolution options only, and MUST NOT be used as DID URL
query parameters.
When a did:vh DID URL is dereferenced, the DID URL dereferencer (the client
of the Resolver) decides which of these parameters to pass to
resolve as resolution options:
- It SHOULD pass a
versionId,versionTimeorversionNumberDID URL parameter as the resolution option of the same name. These select a version as defined in VH-Log’s Selecting a Version section. - A
srcDID URL parameter MUST be percent-encoded as required for a query parameter value by [RFC3986] (Section 3.4 and, for characters that conflict with delimiters such as&and=, Section 2.2), and a DID URL MUST NOT include more than one. The dereferencer MUST percent-decode it once and validate it as defined in ThesrcOption, and MUST return theinvalidDidUrlerror if it is not valid. - A
srcDID URL parameter MUST NOT be a local directory or loopback reference. The dereferencer MUST return theinvalidDidUrlerror for such a reference, and MUST NOT pass it to the Resolver. - The dereferencer MAY apply its own policy to a valid
srcvalue — for example, using it only if it names a location the dereferencer trusts, or ignoring it in favour of a copy of the DID Log it already has. If it uses thesrcvalue, it passes it as thesrcresolution option, or retrieves the files itself and passes them directly indidLoganddidWitness.
The src parameter never changes which version is returned. As a DID URL
query parameter, src is equivalent to the src parameter of
did:scid
when its value is an https URL.
Update (Rotate)§
Updating a did:vh DID follows the Update algorithm defined in
VH-Log, with the following did:vh-specific constraints:
- State changes (VH-Log Update step 1): Changes are made to the
DIDDoc. The top-level
idMUST remaindid:vh:<SCID>. - Parameters:
parametersMUST followdid:vhDID Method Parameters. - Witnesses: If witnesses are active, the DID Controller MUST collect the threshold of witness proofs, and make the updated witness proofs file available, before distributing the updated DID Log.
- Distribution: The DID Controller SHOULD make the updated DID Log available through every DID Log source where it previously made the log available: updating each web location, notifying watchers (see Watchers), and sending it to peers.
Applying Peer-to-Peer Updates§
When DID Logs are exchanged peer-to-peer, each party holds the only copies of the other’s log, and an update may carry only the new entries. A party that receives new DID log entries for a DID Log it holds MUST apply them as follows:
- Skip any received entry whose
versionIdis identical to that of an entry it already holds. If a received entry has the same version number as a held entry but a differentversionId, the update is duplicitous and MUST be rejected. - Append the remaining entries, in order, to a copy of the held DID Log.
- Resolve the DID with that copy as
didLog, the received witness proofs file (or, if none was received, the held one) asdidWitness, and theversionIdof the last appended entry asversionId. - If resolution succeeds, replace the held DID Log and witness proofs file with the ones used in step 3. Otherwise, reject the update and keep the held files unchanged.
A party SHOULD keep a rejected update as evidence of duplicity.
No second copy of the log is needed to detect an update that does not extend
the held log. The entry hash of each entry is calculated with the
versionId of the previous entry as input, so an appended entry verifies only
if it continues from the last held entry. Requesting the versionId of the
last appended entry in step 3 ensures that resolution fails, rather than
returning an earlier version, if any appended entry is invalid.
Deactivate (Revoke)§
A did:vh DID is deactivated as defined in VH-Log's
Deactivate section, by adding
"deactivated": true to the parameters of a new
DID log entry. Once a DID is deactivated, a Resolver
MUST NOT return the DIDDoc and MUST include
"deactivated": true in the DID Document Metadata, as defined in
[DID-CORE]. Prior versions MAY be resolved with the version query
parameters, and the metadata for them MUST include "deactivated": true.
As defined in VH-Log’s Deactivate section, a
DID Controller can instead set updateKeys to [] without setting
deactivated, so that the final DIDDoc is still returned but cannot
be updated.
Unlike did:webvh, removing a published DID Log does not effectively
deactivate a did:vh DID, because copies may be held by watchers,
peers, and other sources. A DID Controller that wants to retire a DID
SHOULD deactivate it explicitly and distribute the final log, so that all
sources report the deactivation. See Log Freshness and
Duplicity for why a Resolver may not
see the deactivation immediately.
Sourcing the DID Log§
This section is non-normative.
A did:vh Resolver resolves the DID Log it is given. Before
calling resolve, the client must therefore source the DID Log: it
either obtains the DID Log and witness proofs themselves, which it
passes directly in didLog and didWitness, or learns a reference to where
they are stored, which it passes in src. In this specification, “source”
covers both outcomes, while “obtain” and “retrieve” mean getting the files
themselves. How the client
sources the log depends on how it received the DID. Each place it can source
the DID Log from is a DID Log source; this section describes
the common ones. They can be combined, and a DID Log sourced from any
of them is verified by the Resolver in exactly the same way.
Known in Context§
In many uses, a client already has the DID Log, or knows where to get it, because of the context in which it received the DID. For example:
- A log sent with the DID. A protocol that carries a DID — such as a
credential or presentation exchange — also carries the DID Log and
witness proofs, or a web location for them. The client passes them
directly, or passes the web location by reference in
src. - An ecosystem DID host. An ecosystem requires its participants to publish
their
did:vhDID Logs to a registry or database it operates. The client retrieves the files from the host and passes them directly, or passes the host’s web location by reference insrc. - A previously resolved log. The client kept the files from an earlier resolution, and passes them directly, or by reference to the local directory where it keeps them — perhaps after checking another source for newer entries.
- A DID URL with a
srcparameter. The client received a DID URL such asdid:vh:<SCID>?src=https://example.com/dids/issuer, and uses the location as described in Readingdid:vhDID URLs.
From Watchers§
A watcher retrieves, verifies, archives and re-serves
DID Logs, indexed by SCID. Because a did:vh DID is its
SCID, a client that knows of a watcher holding the DID —
for example, one its ecosystem uses — can retrieve:
- the DID Log with GET
<WATCHER URL>/log?scid=<SCID>, and - if witnesses are active, the witness proofs file with
GET
<WATCHER URL>/witness?scid=<SCID>.
These are the operations defined in VH-Log’s Watcher HTTP API
Operations. The client then
passes the files directly, or stores them in a local directory and passes
that by reference in src.
Instead of retrieving from watchers itself, a client can pass the
copy it has and ask the Resolver to check it against
watchers, using the checkWatchers option for watchers
listed in the log and the extraWatchers option for others. See did:vh
Resolution Options.
Once a client has resolved the DID, the watchers metadata lists the
watchers the DID Controller has chosen. A client can use them
to check for newer entries, for example when the copy it holds may be out of
date. A client is not limited to those watchers: any party can run
its own watcher, or use one its ecosystem operates, and send it the
DID Logs it relies on. See Log Freshness and
Duplicity.
Peer-to-Peer Exchange§
Two or more parties can use did:vh DIDs with one another by exchanging
DID Logs directly, in the manner of did:peer [DID-PEER], without publishing
them anywhere. Unlike did:peer, the DIDs keep all the VH-Log features,
including key rotation and pre-rotation. Each party keeps the other’s
DID Log (and witness proofs file, if witnesses are active),
and its client passes them directly, or by reference to the local
directory where it keeps them.
Initial exchange. The DID Controller gives the other parties the complete DID Log from the first entry, and the witness proofs file if witnesses are active.
Updates. When the DID is updated, the DID Controller sends each party either the complete DID Log or just the new DID log entry. Sending just the new entry keeps updates small, and works when each party receives every update in turn; a party that has missed an update cannot apply it, and needs the complete DID Log. If the new entry must be witnessed, the DID Controller also sends the complete current witness proofs file; otherwise that is optional. The protocol used to send updates is outside the scope of this specification.
Applying an update. A party receiving new entries applies them as defined in Applying Peer-to-Peer Updates. Because each entry hash chains to the previous entry, this rejects any entry that does not continue from the log the party holds, without needing a second copy of the log.
A did:vh DID used only peer-to-peer can be created for each relationship, so
that no identifier is shared between relationships.
From a Web Location§
A client that learns a web location where the DID Controller
publishes the DID Log can pass it by reference in the src option, or retrieve
did.jsonl and did-witness.json itself and pass them directly.
A client can learn such a location from a src DID URL query parameter, from
an alsoKnownAs entry in a previously resolved DIDDoc (see
Advertising DID Log Sources), or from the
context in which it received the DID.
Advertising DID Log Sources§
A DID Controller can tell others where current copies of the DID Log are kept:
- The
watchersparameter lists watchers that archive the log. - The DIDDoc
alsoKnownAsproperty can includedid:vhDID URLs for the same DID with asrcparameter, one for each location where the DID Log is published (a web location, or another scheme such asipns), as indid:scid. Each location listed this way is expected to hold the same DID Log, although some may briefly lag others while an update is distributed.
"alsoKnownAs": [
"did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ?src=https://example.com/dids/issuer",
"did:vh:QmfGEUAcMpzo25kF2Rhn8L5FAXysfGnkzjwdKoNPi615XQ?src=https://backup.example.org/{SCID}"
]
Both are available only after the DID has been resolved at least once, so they serve to check for newer entries rather than to source the log in the first place.
Log Freshness and Duplicity§
A did:vh DID Log has no single authoritative location, so a client
faces two risks that did:webvh handles by trusting the DID’s web location:
- Staleness. A source may hold an older, shorter copy of the log, and so miss updates such as a key rotation or deactivation. A Resolver verifies the log it is given, but cannot know whether newer entries exist elsewhere.
- Duplicity. A DID Controller, or an attacker holding its keys, could create two different extensions of the same log and show different ones to different parties.
For two verified copies of a DID Log for the same DID, log B
extends log A if B contains every entry of A, in the same positions, with
the same versionIds. Since each versionId includes a hash chained to the
previous entry, it is enough to check that B contains an entry with the
versionId of A’s last entry, at the same position.
A client that needs the current version of a DID can reduce the risk of
staleness by sourcing the log from a source expected to be current — such as
a watcher listed in the log — rather than relying only on a cached
copy or a copy supplied by the party presenting the DID. The ttl metadata
indicates how long the DID Controller expects a copy to stay current.
A client that obtains copies from more than one source can compare them. If
one extends the other, the longer is the more current. If neither extends the
other, the log is duplicitous: the client should not rely on any version
after the last entry the copies have in common, and may keep the conflicting
entries as evidence and report them, for example to watchers. A
client can also have the Resolver make these comparisons, with the
checkWatchers, extraWatchers and minCopies resolution
options; the Resolver then fails with
logForked if the log has been forked.
Witnesses and watchers address duplicity as described in
VH-Log’s
Witnesses and
Watchers
sections: witnesses are expected to approve only an entry that
extends their own copy of the log, but no one else can confirm that they do,
while watchers detect conflicting copies directly, but only the
copies they see. For did:vh these matter more than for did:webvh, because
there is no web location to act as the reference copy. A relying party that
runs its own watcher, or uses one its ecosystem operates, gets a
check that is independent of the DID Controller; extraWatchers
lets it name such watchers when resolving. DID Controllers
of did:vh DIDs that are relied on by many parties are encouraged to use
witnesses and watchers, and parties relying on such DIDs are
encouraged to use watchers they trust.
As VH-Log’s Selecting a
Version
section notes, selecting a version with versionNumber is less safe than with
versionId. If the log is duplicitous, did:vh:<SCID>?versionNumber=3 can
resolve to a different DIDDoc for different parties, while
did:vh:<SCID>?versionId=3-Qm... resolves to one DIDDoc or fails.
DID Method Processes§
did:vh DID Method Parameters§
did:vh uses the VH-Log
parameters mechanism, including its
general rules. The parameters scid, updateKeys, nextKeyHashes, witness,
watchers, deactivated, and ttl are used exactly as defined in
VH-Log, with one did:vh-specific constraint: witness id values
MUST be did:key DIDs (see Witnesses). The parameters
object MUST NOT include any other properties, except those listed below.
The parameters property in the first DID log entry:
{
"method": "did:vh:1.0",
"scid": "{SCID}",
"updateKeys": [
"z82LkqR25TU88tztBEiFydNf4fUPn8oWBANckcmuqgonz9TAbK9a7WGQ5dm7jyqyRMpaRAe"
],
"nextKeyHashes": [
"enkkrohe5ccxyc7zghic6qux5inyzthg2tqka4b57kvtorysc3aa"
]
}
method: Thedid:vhform of VH-Log’slogVersionparameter, with the same rules: it MUST appear in the first entry, MAY appear in later entries to upgrade to a later version, and a value that is not exactly one of the acceptable values MUST cause resolution to terminate.logVersionitself MUST NOT be used. Acceptable values:did:vh:1.0— corresponds to VH-Logvh-log:1.0, and permits the same hash algorithm (SHA-256only) and Data Integrity cryptosuite (eddsa-jcs-2022[DI-EDDSA-V1.0] only) for both log-entry and witness proofs.
did:vh does not use the did:webvh portable parameter. An entry
that includes it MUST be rejected.
Cryptographic Agility§
did:vh inherits cryptographic agility from VH-Log unchanged, with
the method parameter in the role of logVersion.
SCID Generation and Verification§
The SCID is generated and verified exactly as defined in VH-Log’s
SCID Generation and
Verification section.
The preliminary log entry is the one described in Create
(Register), in which the {SCID} placeholder appears in
the DID string did:vh:{SCID} wherever it is used, and in parameters.scid.
Entry Hash Generation and Verification§
The entry hash is generated and verified exactly as defined in VH-Log’s Entry Hash Generation and Verification section.
Authorized Keys and Pre-Rotation§
The authorized keys mechanism is as defined in VH-Log’s Authorized
Keys section, and key pre-rotation as
defined in its Pre-Rotation Key Hash Generation and
Verification
section. The proof cryptosuite MUST be one permitted by the active
method parameter; Resolvers MUST NOT accept a
structurally valid signature using any other cryptosuite.
A did:vh log has no location whose control an attacker would also need in
order to publish an update (see No Authoritative
Location), so DID Controllers SHOULD
use pre-rotation.
Witnesses§
did:vh uses the witness mechanism defined in VH-Log’s
Witnesses section, with the same
identifier and key rules as did:webvh:
- Each
witnessidMUST be a did:key DID whose key is compatible with a cryptosuite permitted by the activemethod. Awitnessparameter containing any otheridMUST be rejected when the parameter is validated. - A witness proof’s
verificationMethodMUST be adid:keyDID URL of the formdid:key:<multibase>#<multibase>, with the two multibase values byte-for-byte equal. The verification key MUST be recovered only by decoding thedid:key; Resolvers MUST NOT resolve the witness DID or consult any other key store. - The witness proofs file is
did-witness.json, with the data model defined in VH-Log’s Witness Proofs File section.
The witness proofs file reaches the Resolver in the same way as the
DID Log: passed directly in didWitness, or retrieved from the
location the src reference names. When passing the files directly, a client can obtain the
witness proofs file from a different DID Log source than the
DID Log — for example, from a watcher's /witness
operation.
Witnesses matter more for did:vh than for did:webvh. With no single
location for the log, an attacker holding the update keys can distribute an
update through any source; with witnesses active, the update also
needs a threshold of witness proofs. DID Controllers SHOULD use
witnesses for DIDs relied on by many parties. Their value against
duplicity depends on how far the
witnesses are trusted, as described there.
Watchers§
did:vh uses the watcher mechanism defined in VH-Log’s
Watchers section, including its HTTP API, which
the did:webvh Watcher OpenAPI
definition
describes. For did:vh, watchers are also a primary DID Log, as described in From Watchers. Any party can run a
watcher for a did:vh DID, whether or not it is listed in the
watchers parameter. When resolving a did:vh DID,
Resolvers MUST return the active list of watchers in the
DID Document Metadata.
VH-Log’s notification operation, POST <WATCHER URL>/log?id=<identifier>,
asks the watcher to retrieve the latest log from its location. A
did:vh DID has no location, so for did:vh:
- POST
<WATCHER URL>/log?id=<DID URL>, where the DID URL includes asrcquery parameter, asks the watcher to retrieve the log (and witness proofs file) from that location. As for any DID URL, thesrcvalue cannot be a local directory or loopback reference. - POST
<WATCHER URL>/log?id=<DID>, where there is nosrcparameter, MUST carry the complete DID Log as the request body, with media typetext/jsonl. If witnesses are active, the DID Controller MUST first send the witness proofs file with POST<WATCHER URL>/witness?id=<DID>, with media typeapplication/json.
In both cases the watcher MUST fully verify the log, MUST confirm that it extends any copy the watcher already holds (see Log Freshness and Duplicity), and indexes it by SCID.
Security Considerations§
This section is non-normative.
This section follows the guidelines in [RFC3552] and aligns with the
[DID-CORE] requirements in DID Core
7.3. The security
considerations in VH-Log’s Security
Considerations section apply to
did:vh unchanged, except as noted below. The sections below cover only what
differs for did:vh. The requirements referred to here are defined in the
normative sections of this specification and of VH-Log.
No Authoritative Location§
A did:webvh Resolver treats the DID’s web location as the
authoritative place to find the current DID Log. A did:vh DID has
no such location. The integrity of any copy of the log is fully protected by
the SCID, the hash chain and the proofs, so a Resolver can
safely accept a log from any source. What a Resolver cannot know from
the log alone is whether it is complete — whether newer entries exist.
The resulting threats, and their mitigations, are:
- Withholding and truncation. A source, or the party presenting a DID, supplies an older copy of the log, for example one from before a key rotation or deactivation. A Resolver verifies the log it is given but cannot detect this. Mitigation: clients that need the current version source the log from a source expected to be current, such as a listed watcher, and never treat the absence of newer entries at one source as proof that none exist. See Log Freshness and Duplicity.
- Duplicity (split view). A DID Controller, or an attacker with its update keys, creates two different extensions of one log and gives them to different parties. Mitigation: clients that obtain copies from several sources compare them and do not rely on versions past the point of divergence; peers apply updates so that non-extending entries are rejected; witnesses are expected to refuse an entry that does not extend the log they hold, although others cannot verify that they do; watchers — including ones run by relying parties — detect and can report conflicting logs.
- Compromised keys and no location to reclaim. In
did:webvh, control of the web location is a second factor an attacker who steals the update keys also needs in order to publish. Adid:vhlog has no such location, so an attacker with the update keys can distribute a valid update through any source. Mitigation: DID Controllers are expected to use pre-rotation (see Authorized Keys and Pre-Rotation), and to use witnesses for DIDs relied on by many parties, so that an update also needs the approval of a threshold of witnesses (see Witnesses).
The src Option and Other Client-Supplied Values§
The src resolution option, and a src DID URL query parameter, are supplied
by the client or by whoever gave it the DID URL, and so are untrusted input.
The same is true of a didLog value, which is why it is verified in full:
- Server-side request forgery. A web location
srcvalue can name any host. Resolvers apply to web location retrievals the transport requirements in VH-Log’s Retrieving Log Resources section (see Web Locations), including rejecting IP literals and not following redirects automatically. A Resolver can also decline to retrieve fromsrcreferences at all (seedid:vhResolution Options), or allow only locations permitted by its configuration. The same hardening applies to a client retrieving from a web location or a watcher itself. The one exception is a loopback (http) reference, which is accepted only by a Resolver local to its client and never from a DID URL; see Web Locations. A Resolver supporting other schemes applies equivalent protections to those retrievals and to any gateway it uses. - Stale or wrong logs. A web location may serve an old copy of the log, or a log for a different DID. The first is covered under No Authoritative Location; the second is detected by the SCID check that the Resolution Algorithm applies to every entry.
- Local file and service access. A local directory or loopback
srcreference is accepted only by a Resolver local to its client; a Resolver that accepts requests from other systems never reads local files or retrieves from loopback hosts, and asrcDID URL parameter is never a local directory or loopback reference. A local Resolver reads onlydid.jsonlanddid-witness.jsonfrom the named directory. See Local Directories. - Misleading association. The domain in a
srcvalue says nothing about who controls the DID. A DID Controller can publish a log at any location it can write to, and anyone can put anysrcvalue in a DID URL. For this reason, Resolvers and their clients do not treat a web location as evidence of an association between the DID and the owner of the domain (see ThesrcOption).
Endpoint Authentication§
Retrievals from web locations and from watchers over HTTP use HTTPS
with server authentication, as described in VH-Log’s Endpoint
Authentication section. The only
exception is a retrieval from a loopback (http) reference by a
Resolver local to its client. As with
all sources, a DID Log is verified by its content, not by the
authentication of the server that provided it.
Peer-to-Peer Use§
When DID Logs are exchanged peer-to-peer, each party holds the only copies of the other’s log, and an update may carry only the new entry. With no other copy to compare against, the hash chain is what protects a party: it applies an update as defined in Applying Peer-to-Peer Updates, so that entries that do not continue from the log it holds are rejected, and keeps a rejected update as evidence of duplicity.
Post Quantum Attacks§
As defined in VH-Log’s Post Quantum
Attacks section.
Pre-rotation is especially valuable for did:vh, for the reason
given under No Authoritative Location.
Resolver Validation Checklist§
This checklist extends VH-Log’s Resolver Validation
Checklist with
did:vh-specific points. It does not restate or replace the normative
requirements.
- DID syntax: the
didinput matches thedid:vhABNF. - Resolution options:
didLogis a string,didWitness(only withdidLog) a JSON array; asrcvalue is an absolute URL with no query or fragment that is either a valid web location —httpswith a domain name host (orhttpwith a loopback host), an optional port, and valid path segments — a valid local directory — afile:URL with an absolute path and an empty orlocalhosthost — or a URL with another scheme, which returnsfeatureNotSupportedif the Resolver does not support it; at most one version option; malformed options returninvalidOptions. AdidLogvalue is verified in full, like any other copy. Local directory and loopback references are accepted only by a Resolver local to its client, and never from a DID URL. - Parameters:
methodis an acceptabledid:vhvalue;logVersionandportableare absent. - SCID and identity: every entry’s
state.idis exactlydid:vh:plus the first entry’sparameters.scid, which equals the SCID in the DID being resolved. - Witnesses: as defined in Witnesses —
did:keywitness identifiers, keys recovered only from thedid:key, body and fragment multibase values equal. - Passing the log: exactly one of
didLogandsrc;didWitnessonly withdidLog; a declinedsrcreturnsfeatureNotSupported.
Privacy Considerations§
This section is non-normative.
This section addresses the privacy considerations in alignment with
[RFC6973] Section 5, and aligns with the [DID-CORE] requirements
in DID Core 7.4. The
privacy considerations in VH-Log’s Privacy
Considerations section apply to
did:vh unchanged, except as noted below.
Surveillance§
Retrieving a DID Log reveals the Resolver's interest in the
DID to the source it retrieves from: the host of a web location, or a
watcher. Because did:vh lets a Resolver choose its
sources, a Resolver can reduce this by using a cached copy, a
watcher it trusts, or a copy supplied by the party presenting the
DID, and by not retrieving web locations chosen by others. A
Resolver or client can also retrieve through privacy-enhancing
network tools, such as Tor or a VPN, so that the source does not learn the
network address of the party interested in the DID.
Correlation and Identification§
A did:vh DID contains no domain name, so it does not by itself link its
controller to a domain owner. src values and alsoKnownAs entries can
reintroduce such a link, so DID Controllers that want to avoid it are
advised not to publish them.
For peer-to-peer use, a DID Controller can create a separate did:vh
DID for each relationship, so that the relationships cannot be correlated by
identifier.
Right to Erasure (GDPR Art. 17)§
A did:vh DID Log is likely to be held in several places — by
watchers, at web locations, and by peers. A DID Controller
cannot remove every copy itself. The watcher deletion operation
defined in VH-Log can be used to request removal from watchers; how
such requests are handled is best defined by ecosystem governance.
Definitions§
- VH-Log
- The Verifiable History Log specification defines a general-purpose,
append-only, cryptographically chained log structure for recording the
verifiable history of a versioned state object.
did:vhis a specialisation of VH-Log. See the VH-Log specification. - specialisation
- As defined in VH-Log: a
specification that uses VH-Log as its foundation.
did:vhis a specialisation of VH-Log in which the state is a W3C DID Document (DIDDoc) and the DID contains only the SCID. - state
- As defined in VH-Log: the versioned object
recorded in each log entry. In
did:vh, the state is the DIDDoc for that version of the DID. - Data Integrity
- As defined in VH-Log: the W3C specification of mechanisms for ensuring the authenticity and integrity of structured digital documents using digital signatures and other cryptographic proofs.
- Decentralized Identifier
- Decentralized Identifiers (DIDs) [DID-CORE] are a type of identifier that enable verifiable, decentralized digital identities. A DID refers to any subject (e.g., a person, organization, thing, data model, abstract entity, etc.) as determined by the controller of the DID.
- DID Controller
- The entity that controls (creates, updates, deactivates) a given DID, as defined in [DID-CORE].
- DIDDoc
- A DID Document as defined by [DID-CORE] — the document returned when a DID is resolved.
- DID Log
- The VH-Log log for a
did:vhDID: a list of DID log entries, one added for each update of the DID. - DID Log Entry
- A JSON object in a DID Log that defines an authorized version of the DIDDoc and the parameters in effect. The first entry establishes the DID and version 1 of the DIDDoc.
- DID Log source
- A place from which a client sources the DID Log of a
did:vhDID — that is, gets either the log itself or a reference to it — before passing it to a Resolver: the context in which the DID was received, a watcher, a peer, or a web location. See Sourcing the DID Log. - DID Method
- The mechanism by which a particular type of DID and its associated DID
document are created, resolved, updated, and deactivated, defined in a DID
method specification. This document is the DID method specification for
did:vh. - did:key
did:key, as described in the W3C CCG specification, is a DID method that derives a DID document directly from a single encoded public key, requiring no registry or network interaction to resolve.did:vhusesdid:keyDIDs to identify witnesses.- Entry Hash
- As defined in VH-Log: a hash over a
DID log entry (excluding its proof) that chains the entry to its
predecessor, and is included in the entry’s
versionId. - ISO8601
- As defined in VH-Log: a date/time expressed using the ISO8601 Standard.
- JSON Lines
- As defined in VH-Log: lines of JSON with whitespace removed, separated by newlines, as described at https://jsonlines.org/.
- parameters
- As defined in VH-Log: the configuration in each DID log entry that controls how the DID Controller generates entries and how Resolvers process the DID Log.
- Pre-Rotation
- As defined in VH-Log: a technique by which the controller of a key commits to the key it will rotate to next, without revealing it, protecting against an attacker who learns the current private key.
- Resolver
- As defined in VH-Log: a party that obtains and verifies a DID Log to produce the current or a historical DIDDoc.
- self-certifying identifier
- As defined in VH-Log:
an identifier derived from the hash of the first DID log entry,
generated with the placeholder
{SCID}wherever the SCID is to appear. Adid:vhDID isdid:vh:followed by its SCID. - watcher
- As defined in VH-Log: a party that
retrieves, verifies, archives and re-serves DID Logs, indexed by
SCID. For
did:vh, watchers are also a primary DID Log source. - witness
- As defined in VH-Log: a party that
verifies a DID log entry before it is distributed and, if it
approves, returns a Data Integrity proof.
did:vhwitnesses are identified by did:key DIDs.
References§
- DI-EDDSA-V1.0
- Data Integrity EdDSA Cryptosuites v1.0. Dave Longley; Manu Sporny; 2024-12-08. Status: W3C Technical Recommendation.
- DID-CORE
- Decentralized Identifiers (DIDs) v1.0. Manu Sporny; Amy Guy; Markus Sabadello; Drummond Reed; 2022-07-19. Status: REC.
- DID-EXTENSION-RESOLUTION
- DID Resolution Extensions Registry. The Decentralized Identifier Working Group (W3C); 2024-11-19. Status: W3C Technical Report.
- DID-PEER
- Peer DID Method Specification. Daniel Hardman; Stephen Curran; Sam Curren; 2025-05-20. Status: DIF Draft v1.0.
- DID-RESOLUTION
- Decentralized Identifier Resolution (DID Resolution) v1. Stephen Curran; Joe Andrieu; 2026-09-02. Status: W3C Editor's Draft.
- RFC2119
- Key words for use in RFCs to Indicate Requirement Levels. S. Bradner; 1997-03. Status: Best Current Practice.
- RFC3552
- Guidelines for Writing RFC Text on Security Considerations. E. Rescorla; B. Korver; 2003-07. Status: Best Current Practice.
- RFC3986
- Uniform Resource Identifier (URI): Generic Syntax. T. Berners-Lee; R. Fielding; L. Masinter; 2005-01. Status: Internet Standard.
- RFC5234
- Augmented BNF for Syntax Specifications: ABNF. D. Crocker, Ed.; P. Overell; 2008-01. Status: Internet Standard.
- RFC5891
- Internationalized Domain Names in Applications (IDNA): Protocol. J. Klensin; 2010-08. Status: Proposed Standard.
- RFC6973
- Privacy Considerations for Internet Protocols. A. Cooper; H. Tschofenig; B. Aboba; J. Peterson; J. Morris; M. Hansen; R. Smith; 2013-07. Status: Informational.
- RFC8089
- The "file" URI Scheme. M. Kerwin; 2017-02. Status: Proposed Standard.
- RFC8174
- Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba; 2017-05. Status: Best Current Practice.
- RFC9457
- Problem Details for HTTP APIs. M. Nottingham; E. Wilde; S. Dalal; 2023-07. Status: Proposed Standard.
did:vh Version Changelog§
- Version 0.1 (Pre-Draft)
- Initial draft. Defines
did:vhas a specialisation of VH-Log, derived fromdid:webvhwith the domain and path removed from the DID. - Defines resolution as the DID Resolution
resolve(did, resolutionOptions)function, withdid:vhresolution options for the two ways of passing the log: directly (didLog,didWitness) or by reference (src, aligned withdid:scid, naming anhttpsweb location, a location using another supported URL scheme such asipns, or, for a local Resolver, a loopbackhttplocation or a local directory), plus the version options. - Describes, non-normatively, how a client sources the DID Log (the log itself or a reference to it) before resolution — known in context, from watchers, peer-to-peer exchange (with updates sent as the complete log or just the new entry), and from a web location — and how to manage freshness and duplicity.
- Removes the
did:webvhfeatures that depend on a web location: the DID-to-HTTPS transformation, theportableparameter, the implicit#filesand#whoisservices, and paralleldid:webpublishing.
- Initial draft. Defines