Introduction
The biggest challenge for any Bitcoin-based identity system is update cost. Bitcoin transactions aren't free, and if every DID update requires its own transaction, the system can't scale. did:btcr2 addresses this with a three-tier beacon architecture — Singleton, CAS, and SMT — ranging from simple one-to-one updates to privacy-maximizing aggregation across many participants.
The Problem: Updates Need an Anchor
Creating a btcr2 DID is free — it happens offline. But updates (key rotation, service endpoint changes, document modifications) need to be anchored to Bitcoin to inherit its immutability and ordering guarantees. Without an anchor, there's no way to establish a canonical history or detect tampering.
The question is: how do you anchor updates efficiently?
Tier 1: Singleton Beacon
The simplest approach. One DID controller, one update, one Bitcoin transaction.
How It Works
- The controller constructs a BTCR2 Update — a list of JSON Patch (RFC 6902) operations against the DID document, signed with the
bip340-jcs-2025Data Integrity cryptosuite (BIP-340 Schnorr over secp256k1) - The signed update is hashed via the spec's
JSON Document Hashingalgorithm (JCS canonicalization + SHA-256), yielding a 32-byte digest used as the Signal Bytes - A Bitcoin transaction is created spending from the Beacon Address with an
OP_RETURNoutput carrying the Signal Bytes - The transaction is broadcast and confirmed
When to Use It
Singleton beacons are ideal for:
- Individual controllers who update infrequently
- High-value identity operations where dedicated on-chain presence is worth the cost
- A fallback service alongside Aggregate Beacons (the spec recommends every DID document include at least one Singleton Beacon for resilience if cohorts fail)
- Testing and development
Cost
One full Bitcoin transaction fee per update. At typical fee rates, this is affordable for occasional use but doesn't scale for high-frequency or high-volume scenarios.
Tier 2: CAS Beacon (Content Addressable Storage)
The middle tier introduces aggregation. Multiple DID updates from different controllers are combined into a single Bitcoin transaction.
How It Works
- Multiple controllers (Aggregation Participants) submit signed updates to an Aggregation Service, each with a participant-provided index keyed to their DID
- The service assembles a Beacon Announcement Map mapping each index to a BTCR2 Update Announcement (the
updateHashof the participant's update) - The SHA-256 hash of the Map becomes the Signal Bytes, committed via an
OP_RETURNoutput in a single Bitcoin transaction. The transaction spends from the cohort'sn-of-nMuSig2 P2TR Beacon Address — its witness is a single aggregated Schnorr signature built from partial signatures contributed by every participant - To resolve, the verifier needs both the Map and the relevant updates. The spec defines two equally valid distribution paths — Sidecar (the controller hands the data to the verifier directly) and CAS (typically IPFS, where the data is retrievable by its SHA-256 hash). The spec recommends picking one and sticking with it for a given DID's lifetime rather than mixing the two
The Aggregation Economics
If 100 controllers share a CAS beacon transaction, each effectively pays 1/100th of the transaction fee. At 1,000 participants, the per-update cost becomes negligible.
Trust Model
The Aggregation Service can't forge updates — each is signed by its controller, and every cohort member has to partially sign the resulting Bitcoin transaction, so a single rogue service can't broadcast on its own. The privacy story is more sobering, though: per the Privacy Considerations appendix, every member of a CAS cohort learns all the DIDs being updated in each beacon signal — they need to verify the Map contents before they'll partially sign. So a CAS Beacon is a fee-pooling arrangement among parties who are willing to be visible to one another, not a privacy-preserving one. For a CAS Beacon, proof of non-inclusion is simply the DID's absence from the Map. If a service misbehaves, controllers can switch to a different cohort or fall back to a Singleton Beacon listed alongside it.
Tier 3: SMT Beacon (Sparse Merkle Tree)
Maximum privacy aggregation. Per the spec: "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."
How It Works
- Each controller's leaf position in a 256-deep Optimized Sparse Merkle Tree is
hash(did). The leaf value ishash(hash(nonce) + updateId)— a nonce-blinded commitment to the update hash - Controllers submit their
indexand leaf value to the Aggregation Service. They don't have to reveal the underlying DID or the update content - The service builds the optimized SMT, computes the root, and commits the 32-byte root as the Signal Bytes via
OP_RETURN. Each participant gets back an SMT Proof for their index - To prove an update was included at a given anchor, the controller presents the SMT Proof; the verifier walks from the leaf up using
hash(did)to choose left/right at each level, validates against the on-chain root, and accepts or rejects
Privacy Properties
- The aggregator doesn't have to learn participants' DIDs — by design the controller never has to reveal their DID or update content to the aggregator (per the spec's privacy framing); the aggregator works with
hash(did)paths and nonce-blinded leaf values. (Caveat: the aggregator necessarily knows every path in its cohort by construction. Sohash(did)being deterministic means anyone with the cohort's path set — most obviously the aggregator itself — can correlate a candidate DID against it. The privacy is from passive on-chain observers, not from the aggregator.) - On-chain observers see only the SMT root — a single 32-byte hash. The number of participants, the indexes used, and the contents of the updates are not revealed by the on-chain data alone.
- Non-inclusion proofs — empty subtrees deterministically hash to known "hashed-zero" values at each tree level (precomputed in a cache so implementations skip recomputation). An SMT Proof for an unoccupied index walks from a zero leaf up to the root using a mix of cached zero hashes for empty sibling subtrees and actual sibling hashes for occupied ones. If the recomputed root matches the on-chain root, the verifier can confirm the given DID has no update at that anchor.
The 256-Deep Tree
hash(did) is SHA-256, so the tree's address space is 2^256. This means:
- Every possible DID has a unique, predetermined leaf position
- The tree is sparse — only positions with actual updates carry non-zero values; the spec's hashed-zero cache lets implementations skip the empty branches
- Collision resistance is inherited from SHA-256
Multi-Party Coordination
CAS and SMT beacons require participants to coordinate. The btcr2 spec doesn't lock in a single coordination protocol — it explicitly says the aggregation protocol "is out of scope for this specification, but a RECOMMENDED example is provided for illustration." That recommended example pairs MuSig2 (BIP-327) for the aggregated Schnorr signature on the beacon transaction with nostr (or DIDComm) for off-chain communication between the Aggregation Service and participants.
MuSig2 is a two-round Schnorr multi-signature scheme (round 1 = nonce exchange, round 2 = partial signatures), so a beacon round looks like:
- Cohort formation — The Aggregation Service advertises a cohort, accepts enrollments, and constructs an
n-of-nPay-to-Taproot Beacon Address from the participants' Schnorr public keys - Round 1 — nonce exchange — Each participant generates a MuSig2 nonce per BIP-327 and shares its public part with the service; the service aggregates them
- Round 2 — partial signing — The service sends each participant the unsigned beacon transaction plus the aggregated nonce; each participant verifies their inputs are correctly represented and returns a partial signature
- Aggregate and broadcast — The service aggregates the partial signatures into a single Schnorr signature, finalizes the transaction, and broadcasts it. The witness — a 64-byte Schnorr signature in a key-path P2TR spend — is bit-for-bit indistinguishable from a solo Schnorr signature. Anyone tracking the published Beacon Address can recognize the spend as a beacon signal (and read the Signal Bytes from the
OP_RETURN), but the witness itself doesn't reveal whether the signing key was a single party or an n-of-n cohort
Choosing the Right Tier
| Consideration | Singleton | CAS | SMT |
|---|---|---|---|
| Setup complexity | None | Aggregation Service needed | Aggregation Service needed |
| Cost per update | Full tx fee | Shared (≈1/N) | Shared (≈1/N) |
| Privacy from cohort | N/A | Service and every cohort member learn all DIDs in each Map | Service operates on hash(did) paths and nonce-blinded leaf values |
| Privacy from observers | Update hash visible on chain | Map hash visible on chain | Only the SMT root visible |
| Resolution data needed | Just the update | Map + the relevant update | SMT Proof + the update |
| Failure mode | None — controller signs solo | Cohort fails → no signal until reformed | Cohort fails → no signal until reformed |
Conclusion
btcr2's beacon system trades a single fixed model for a tiered one. Singletons are the simplest and the recommended fallback. CAS Beacons amortize fees across a cohort by committing to a Map of update announcements. SMT Beacons go further and hide DID identity from the Aggregation Service itself. All three commit to 32-byte Signal Bytes via OP_RETURN on Bitcoin, so resolvers process them under one model — the differences are in how update data reaches the verifier (sidecar or CAS) and how much the aggregator gets to see along the way. The right tier depends on the controller's threat model, update cadence, and tolerance for coordination overhead.