The did:namid DID method.
Every NamID name is a W3C Decentralized Identifier. This page is the method specification: the identifier syntax, the DID document a name resolves to, the four operations, and the security and privacy considerations. Resolve one now: https://namid.net/api/did/resolve?did=did:namid:testnet11:alice.mojo
Status: Draft, 2026-09-23 · Owner: Web3UTXOs Technologies (NamID Protocol)
Method name: namid · Ledger: Chia blockchain (singleton coins) · Licence: CC0
Registry entry: to be submitted to the W3C DID Extensions "DID Methods" registry
(w3c/did-extensions, methods.json) once this document is published at
https://namid.net/did-namid.html.
Reference implementation: apps/NalandaX/registry-Backend-artefacts/did_namid.py and
tld_uri.py in github.com/DIPMR/Codex-Namid-Protocol-V0; tests in
tests/test_did_namid.py.
This document follows the requirements for DID method specifications in DID Core §8: method name, method-specific identifier syntax, the four operations, security and privacy considerations.
1. Why a method of its own
NamID is a naming protocol on Chia in which every name is an identity: a root (mojo,
xch, chia) is a soulbound singleton coin, and a name beneath it (alice.mojo) is a
Chia coin bound to its holder. Chia wallets already print DIDs as did:chia:1…, but
did:chia is not a registered DID method and has no method specification; the only
Chia-singleton method in the W3C registry is did:julia. A NamID identifier presented to
the wider DID ecosystem therefore needs a method that is specified, resolvable and
registered. did:namid is that method.
Nothing older changes. The same 32 launcher bytes remain spellable as did:chia:1…
(Chia-ecosystem interop), tld:1… (protocol-internal) and namid:1… (the protocol's own
URI); the did:namid document lists all of them under alsoKnownAs.
2. Method name
The method name is namid. A DID that uses this method MUST begin with did:namid:.
3. Method-specific identifier
did-namid = "did:namid:" [ network ":" ] id
network = 1*16( %x61-7A / DIGIT ) ; lowercase; OMITTED on mainnet
id = launcher-id / name
launcher-id = "1" 1*bech32-char ; bech32m, checksum computed over the hrp "namid:"
name = label *( "." label )
label = ( %x61-7A / DIGIT ) *61( %x61-7A / DIGIT / "-" )
- Launcher form —
did:namid:1<bech32m>(mainnet) ordid:namid:testnet11:1<bech32m>. The bech32m string afterdid:is exactly the protocol URInamid:1…: the human-readable part of the checksum isnamid:, sodid:namid:1…andnamid:1…share one checksum and one 32-byte payload, the launcher id of the name's singleton coin. This form is the canonical DID of a name once its coin exists on chain; it never changes for the life of the coin lineage. - Name form —
did:namid:alice.mojo/did:namid:testnet11:alice.mojo. A valid DID (DID Core allows.and-in the method-specific id) that resolves to the same document. It is the DID of a name before its coin is minted, and anequivalentIdof the launcher form afterwards. - Network — omitted for the Chia mainnet; any other network names itself
(
testnet11).did:namid:mainnet:…is invalid. A resolver serves one network and answersnotFoundfor another. - Case — a
did:namididentifier is lowercase; uppercase is invalid, not normalised. - Payment addresses are not identifiers — an id matching
^t?xch1[bech32]{20,}$is invalid by grammar, because anxch1…string is a Chia address and an identifier that looks like one will be pasted into a Send box.
Examples:
did:namid:14w46h2at4w46h2at4w46h2at4w46h2at4w46h2at4w46h2at4w4snsj9a4
did:namid:testnet11:14w46h2at4w46h2at4w46h2at4w46h2at4w46h2at4w46h2at4w4snsj9a4
did:namid:testnet11:alice.mojo
4. DID document
{
"@context": ["https://www.w3.org/ns/did/v1", "https://namid.net/ns/did/v1"],
"id": "did:namid:testnet11:1…",
"alsoKnownAs": ["namid:alice.mojo", "did:namid:testnet11:alice.mojo",
"did:chia:1…", "tld:1…", "namid:1…"],
"controller": "did:key:z6Mk…",
"verificationMethod": [{
"id": "did:namid:testnet11:1…#owner", "type": "Bls12381G1Key2020",
"controller": "did:namid:testnet11:1…", "publicKeyMultibase": "z…" }],
"authentication": ["did:namid:testnet11:1…#owner"],
"capabilityInvocation": ["did:namid:testnet11:1…#owner"],
"service": [
{ "id": "…#namid", "type": "NamIDName",
"serviceEndpoint": "https://namid.net/api/names/resolve?name=alice.mojo" },
{ "id": "…#xch", "type": "ChiaPaymentAddress",
"serviceEndpoint": { "address": "txch1…", "network": "testnet11" } },
{ "id": "…#website", "type": "LinkedDomains", "serviceEndpoint": "https://alice.example" },
{ "id": "…#dns", "type": "NamIDDNSRecords", "serviceEndpoint": { "records": [] } }
]
}
controlleris the holder's DID when the name is bound to one (a soulbound name is issued to adid:keyordid:chiaand never moves). It is absent when the name is controlled only by its owner key.verificationMethodcarries the name's BLS12-381 G1 owner key when the name has one (transferable names); the key authorises record updates and, for transferable names, transfer. Soulbound names issued to a DID carry no key of their own.serviceentries are derived from the name's on-chain record set: the resolver endpoint, the XCH payment address, a linked website and DNS records. Nothing in the document is written by hand; it is a projection of the coin and its records.
DID document metadata (returned by resolution, not part of the document):
| key | meaning |
|---|---|
canonicalId |
the launcher form, once the coin exists |
equivalentId |
[the name form] |
versionId |
the current coin id of the singleton |
created / updated |
registry timestamps |
deactivated |
true after lapse or a spend to nil; always false for renewal: never |
namid |
{name, root, lock_mode, renewal, issuer, namespace, mint_status, launcher_id, coin_id, record_sequence, expiry_block} — the protocol's own view (standards/ROOT-PROFILES.md) |
5. Operations
5.1 Create
A did:namid is created by creating the name:
- a root is won at the sealed-bid auction and minted as a soulbound singleton
(
namid-protocol.md§5); - a name under a root is issued by the root's issuer through the signed issuer route
(
POST /api/names/issue, HMAC over the canonical body,ROOT-PROFILES.md), or registered by its owner where the root'sissuanceisopen.
The name form of the DID exists from that moment; the launcher form exists once the coin
is on chain (mint_status: minted). No separate "DID registration" step exists: a name
that exists is a DID.
5.2 Read (resolve)
GET https://namid.net/api/did/resolve?did=<did>
GET https://namid.net/1.0/identifiers/<did> ; Universal Resolver driver shape
GET https://namid.net/api/did/method ; the method descriptor
The response is a DID Resolution Result (@context: https://w3id.org/did-resolution/v1)
with didDocument, didResolutionMetadata (contentType: application/did+ld+json,
retrieved, did, kind) and didDocumentMetadata (§4). Errors use the registered
names: invalidDid (400), notFound (404, including a network the resolver does not
serve), methodNotSupported (400).
A resolver MUST answer only with a record it can tie to the chain (the NamID
verify-or-refuse rule: /api/resolve carries the proof) or refuse; a client MAY verify the
singleton lineage itself with the light client in chia-consensus-light-client.md
against didDocumentMetadata.namid.launcher_id.
5.3 Update
Records (address, profile, DNS, services) are updated by the owner key through the
registry's signed record routes; each update increments record_sequence and, when the
coin is spent, changes versionId. For a soulbound name bound to a DID, the holder DID
signs. Keys rotate through the two-phase rotation with a clawback window
(tld-vault-design.md). The DID string never changes on update.
5.4 Deactivate
- A term name that is not renewed lapses at
expiry_block; the document resolves withdeactivated: trueuntil the label is re-issued, at which point a new coin and a new launcher-form DID exist (the name form resolves to the new one). - A soulbound, never-renewed name (
renewal: never) has no lapse; it is deactivated only by its issuer re-issuing to the same holder DID (recovery) or by the singleton being spent to nil. - A root is never transferred; it is deactivated only by the DAO's threshold action
in the cases the policy allows (
TLD-POLICY.md).
6. Security considerations
- Key compromise. The owner key authorises updates (and transfer, for transferable names). Rotation is two-phase with a clawback window; the Vault gives m-of-n recovery for roots. A soulbound name bound to a DID has no key to steal: the holder's DID controls it.
- Issuer compromise. An issuer secret lets an attacker issue new names under that root; it cannot move or alter existing ones. Secrets are per issuer host and rotatable; every issuance is a coin creation visible on chain.
- Resolver trust. The resolver is a projection of chain state and says so: the
namid.launcher_idandversionIdin the metadata let any client verify the lineage independently. A resolver that cannot produce chain evidence refuses rather than guesses. - Address confusion.
did:namid:xch1…is invalid by grammar. - Network confusion. Mainnet omits the network segment; every other network names itself; a resolver answers only for the network it serves.
- Sanctions. Registration refuses labels on the protocol's OFAC-derived list
(
blocked-ofac.tsv). - Denial of service. Resolution is a read of a local index plus optional chain verification; the registry rate-limits per client address behind nginx.
7. Privacy considerations
- A DID document contains only what the holder chose to publish as records (address,
profile display, website, DNS). Rich records marked sensitive by the kind taxonomy
(
/api/records/kinds) are anchored by hash and never served in a document. - The name form makes a DID human-readable by design; a holder who wants an unlinkable identifier should not use a NamID name as one. The launcher form is pseudonymous but stable, and links every update of the same coin.
- The resolver does not log the caller beyond what rate limiting needs.
- Holders can correlate across services by choice (
alsoKnownAs), never by default.
8. Relationship to other identifiers
| form | what it is | in the document |
|---|---|---|
did:namid:… |
this method; canonical DID of a NamID | id |
namid:1… / namid:alice.mojo |
the protocol's URI scheme (not a DID) | alsoKnownAs |
did:chia:1… |
the Chia-ecosystem spelling of the same launcher; not a registered method | alsoKnownAs |
tld:1… |
protocol-internal view | alsoKnownAs |
did:key:… / did:chia:… of the holder |
who the name is bound to | controller |
9. Conformance
An implementation conforms if it produces documents and resolution results as in §4–§5 for
every valid identifier in §3, refuses every invalid one with invalidDid, and never
answers a resolution it cannot tie to the chain. The reference implementation's test suite
(tests/test_did_namid.py, tests/test_namid_uri.py) is the conformance vector set.
NamID Protocol