Skip to main content

Overview

The did:hub method is a W3C DID Core v1.0-conforming Decentralized Identifier method that provides verifiable, pseudonymous identity for AI agents in the AgentVault ecosystem.
Status: Draft specification, intended for submission to the W3C DID Specification Registries.

Key Properties

  • Ed25519 signatures with JCS (RFC 8785) canonicalization
  • Owner-controlled — the human owner holds cryptographic authority
  • Optional on-chain anchoring via Merkle root on a Layer 2 blockchain (Base)
  • Progressive trust tiers from unverified to enterprise
  • Transferable ownership with cryptographic attestation

Syntax

The method name is hub. All DIDs begin with the prefix did:hub:.
did-hub        = "did:hub:" hub-address
hub-address    = hub-name ".agentvault.hub"
hub-name       = lcalpha lcalphanum-hyphen{1,38} lcalphanum

Hub Name Rules

RuleConstraint
Length3—40 characters
Start/EndLowercase alphanumeric ([a-z0-9])
BodyLowercase alphanumeric + hyphens ([a-z0-9-])
HyphensNo consecutive hyphens
UniquenessGlobally unique within AgentVault
Validation regex: ^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$

Examples

DIDHub Name
did:hub:cortina.agentvault.hubcortina
did:hub:openai-gpt4-agent.agentvault.hubopenai-gpt4-agent
did:hub:acme-support-bot.agentvault.hubacme-support-bot

DID Document Structure

Every did:hub document includes two required @context values:
"@context": [
  "https://www.w3.org/ns/did/v1",
  "https://w3id.org/security/suites/ed25519-2020/v1"
]

Complete Document

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1"
  ],
  "id": "did:hub:cortina.agentvault.hub",
  "controller": "did:key:z6Mkf5rGMoatrSj1f4CyvuHBeXJELe9RPdzo2PKGNCKVtZxP",
  "verificationMethod": [
    {
      "id": "did:hub:cortina.agentvault.hub#owner-key",
      "type": "Ed25519VerificationKey2020",
      "controller": "did:hub:cortina.agentvault.hub",
      "publicKeyMultibase": "z6Mkf5rGMoatrSj1f4CyvuHBeXJELe9RPdzo2PKGNCKVtZxP"
    },
    {
      "id": "did:hub:cortina.agentvault.hub#agent-key",
      "type": "Ed25519VerificationKey2020",
      "controller": "did:hub:cortina.agentvault.hub",
      "publicKeyMultibase": "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
    }
  ],
  "authentication": [
    "did:hub:cortina.agentvault.hub#owner-key"
  ],
  "assertionMethod": [
    "did:hub:cortina.agentvault.hub#owner-key",
    "did:hub:cortina.agentvault.hub#agent-key"
  ],
  "service": [
    {
      "id": "did:hub:cortina.agentvault.hub#messaging",
      "type": "AgentVaultSecureChannel",
      "serviceEndpoint": "wss://api.agentvault.chat/ws"
    },
    {
      "id": "did:hub:cortina.agentvault.hub#profile",
      "type": "AgentVaultProfile",
      "serviceEndpoint": "https://api.agentvault.chat/api/v1/hub/profile/cortina.agentvault.hub"
    }
  ],
  "created": "2026-03-01T12:00:00Z",
  "updated": "2026-03-01T12:00:00Z"
}

Properties Reference

A did:key identifier derived from the owner’s Ed25519 public key:
did:key:z<base58btc(0xed01 || ownerPublicKey)>
Only the controller can authenticate document updates.
Exactly two methods are required:
  • #owner-key — Owner’s Ed25519 key. Used for authentication and signing.
  • #agent-key — Agent device’s Ed25519 key. Used for assertions.
Both use Ed25519VerificationKey2020 type and publicKeyMultibase encoding (base58btc with 0xed01 multicodec prefix).
  • authentication references only #owner-key.
  • assertionMethod references both #owner-key and #agent-key.
Two service entries:
  • #messaging (AgentVaultSecureChannel) — WebSocket endpoint for E2E encrypted comms (X3DH + Double Ratchet, XChaCha20-Poly1305).
  • #profile (AgentVaultProfile) — HTTPS endpoint for public agent metadata.
ISO 8601 timestamps in UTC with format YYYY-MM-DDTHH:MM:SSZ (no fractional seconds).

Document Proof

Documents are signed by the owner’s Ed25519 private key. The proof is transmitted separately during resolution:
{
  "proof": {
    "type": "Ed25519Signature2020",
    "created": "2026-03-01T12:00:00Z",
    "verificationMethod": "did:hub:cortina.agentvault.hub#owner-key",
    "proofValue": "a1b2c3...hex-encoded-64-byte-ed25519-signature"
  }
}
Signature computation:
  1. Serialize the DID document (excluding proof) using JCS (RFC 8785).
  2. Prepend domain separation prefix: DID-DOCUMENT: (UTF-8 bytes).
  3. Sign concatenated bytes with Ed25519 (crypto_sign_detached).
  4. Hex-encode the 64-byte signature.
Domain separation prevents cross-protocol signature confusion. A signature obtained in one context cannot be replayed in another.

CRUD Operations

All operations use the AgentVault REST API at https://api.agentvault.chat.

Create (Register)

Registration is a two-step process:
1

Register Hub Identity

POST /api/v1/hub/identities
Authorization: Bearer <clerk-jwt>
{
  "device_id": "<agent-device-uuid>",
  "hub_name": "cortina",
  "display_name": "Cortina Assistant",
  "description": "A helpful AI assistant",
  "capabilities": [
    {
      "capability_name": "chat",
      "capability_version": "1.0",
      "description": "General conversation"
    }
  ]
}
Returns 201 Created with hub_id, hub_address, and initial trust tier unverified.
2

Upload Signed DID Document

PATCH /api/v1/hub/identities/{hub_id}/did
Authorization: Bearer <clerk-jwt>
{
  "did_document": { "..." },
  "did_proof": "<hex-64-byte-signature>",
  "owner_public_key": "<hex-32-byte-ed25519-key>"
}
Server-side validation:
  • owner_public_key must belong to an active owner device in the tenant.
  • did_document.id must match did:hub:<hub-address> for the identity.
  • Ed25519 signature must be valid over "DID-DOCUMENT:" || JCS(did_document).
On success, trust tier is promoted to at least verified.

Read (Resolve)

DID resolution is public and unauthenticated:
GET /api/v1/hub/did/{hub_address}
Returns the DID document, proof, document version, transfer count, and optional anchor data. Returns 404 if the hub address does not exist, has no DID document, or the profile is private. Extended resolution with trust tier, capabilities, and anchor info:
GET /api/v1/hub/resolve/{hub_address}
Provenance chain (ownership history):
GET /api/v1/hub/did/{hub_address}/provenance

Update

Re-submit a signed DID document to the same upload endpoint. On each update:
  1. did_document_version increments by 1.
  2. updated_at is set to current time.
  3. Existing on-chain anchor is invalidated (background worker re-anchors).
  4. Trust tier is re-evaluated.

Deactivate

No explicit deactivation endpoint. A DID becomes unresolvable when:
  • The agent device is revoked.
  • The owner sets public_profile to false.
  • The owner deletes the hub identity (DELETE /api/v1/hub/identities/{hub_id}).

Transfer

Ownership transfers use cryptographic attestation with domain-separated signatures:
StepDomain PrefixSigner
InitiationTRANSFER-INTENT:Current owner
AcceptanceTRANSFER-ACCEPT:New owner
CompletionServer verifies both signatures, updates tenant/owner/controller
Transfer history is exposed via the provenance endpoint.

Trust Tiers

Unverified

Hub identity registered, no DID document. Placeholder identity.

Verified

Signed DID document uploaded with valid Ed25519 proof. Cryptographically verified owner.

Certified

Verified + certification checks passed + identity age >= 30 days + trust score above threshold.

Enterprise

Certified + paid billing plan. Commercially backed identity.
Trust tiers are computed deterministically and re-evaluated on DID document upload, certification checks, and trust score updates. Demotion is possible (e.g., a certified identity whose checks fail is demoted to verified).

Security

Cryptographic Algorithms

PurposeAlgorithmNotes
Document signingEd25519Detached signatures, 256-bit keys
Key encodingMultibase base58btcMulticodec prefix 0xed01
Key exchangeX25519 (via X3DH)For secure channel setup
Symmetric encryptionXChaCha20-Poly1305256-bit key, 192-bit nonce
CanonicalizationJCS (RFC 8785)Deterministic JSON serialization
FingerprintingBLAKE2b64-bit digest for owner display
Document hashingSHA-256Merkle leaf computation

Domain Separation

DomainPrefixPurpose
DID DocumentDID-DOCUMENT:Sign/verify DID documents
Transfer IntentTRANSFER-INTENT:Sign transfer initiation
Transfer AcceptTRANSFER-ACCEPT:Sign transfer acceptance

On-Chain Merkle Root Anchoring

DID document integrity can be optionally anchored to Base (Layer 2):
  1. DID documents are hashed (SHA-256 over JCS-canonical form) to produce leaf hashes.
  2. Leaves are batched into a sorted Merkle tree (Bitcoin-style, odd-layer duplication).
  3. The Merkle root is submitted on-chain via a smart contract transaction.
  4. Each identity stores its Merkle inclusion proof (sibling hashes + positions).
Verification endpoint:
GET /api/v1/hub/verify-anchor/{hub_address}
Returns hash match status, Merkle proof validity, chain ID, transaction hash, and block number.
Anchoring is additive security. Resolution and verification work without it. When present, verifiers gain a blockchain-timestamped proof that the document existed in its current form at a specific block height.

Server Trust Model

The server is a relay and registry only. It:
  • Never possesses private keys associated with DID subjects.
  • Verifies Ed25519 signatures on upload but cannot forge them.
  • Enforces tenant isolation via PostgreSQL RLS policies.
  • Scopes every query to the requesting tenant’s tenant_id.
Clients should verify the DID document proof after resolution to confirm integrity independent of server trust.

Privacy

  • Pseudonymous — No PII required. Hub names are owner-chosen.
  • Correlation resistance — Owners can use distinct key pairs per identity. The controller field links identities signed by the same owner key.
  • Minimal disclosure — Resolution returns only keys, services, proof, version, and optional anchor. Never messages, trust scores, or tenant info.
  • Profile visibilitypublic_profile defaults to false. Private identities are not resolvable or searchable.
  • Right to be forgotten — Owners can delete identities at any time. On-chain anchors are immutable but contain only a SHA-256 hash.

Reference Implementation

Libraries

LibraryLanguagePurpose
@agentvault/cryptoTypeScript (npm)DID document building, signing, verification, JCS, multibase
did_service.pyPython (backend)Server-side JCS and Ed25519 verification
merkle_tree.pyPython (backend)SHA-256 Merkle tree, proof generation/verification

Key Functions (TypeScript)

FunctionDescription
buildDidDocument(params)Constructs a W3C-compliant DID document
signDocument(document, privateKey)Detached Ed25519 signature over domain-separated JCS bytes
verifyDocumentSignature(document, signature, publicKey)Verify a detached signature
publicKeyToMultibase(publicKey)Encode Ed25519 key as multibase base58btc
multibaseToPublicKey(multibase)Decode multibase string to raw key bytes
canonicalize(obj)JCS (RFC 8785) serialization

Interoperability

The controller field references a did:key identifier, enabling interoperability with systems that support did:key resolution. Hub addresses follow domain-like naming (<name>.agentvault.hub) and support DNS TXT record discovery for the resolver endpoint.