DID

Aperçu

did:stellar est une méthode d'identifiant décentralisé (DID) du W3C construite sur le réseau Stellar. Elle donne à chaque émetteur et titulaire une identité portable et auto-contrôlée dont l'état vit dans un smart contract Soroban (le did-stellar-registry), de sorte que n'importe qui peut la résoudre et la vérifier avec un simple endpoint RPC Stellar.

La méthode a été développée par ACTA et est enregistrée dans le registre W3C DID Extensions sous la méthode stellar. C'est l'identité d'émetteur obligatoire pour l'émission de credentials dans ACTA : les adresses de wallet brutes et did:pkh ne sont pas acceptés.

Qu'est-ce que did:stellar ?

  • Décentralisé : la source de vérité est le contrat de registre sur la chaîne, pas un serveur ACTA. Un DID est valide si et seulement s'il est enregistré sur la chaîne.
  • Confiance minimisée : tout vérificateur peut résoudre n'importe quel did:stellar avec seulement une URL RPC Stellar et l'identifiant du contrat de registre. Le resolver hébergé sur https://did.acta.build est une commodité sans état, pas un gardien.
  • Non custodial : ni le resolver ni les bibliothèques ne détiennent jamais de clés privées. Chaque mutation est signée par le wallet Stellar du contrôleur lui-même.

Syntaxe du DID

text
did:stellar:{network}:{didId}
PartieRègle
networkmainnet ou testnet (ensemble fermé, pas d'alias)
didId16 octets aléatoires encodés en base32 RFC 4648 minuscule, sans padding : exactement 26 caractères de [a-z2-7]

La regex de validation canonique est :

text
^did:stellar:(mainnet|testnet):([a-z2-7]{26})$

Exemple (un vrai DID testnet, résoluble de façon permanente) :

text
did:stellar:testnet:znfxngsh46vkyqu6inrx4omphi

L'identifiant est généré avec Web Crypto (crypto.getRandomValues) ; la génération échoue bruyamment si aucune source aléatoire sécurisée n'est disponible.

Pourquoi le DID n'est pas votre wallet

Le didId de 128 bits est opaque : il n'est délibérément dérivé d'aucun compte Stellar. Cela a trois conséquences pratiques :

  • La chaîne du DID survit à la rotation de clés : vous pouvez transférer le contrôle à un nouveau wallet avec transfer_controller et le DID ne change pas.
  • Un même wallet peut contrôler plusieurs DIDs.
  • Le wallet n'apparaît que dans le champ controller de l'enregistrement sur la chaîne, jamais dans la chaîne du DID elle-même.

Modèle de contrôleur

Le contrôleur est un compte Stellar classique (G...). Chaque mutation de l'enregistrement DID (update, transfer_controller, deactivate) exige la signature du contrôleur actuel : le contrat applique controller.require_auth(). Il n'existe aucun rôle privilégié dans la couche HTTP.

Le document DID

La résolution d'un did:stellar produit un document conforme à W3C DID Core 1.1. Les clés utilisent le format Multikey, les relations de vérification contiennent des références de fragments (#auth-1, #assert-1, #keyagr-1), et il n'y a pas de champ controller racine (le document est auto-contrôlé).

json
{
  "didDocument": {
    "@context": [
      "https://www.w3.org/ns/did/v1",
      "https://w3id.org/security/multikey/v1"
    ],
    "id": "did:stellar:testnet:znfxngsh46vkyqu6inrx4omphi",
    "verificationMethod": [
      {
        "id": "did:stellar:testnet:znfxngsh46vkyqu6inrx4omphi#auth-1",
        "type": "Multikey",
        "controller": "did:stellar:testnet:znfxngsh46vkyqu6inrx4omphi",
        "publicKeyMultibase": "z6MkwBw2szL21i4Ym1wqzV8bPWwJyp1WDt8oRofTEs9ZntSq"
      }
    ],
    "authentication": [
      "did:stellar:testnet:znfxngsh46vkyqu6inrx4omphi#auth-1"
    ],
    "assertionMethod": [],
    "keyAgreement": [],
    "service": []
  },
  "didDocumentMetadata": {
    "versionId": "1",
    "deactivated": false,
    "method": {
      "network": "testnet",
      "stellarAccount": "G..."
    }
  },
  "didResolutionMetadata": { "contentType": "application/did+ld+json" }
}

didDocumentMetadata.method.stellarAccount expose le compte contrôleur, ce qui permet aux vérificateurs de lier le DID au wallet qui le contrôle.

Types de clés

RelationCourbePréfixe multibaseClés max
authenticationEd25519z6Mk...1 à 3 (au moins 1 requise)
assertionMethodEd25519z6Mk...0 à 3
keyAgreementX25519z6LS...0 ou 1

Les clés brutes doivent faire 32 octets. La même clé peut apparaître dans plusieurs relations (la forme idiomatique pour un émetteur est une clé Ed25519 à la fois dans authentication et assertionMethod) ; les doublons au sein d'une même relation sont rejetés avec duplicate_key.

Rôles du DID

  • Titulaire : clé authentication uniquement.
  • Émetteur : authentication plus au moins une clé `assertionMethod` (obligatoire ; les vérificateurs W3C rejettent les credentials signés sans clé d'assertion).
  • Destinataire DIDComm : ajoute une clé keyAgreement X25519.

Cycle de vie

OpérationSignée parNotes
registerLe contrôleur de l'enregistrementCrée le DID ; version démarre à 1
updateContrôleur actuelRemplacement complet de l'enregistrement (pas un patch) ; exige expectedVersion
transfer_controllerContrôleur actuelFait tourner le wallet de contrôle ; la chaîne du DID reste inchangée
deactivateContrôleur actuelIrréversible ; le DID se résout comme une pierre tombale avec HTTP 410 Gone

Chaque mutation incrémente version (concurrence optimiste) : envoyer un expectedVersion périmé échoue avec version_mismatch.

Proof of Control

did:stellar définit un protocole hors chaîne de Proof of Control (par exemple pour la connexion par DID) :

  1. Le vérificateur émet un défi { did, domain, nonce, timestamp }.
  2. Le signataire le canonicalise avec JCS (RFC 8785) et signe avec une clé authentication Ed25519 (signature en base64url, sans padding).
  3. Le vérificateur contrôle, dans l'ordre : timestamp dans une fenêtre de 5 minutes, correspondance du domaine, fraîcheur du nonce, et la signature Ed25519 contre chaque clé authentication du document résolu.

La bibliothèque TypeScript fournit ce protocole prêt à l'emploi (voir ).

Comment ACTA utilise did:stellar

  • L'identité d'émetteur est obligatoire : POST /contracts/vc/issue exige un issuerDid qui se résout sur le registre du réseau et dont le contrôleur sur la chaîne est égal à l'émetteur signataire (sinon l'API retourne issuerDid_controller_mismatch).
  • Le Credentials SDK réalise son auto-onboarding : appeler issue sans issuerDid génère de manière transparente les clés, enregistre un did:stellar avec une seule signature de wallet, et le réutilise ensuite (voir ).
  • La dApp guide l'enregistrement avec une seule signature de wallet.
  • Domaines de confiance séparés : l'API de credentials n'importe délibérément pas la bibliothèque DID ; identité et credentials évoluent indépendamment.

Poursuivez avec pour le contrat sur la chaîne et l'API HTTP, ou pour le code.