Skip to content

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:btcr2 identifier 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.

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.

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 identifier did:btcr2:_ that must include at least one beacon service entry. Random Inputs uses the Genesis Document from the generator above, or builds a new one with api.btcr2.buildGenesisDocument(). Keep the document: the hash is one-way, so resolving the resulting x1… 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.

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.

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.

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.

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 the assertionMethod of the document. The result is the text and a bip340-jcs-2025 Data Integrity proof. The proof purpose is always assertionMethod, 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, and signature. 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.