Demo
The DID Method specification covers four CRUD operations. The widgets on this page
run the TypeScript reference implementation (@did-btcr2/api) directly in
your browser. Start with the inputs:
- Key Pair and Genesis Document: generate test inputs for the other demos.
- Create: produce a new
did:btcr2identifier from a public key or a Genesis Document. - Resolve: resolve an identifier using Bitcoin beacon signals and optional sidecar data.
- Update: apply a JSON Patch to the DID document and announce it on-chain.
- Deactivate: special-case Update that adds
{"deactivated": true}to the DID document. - Sign and Verify a Message: sign a text with a key of a DID, and verify a signed message.
Key Pair and Genesis Document
Section titled “Key Pair and Genesis Document”Create needs a public key or a Genesis Document. Update, Deactivate, and Sign need the matching secret key. The toggle selects what Generate makes:
- Key Pair: a new secp256k1 key pair, made in your browser.
- Genesis Document: a document with the public key of the key pair and one to three beacons. Select the network, and the type and the address type of each beacon. Each beacon needs its own address, so each address type is allowed once.
A CAS Beacon or an SMT Beacon from this generator has one party. Its address comes from your key, and you sign each signal alone. The specification recommends an n-of-n P2TR address for the beacon of an Aggregation Cohort. This demo does not make that address.
Copy the output into the demos below. Random Inputs in Create uses this key pair and this Genesis Document, so you have the secret key that updates the new DID.
Create
Section titled “Create”Creating a did:btcr2 identifier is fully off-chain; no network round-trip is
needed. The Create operation accepts either:
KEY(deterministic): a compressed secp256k1 public key (33 bytes, SEC-encoded).EXTERNAL: the SHA-256 hash of a JCS-canonicalized Genesis Document, a DID document written against the placeholder identifierdid:btcr2:_that must include at least one beaconserviceentry. Random Inputs uses the Genesis Document from the generator above, or builds a new one withapi.btcr2.buildGenesisDocument(). Keep the document: the hash is one-way, so resolving the resultingx1…identifier requires it as sidecar data.
The response also lists the beacon addresses of the new DID. Fund one of them before the first Update.
Supported networks: testnet3, testnet4, signet, mutinynet.
Resolve
Section titled “Resolve”Resolution drives the Resolver
state machine. The demo connects to the network that the DID encodes, and the
@did-btcr2/api facade gets the beacon signals from it.
Sidecar data is optional:
- A
did:btcr2:x1…identifier encodes only a hash. Resolution needs the Genesis Document as{ "genesisDocument": … }. The “Sidecar for Resolve” output of Create pastes straight in, and the demo wraps a bare genesis document for you. - A DID with updates needs the signed updates (and any CAS announcements or SMT proofs), unless a CAS holds them. The “Sidecar for Resolve” output of Update contains them.
Resolution ignores a beacon signal with fewer confirmations than minConf. The
specification default is 6.
Update
Section titled “Update”Updates are applied as JSON Patch
documents. api.updateDid(...) resolves the current document, applies your
patches, signs the update with your key, and broadcasts a beacon signal. The
signal spends the confirmed UTXOs of the beacon address, up to 20. The value of
each UTXO must be more than the fee of its own input. The total value must be
more than the fee of the transaction. The demo takes the fee rate for the next
block from the Esplora API of the network, with a minimum of 1 sat/vB. If that
request fails, the demo uses 1 sat/vB. If you leave the verification method or
the beacon empty, the api uses the method that publishes your key and the only
beacon that can fund the signal.
The response includes the signed update and the signal txid. The “Sidecar for
Resolve” output adds the signed update to the sidecar data that you gave. Paste
it into Resolve, or into the next Update.
Before the next Update or Deactivate, wait until the beacon signal of the last
update has minConf confirmations. The api compares the resolved version with
the signed updates in the sidecar data. If the resolution does not apply all of
them, the api refuses the update. A second update for the same version makes the
DID fail with LATE_PUBLISHING.
The Update and Deactivate demos refuse a bitcoin (mainnet) DID.
Deactivate
Section titled “Deactivate”Deactivation is an Update with the well-known patch
[{ "op": "add", "path": "/deactivated", "value": true }]. The demo calls
api.deactivateDid(...), which adds that patch for you. Deactivation is
permanent: the api refuses any later update.
Sign and Verify a Message
Section titled “Sign and Verify a Message”A key of the DID can sign a text message. The toggle selects the operation:
- Sign resolves the current DID document and calls
api.btcr2.signMessage(...). The key must be in theassertionMethodof the document. The result is the text and abip340-jcs-2025Data Integrity proof. The proof purpose is alwaysassertionMethod, so a message signature is never valid as an update proof or as a transaction signature. - Verify resolves the current DID document and calls
api.btcr2.verifyMessage(...). The report has five checks in order:structure,signer,active,assertionMethod, andsignature. After a key rotation or a deactivation, an old message fails.
Both operations need the sidecar data of the DID, as Resolve does. After Sign, Verify uses the new signed message. The format has no time and no replay protection: put the date, a nonce, and the audience in the text.
The specification does not define message signatures: the format is a choice of the TypeScript implementation (ADR 137).
Sign refuses a bitcoin (mainnet) DID. Verify is read-only, so it also accepts one.