Skip to content

Diagrams

Below are UML diagrams of the various objects and algorithms in the specification.

The below architecture diagram is a high-level view of the key parts of the specification and their interactions.

flowchart LR
  %% Main Actors
  Controller([DID Controller])
  Resolver([DID Resolver])

  %% Impl Libs & Apps
  subgraph SDK["Application / SDK"]
    Create[Create]
    Deactivate[Deactivate]
    Update[Update]
    Read[Read]
    KMS[Key Manager]
    Crypto[Cryptosuite]
  end

  subgraph BTCR2Beacon
    SingletonBeacon
    MapBeacon
    SMTBeacon
  end

  %% Data
  BTC[(Bitcoin Blockchain)]
  CAS[("CAS (IPFS)")]
  Sidecar[(Sidecar Data)]

  %% DID Resolver
  Resolver ---> Read

  %% DID Controller
  Controller --> Create
  Controller --> Update
  Controller --> Deactivate
  
  %% Update
  Update --> KMS
  Update --> Crypto
  Update --> Sidecar

  %% Beacons
  Update --> BTCR2Beacon
  BTCR2Beacon --> BTC

  %% Read
  Read --> BTC
  Read --> CAS
  Read --> Sidecar
  Read --> Crypto

  %% Deactivate (Reuses Update)
  Deactivate --> Update

The protocol stack diagram groups the moving parts of did:btcr2 into layers, from end-user applications down to the Bitcoin ledger.

---
title: DID BTCR2 Protocol Stack
---

graph TB
  %% ---------- Styles ----------
  classDef layer fill:#f7f7fb
  classDef comp fill:#ffffff,stroke:#c7cdd1,rx:6,ry:6,color:#202124

  %% ---------- Layers ----------
  subgraph L6[Application / Use Layer]
    direction TB
    Wallets[Identity Wallets]:::comp
    VCVerify[VC / Signature Verification]:::comp
  end

  subgraph L5[DID Resolution & API Layer]
    direction TB
    Resolver[BTCR2 Resolver<br/>Traverse History<br>Apply patches<br>Update DID Document]:::comp
    JSONLD[JSON-LD<br/>Processing]:::comp
    DIDCore[DID Core<br/>Compliance]:::comp
    APIs[Resolver APIs]:::comp
  end

  subgraph L4[Data Integrity & Proof Layer]
    direction TB
    KeyMgr[Key<br/>Manager]:::comp
    BIP340Crypto[BIP340<br/>Cryptosuite]:::comp
    BIP340Multikey[BIP340<br/>Multikey]:::comp
    BIP340DIPCrypto[BIP340<br/>Proofs]:::comp
    MuSig[MuSig2<br/>Aggregation]:::comp
  end

  subgraph L3[DID Document State Layer]
    direction TB
    Patches[JSON Patch]:::comp
    Model[BTCR2 DID Document]:::comp
    InterDoc[Intermediate<br/>DID documents]:::comp
    Rules[Resolution Rules<br/>& Versioning]:::comp
  end

  subgraph L2[Beacon Layer]
    direction TB
    Ops[BTCR2 Update]:::comp
    Anchors[BTCR2 Beacon Signals<br/>commitments to state/patches]:::comp
    Beacon[SingletonBeacon<br/>MapBeacon<br/>SMTBeacon]:::comp
    Linkage[Tx hash linkage & verification]:::comp
  end

  subgraph L1[Bitcoin Ledger Layer]
    direction TB
    BTC[Bitcoin tx on main/test/reg networks]:::comp
    OPRET[OP_RETURN CID Embedding]:::comp
    OPRET[SMT Proof Aggregation]:::comp
    PSBT["PSBT"]:::comp
    Finality[Consensus, confirmations, finality]:::comp
  end

  %% ---------- Layer connections ----------
  L6 --> L5 --> L4 --> L3 --> L2 --> L1

  %% Optional: show a typical data flow up & down (comment out if noisy)
  %% Resolver ==> uses proofs/state anchored on chain
  Resolver -.reads/applies.-> Patches
  Resolver -.reads.-> Anchors
  Anchors -.on-chain.-> BTC

  %% ---------- Apply layer framing ----------
  class L1,L2,L3,L4,L5,L6 layer

The state diagram below tracks a DID document from creation through resolution, updates, and its final target state.

stateDiagram-v2
    state "Initial Document" as Initial
    state "Intermediate Document" as Intermediate
    state "Target Document" as Target
    state "Contemporary Document v1" as ContemporaryV1
    state "Contemporary Document V2" as ContemporaryV2

    [*] --> Initial: Create From<br>Deterministic Key Pair
    [*] --> Intermediate: Create From<br>External DID Document
    Intermediate --> Initial: Replace placeholder DID
    Initial --> ContemporaryV1: Resolve
    %% Stack of versioned state contemp docs
    ContemporaryV1 --> ContemporaryV2: Traverse<br>Bitcoin Blockchain
    ContemporaryV2 --> Target: 
    Target --> [*]

The below data flowcharts map the high-level algorithm calls made for each of the CRUD Operations in the specification.

The Create operation consists of two main algorithms for creating identifiers and DID documents.

  1. From Deterministic Key Pair to encode a secp256k1 public key as a did:btcr2 identifier.
  2. From External Intermediate DID document encodes an external intermediate DID document as a did:btcr2 identifier. Doing so allows for more complex initial DID documents with features such as the ability to include Service Endpoints and BTCR2 Beacons that support aggregation.

In both cases, DID creation can be undertaken in an offline manner, i.e., the DID controller does NOT need to interact with the Bitcoin network to create their DID.

flowchart TD
    %% Start
    Start@{shape: circle, label: Create DID &<br/>DID Document} --> CheckIdType{idType}
    
    %% Deterministic
    CheckIdType -->|KEY|Deterministic@{shape: subproc, label: From Deterministic<br/>Key Pair}
    Deterministic --> IdentifierEncodingK1@{shape: subproc, label: Identifier<br/>Encoding (k1)}
    IdentifierEncodingK1 ---> ResolveDeterministic@{shape: subproc, label: Deterministically Generate<br/>Initial DID Document}

    %% External
    CheckIdType -->|EXTERNAL|External@{shape: subproc, label: From External<br/>Intermediate DID Document}
    External --> JSONCanonicalizeHash@{shape: subproc, label: JSON Canonicalization<br/>and Hash}
    JSONCanonicalizeHash --> IdentifierEncodingX1@{shape: subproc, label: Identifier<br/>Encoding (x1)}
    IdentifierEncodingX1 --> CheckStoreOnCAS{Store on CAS?}
    CheckStoreOnCAS -->|TRUE|StoreOnCAS@{shape: subproc, label: "Publish Intermediate DID Document to CAS"}
    CheckStoreOnCAS -->|FALSE|Return
    StoreOnCAS --> Return

    %% Error
    CheckIdType -->|ERROR|InvalidIdType@{shape: stadium, label: InvalidIdType}
  
    %% Return
    ResolveDeterministic --> Return@{shape: lean-l, label: "Return<br/>did, initialDocument"}

The Read operation is executed by a DID Resolver after receiving a resolution request for a specific did:btcr2 identifier.

It consists of two main subprocesses:

  1. Resolve Initial DID Document to resolve an initial DID document for the given did:btcr2 identifier.
  2. Resolve Target Document to resolve the target document using updates found on the Bitcoin blockchain.
flowchart TD
    Start@{shape: circle, label: Read} --> IdentifierDecoding@{shape: subproc, label: Identifier Decoding}
    IdentifierDecoding --> ResolveInitial@{shape: subproc, label: Resolve Initial DID Document}
    ResolveInitial --> ResolveTarget@{shape: subproc, label: Resolve Target Document}
    ResolveTarget --> Return@{shape: lean-l, label: Return targetDocument}

Resolve Initial DID Document is the first subprocess of the Read operation consisting of two additional subprocesses.

flowchart TD

    Start@{shape: circle, label: Resolve Initial<br>DID Document} --> CheckIdType{idType}

    %% Deterministic Path
    CheckIdType -->|KEY| Deterministic@{shape: subproc, label: Deterministically<br>Generate<br/>Initial<br>DID Document}
    Deterministic --> GenerateBeacon@{shape: subproc, label: Generate<br/>Beacon Services}
    GenerateBeacon --> EstablishSingleton@{shape: subproc, label: Establish<br/>Singleton Beacon}

    %% External Path
    CheckIdType -->|EXTERNAL| External@{shape: subproc, label: External Resolution}
    External -->CheckSidecarData{resolutionOptions.<br>sidecarData.<br>initialDocument}
    CheckSidecarData-->|NOT NULL| SidecarValidate@{shape: subproc, label: Sidecar Initial<br/>DID Document<br>Validation}
    CheckSidecarData-->|NULL| CasRetrieval@{shape: subproc, label: CAS Retrieval}
    CasRetrieval-->CheckInitialDocument{initialDocument}
    SidecarValidate-->CheckInitialDocument
    CheckInitialDocument-->|VALID| ReturnInitialDocument@{shape: lean-l, label: Return initialDocument}

    %% Error
    CheckIdType -->|ERROR| InvalidHRPValue@{shape: stadium, label: InvalidHRPValue}
    CheckInitialDocument-->|INVALID| InvalidDIDDocumentError@{shape: stadium, label: InvalidDIDDocumentError}

    %% Return
    EstablishSingleton --> ReturnInitialDocument

Resolve Target Document is the second subprocess of the Read operation, which calls a single recursive subprocess, Traverse Bitcoin Blockchain History, which walks the Bitcoin blockchain and identifies spending transactions from bitcoin addresses listed in the DID document. These spends are called Beacon Signals and may contain announcements about changes made to the DID document controlled by the did:btcr2 identifier being resolved.

flowchart TD
    Start@{shape: circle, label: Resolve Target<br>Document} --> TraverseHistory@{shape: subproc, label: Traverse Bitcoin<br/>Blockchain History}
    TraverseHistory --> WhileUpdates{orderedUpdates.length > 0}
    WhileUpdates -->|TRUE| JSONCanonicalizeHash1@{shape: subproc, label: JSON Canonicalization<br/>and Hash}
    JSONCanonicalizeHash1 --> FindNextSignals@{shape: subproc, label: Find Next Signals}
    FindNextSignals --> ProcessBeaconSignals@{shape: subproc, label: Process Beacon Signals}
    ProcessBeaconSignals --> TargetVersionId{update<br/>.targetVersionId}
    TargetVersionId -->| \> currentVersionId + 1| LatePublishing@{shape: stadium, label: LatePublishingError}
    TargetVersionId -->| = currentVersionId + 1| ApplyDidUpdate@{shape: subproc, label: Apply<br/>DID Update}
    TargetVersionId -->| <= currentVersionId| ConfirmDupeUpdate@{shape: subproc, label: Confirm Duplicate Update} 
    ApplyDidUpdate --> JSONCanonicalizeHash2@{shape: subproc, label: JSON Canonicalization<br/>and Hash}
    JSONCanonicalizeHash2 --> TraverseHistory
    ConfirmDupeUpdate --> TraverseHistory
    WhileUpdates -->|FALSE| ReturnTargetDocument@{shape: lean-l, label: Return targetDocument}

The Update operation is executed by a DID Controller to make changes to a DID document. Updates to a DID document is achieved by constructing JSON Patches, invoking and securing them and announcing them to the Bitcoin blockchain.

It consists of three main subprocesses:

  1. Construct BTCR2 Update to construct an unsecured BTCR2 update
  2. Invoke BTCR2 Update to add a signature unsecured BTCR2 update
  3. Announce DID Update to broadcast the BTCR2 update to the Bitcoin blockchain
flowchart TD
    Start@{shape: circle, label: Update} --> ConstructUpdate@{shape: subproc, label: Construct BTCR2 Update}
    ConstructUpdate --> InvokeUpdate@{shape: subproc, label: Invoke BTCR2 Update}
    InvokeUpdate --> AnnounceUpdate@{shape: subproc, label: Announce DID Update}
    AnnounceUpdate --> End@{shape: lean-l, label: Return signalsMetadata}

Construct BTCR2 Update is the first subprocess of the Update algorithm. The goal of this subprocess is to apply a JSON Patch document to a source DID document and verify that the resulting updated target DID document is a valid, conformant DID document.

flowchart TD
    Start@{shape: circle, label: Construct<br>BTCR2 Update} --> ConstructPatch@{shape: subproc, label: Apply JSON Patch<br>to sourceDocument}
    ConstructPatch --> ValidateTargetDoc{Is targetDocument<br>conformant?}
    ValidateTargetDoc -->|TRUE|JSONCanonicalizeHash@{shape: subproc, label: Canonicalize and Hash sourceDocument and targetDocument}
    ValidateTargetDoc -->|FALSE|HandleError@{ shape: stadium, label: "InvalidDIDUpdateError" }
    JSONCanonicalizeHash --> End@{shape: lean-l, label: Return unsecuredBtcr2Update}

Invoke BTCR2 Update is section 7.3.2 of the DID BTCR2 Method specification. It is the second subprocess of the Update algorithm with the goal of retrieving and use the private key associated with the verification method listed in the source DID document to sign and add a Data Integrity Proof to the BTCR2 Update.

flowchart TD
    Start@{shape: circle, label: Invoke<br>BTCR2 Update} --> DeriveZCap@{shape: subproc, label: Derive Root<br>Capability from<br>did:btcr2 Identifier}
    DeriveZCap --> InstantiateCryptosuite@{shape: subproc, label: Instantiate<br>BIP340 Cryptosuite}
    InstantiateCryptosuite --> AddProof@{shape: subproc, label: Add Proof to<br>btcr2Update}
    AddProof --> Return@{shape: lean-l, label: Return btcr2Update}

Announce DID Update is the third subprocess of the Update algorithm. The goal of this subprocess is to retrieve the services object(s) from the source DID document and call the Broadcast DID Update algorithm corresponding to the type of the BTCR2 Beacon: Singleton Beacon, Map Beacon or SMT Beacon.

flowchart TD
    Start@{shape: circle, label: Announce<br>BTCR2 Update} --> FindBeacons{Find<br>beaconServices}
    FindBeacons -->|NOT FOUND| BeaconNotFound@{shape: stadium, label: BeaconNotFoundError}
    FindBeacons -->|FOUND| ForEach[For each<br>beaconService]
    ForEach -->AddMoreBeacons{beaconService<br>.type}
    AddMoreBeacons -->|SingletonBeacon| BroadcastSingleton@{shape: subproc, label: Broadcast Singleton<br>Beacon Signal}
    AddMoreBeacons -->|MapBeacon| BroadcastMap@{shape: subproc, label: Broadcast Map<br>Beacon Signal}
    AddMoreBeacons -->|SMTBeacon| BroadcastSMT@{shape: subproc, label: Broadcast SMT<br>Beacon Signal}
    AddMoreBeacons -->|ELSE| InvalidBeacon@{shape: stadium, label: InvalidBeaconError}
    BroadcastSingleton --> SignalMetadata[signalMetadata]
    BroadcastMap --> SignalMetadata
    BroadcastSMT --> SignalMetadata
    SignalMetadata --> MergeSignalsMetadata[Merge<br>signalMetadata]
    SignalMetadata --> ForEach
    MergeSignalsMetadata --> Return@{shape: lean-l, label: Return<br>signalsMetadata}

The Deactivate operation data flowchart is almost identical to the Update flow since the process of deactivation is simply that of creating an update to the DID document. DID Controllers create a JSON Patch to add the key-value pair {"deactivated": true} to the DID document. Below is an example of a BTCR2 Update that would be used to deactivate a DID and DID document.

{
"updatePayload": {
"@context": [
"https://w3id.org/security/v2",
"https://w3id.org/zcap/v1",
"https://w3id.org/json-ld-patch/v1"
],
"patch": [
{
"op": "add",
"path": "/deactivated",
"value": true
}
],
"targetHash": "ER5jJUisvZafd8n6V2Bo...",
"targetVersionId": 2,
"sourceHash": "3osrqR3kJ2YMEDfwcKow...",
"proof": {
"cryptosuite": "bip340-jcs-2025",
"type": "DataIntegrityProof",
"verificationMethod": "did:btcr2:k1xyz123#initialKey",
"proofPurpose": "capabilityInvocation",
"capability": "urn:zcap:root:did%3Abtcr2%3Ak1xyz123",
"capabilityAction": "Write",
"@context": [
"https://w3id.org/security/v2",
"https://w3id.org/zcap/v1",
"https://w3id.org/json-ld-patch/v1"
],
"proofValue": "z3LhCeApi5wirR4jubkKQhEEiVRPZADDamf..."
}
}
}