Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

did:btrc2 DID Method

WARNING This specification is still under active development and may be subject to breaking changes.

Authors

Contributors

Publication Date

… 2025

License

Mozilla Public License Version 2.0

© 2024-2025 Digital Contract Design

Abstract

did:btcr2 is a censorship-resistant Decentralized Identifier (DID) method using the Bitcoin blockchain as a Verifiable Data Registry to announce changes to the DID document. It supports zero-cost off-chain DID creation; aggregated updates for scalable on-chain update costs; long-term identifiers that can support frequent updates; private communication of the DID document; private DID resolution; and non-repudiation.


Introduction and Motivation

Public digital identity was introduced to the Internet through Pretty Good Privacy’s (PGP) foundational legal work in the 1990s. With Decentralized Identifiers (DIDs), digital identity can be preserved through a rotation of key material, without relying on a centralized party. This specification defines did:btcr2, a DID method designed and motivated by the following considerations:

Anti-censorship

Our primary motivation is to leverage the anti-censorship capability of Bitcoin to enable individuals to control decentralized identifiers without interference by centralized players. That means creating a W3C conformant DID method capable of creating identifiers usable for a range of verifiable interactions, including issuing Verifiable Credentials and proving that the current presenter is the subject of a Verifiable Credential. This DID method gives organizations and states the ability to anchor private attestations to identifiers under individuals’ direct control, giving humans an unprecedented ability to participate in digital interactions on their own terms, using the identifiers they choose, when they choose.

Privacy

The first DID method anchoring on the Bitcoin blockchain, did:btcr, focused on censorship resistance. However, self-sovereign identity is not complete without options for privacy as well, and the initial promise of privacy in the DID ecosystem was dubious, with heavy reliance on public DID documents. There has been a presumption that anyone who has the DID itself should be able to resolve it to get the current DID document. This presumption places more information in the public eye than is strictly necessary for securing interactions related to the DID.

To tackle reliance on public DID documents head-on, this DID method introduces private DID documents, in which resolving the DID requires additional information delivered either alongside or in a separate communication from the DID controller. We call this transfer Sidecar delivery. Our approach ensures that successful resolution ALWAYS results in the same DID document for all parties, so that every party in the ecosystem sees the same cryptographically anchored result.

Late Publishing

Many DID methods lack verifiable provenance: it is simply impossible to reconstruct a cryptographically verifiable history of updates. Instead, they use a Verifiable Data Registry that can rewrite history. Bitcoin’s blockchain is the premiere global network for immutably anchoring information to a specific time. This DID method ensures that every BTCR2 DID is anchored on a single, canonical, immutable history for the lifetime of the DID. It is simply not possible for anyone to modify the history of the DID. We call this feature Non-Repudiation.

Offline Creation

Finally, we wanted to support the creation of DIDs without requiring on-chain interactions. BTCR creation depended on getting a transaction on-chain. BTCR2 supports creating DIDs with sophisticated DID documents without registering them on-chain. In fact, all BTCR2 DIDs start with offline creation. Only updates to the DID document require on-chain interactions. Our approach supports both key-based deterministic DIDs and document-based deterministic DIDs. In key-based DIDs, the DID itself contains everything you need to bootstrap an initial DID Document with usable verification methods suitable for authentication, attestation, and capability invocation and delegation. For document-based DIDs, additional Sidecar Data - a Genesis Document - must be used to create the Initial DID document. Offline creation allows unlimited DID creation and use without requiring any on-chain or online interactions, making it suitable for a wide range of high-volume, low cost use cases.

Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

The key words MAY, MUST, MUST NOT, RECOMMENDED, SHOULD, and SHOULD NOT in this document are to be interpreted as described in [BCP14] when, and only when, they appear in all capitals, as shown here.

Interoperability of implementations of the did:btcr2 DID method is tested by evaluating an implementation’s ability to create, update, deactivate, and resolve did:btcr2 identifiers and DID Documents that conform to this specification. Interoperability for producers and consumers of did:btcr2 identifier and DID Documents is provided by ensuring the DIDs and DID Documents conform.

Implementations MUST be conformant to all normative statements in Decentralized Identifiers v1.1 [DID-CORE] and DID Resolution v0.3 [Unknown bib ref: DID-RESOLTUION].

Terminology

Aggregate Beacon

A collection of BTCR2 Updates can optionally be aggregated into a single Beacon Signal by an Aggregation Service for multiple entities (possibly controlling multiple DIDs and possibly posting multiple updates).

There can only ever be one BTCR2 Update per did:btcr2 DID in a Beacon Signal from an Aggregate Beacon.

Aggregation Cohort

The set of Aggregation Participants within an Aggregate Beacon.

Aggregation Participant

A member of an Aggregation Cohort, typically a DID controller, that controls cryptographic keys required to partially authorize spends from a Beacon Address.

Aggregation Service

The entity that coordinates the protocols of an Aggregate Beacon in order to establish a Aggregation Cohort and aggregate BTCR2 Update Announcements in a Beacon Signal.

Authorized Beacon Signal

An Authorized Beacon Signal is a Beacon Signal from a BTCR2 Beacon with a Beacon Address in a then-current DID document.

Beacon Address

The Bitcoin address of a BTCR2 Beacon. Spends of UTXO controlled by this address are identified as Beacon Signals.

Beacon Announcement Map

A document that maps did:btcr2 identifiers to BTCR2 Update Announcements. This is used to distinguish which BTCR2 Update Announcement applies to which did:btcr2 identifier.

Beacon Signal

Beacon Signals are Bitcoin transactions that spend from a Beacon Address and include a transaction output of the format defined in Signal Bytes. Beacon Signals announce one or more BTCR2 Updates and provide a means for these updates to be validated against the Beacon Signal.

The type of the BTCR2 Beacon determines how these Beacon Signals are constructed and processed to validate a set of BTCR2 Updates against the Signal Bytes contained within the Beacon Signal.

Beacon Type

The type of a BTCR2 Beacon. The Beacon Type defines how BTCR2 Update Announcements are included within a Beacon Signal broadcast on the Bitcoin network. It also defines how the content committed within BTCR2 Update Announcements can be validated against the Beacon Signal.

BTCR2 Beacon

A service listed in a BTCR2 DID document that informs resolvers how to find authentic updates to the DID. It MUST be either a Singleton Beacon, SMT Beacon, or a CAS Beacon.

BTCR2 Update

A data structure used for transforming a source DID document into a target DID document. It contains a JSON Patch [RFC6902] object, a version number for the target DID document, and SHA-256 hashes for the source and target DID documents.

BTCR2 Unsigned Update

A BTCR2 Update without a proof attached to it.

Example: BTCR2 Unsigned Update (data structure).

BTCR2 Update Announcement

A 32-byte SHA-256 hash committing to a BTCR2 Update that has been broadcast by a BTCR2 Beacon in a DID’s then-Authorized Beacon Signal. Beacon Signals can optionally aggregate one or more BTCR2 Update Announcements. How Beacon Signals aggregate announcements is defined by the Beacon Type.

BTCR2 Signed Update

A BTCR2 Update with a proof attached to it.

A capability invocation secured using Data Integrity [VC-DATA-INTEGRITY] that invokes an authorization capability to update a specific did:btcr2 DID document. This capability invocation Data Integrity proof secures the BTCR2 Unsigned Update document.

Example: BTCR2 Signed Update (data structure).

CAS

Content Addressable Storage

CAS Beacon

A type of BTCR2 Beacon which aggregates multiple BTCR2 Update Announcements. A Beacon Signal from a CAS Beacon commits to a Beacon Announcement Map.

CID

Content Identifier

Content Addressable Storage

Content Addressable Storage (CAS) is a data storage system where content is addressable using Content Identifiers (CIDs). The InterPlanetary File System (IPFS) is an example of CAS.

Content Identifier (CID)

An identifier for some digital content (e.g., a file) generated from the content itself such that for any given content and CID generation algorithm there is a single, unique, collision-resistant identifier. This is typically done through some hashing function.

Current DID Document

The transient state of the DID document during DID Resolution. The Current DID Document is iteratively updated as a resolver traverses the blockchain and applies the relevant BTCR2 Updates announced by Authorized Beacon Signals it identifies in specific Bitcoin blocks.

Data Integrity Proof

A digital signature added to a BTCR2 Unsigned Update in order to convert to a BTCR2 Signed Update.

The algorithm is specified in BIP340 Cryptosuites v0.1 [BIP340-Cryptosuite] and Verifiable Credential Data Integrity 1.0 [VC-DATA-INTEGRITY].

Genesis Bytes

The bytes used to generate a did:btcr2 identifier. These bytes are either a 33-byte compressed SEC encoded secp256k1 public key or a 32-byte SHA-256 hash of a Genesis Document.

Genesis Document

An intermediate representation of an Initial DID Document with the identifier set to the placeholder value.

Example: Genesis Document (data structure).

Initial DID Document

The canonical, conformant version 1 of a DID document for a specific did:btcr2 identifier.

Example: Initial document (data structure).

Late Publishing

Late Publishing is the ability for DID updates to be revealed at a later point in time, which alters the history of a DID document such that a state, that appeared valid before the reveal, appears after Late Publishing to never have been valid. Late Publishing breaks Non-Repudiation.

Merkle Tree

A tree data structure in which the leaves are a hash of a data block and every node that is not a leaf is a hash of its child node values.

The root of a Merkle Tree is a single hash that is produced by recursively hashing the child nodes down to the leaves of the tree. Given the root of a Merkle Tree it is possible to provide a Merkle path that proves the inclusion of some data in the tree.

Non-Repudiation

Non-Repudiation is a feature of DID methods that can clearly state that all data is available to present one canonical history for a DID.

If some data is needed but not available, the DID method MUST NOT allow DID resolution to complete. Any changes to the history, such as may occur if a website edits a file, MUST be detected and disallowed. The Late Publishing problem breaks Non-Repudiation.

Offline Creation

Offline Creation refers to when a did:btcr2 identifier and corresponding initial DID document are created without requiring network interactions.

did:btcr2 supports offline creation in two modes:

  • Key Pair Deterministic Creation; and
  • DID Document Initiated Creation.

Resolution Time

A Coordinated Universal Time (UTC) timestamp set when the resolver receives a resolution request.

Schnorr Signature

An alternative to Elliptic Curve Digital Signature Algorithm (ECDSA) signatures with some major advantages, such as being able to combine digital signatures from multiple parties to form a single digital signature for the composite public key.

Bitcoin Schnorr signatures are still over the secp256k1 curve, so the same keypairs can be used to produce both Schnorr signatures and ECDSA signatures.

Sidecar

A mechanism by which data necessary for resolving a DID is provided alongside the did:btcr2 identifier being resolved, rather than being retrieved through open and standardized means (e.g., by retrieving from IPFS).

To explain the metaphor, a sidecar on a motorcycle brings along a second passenger in a transformed vehicle, the same way the DID controller MUST bring along the DID document history to transform the situation into one that is verifiable.

Sidecar Data

Data transmitted via Sidecar.

Signal Bytes

The 32 bytes of information that are included within the last transaction output of a Beacon Signal. The script of this transaction output has the following form:

[OP_RETURN, OP_PUSH_BYTES, <signal_bytes>]

Singleton Beacon

A type of BTCR2 Beacon whose Beacon Signals each contain a single BTCR2 Update Announcement.

SMT

Sparse Merkle Tree

SMT Beacon

A type of BTCR2 Beacon which aggregates multiple BTCR2 Update Announcements using an optimized Sparse Merkle Tree.

A Beacon Signal from an SMT Beacon contains the root of an optimized Sparse Merkle Tree.

SMT Proof

A set of SHA-256 hashes for nodes in a Sparse Merkle Tree that together form a path from a leaf in the tree to the Merkle root, proving that the leaf is in the tree.

Sparse Merkle Tree

A Merkle Tree data structure where each data point included at the leaf of the tree is indexed.

This data structure enables proofs of both inclusion and non-inclusion of data at a given index. The instantiation in this specification has 2^256 leaves that are indexed by the SHA-256 hash of a did:btcr2 identifier.

Unsigned Beacon Signal

The Bitcoin transaction of the Beacon Signal before its transaction inputs have been signed, effectively spending these inputs.

Unspent Transaction Output (UTXO)

A Bitcoin transaction takes in transaction outputs as inputs and creates new transaction outputs potentially controlled by different addresses. An Unspent Transaction Output (UTXO) is a transaction output from a Bitcoin transaction that has not yet been included as an input, and hence spent, within another Bitcoin transaction.

UTXO

Unspent Transaction Output

BTCR2 Update Data Distribution

In many cases, additional data is required for resolution. In those cases, the resolver can receive data via two primary means from a DID controller, both secured by cryptographic hash:

  1. Sidecar
  2. Content Addressable Storage (CAS)

All BTCR2 Update data must be made available to the resolver to enable full resolution of the DID document. Cryptographic hashes and signatures ensure the integrity and authenticity of data shared from controller to resolver.

All documents used for resolution are JSON documents, identified by their SHA-256 cryptographic hash calculated after first canonicalizing the document according to the JSON Document Hashing algorithm.

As a resolver goes through the resolution process, it encounters one or more document hashes, which it uses to identify the files of interest. See Process Sidecar Data.

While it’s possible for a single did:btcr2 identifier to mix the two distribution mechanisms, it is NOT RECOMMENDED. Instead, it is RECOMMENDED that controllers pick a distribution mechanism and use it throughout the lifetime of a given DID.

Sidecar

Sidecar provides additional update data alongside the did:btcr2 identifier being resolved. This is analogous to a sidecar on a motorcycle bringing along a second passenger: the DID controller provides the DID document history (in the form of BTCR2 Updates and any additional proofs) along with DID to the relying party so that the resolver can construct the DID document.

When a resolver is presented with a did:btcr2 identifier, it is also presented with documents matching the SHA-256 hashes it encounters during the resolution process. If any SHA-256 hash doesn’t have a corresponding file, the resolution fails.

Content Addressable Storage (CAS)

Content Addressable Storage (CAS) is a mechanism by which a digital file is stored on a network for retrieval based on its content, not its name or location. The content address is determined by a cryptographic hash of the file. The hash is then passed into a retrieval function specific to the type of CAS to retrieve the file.

Any CAS that provides a deterministic mapping from a SHA-256 hash of a file may be used, and a resolver SHOULD be informed of the specific CAS mechanism so that it can retrieve documents associated with a did:btcr2 identifier efficiently. If the CAS mechanism is not provided, the resolver MAY iterate through all supported CAS mechanisms to find the files or it MAY return with an error indicating that the CAS mechanism is required.

At this time, IPFS is the only known CAS to provide a deterministic mapping from a SHA-256 hash.

Interplanetary File System (IPFS)

The Interplanetary File System (IPFS) “is a set of open protocols for addressing, routing, and transferring data on the web, built on the ideas of content addressing and peer-to-peer networking.”

A detailed description is available at the IPFS documentation site, but for the purposes of did:btcr2, it is a distributed file system where the files are identified using a unique Content Identifier (CID) based on the content of the file. The content of the file determines the CID, and the CID may be used by anyone, anywhere, to retrieve the file.

For did:btcr2 identifiers, files stored in IPFS MUST override the default chunking behaviour by storing the file as a raw binary using the Raw Leaves option. This limits the file size to the block size (default 256 kB, maximum 1 MB), but that should be sufficient for most applications, ensuring that the entire file is included when calculating the CID.

The IPFS CIDv1 is a binary identifier constructed from the file hash as:

  • 0x01, the code for CIDv1;
  • 0x00, the multicodec code for raw binary;
  • 0x12, the multihash code for SHA-256; and
  • the SHA-256 of the file.

The stringified version of the CIDv1 is accomplished using multibase encoding. The final URL is "ipfs://<stringified CIDv1>".

A resolver retrieves a file associated with a SHA-256 hash by constructing the IPFS CIDv1 and requesting the file from an IPFS node.

Beacons

A BTCR2 Beacon is a service listed in a BTCR2 DID document that informs resolvers how to find authentic updates to the DID. The service properties define a Bitcoin address to watch for Beacon Signals.

All Beacon Signals broadcast from a BTCR2 Beacon in the Current DID Document MUST be processed as part of DID document resolution. The Beacon Type in the service defines how Beacon Signals MUST be processed.

Any on-chain Beacon Signal that cannot be processed renders the related DID invalid. For this reason, all DID controllers SHOULD ensure the Beacon Addresses they include in their DID document require appropriate approval to spend UTXOs controlled by the address, so that only approved Beacon Signals can be posted to Bitcoin. For resilience, BTCR2 DIDs can specify any number of Beacons and SHOULD include at least one Singleton Beacon as a fallback in case all Aggregate Beacons fail.

A Beacon Signal commits to, and anchors in a Bitcoin block, 32 bytes of information. These Signal Bytes represent one of the following:

did:btcr2 supports different Beacon Types, with each type defining a set of algorithms for:

The current, active, BTCR2 Beacons of a DID document are specified in the document’s service property. By updating the DID document, a DID controller can change the set of BTCR2 Beacons they use to broadcast updates to their DID document over time. Resolution of a DID MUST process signals from all BTCR2 Beacons identified in the Current DID Document and apply them in the order determined by the targetVersionId declared in the BTCR2 Signed Update (data structure).

All did:btcr2 DID resolvers MUST support the Beacon Types defined in this specification.

Table 1: Beacon Types

Service typeBeacon Type
"SingletonBeacon"Singleton Beacon
"CASBeacon"CAS Beacon
"SMTBeacon"SMT Beacon

Singleton Beacon

A Singleton Beacon is a BTCR2 Beacon that can be used to announce commitments to a single BTCR2 Update targeting a single DID document. It creates a Beacon Signal that commits to a single BTCR2 Update Announcement. This is typically done directly by the DID controller, as there is no Aggregation Cohort.

If the BTCR2 Update committed to by the BTCR2 Update Announcement is not publicly discoverable (i.e., is not published to a CAS under its hash), the only parties that are aware of it are the DID controller and any parties provided it by the DID controller.

The type of a service defining a Singleton Beacon in a DID document is "SingletonBeacon".

CAS Beacon

A CAS Beacon creates a Beacon Signal that commits to multiple BTCR2 Update Announcements through a Beacon Announcement Map. To do so, it constructs a Map where the key is the did:btcr2 identifier and the value is the hash of the corresponding BTCR2 Update. The Beacon Signal contains a SHA-256 hash of the Map.

If a BTCR2 Update is not publicly discoverable (i.e., is not published to a CAS under its hash), the only parties with access to the update are the DID controller and any parties they gave it to (etc.).

For a CAS Beacon, proof of non-inclusion of a did:btcr2 identifier is simply its absence from the Map.

The type of a service defining a CAS Beacon in a DID document is "CASBeacon".

SMT Beacon

An SMT Beacon creates a Beacon Signal that commits to multiple BTCR2 Update Announcements, each identified by a did:btcr2 identifier. To do so, it constructs an optimized Sparse Merkle Tree as defined in Appendix: Optimized Sparse Merkle Tree Implementation and publishes the Merkle root.

An SMT Beacon provides maximum privacy for the DID controller, as the DID controller never has to reveal their DIDs or BTCR2 Updates to the aggregator.

The type of a service defining an SMT Beacon in a DID document is "SMTBeacon".

Aggregate Beacons

DID controllers can use a CAS Beacon, an SMT Beacon, or both to participate in BTCR2 Update Aggregation. In contrast to a Singleton Beacon, which only allows for one BTCR2 Update per Bitcoin transaction, Aggregate Beacons combine multiple BTCR2 Updates into one Bitcoin transaction for any number of DID controllers. In this context, DID BTCR2 controllers are called Aggregation Participants.

BTCR2 Update Aggregation

BTCR2 Update Aggregation is the coordination protocol used by an Aggregation Service and Aggregation Participants to perform aggregation. A full protocol definition is out of scope for this specification, but a RECOMMENDED example is provided for illustration.

Example Using Musig2, secp256k1, and Schnorr Signatures

One implementation, centered on Schnorr signatures, allows all Aggregation Participants to veto any Beacon Signal for which their own proof data does not match the proposed OP_RETURN data. DID controllers that wish to join an Aggregation Cohort and become an Aggregation Participant would need to provide the Aggregation Service with a Schnorr public key.

The Aggregation Service coordinates the construction of an n-of-n Pay-to-Taproot address as the Beacon Address, where each Aggregation Participant’s public key is one of the n keys. This ensures that all on-chain Beacon Signals are cryptographically signed by every Aggregation Participant, while the Aggregation Service remains minimally trusted.

An Aggregation Cohort may fail if Aggregation Participants stop participating or the Aggregation Service is compromised. If that happens, the Aggregate Beacon simply fails to broadcast Beacon Signals that announce BTCR2 Updates.

The Aggregation Service decides when to finalize the membership of the Aggregation Cohort. After it does, it computes an n-of-n Pay-to-Taproot address from the public keys the Aggregation Participants provided. This Beacon Address must be sent to all Aggregation Participants with the set of keys used to construct it. Each Aggregation Participant should verify the address and confirm that their key is included.

Once the Aggregation Participants have verified the newly formed Beacon Address, they can construct the service object that can be included within their DID document’s service array.

This RECOMMENDED setup ensures that neither the Aggregation Service nor other Aggregation Participants can compromise or invalidate a did:btcr2 identifier of another Aggregation Participant in the cohort.

The actors involved in aggregation are as follows.

Step 1: Create Aggregation Cohort

Creating an Aggregation Cohort requires that the Aggregation Service define the conditions for it, advertise the new cohort to prospective Aggregation Participants, and accept enrollment.

When defining an Aggregation Cohort, the Aggregation Service can define conditions such as:

Advertising Aggregation Cohorts to participants can be done with nostr or DIDComm.

Enrolling in an Aggregation Cohort requires exchanging DIDs or indexes (hashes of DIDs) and the public keys used to create the n-of-n MuSig2 Bitcoin address.

Step 2: Announcing Update Opportunities

After the Aggregation Cohort is created, an Aggregation Service MAY choose between two flows for presenting and engaging with update opportunities:

  1. Pull Flow: Aggregation Service periodically announces update opportunities to Aggregation Participants
  2. Push Flow: Aggregation Participants send updates to the Aggregation Service when ready

The cohort definition states which flow applies.

All Aggregation Participants must be made aware of each opportunity because every participant must respond.

Respond to Update Opportunities

Aggregation Participants must submit a response to every update opportunity announced by the Aggregation Service; otherwise the Aggregation Service cannot broadcast Beacon Signals. This response must include:

  • For a CAS Beacon:

    • Either a negative acknowledgement (for no update to be included)
    • Or …
      • did: The DID to be updated.
      • updateHash: The SHA-256 hash of the BTCR2 Update to be included, created with the JSON Document Hashing algorithm. (I.e., json_document_hash(update))
    • MuSig2 Nonce: A MuSig2 nonce constructed according to the nonce generation algorithm specified in [BIP327].
  • For an SMT Beacon:

    • didIndex: The SHA-256 hash of the DID to be updated.
    • updateHash:
      • If there is an update:
        • If a nonce is used: hash(hash(nonce) + json_document_hash(update))
        • If a nonce is not used: json_document_hash(update)
      • If there is not an update:
        • If a nonce is used: hash(hash(nonce))
        • If a nonce is not used: 0
    • Participants MUST persist their nonce values.
    • MuSig2 Nonce: A MuSig2 nonce constructed according to the nonce generation algorithm specified in [BIP327].

This response SHOULD be sent over a secure communication channel and MAY be signed.

Once responses to an update opportunity are collected, the Aggregation Service can prepare a candidate Beacon Signal for confirmation by the cohort.

Step 3: Aggregate & Request Signal Confirmation

Once the Aggregation Service has received responses to an update opportunity from all Aggregation Participants in the Aggregation Cohort, it aggregates the update announcements into an Unsigned Beacon Signal. All Aggregation Participants MUST respond. The Aggregation Service needs every update/no-update decision and every MuSig2 nonce to build the complete signal payloads and the n-of-n aggregated nonce. It then sends this signal, along with the information required to confirm its construction, to each Aggregation Participant. The Aggregation Service also combines the MuSig2 nonces from each Aggregation Participant following the nonce aggregation algorithm in [BIP327].

Aggregation of updates into a Beacon Signal depends on the type of BTCR2 Beacon.

For a CAS Beacon, the request signal confirmation message contains:

For an SMT Beacon, the request signal confirmation message contains:

Confirm Signal Request

The Aggregation Participant must validate the contents of the Beacon Signal (partially signed transaction) according to the type of the BTCR2 Beacon:

Once the Aggregation Participant is satisfied that the Beacon Signal only announces the BTCR2 Updates they submitted for DIDs they control, they partially sign the Bitcoin transaction according to the signing algorithm specified in [BIP327]. Aggregation Participants use the private key that matches the public key they provided when joining the Aggregation Cohort and the MuSig2 aggregated nonce provided by the Aggregation Service. Finally, Aggregation Participants return the partially signed Bitcoin transaction to the Aggregation Service, confirming the Beacon Signal.

Aggregation Participants SHOULD maintain the set of data required to validate their BTCR2 Updates against the Beacon Signal.

Step 4: Broadcast Aggregated Signal

After the Aggregation Service receives confirmation of the Beacon Signal from all Aggregation Participants within the Aggregation Cohort, it finalizes the signature on the Beacon Signal. Each confirmation contains a partial signature. The Aggregation Service aggregates these partial signatures to create a final signature that spends the UTXO controlled by the Beacon Address input in the Beacon Signal.

Aggregation of partial signatures is done following the partial signature aggregation algorithm specified in [BIP327]. The result is a signed Bitcoin transaction. The Aggregation Service then broadcasts this transaction onto the Bitcoin network.

Data Structures

For the purposes of interoperability, this specification defines data structures using the data model defined by the DID core v1.1 specification [DID-CORE].

Concrete representations of these data structures MUST conform to the JSON-LD 1.1 specification [JSON-LD].

All SHA-256 hashes [SHA256] that appear in concrete representations of these data structures MUST be encoded as a string using the "base64url" [RFC4648] encoding.

DID Document

A DID document is a map data structure defined by the DID core v1.1 specification [DID-CORE].

The following properties MUST be included:

  • @context: A context array containing the following context URLs:
    • "https://www.w3.org/TR/did-1.1"
    • "https://btcr2.dev/context/v1"
  • id: The did.

It can optionally include one or more of the following properties:

  • verificationMethod: A set of verification method objects.
  • assertionMethod: A set of references to verification methods or embedded verification method objects to be used for assertions.
  • capabilityInvocation: A set of references to verification methods or embedded verification method objects to be used for capability invocations.
  • service: An array of service objects.

In order for this DID document to be updatable, controllers must include at least one verification method with a capability invocation verification relationship and at least one BTCR2 Beacon service.

Genesis Document

A Genesis Document is a DID document (data structure) with the identifier set to the placeholder value (did:btcr2:_).

Initial DID Document

An Initial DID Document is a conformant DID document (data structure).

BTCR2 Unsigned Update

A BTCR2 Unsigned Update is a Map data structure with the following properties:

  • @context: A context array containing the following context URLs:
    • "https://w3id.org/zcap/v1"
    • "https://w3id.org/security/data-integrity/v2"
    • "https://w3id.org/json-ld-patch/v1"
    • "https://btcr2.dev/context/v1"
  • patch: A JSON Patch [RFC6902] object that defines a set of transformations to be applied to a DID document. The result of applying the patch MUST be a conformant DID document according to the DID core v1.1 specification [DID-CORE].
  • targetVersionId: The versionId of the DID document after the patch has been applied. The targetVersionId MUST be one more than the versionId of the DID document being updated.
  • sourceHash: A SHA-256 hash of the DID document that the patch MUST be applied to. The hash MUST be produced by the JSON Document Hashing algorithm.
  • targetHash: A SHA-256 hash of the DID document that results from applying the patch to the source document. The hash MUST be produced by the JSON Document Hashing algorithm.

BTCR2 Signed Update

A BTCR2 Signed Update is a Map data structure with the same properties as BTCR2 Unsigned Update (data structure) and one additional property:

Data Integrity Config

A Data Integrity [VC-DATA-INTEGRITY] proof with the proofPurpose set to "capabilityInvocation" and proofValue omitted.

The following properties MUST be included in the Data Integrity Config:

  • @context: A context array containing the follow context URLs:
    • "https://w3id.org/security/v2"
    • "https://w3id.org/zcap/v1"
    • "https://w3id.org/json-ld-patch/v1"
    • "https://btcr2.dev/context/v1"
  • type: The string "DataIntegrityProof".
  • cryptosuite: The string "bip340-jcs-2025".
  • verificationMethod: A valid verificationMethod reference that exists in the most recent DID document.
  • proofPurpose: The string "capabilityInvocation".
  • capability: A URN of the following format: urn:zcap:root:${encodeURIComponent(did)}.
  • capabilityAction: A string declaring the action required for the capability invocation. The string MUST be set to "Write".

Data Integrity Proof

A Data Integrity Proof with the proofPurpose set to "capabilityInvocation". This proof MUST be a valid invocation of the capability to update a did:btcr2 DID document.

This data structure is a Map data structure with the same properties as Data Integrity Config (data structure) and one additional property:

  • proofValue: MUST be a detached Schnorr signature produced according to Schnorr Signatures for secp256k1 [BIP340], as a Multibase "base-58-btc" [CID] encoded string.

Sidecar Data

The Sidecar Data contains optional properties:

SMT Proof

A SMT Proof data structure contains the following properties:

  • id: SHA-256 hash of the root node.
  • nonce: OPTIONAL 256-bit nonce generated for each update. MUST be encoded as a string using the "base64url" [RFC4648] encoding.
  • updateId: The OPTIONAL BTCR2 Signed Update (data structure) hashed with the JSON Document Hashing algorithm.
  • collapsed: Bitmap of zero nodes within the path (see: collapsed leaves).
  • hashes: Array of SHA-256 hashes representing the sibling SMT nodes from the leaf, containing the SHA-256 hash of the BTCR2 Signed Update or the “zero identity”, to the root.

Resolution Options

This data structure is defined by DID Resolution v0.3 [DID-RESOLUTION].

Resolution options MAY contain the following properties:

  • versionId: OPTIONAL ASCII string representation of the specific version of a DID document to be resolved.
  • versionTime: OPTIONAL XML Datetime normalized to UTC without sub-second decimal precision. The DID document to be resolved is the most recent version of the DID document that was valid for the DID before the specified versionTime.
  • sidecar: Sidecar Data (data structure).

DID Resolution Metadata

This data structure is defined by DID Resolution v0.3 [DID-RESOLUTION].

Resolution metadata MAY contain the following properties:

  • contentType: OPTIONAL media type of the returned DID document. E.g., "application/ld+json".
  • error: REQUIRED if an error occurs during DID resolution.

DID Document Metadata

This data structure is defined by DID Resolution v0.3 [DID-RESOLUTION].

Document metadata MAY contain the following properties:

  • deactivated: REQUIRED boolean that represents whether the resolved DID document has been deactivated.
  • updated: OPTIONAL XML Datetime normalized to UTC without sub-second decimal precision of the last Update operation for the resolved DID document.
  • versionId: OPTIONAL ASCII string representation of the version of the last Update operation for the resolved DID document.

CAS Announcement

A data structure that maps DIDs to BTCR2 Signed Update hashes. All BTCR2 Signed Updates (data structure) MUST be hashed with the JSON Document Hashing algorithm. The concrete representation of this data structure will be published to a CAS.

Root Capability

A Root Capability is an Object Capability used to authorize updates to a DID document. Implementation MAY use ZCAP-LD for capability invocations [ZCAP-LD].

The Root Capability MUST be a map containing only the following properties:

  • @context: MUST be the context string "https://w3id.org/zcap/v1"
  • id: MUST be a URN of the following format: urn:zcap:root:${encodeURIComponent(did)}
  • invocationTarget: MUST be the did.
  • controller: MUST be the did.

Operations

Creating and using did:bctr2 DIDs is achieved through specified cryptographic and network operations, with all updates anchored to Bitcoin transactions. This section defines the Create, Resolve, Update, and Deactivate operations for the did:btcr2 method.

Create

Creating a did:btcr2 identifier from an secp256k1 public key will result in an Initial DID Document when first resolved. Creating a did:btcr2 identifier from a Genesis Document allows for the creation of a more complex Initial DID Document, including the ability to include service endpoints and BTCR2 Beacons that support aggregation. Any active did:btcr2 DID document can be updated later with new key material and service endpoints.

Process

A did:btcr2 identifier encodes a few pieces of information: an indicator for a specific Bitcoin network and a collection of Genesis Bytes. A specification version number is also included. These three values are encoded with the DID-BTCR2 Identifier Encoding algorithm.

The Genesis Bytes can be created in two ways: from an secp256k1 public key or from a Genesis Document.

secp256k1 Public Key

An secp256k1 public key can be used as the Genesis Bytes. The key MUST be in its compressed SEC format: a 33-byte representation consisting of a single prefix byte (0x02 or 0x03) followed by the 32-byte x-coordinate of the elliptic curve point. Reference Section 2.3.3 in SEC 1: Elliptic Curve Cryptography [SEC].

Genesis Document Hash

A Genesis Document can be used as the Genesis Bytes, but MUST be hashed to 32 bytes with the JSON Document Hashing algorithm.

Resolve

Resolving a did:btcr2 identifier iteratively builds a DID document by applying BTCR2 Updates to an Initial DID Document that have been committed to the Bitcoin blockchain by Authorized Beacon Signals. The Initial DID Document is either deterministically created from the DID or provided by Sidecar Data.

DID resolution is defined by DID Resolution v0.3 [DID-RESOLUTION].

The resolve operation has the following function signature:

fn resolve(did, resolutionOptions) ->
  (didResolutionMetadata, didDocument, didDocumentMetadata)

Process

Input values MUST first go through Decoding the DID and Processing Sidecar Data.

Resolution maintains the following state while building the DID document:

  • updates: a list of tuples, each containing Bitcoin block metadata (height, time, confirmations) and a BTCR2 Signed Update (data structure).
  • current_document: the DID document being assembled.
  • current_version_id: the version number being processed (starts at 1).
  • update_hash_history: a list of BTCR2 Unsigned Update hashes used to detect duplicates.
  • block_confirmations: confirmations for the Bitcoin block that contains the most recently applied unique update.

The resolver:

  1. Establishes current_document from the DID or from Sidecar Data.
  2. Repeats the following loop:
    • Process Beacon Signals to populate updates from the beacon services in current_document.
    • Process updates Array to apply updates to current_document and refresh block_confirmations.
    • Stops when processing updates returns early with a resolved didDocument or an error occurs.

The resolver returns:

Decode the DID

The did MUST be parsed with the DID-BTCR2 Identifier Decoding algorithm to retrieve version, network, and genesis_bytes. An INVALID_DID error MUST be raised in response to any errors raised while decoding.

Process Sidecar Data

resolutionOptions contains a sidecar property (Sidecar Data (data structure)) which SHOULD be prepared as lookup tables:

If genesis_bytes is a SHA-256 hash, hash sidecar.genesisDocument with the JSON Document Hashing algorithm. Raise an INVALID_DID error if the computed hash does not match genesis_bytes.

Establish current_document

Resolution begins by creating an Initial Did Document called current_document (Current DID Document). The current_document is iteratively patched with BTCR2 Signed Updates announced by Authorized Beacon Signals.

Choose how to establish current_document based on the type of genesis_bytes retrieved from the decoded did:

If genesis_bytes is a SHA-256 Hash

Process the Genesis Document provided in sidecar.genesisDocument by replacing the identifier placeholder ("did:btcr2:_") with the did. A simple string replacement is sufficient. Parse the result as JSON to form current_document. The resulting DID Document (data structure) MUST be conformant to DID Core v1.1 [DID-CORE].

If genesis_bytes is a secp256k1 Public Key

Render the Initial DID Document template with these values (Bitcoin addresses MUST use the Bitcoin URI Scheme [BIP321]):

  • did: The did.
  • public-key-multikey: Public key as a Multibase "base-58-btc" [CID] encoded string.
  • p2pkh-bitcoin-address: Pay-to-Public-Key-Hash (P2PKH) Bitcoin address produced from the public key.
  • p2wpkh-bitcoin-address: Pay-to-Witness-Public-Key-Hash (P2WPKH) Bitcoin address produced from the public key.
  • p2tr-bitcoin-address: Pay-to-Taproot Bitcoin address produced from the public key.

Parse the rendered template as JSON to form current_document. The resulting DID Document (data structure) MUST be conformant to DID Core v1.1 [DID-CORE].

Process Beacon Signals

Scan the service entries in current_document (DID Document (data structure)) and identify BTCR2 Beacons by matching service type to Beacons Table 1: Beacon Types. Parse each beacon serviceEndpoint as a Beacon Address, then use those Beacon Addresses to find Bitcoin transactions whose last output script contains Signal Bytes.

Implementations are RECOMMENDED to query an indexed Bitcoin blockchain RPC service such as electrs or Esplora. Implementations MAY instead traverse blocks from the genesis block. Cache Beacon Addresses to avoid repeated transaction lookups.

For each transaction found:

Process CAS Beacon

Treat Signal Bytes as map_update_hash. Look up map_update_hash in cas_lookup_table to retrieve a CAS Announcement (data structure) and read update_hash from the announcement entry keyed by did.

Process SMT Beacon

Treat Signal Bytes as smt_root. Look up smt_root in smt_lookup_table to retrieve an SMT Proof (data structure). Validate the proof with the SMT Proof Verification algorithm. Use smt_proof.updateId as update_hash.

Process updates Array

Return current_document as the resolved didDocument if updates is empty.

Otherwise:

  1. Sort updates by BTCR2 Signed Update (data structure) targetVersionId (ascending) with the tuple’s block height as a tiebreaker. Take the first tuple.
  2. Set block_confirmations to the tuple’s block confirmations.
  3. If resolutionOptions.versionTime is provided and the tuple’s block time is more recent, return current_document as the resolved didDocument.
  4. Set update to the tuple’s BTCR2 Signed Update (data structure) and check update.targetVersionId.
  5. Increment current_version_id.
  6. If current_version_id is greater than or equal to the integer form of resolutionOptions.versionId, return current_document.
  7. If current_document.deactivated is true, return current_document.

Check update.targetVersionId

Compare update.targetVersionId to current_version_id. Only one of three possible conditions will occur:

Confirm Duplicate Update

This step confirms that an update with a lower-than-expected targetVersionId is a true duplicate.

Create unsigned_update by removing the proof property from update. Hash unsigned_update with the JSON Document Hashing algorithm and compare it to update_hash_history[update.targetVersionId - 2]. Raise a LATE_PUBLISHING error if the hashes differ.

Apply update

Hash current_document with the JSON Document Hashing algorithm. Raise an INVALID_DID_UPDATE error if the result does not match the decoded update.sourceHash.

Check update.proof.

Apply the update.patch JSON Patch [RFC6902] to current_document.

Verify that current_document conforms to DID Core v1.1 [DID-CORE] and that current_document.id equals did. Otherwise raise INVALID_DID_UPDATE.

Hash the patched current_document with the JSON Document Hashing algorithm. Raise an INVALID_DID_UPDATE error if the result does not match the decoded update.targetHash.

Create unsigned_update by removing the proof property from update, hash it with the JSON Document Hashing algorithm, and append the hash to update_hash_history.

Check update.proof

Implementations MAY derive a Root Capability (data structure) from update.proof and invoke it according to Authorization Capabilities for Linked Data v0.3 [ZCAP-LD].

The resolver must locate publicKeyMultibase in current_document.verificationMethod whose id matches update.proof.verificationMethod. Otherwise raise INVALID_DID_UPDATE. Raise the same error if current_document.capabilityInvocation does not contain update.proof.verificationMethod.

Use a BIP340 Cryptosuite [BIP340-Cryptosuite] instance with publicKeyMultibase and the "bip340-jcs-2025" cryptosuite to verify update. Raise INVALID_DID_UPDATE if verification fails.




  1. The number of confirmations for the Bitcoin block that contains the most recently applied unique update that yielded the resolved DID document. “Unique” refers to handling duplicated updates. When deduplicating, use the lowest block height to determine confirmations.

Update

did:btcr2 DID documents can be updated by anchoring BTCR2 Updates to Bitcoin transactions. These transactions MAY be published to the Bitcoin network.

Any property in the DID document may be updated except the id. Doing so would invalidate the DID document.

The update operation has the following function signature:

fn update(
  didSourceDocument,
  jsonPatches,
  targetVersionId,
  verificationMethodId,
  privateKey,
) ->
  signedUpdate

Input arguments:

  • didSourceDocument: The source DID document.
  • jsonPatches: An array of JSON patch documents [RFC6902] with the changes to be made to the source DID document.
  • targetVersionId: The versionId of the target DID document that the new BTCR2 Signed Update will yield.
  • verificationMethodId: The verificationMethod ID used for signing the BTCR2 Update.
  • privateKey: Private key associated with the verificationMethodId.
    • An implementation MAY use the verificationMethodId ID to retrieve the private key from a key material manager.

Outputs:

Process

Updating a did:btcr2 DID document is a matter of constructing a BTCR2 Signed Update then announcing that update via one or more BTCR2 Beacons listed in the DID document. The update announcement process varies depending on the Beacon Type.

Constructing a BTCR2 Signed Update is a two-step process. First, a BTCR2 Unsigned Update is constructed. Then the update is signed with a private key to construct the BTCR2 Signed Update.

Construct BTCR2 Unsigned Update

This process constructs a BTCR2 Unsigned Update (data structure).

Apply all JSON patches in jsonPatches to didSourceDocument to create didTargetDocument. didTargetDocument MUST be conformant to DID Core v1.1 [DID-CORE]. An INVALID_DID_UPDATE error MUST be raised if didTargetDocument.id is not equal to didSourceDocument.id.

Fill the BTCR2 Unsigned Update (data structure) template below with the required template variables.

  • array-of-patches: jsonPatches serialized to a JSON string.
  • source-hash: didSourceDocument hashed with the JSON Document Hashing algorithm.
  • target-hash: didTargetDocument hashed with the JSON Document Hashing algorithm.
  • target-version-id: The value of targetVersionId.

Let update be the result of parsing the rendered template as JSON. The resulting BTCR2 Unsigned Update (data structure) MUST be conformant to this specification.

Construct BTCR2 Signed Update

This process constructs a BTCR2 Signed Update (data structure) from update, a BTCR2 Unsigned Update (data structure).

An INVALID_DID_UPDATE error MUST be raised if the didSourceDocument.verificationMethod Set does not contain an id matching verificationMethodId.

An INVALID_DID_UPDATE error MUST be raised if the didSourceDocument.capabilityInvocation Set does not contain verificationMethodId.

Create cryptosuite as a BIP340 Cryptosuite [BIP340-Cryptosuite] instance with privateKey and "bip340-jcs-2025" cryptosuite.

Fill the Data Integrity [VC-DATA-INTEGRITY] template below with the required template variables.

  • verification-method: The value of verificationMethodId.
  • capability: A URN of the following format: urn:zcap:root:${encodeURIComponent(didSourceDocument.id)}.

Let proofConfig be the result of parsing the rendered template as JSON. The resulting Data Integrity Config (data structure) MUST be conformant to Verifiable Credentials Data Integrity 1.0 [VC-DATA-INTEGRITY].

Pass update and proofConfig to the cryptosuite.createProof method and set update.proof to the resulting Data Integrity Proof (data structure).

Announce DID Update

BTCR2 Signed Updates are announced to the Bitcoin blockchain depending on the Beacon Type.

Announcing to a Singleton Beacon

A BTCR2 Update Announcement for a Singleton Beacon is the BTCR2 Signed Update hashed with the JSON Document Hashing algorithm. This 32-byte SHA-256 hash is used as the Signal Bytes when constructing a Beacon Signal Bitcoin transaction. The Beacon Signal is signed by the private key that controls the Beacon Address and broadcast to the Bitcoin network. To broadcast signed Bitcoin transactions, see the [Bitcoin-Core] source code.

Announcing to an Aggregate Beacon

Aggregating and announcing updates for multiple did:btcr2 identifiers is the responsibility of the Aggregation Service. The main responsibilities include establishing a protocol for one or more rounds of secure group communications amongst Aggregation Participants, advertising available Aggregation Cohorts to Aggregation Participants including the creation, management, timing and scheduling of those Aggregation Cohorts, and broadcasting a Bitcoin transaction to the Bitcoin network that includes signatures from all Aggregation Participants in a given Aggregation Cohort.

Deactivate

To deactivate a did:btcr2, the DID controller MUST add the property deactivated with the value true to the DID document. To do this, the DID controller constructs a valid BTCR2 Update with a JSON Patch [RFC6902] that adds this property and announces the BTCR2 Update by broadcasting an Authorized Beacon Signal following the algorithms defined in Update. Once a did:btcr2 has been deactivated this state is considered permanent and resolution MUST terminate.

Algorithms

These algorithms are referenced throughout this specification.

DID-BTCR2 Identifier Encoding

Any errors encountered during this algorithm MUST raise an INVALID_DID error.

A did:btcr2 identifier is created from three arguments: version_number, network_name and key_or_hash (Genesis Bytes).

key_or_hash MUST be one of the supported Genesis Bytes variants defined in the Terminology chapter and MUST be representable as a 33-byte secp256k1 public key or a 32-byte SHA-256 hash. Implementations SHOULD require key_or_hash to include additional type information that clearly distinguishes between the supported Genesis Bytes variants. This type information determines how the identifier is encoded.

The version_number value MUST be 1, declaring the encoding follows this specification.

The network_name value declares which Bitcoin network anchors the identifier. Implementations SHOULD require network_name to include additional type information using symbolic names that MUST be representable as integer values listed in the following table:

Table 1: Network Values

network_namenetwork_value
bitcoin0
signet1
regtest2
testnet33
testnet44
mutinynet5
Reserved6..11
Custom networks12..14

Introduce btcr2_version as version_number - 1 (i.e., 0). Combine btcr2_version in the low 1 nibble and network_value in the high 1 nibble into a single byte value.

Append key_or_hash to the first byte to produce the unencoded data bytes. Its format is:

Table 2: Unencoded Data Bytes

btcr2_versionnetwork_valuegenesis_bytes
Size:4 bits4 bits32 or 33 bytes
Index 2:048

Encode the unencoded data bytes with Bech32m [BIP350] to produce the method-specific-id. Use "k" as the hrp for key-based key_or_hash and "x" as the hrp for Genesis Document-based key_or_hash.

Prefix the method-specific-id with the string "did:btcr2:" to produce the final did:btcr2 identifier.

DID-BTCR2 Identifier Decoding

Any errors encountered during this algorithm MUST raise an INVALID_DID error.

Parsing a did:btcr2 identifier produces three values: version_number, network_name, and key_or_hash (Genesis Bytes).

A did:btcr2 identifier MUST be processed according to the DID Resolution Algorithm [DID-RESOLUTION] to retrieve the did:btcr2 DID Method-specific ID method-specific-id. (I.e., the first 10 characters in the string MUST be exactly "did:btcr2:".)

Decode the method-specific-id as a Bech32m encoded string [BIP350] to retrieve the unencoded data bytes and hrp. Parse the unencoded data bytes according to Table 2: Unencoded Data Bytes to retrieve the btcr2_version, network_value and genesis_bytes.

  • btcr2_version MUST be 0. Introduce version_number as btcr2_version + 1. I.e., version_number MUST be returned to the caller as a type that can be represented as the value 1.
  • network_value MUST be one of the values in Table 1: Network Values. network_name SHOULD be returned to the caller including additional type information using symbolic names that can be represented as integer values.
  • The hrp MUST be either "k" or "x".

If the hrp is "k" (key-based btcr2:did identifier), key_or_hash MUST be genesis_bytes interpreted as a 33-byte SEC encoded secp256k1 public key.

If the hrp is "x" (Genesis Document-based btcr2:did identifier), key_or_hash MUST be genesis_bytes interpreted as a 32-byte SHA-256 hash of a Genesis Document.

JSON Document Hashing

  • Encode the document using JCS [RFC8785].
  • Hash the encoded document with SHA-256 [SHA256].

SMT Proof Verification

To verify the inclusion or non-inclusion of a DID in the SMT Proof, perform the following steps:

Construct a hashed-zero cache. Two zero leaves are hashed together by concatenating the value 0 with itself for the bottom level, and then hashed again with its next sibling, also itself, at each level up the tree. Each computed hash value can be cached in an array.

The SMT Proof (data structure) is verified by walking the tree starting from the leaf node value, given by hash(hash(proof.nonce) + proof.updateId), to the root proof.id. Walking the tree means hashing sibling hashes from proof.hashes concatenated with a candidate hash to construct each node value. Each bit within the leaf node index (given by hash(did)) informs the algorithm which side of the concatenation operation the sibling hash belongs on: 0 for left, 1 for right.

The tree is “optimized” by collapsing empty nodes. (See Appendix: Optimized Sparse Merkle Tree Implementation for definition of “optimized”.) Each bit within proof.collapsed informs the algorithm whether to take the next sibling hash from proof.hashes (0) or use a hashed zero from the current height of the tree (1).

The last step is asserting that the computed candidate hash is equivalent to proof.id (the Merkle root).




  1. Little Endian. ↩2

  2. The “Index” is a Little Endian bit count starting from 0 on the left and ending in 263 or 271 on the right (inclusive).

Errors

The algorithms described in this specification can raise the specific errors listed below. Additional error types defined in Section 10 of DID Resolution v0.3 [DID-RESOLUTION] may also be raised.

These errors are assumed to be fatal and all did:btcr2 operations must abort when one of these errors are raised.

INVALID_DID_UPDATE

An error was found when creating or applying a BTCR2 Update.

LATE_PUBLISHING

An error was found when processing the full history of BTCR2 Updates announced by all relevant Beacon Signals. See Late Publishing.

MISSING_UPDATE_DATA

BTCR2 Update data can not be found in either the provided Sidecar Data nor in CAS.

Appendix

The appendix contains privacy and security considerations made by the developers of this specification. This section is designed to complement the main specification and provide additional rationale, edge-case analyses, and guidance intended to help implementers understand subtle aspects of the BTCR2 design.

BTCR2 Update Aggregation

Below are two design considerations regarding how BTCR2 handles the update aggregation. It outlines the trust assumptions, describes how multi-party signing preserves the controller’s authority, and discusses the expected behavior and failure modes inherent in aggregated beacon-based updates.

No Privileged Role

Although update aggregation in did:btcr2 does depend on some party (or protocol) acting as the Aggregation Service (i.e., coordinator and publisher) of Beacon Signals, that role may be satisfied by any party. To ensure that the Aggregation Service gains no specific benefit with regard to the authority to publish a Beacon Signal, those participating in aggregation SHOULD use a protocol that ensures every Aggregation Participant in the Aggregation Cohort has explicitly signed the Beacon Signal itself. It is RECOMMENDED that Aggregate Beacons use a Beacon Address that requires an n-of-n Schnorr Signature where each Aggregation Participant explicitly signs in a provable manner.

Worst Case

Since aggregation depends on others, it should be expected that any given BTCR2 Beacon might fail. Perhaps the Aggregation Service stops providing the service or a peer in the Aggregation Cohort stops signing their portion of the Beacon Signal. The best practice to avoid complete failure is to have at least one Singleton Beacon in every DID document, ensuring a fallback mechanism should all Aggregate Beacons fail.

However, even in the case of failure at the aggregation layer, only two negative consequence are possible:

  1. If the Beacon Signal does not require n-of-n signing, a hostile Aggregation Cohort (or Aggregation Service) could invalidate the DID by publishing a Beacon Signal with a malformed update.

  2. When the Beacon Signal does require n-of-n signing, a hostile Aggregation Cohort (or Aggregation Service) could render that Beacon inoperable, preventing publication of BTCR2 Updates through that address. However, this has no effect on other beacons.

In no case is it possible for a [Beacon Participant] other than the DID controller to compromise the DID document itself. All BTCR2 Updates remain cryptographically secured. Compromising the DID document requires compromising the controller’s key store: a threat which is already the primary attack vector for compromising DIDs. No new threats to DID document provenance are created by aggregation.

Privacy Considerations

Design Considerations

Updates Can Be Private

did:btcr2 was designed such that updates to Decentralized Identifier (DID) documents are NOT REQUIRED to be public. Bitcoin is used to publicly announce and anchor updates to DID documents, however the updates themselves can be kept private by DID controllers and provided through a Sidecar mechanism at Resolution Time.

DID Documents Can Be Private

Since updates to DID documents are NOT REQUIRED to be public, neither are did:btcr2 DID documents. A did:btcr2 DID document is an initial document plus a series of updates to that DID document. To keep the DID document fully private, the DID controller can choose to use an externally resolved initial did:btcr2 and not place the initial DID document on a Content Addressable Storage (CAS) system such as the InterPlanetary File System (IPFS). The initial DID document can be provided at Resolution Time through a Sidecar mechanism along with the collection of BTCR2 Updates that can be verified against the relevant Beacon Signals for the DID being resolved.

Offline DID Creation

did:btcr2 was designed to support offline creation, that is, the generation of a did:btcr2 identifier and associated DID document without any network calls to the Bitcoin blockchain. This is possible in both deterministic and externally resolvable DIDs.

Aggregation Services Only Need Hashes

Aggregation Services in did:btcr2 are entities that coordinate Aggregate Beacons and the corresponding Beacon Signals that announce and anchor an aggregated set of BTCR2 Updates. However, in did:btcr2, aggregators are able to coordinate Beacon Signals without needing to view or validate DID documents or the updates. Instead, they are provided with a hash or Content Identifier (CID) of the update for a specific DID which they include in the Beacon Signal according to the type of the BTCR2 Beacon.

Consensus Splits Break Non-Repudiation

Because Non-Repudiation requires following a complete stream of updates to a DID, any consensus forks in which DID updates to apply can be used to permanently diverge the history for a DID, and thus the key material, creating alternate attestation histories.

As a concrete example, a seemingly small difference between two clients in interpretation of the specification could be used fraudulently to sign a loan in one history and claim that it was never signed in another history.

In order to prevent consensus splits, did:btcr2 needs a particularly good test suite. It MUST be designed to challenge all the foreseeable edge cases as well as maintained to find new ones.

Deployment Considerations

CAS Systems Lack Privacy

Specifically, in this context, the relevant content are BTCR2 Updates being stored in Content Addressable Storage (CAS) such as IPFS. These SHOULD be considered public. Anyone MAY retrieve this information (assuming they have the CID) and use it to track the DID over time. IPFS node operators would have access to all content stored on IPFS and could choose to index certain data like BTCR2 Updates, including the updates posted by a BTCR2 Beacon connected to a specific DID. This MAY advertise information about the DID that the controller wishes to remain private.

Those parties most concerned about privacy SHOULD maintain their BTCR2 Updates in a Sidecar manner and provide them to necessary parties during resolution. It is RECOMMENDED not to include any sensitive data other than the necessary DID update data.

Aggregation Participants Provide DIDs to Aggregation Services

Within SMT Beacons, the DID is used as a path to an SMT leaf node. The Aggregation Service MUST know these paths to be able to construct the tree and generate the correct proof paths. Within CAS Beacons, the Aggregation Service MUST construct a CAS Announcement (data structure). This means that for both types of Aggregate Beacons, the Aggregation Service necessarily MUST know all DIDs in the Aggregation Cohort.

All DIDs are Visible to CAS Beacon Aggregation Cohort

Aggregation Cohort members participating in a CAS Beacon learn all DIDs that are updated in each Beacon Signal because the contents of a CAS Beacon Signal is a JSON object that maps participant did:btcr2 identifiers to CID values, where each CID value is that DID’s respective BTCR2 Update. Each DID controller SHOULD independently retrieve and verify the contents of the update bundle to ensure it contains the expected update for their DID before authorizing the Aggregation Service creates the CAS Announcement (data structure) from the CAS Beacon Signal and broadcasts it.

Non-Repudiation Reveals DID Document History

One of the side effects of using a DID is that a DID controller’s relying party will see their DID Document. In addition, resolving a DID document requires making available to the resolver all prior DID document updates.

Security Considerations

Late Publishing

did:btcr2 was designed to avoid Late Publishing such that, independent of when a resolution occurs, the DID document history and provenance are guaranteed to be invariant. Resolvers MUST enforce strict ordering of the BTCR2 Updates and process all relevant Beacon Signals.

Invalidation Attacks

Invalidation attacks are where adversaries are able to publish Beacon Signals that claim to contain updates for DIDs they do not control. Due to the requirement for processing all relevant Beacon Signals, if these updates cannot be retrieved by a resolver, the DID MUST be considered invalid. To prevent these attacks, all Beacon Signals SHOULD be authorized by signatures: either from the DID controller when using a Singleton Beacon or with a n-of-n multisignature from all n members of an Aggregation Cohort when using an Aggregate Beacon. DID controllers SHOULD verify the updates announced within a Beacon Signal before authorizing it.

Deployment Considerations

Data Retention

BTCR2 Updates MUST be available to resolver at the time of resolution. It is the responsibility of DID controllers to persist this data, otherwise the consequence is that the DID MAY not be resolvable (depending on data accessibility from the perspective of the resolver). DID controllers MAY store BTCR2 Updates on a CAS system. DID controllers SHOULD consider that in some constrained environments it is preferable to discard a DID and replace it with a newly issued DID, rather than rotating a key.

Aggregate Beacon Address Verification

A Beacon Address of an Aggregate Beacon SHOULD be an n-of-n Pay-to-Taproot (P2TR) address, with a key contributed to the n by each of the participants in an Aggregation Cohort. DID controllers participating in an Aggregation Cohort SHOULD verify the Beacon Address is an n-of-n and that one of the n keys is the key that they provided to the Aggregation Service. This can be achieved only by constructing the Beacon Address for themselves using the set of keys from the Aggregation Cohort that SHOULD be provided by the Aggregation Service.

Aggregate Beacon Signal Verification

When submitting Beacon Signals to Aggregation Services, a DID controller will either: announce an BTCR2 Update for their DID or not. The DID controller SHOULD verify that the Beacon Signal announces the BTCR2 Update they expect (or no BTCR2 Update) for all Beacon Signals broadcast by Aggregation Services before final authorization. If they do not, then invalidation attacks become possible where a Beacon Signal announces a BTCR2 Update that cannot be retrieved for a particular DID, causing the DID to be invalidated.

Key Compromise

In did:btcr2, cryptographic keys authorize both BTCR2 Updates and Beacon Signals. Should these keys get compromised without the DID controller’s knowledge, it would be possible for an adversary to take control of a DID by submitting a BTCR2 Update to a BTCR2 Beacon that replaces key material and BTCR2 Beacons in the DID document for ones under the adversary’s control. Such an attack would be detectable by the DID controller, as they would see a valid spend from a BTCR2 Beacon that they did not authorize. Additionally, if the DID relied on Sidecar Data, without access to this data the DID would be useless to the adversary as they would be unable to demonstrate a valid complete history of the DID during resolution.

Cryptographic Compromise

The security of did:btcr2 identifiers depends on the security of Schnorr Signatures over the secp256k1 curve. It is this signature scheme that is used to secure both the Beacon Signals and BTCR2 Updates. Should vulnerabilities be discovered in this scheme or if advancements in quantum computing compromise its cryptographic foundations, the did:btcr2 method would become obsolete.

Bitcoin Blockchain Compromise

The security of did:btcr2 identifiers depends on the security of the Bitcoin blockchain. Should the Bitcoin blockchain become compromised such that its history could be rewritten, for example through a 51% attack, then Beacon Signals that were once part of the blockchain could be removed or replaced – although the longer these Beacon Signals have been included in the blockchain the more difficult this becomes. A 51% attack could prevent future Beacon Signals from being included within the network, however this would require the 51% attack to remain indefinitely enforced. Furthermore, without key compromise related to a specific DID, the compromise of the Bitcoin blockchain would not enable adversarial parties to take control of a DID.

Optimized Sparse Merkle Tree Implementation

From Wikipedia:

In cryptography and computer science, a hash tree or Merkle tree is a tree in which every “leaf” node is labelled with the cryptographic hash of a data block, and every node that is not a leaf (called a branch, inner node, or inode) is labeled with the cryptographic hash of the labels of its child nodes. A hash tree allows efficient and secure verification of the contents of a large data structure. A hash tree is a generalization of a hash list and a hash chain.

flowchart TD
    classDef rootHash color:#000000,fill:#fb8500
    classDef nodeHash color:#000000,fill:#219ebc
    classDef leafHash color:#ffffff,fill:#023047
    classDef dataBlock color:#000000,fill:#ffb703

    RootHash["`Root Hash
    *hash(Hash 0 + Hash 1)*`"]:::rootHash

    RootHash --> Hash0["`Hash 0
    *hash(Hash 00 + Hash 01)*`"]:::nodeHash
    RootHash --> Hash1["`Hash 1
    *hash(Hash 10 + Hash 11)*`"]:::nodeHash

    Hash0 --> Hash00["`Hash 00
    *hash(Hash 000 + Hash 001)*`"]:::nodeHash
    Hash0 --> Hash01["`Hash 01
    *hash(Hash 010 + Hash 011)*`"]:::nodeHash

    Hash1 --> Hash10["`Hash 10
    *hash(Hash 100 + Hash 101)*`"]:::nodeHash
    Hash1 --> Hash11["`Hash 11
    *hash(Hash 110 + Hash 111)*`"]:::nodeHash

    Hash00 --> Hash000["`Hash 000
    *hash(Hash 0000 + Hash 0001)*`"]:::nodeHash
    Hash00 --> Hash001["`Hash 001
    *hash(Hash 0010 + Hash 0011)*`"]:::nodeHash

    Hash01 --> Hash010["`Hash 010
    *hash(Hash 0100 + Hash 0101)*`"]:::nodeHash
    Hash01 --> Hash011["`Hash 011
    *hash(Hash 0110 + Hash 0111)*`"]:::nodeHash

    Hash10 --> Hash100["`Hash 100
    *hash(Hash 1000 + Hash 1001)*`"]:::nodeHash
    Hash10 --> Hash101["`Hash 101
    *hash(Hash 1010 + Hash 1011)*`"]:::nodeHash

    Hash11 --> Hash110["`Hash 110
    *hash(Hash 1100 + Hash 1101)*`"]:::nodeHash
    Hash11 --> Hash111["`Hash 111
    *hash(Hash 1110 + Hash 1111)*`"]:::nodeHash

    Hash000 --> Hash0000["`Hash 0000
    *hash(Data Block 0000)*`"]:::leafHash
    Hash000 --> Hash0001["`Hash 0001
    *hash(Data Block 0001)*`"]:::leafHash

    Hash001 --> Hash0010["`Hash 0010
    *hash(Data Block 0010)*`"]:::leafHash
    Hash001 --> Hash0011["`Hash 0011
    *hash(Data Block 0011)*`"]:::leafHash

    Hash010 --> Hash0100["`Hash 0100
    *hash(Data Block 0100)*`"]:::leafHash
    Hash010 --> Hash0101["`Hash 0101
    *hash(Data Block 0101)*`"]:::leafHash

    Hash011 --> Hash0110["`Hash 0110
    *hash(Data Block 0110)*`"]:::leafHash
    Hash011 --> Hash0111["`Hash 0111
    *hash(Data Block 0111)*`"]:::leafHash

    Hash100 --> Hash1000["`Hash 1000
    *hash(Data Block 1000)*`"]:::leafHash
    Hash100 --> Hash1001["`Hash 1001
    *hash(Data Block 1001)*`"]:::leafHash

    Hash101 --> Hash1010["`Hash 1010
    *hash(Data Block 1010)*`"]:::leafHash
    Hash101 --> Hash1011["`Hash 1011
    *hash(Data Block 1011)*`"]:::leafHash

    Hash110 --> Hash1100["`Hash 1100
    *hash(Data Block 1100)*`"]:::leafHash
    Hash110 --> Hash1101["`Hash 1101
    *hash(Data Block 1101)*`"]:::leafHash

    Hash111 --> Hash1110["`Hash 1110
    *hash(Data Block 1110)*`"]:::leafHash
    Hash111 --> Hash1111["`Hash 1111
    *hash(Data Block 1111)*`"]:::leafHash

    Hash0000 --> DataBlock0000[("Data Block 0000")]:::dataBlock
    Hash0001 --> DataBlock0001[("Data Block 0001")]:::dataBlock
    Hash0010 --> DataBlock0010[("Data Block 0010")]:::dataBlock
    Hash0011 --> DataBlock0011[("Data Block 0011")]:::dataBlock
    Hash0100 --> DataBlock0100[("Data Block 0100")]:::dataBlock
    Hash0101 --> DataBlock0101[("Data Block 0101")]:::dataBlock
    Hash0110 --> DataBlock0110[("Data Block 0110")]:::dataBlock
    Hash0111 --> DataBlock0111[("Data Block 0111")]:::dataBlock
    Hash1000 --> DataBlock1000[("Data Block 1000")]:::dataBlock
    Hash1001 --> DataBlock1001[("Data Block 1001")]:::dataBlock
    Hash1010 --> DataBlock1010[("Data Block 1010")]:::dataBlock
    Hash1011 --> DataBlock1011[("Data Block 1011")]:::dataBlock
    Hash1100 --> DataBlock1100[("Data Block 1100")]:::dataBlock
    Hash1101 --> DataBlock1101[("Data Block 1101")]:::dataBlock
    Hash1110 --> DataBlock1110[("Data Block 1110")]:::dataBlock
    Hash1111 --> DataBlock1111[("Data Block 1111")]:::dataBlock

To use Merkle trees to signal commitments in BTCR2 Beacons:

  • The index (the identification of the leaf node) is the hash of the DID with the hash byte stream converted to an integer using big-endian conversion, i.e., index = int(hash(did)).
    • Each DID is therefore associated with one and only one leaf node.
    • Binding the index to the DID ensures that no other index can be used by a nefarious actor to post an update to the DID.
    • This produces a data structure with lots of unused leaves, making it a Sparse Merkle Tree.
  • The value stored at a leaf node is the hash of a 256-bit nonce, concatenated with the hash of the BTCR2 Update (the BTCR2 Update Announcement) if available, then the resulting stream is hashed again. I.e., value = hash(hash(nonce) + hash(btcr2Update)) if there is a BTCR2 Update or value = hash(hash(nonce)) if there is not.
    • Provided that it is unique per DID and per signal, the use of a nonce ensures that updates and non-updates are indistinguishable to outside parties (aggregators, other DID controllers, verifiers) unless explicitly informed by the DID controller.
    • The hashing of the nonce ensures that verifiers with limited input validation deal only with a 256-bit result.
  • A node with two empty children is itself empty.
  • The value of a node with one empty child and one non-empty child is the value of the non-empty child.
    • This limits work to only those points in the tree where non-empty indexes diverge.
  • The value of a node with two non-empty children is the hash of the concatenation of the left value (bit 0) and the right value (bit 1), i.e., node_value = hash(left_value + right_value).
  • The only thing published in the Beacon Signal is the root hash (the Merkle root).

Let’s assume that indexes 0 (0000), 2 (0010), 5 (0101), 9 (1001), 13 (1101), and 14 (1110) have DIDs associated with them; and a signal includes updates for DIDs 2, 9, and 13 and non-updates for all others.

The collapsed tree, where empty branches have been trimmed and single-child nodes have been removed, looks like this (note that the positions of nodes Hash 1001 and Hash 11 are reversed due to the Mermaid layout algorithm):

flowchart TD
    classDef rootHash color:#000000,fill:#fb8500
    classDef nodeHash color:#000000,fill:#219ebc
    classDef leafHash color:#ffffff,fill:#023047
    classDef dataBlock color:#000000,fill:#ffb703

    RootHash["`Root Hash
    *hash(Hash 0 + Hash 1)*`"]:::rootHash

    RootHash --> Hash0["`Hash 0
    *hash(Hash 00 + Hash 0101)*`"]:::nodeHash
    RootHash --> Hash1["`Hash 1
    *hash(Hash 1001 + Hash 11)*`"]:::nodeHash

    Hash0 --> Hash00["`Hash 00
    *hash(Hash 0000 + Hash 0010)*`"]:::nodeHash
    Hash0 --> Hash0101["`Hash 0101
    *hash(hash(Nonce 0101))*`"]:::leafHash

    Hash1 --> Hash1001["`Hash 1001
    *hash(hash(Nonce 1001) + hash(Data Block 1001))*`"]:::leafHash
    Hash1 --> Hash11["`Hash 11
    *hash(Hash 1101 + Hash 1110)*`"]:::nodeHash

    Hash00 --> Hash0000["`Hash 0000
    *hash(hash(Nonce 0000))*`"]:::leafHash
    Hash00 --> Hash0010["`Hash 0010
    *hash(hash(Nonce 0010) + hash(Data Block 0010))*`"]:::leafHash

    Hash11 --> Hash1101["`Hash 1101
    *hash(hash(Nonce 1101) + hash(Data Block 1101))*`"]:::leafHash
    Hash11 --> Hash1110["`Hash 1110
    *hash(hash(Nonce 1110))*`"]:::leafHash

    Hash0010 --> DataBlock0010[("Data Block 0010")]:::dataBlock
    Hash1001 --> DataBlock1001[("Data Block 1001")]:::dataBlock
    Hash1101 --> DataBlock1101[("Data Block 1101")]:::dataBlock

The DID controller has to prove that there is either an update or a non-update in the Beacon Signal. To prove an update, the DID controller provides the nonce and either the BTCR2 Update or the hash; to prove a non-update, the DID controller provides the nonce. In addition, the DID controller provides the list of collapsed nodes and hashes of each peer in the tree necessary to recalculate the root hash against which to compare with the value in the Beacon Signal.

Assuming that the DID of interest is at index 13 (int(hash(did)) == int(1101) == 13), the Aggregation Service (the party responsible for constructing the Sparse Merkle Tree) must provide the DID controller with a list of collapsed nodes above leaf node 13 and a list of hashes of the peers for uncollapsed nodes.

The Aggregation Service has the full Sparse Merkle Tree and can construct SMT Proofs. DID controllers request the SMT Proofs from the Aggregation Service and give them to verifiers. An example proof may be:

{
  "id": "<< Hexadecimal of Root Hash >>",
  "nonce": "<< Hexadecimal of Nonce 1101 >>",
  "updateId": "<< Hexadecimal of hash(Data Block 1101) >>",
  "collapsed": "<< Hexadecimal of 0001 >>",
  "hashes": [
      "<< Hexadecimal of Hash 1110 >>",
      "<< Hexadecimal of Hash 1001 >>",
      "<< Hexadecimal of Hash 0 >>"
  ]
}

With an SMT Proof, the verifier has everything necessary to verify that the BTCR2 Update is included or not. Assuming that the verifier can match the root hash in the Beacon Signal to proof.id and the BTCR2 Update to proof.updateId, the proof is verified as follows:

index = int(hash(did)) // 1101

candidateHash = hash(hash(proof.nonce) + proof.updateId)

// First collapsed bit from right is 1, so index bit doesn't apply.
// Skip first index bit.
// Candidate hash is unchanged.

// Next collapsed bit from right is 0, so index bit applies.
// Next index bit from right is 0.
// Candidate hash goes to the left against the next listed hash.
candidateHash = hash(candidateHash + "Hash 1110")

// Next collapsed bit from right is 0, so index bit applies.
// Next index bit from right is 1.
// Candidate hash goes to the right against the next listed hash.
candidateHash = hash("Hash 1001" + candidateHash)

// Next collapsed bit from right is 0, so index bit applies.
// Next index bit from right is 1.
// Candidate hash goes to the right against the next listed hash.
candidateHash = hash("Hash 0" + candidateHash)

// Hashes exhausted.
// Candidate hash must equal root hash.
assert(candidateHash === proof.id)

References

[BCP14] - N/A - Best Current Practice 14: Key words for use in RFCs to Indicate Requirement Levels. - 2017.

Summary/Abstract

BCP 14 is the Best Current Practice that defines and clarifies the usage of requirement-level keywords (MUST, SHOULD, MAY, etc.) in IETF documents. It comprises RFC 2119 (defining the keywords) and RFC 8174 (clarifying that only uppercase usage carries the defined semantics).


[Bitcoin-Core] - Bitcoin Core Developers - Bitcoin Core. - 2025.

Summary/Abstract

Bitcoin Core is the reference implementation of the Bitcoin protocol. It is a full node implementation that validates all transactions and blocks according to the Bitcoin consensus rules.


[BIP321] - Matt Corallo - URI Scheme. - 2024.

Summary/Abstract

This document proposes a URI scheme for describing Bitcoin payment instructions.


[BIP327] - Jonas Nick, Tim Ruffing, Elliott Jin - MuSig2 for BIP340-compatible Multi-Signatures. - 2022.

Summary/Abstract

This document proposes a standard for the MuSig2 multi-signature scheme. The standard is compatible with BIP340 public keys and signatures. It supports tweaking, which allows deriving BIP32 child keys from aggregate public keys and creating BIP341 Taproot outputs with key and script paths.


[BIP340] - Pieter Wuille, Jonas Nick, Tim Ruffing - Schnorr Signatures for secp256k1. - 2020.

Summary/Abstract

This document proposes a standard for 64-byte Schnorr signatures over the elliptic curve secp256k1.


[BIP340-Cryptosuite] - Will Abramson - Data Integrity BIP340 Cryptosuites. - 2025.

Summary/Abstract

This specification describes Data Integrity cryptographic suites for use when creating or verifying a digital signature using the the secp256k1 instantiation of the Schnorr Signature Algorithm as defined in BIP340.


[BIP350] - Pieter Wuille - Bech32m format for v1+ witness addresses. - 2020.

Summary/Abstract

This document defines an improved variant of Bech32 called Bech32m, and amends BIP173 to use Bech32m for native segregated witness outputs of version 1 and later. Bech32 remains in use for segregated witness outputs of version 0.


[CID] - Dave Longley, Manu Sporny, Markus Sabadello, Drummond Reed, Orie Steele, Christopher Allen - Controlled Identifiers v1.0. - 2025.

Summary/Abstract

A controlled identifier document contains cryptographic material and lists service endpoints for the purposes of verifying cryptographic proofs from, and interacting with, the controller of an identifier.


[DID-CORE] - Manu Sporny, Dave Longley, Markus Sabadello, Drummond Reed, Orie Steele, Christopher Allen - Decentralized Identifiers (DIDs) v1.1. - 2025.

Summary/Abstract

Decentralized identifiers (DIDs) are a new type of identifier that enables verifiable, decentralized digital identity. A DID refers to any subject (e.g., a person, organization, thing, data model, abstract entity, etc.) as determined by the controller of the DID. In contrast to typical, federated identifiers, DIDs have been designed so that they may be decoupled from centralized registries, identity providers, and certificate authorities. Specifically, while other parties might be used to help enable the discovery of information related to a DID, the design enables the controller of a DID to prove control over it without requiring permission from any other party. DIDs are URIs that associate a DID subject with a DID document allowing trustable interactions associated with that subject.

Each DID document can express cryptographic material, verification methods, or services, which provide a set of mechanisms enabling a DID controller to prove control of the DID. Services enable trusted interactions associated with the DID subject. A DID might provide the means to return the DID subject itself, if the DID subject is an information resource such as a data model.

This document specifies the DID syntax, a common data model, core properties, serialized representations, DID operations, and an explanation of the process of resolving DIDs to the resources that they represent.



[DID-RESOLUTION] - Markus Sabadello, Dmitri Zagidulin - Decentralized Identifier Resolution (DID Resolution) v0.3. - 2025.

Summary/Abstract

Decentralized identifiers (DIDs) are a new type of identifier for verifiable, self-sovereign digital identity. DIDs are fully under the control of the DID controller, independent from any centralized registry, identity provider, or certificate authority. DIDs resolve to DID Documents — simple documents that describe how to use that specific DID.

This document specifies the algorithms and guidelines for resolving DIDs and dereferencing DID URLs. Additionally, this document describes the input and output metadata related to the DID resolution processes and further describes the data structures that may be returned from a DID resolution request. This document relies on the core DID specification, Decentralized Identifiers (DIDs) v1.1, which describes the underlying DID architecture in full detail.



[JSON-LD] - Manu Sporny, Dave Longley, Gregg Kellogg, Markus Lanthaler, Pierre-Antoine Champin, Niklas Lindström - JSON-LD 1.1. - 2020.

Summary/Abstract

JSON is a useful data serialization and messaging format. This specification defines JSON-LD 1.1, a JSON-based format to serialize Linked Data. The syntax is designed to easily integrate into deployed systems that already use JSON, and provides a smooth upgrade path from JSON to JSON-LD. It is primarily intended to be a way to use Linked Data in Web-based programming environments, to build interoperable Web services, and to store Linked Data in JSON-based storage engines.

This specification describes a superset of the features defined in JSON-LD 1.0 and, except where noted, documents created using the 1.0 version of this specification remain compatible with JSON-LD 1.1.



[RFC4648] - Josefsson, S. - The Base16, Base32, and Base64 Data Encodings. - 2006.

Summary/Abstract

This document describes the commonly used base 64, base 32, and base 16 encoding schemes. It also discusses the use of line-feeds in encoded data, use of padding in encoded data, use of non-alphabet characters in encoded data, use of different encoding alphabets, and canonical encodings.


[RFC6902] - Bryan, P. and Nottingham, M. - JavaScript Object Notation (JSON) Patch. - 2013.

Summary/Abstract

JSON Patch defines a JSON document structure for expressing a sequence of operations to apply to a JavaScript Object Notation (JSON) document; it is suitable for use with the HTTP PATCH method. The application/json-patch+json media type is used to identify such patch documents.


[RFC8785] - Rundgren, A. and Jordan, B. and Erdtman, S. - JSON Canonicalization Scheme (JCS). - 2020.

Summary/Abstract

Cryptographic operations like hashing and signing need the data to be expressed in an invariant format so that the operations are reliably repeatable. One way to address this is to create a canonical representation of the data. Canonicalization also permits data to be exchanged in its original form on the wire while cryptographic operations performed on the canonicalized counterpart of the data in the producer and consumer endpoints generate consistent results.

This document describes the JSON Canonicalization Scheme (JCS). This specification defines how to create a canonical representation of JSON data by building on the strict serialization methods for JSON primitives defined by ECMAScript, constraining JSON data to the Internet JSON (I-JSON) subset, and by using deterministic property sorting.



[SEC] - Certicom Research and Daniel R. L. Brown - Standards for Efficient Cryptography 1 (SEC 1): Elliptic Curve Cryptography. - 2009.

Summary/Abstract

This document specifies public-key cryptographic schemes based on elliptic curve cryptography (ECC). In particular, it specifies:
  • signature schemes;
  • encryption and key transport schemes; and
  • key agreement schemes.

It also describes cryptographic primitives which are used to construct the schemes, and ASN.1 syntax for identifying the schemes.

The schemes are intended for general application within computer and communications systems.



[SHA256] - {National Institute of Standards and Technology} - Secure Hash Standard (SHS). - 2015.

Summary/Abstract

This standard specifies hash algorithms that can be used to generate digests of messages. The digests are used to detect whether messages have been changed since the digests were generated.


[VC-DATA-INTEGRITY] - Dave Longley, Manu Sporny, Ivan Herman - Verifiable Credential Data Integrity 1.0. - 2025.

Summary/Abstract

This specification describes mechanisms for ensuring the authenticity and integrity of verifiable credentials and similar types of constrained digital documents using cryptography, especially through the use of digital signatures and related mathematical proofs.


[ZCAP-LD] - Christine Lemmer-Webber, Manu Sporny, Mark S. Miller - Authorization Capabilities for Linked Data v0.3. - 2025.

Summary/Abstract

Authorization Capabilities for Linked Data (ZCAP-LD for short) provides a secure way for linked data systems to grant and express authority utilizing the object capability model. Capabilities are represented as linked data objects which are signed with Linked Data Proofs. ZCAP-LD supports delegating authority to other entities on the network by chaining together capability documents. Caveats may be attached to capability documents which may be used to restrict the scope of their use, for example to restrict the actions which may be used or providing a mechanism by which the capability may be later revoked.