SolidusExplorer
⌘K
FINALITY
BLOCK HEIGHT
ACTIVE VALIDATORS

Anatomy of a did:solidus Document: Every Field Explained, and Three Places Where It Is Not the Shape a Standard Library Expects

The document, from the chain

One call returns the whole thing, with no account and no key:

solidus_didResolve with did:solidus:testnet:46Hzv2Ek4MXwj1Kenvix4tWCPr1J

What comes back is a single object. The rest of this page is what each part of it is for.

The identity parts

id is the identifier itself, and it is the subject of every other statement in the document.

controller is who may change it. On this document the controller is the subject, which is the self-sovereign case: nobody else can rewrite it.

verification_method is the list of keys. Each entry has its own identifier ending in a fragment, a type naming the algorithm, the controller of that key, and the key material itself.

The five relationships, and why there are five

A key is not simply trusted for everything. The document lists, separately, which keys may:

authenticate as the subject assert claims, which is what signs a credential agree keys for encryption invoke a capability delegate one

All five are present and populated on this chain, rather than the common shortcut of listing authentication and leaving the rest implied. key_agreement comes back as an explicit empty list, which says "none" rather than "unspecified", and those are different statements.

The parts that are not the document

active, created_ms, updated_ms, version_id, recovery_policy and recovery_nonce sit alongside the rest.

In the resolution model those are metadata about the document rather than fields of it, and they belong in a separate metadata object. Here they arrive inline.

The practical consequence is small and real: a consumer that hands this object straight to a standard processor is handing it properties that model does not define.

The field names are the node's, not the standard's

The endpoint emits context, verification_method, assertion_method, key_agreement, capability_invocation and capability_delegation. The standard property names are the camel-cased forms, and the first one is prefixed.

So what you get from a direct call is not a document a standard resolver library will read. It will find no verification methods, because the property it looks for is not there.

The Solidus client library does the conversion, and does it properly: it emits the prefixed context with two entries, renames every relationship, and turns the timestamps into dates.

Which means conformance lives in the library rather than on the wire. Anybody integrating without that library has to know it, and nothing in the response tells them.

And the key encoding is missing its prefix

The conversion renders the key as a multibase value, which is the standard's preferred form.

It base58-encodes the raw key bytes and prefixes the result with z. A conformant value for this key type carries a two-byte codec identifier before the key bytes, and that identifier is why every conformant key of this type begins z6Mk.

Ours does not. Encoding the same key both ways in one command:

ours: z62rYKgP5rhiNcQGY1b4p6PPr72WErY7MspPAbgwNxN9R conformant: z6MkjV7auvdXCFCqiu7EhA2ewUwqvbn6GRMiZqJ6RxuPsavo

This is in the published package, confirmed by downloading it from the public registry into an empty directory rather than by reading our own source.

It fails closed, not open. A standard library either rejects the value or reads the first two bytes of a real key as a codec identifier and gets a key that verifies nothing. It does not accept anything it should have refused, and this page is not describing a way to forge a signature.

The cost is exactly the thing a decentralised identifier exists for. A key that only our own code can read is a key that does not travel.

What would change this

All three are small edits with one hard part. The property names and the metadata split are a serialization change on the response, and nothing outside depends on the current spelling except our own library, which already renames them.

The key encoding is the one with a cost, because a value already published under the current encoding will not decode under the new one. The honest path is to emit the prefixed form, accept both while reading, and say when the old form stops being accepted, which is a compatibility window rather than a flag day.

None of that is scheduled, and this page is not going to imply it is. It is filed.

What is genuinely right here

Five relationships, populated rather than implied. An explicit empty list where the answer is none. A service array, empty here, so the shape is ready for endpoints.

A content-hash version identifier, which is the standard's own idea of a version and is a self-check rather than provenance.

And a recovery policy modelled on-chain, present as a field and null until an owner sets one, so recovery is a property of the record rather than a support process.

Where the standards claim actually stands

The method is registered in the W3C DID Method Registry, which is a listing and is checkable in one request. A listing is not a conformance test, and the three findings above are what a conformance test is for.

What you can check yourself

resolve any identifier, then look at the key names in the response

Count how many of them are the standard's spelling. Then take a publicKeyMultibase from our library and check whether it begins z6Mk.

Keep reading

Anatomy of a did:solidus Document: Every Field Explained, and Three Places Where It Is Not the Shape a Standard Library Expects · Solidus — Solidus Explorer