Introduction
Update cost is a major challenge for a Bitcoin-based identity system. Each Bitcoin transaction has a fee. If each DID update needs its own transaction, the system cannot scale. did:btcr2 addresses this problem with three Beacon Types: Singleton, CAS, and SMT. They range from simple one-to-one updates to aggregation across many participants with more privacy.
The Problem: Updates Need an Anchor
The creation of a btcr2 DID is free, because it occurs offline (Offline Creation). Updates are different. Examples of updates are key rotation, changes to service endpoints, and other changes to the DID document. The controller must anchor each update to Bitcoin to get the immutability and the order of the Bitcoin blockchain. Without an anchor, a resolver cannot find one canonical history or detect changes to that history (Non-Repudiation).
Thus, the design problem is how to anchor updates at a low cost.
Beacon Type 1: Singleton Beacon
This is the simplest Beacon Type. One DID controller puts one update in one Bitcoin transaction (Singleton Beacon).
How It Works
- The controller makes a BTCR2 Signed Update. The update contains a JSON Patch (RFC 6902) for the DID document, a
sourceHash, atargetHash, and atargetVersionId. The controller signs it with thebip340-jcs-2025Data Integrity cryptosuite (BIP-340 Schnorr over secp256k1). - The controller hashes the signed update with the JSON Document Hashing algorithm (JCS canonicalization and SHA-256). The 32-byte digest is the Signal Bytes of the Beacon Signal.
- The controller makes a Bitcoin transaction that spends from the Beacon Address. The last output of the transaction is an
OP_RETURNoutput that holds the Signal Bytes. - The controller broadcasts the transaction, and a miner includes it in a block.
When to Use It
Singleton Beacons fit these cases:
- Individual controllers who do not update frequently
- High-value identity operations, where a dedicated on-chain transaction is worth the cost
- A fallback beside Aggregate Beacons. The spec RECOMMENDS at least one Singleton Beacon in each DID document "as a fallback in case all Aggregate Beacons fail" (Beacons). A key-based DID starts with three Singleton Beacons: the P2PKH, P2WPKH, and P2TR addresses of its key (Resolve).
- Tests and development
Cost
Each update costs one full Bitcoin transaction fee. The fee depends on the size of the transaction and on the fee rate at that time. For occasional updates, one fee for each update can be acceptable. For frequent or high-volume updates, the total cost increases linearly with the number of updates.
Beacon Type 2: CAS Beacon (Content Addressable Storage)
The second Beacon Type adds aggregation. One Bitcoin transaction holds the updates of many DID controllers (Aggregate Beacons).
How It Works
- Many controllers (Aggregation Participants) send a response to each update opportunity from an Aggregation Service. The response contains the DID and the
updateHashof the signed update. If there is no update, the response is a negative acknowledgement. - The service makes a Beacon Announcement Map. The Map connects each DID to its BTCR2 Update Announcement, which is the hash of the signed update (CAS Announcement).
- The SHA-256 hash of the Map is the Signal Bytes. An
OP_RETURNoutput in one Bitcoin transaction holds them. In the RECOMMENDED setup, the transaction spends from then-of-nMuSig2 P2TR Beacon Address of the cohort. The witness is one aggregated Schnorr signature, and each participant contributes a partial signature to it. - To resolve, the verifier needs the Map and the applicable updates. The spec defines two distribution methods. With Sidecar, the controller gives the data directly to the verifier. With CAS, the verifier gets the data by its SHA-256 hash. The spec says that IPFS is the only known CAS that maps a SHA-256 hash to a file deterministically. The spec RECOMMENDS that controllers select one method and use it for the full lifetime of a DID.
The Aggregation Economics
If 100 controllers share the transaction of a CAS Beacon, each controller pays about 1/100 of the transaction fee. With 1,000 participants, each share is about 1/1,000 of the fee. The Aggregation Service can also set a cost of enrollment or a cost for each announcement (Step 1). A larger cohort has a tradeoff. Each participant must respond to each update opportunity, or the service cannot broadcast the Beacon Signal (Step 2).
Trust Model
The Aggregation Service cannot forge updates, because each controller signs its own update. The service gets only hashes, not the DID documents or the updates (Aggregation Services Only Need Hashes). In the RECOMMENDED n-of-n setup, each cohort member must partially sign the Bitcoin transaction. Thus, the service cannot broadcast a Beacon Signal alone (MuSig2 example).
The privacy properties are weaker. Each member of a CAS cohort learns all the DIDs that each Beacon Signal updates (Privacy Considerations appendix). The reason is that the Map connects each participant DID to an update hash, and each member checks the Map before its partial signature. Thus, a CAS Beacon shares fees among parties that accept visibility to each other. It does not give privacy inside the cohort. For a CAS Beacon, proof of non-inclusion is "simply its absence from the Map".
If a service does not operate correctly, the controller can use a Singleton Beacon in the same DID document. With a DID update, the controller can also add the Beacon Address of a different cohort. A hostile cohort can stop a beacon, but this "has no effect on other beacons" (Worst Case).
Beacon Type 3: SMT Beacon (Sparse Merkle Tree)
This Beacon Type gives the most privacy of the three, with an important limit. The Beacons section states the privacy goal in one sentence: "An SMT Beacon provides maximum privacy for the DID controller, as the DID controller never has to reveal their DIDs to the aggregator". The Privacy Considerations appendix adds a qualification to this statement. For each Aggregate Beacon, the service "necessarily MUST know all DIDs in the Aggregation Cohort," because the DID sets the leaf position. With the optional per-leaf nonce, the SMT hides whether a participant updated and what the update contains, but not the cohort membership.
How It Works
- The leaf position of each controller in the 256-level Optimized Sparse Merkle Tree is
hash(did). With a nonce, the leaf value for an update ishash(hash(nonce) + hash(update)). This value is a commitment to the update hash, and the nonce blinds it. With a nonce, the leaf value for no update ishash(hash(nonce)), and an observer cannot tell it apart from an update leaf. The nonce is OPTIONAL. Without a nonce, all parties know if there is an update (SMT Proof Verification). - The Aggregation Service must know the index of each cohort DID to position its leaf and make its proofs (Privacy Considerations appendix). The nonce hides from the service whether the controller updated and what the update contains. The nonce does not hide the identity of the controller.
- The service builds the optimized SMT and calculates the root. An
OP_RETURNoutput holds the 32-byte root as the Signal Bytes. Each participant gets an SMT Proof for each of its indexes. - To prove that a Beacon Signal includes an update, the controller gives the SMT Proof to the verifier. The verifier starts at the leaf and goes up to the root. At each level, one bit of
hash(did)selects the left side or the right side. The verifier compares the result with the on-chain root, and then accepts or rejects the proof.
Privacy Properties
- The aggregator knows the cohort DIDs, but not which participant updated: The Aggregation Service "necessarily MUST know all DIDs in the Aggregation Cohort" (appendix). The service derives each leaf position from the DID, and it must make the correct proof paths. With a nonce, the service does not know whether a participant updated or what the update says. The nonce makes update leaves and no-update leaves look the same, unless the controller discloses the difference. Thus, compared to a CAS Beacon, the SMT adds privacy of update status and update content. It does not hide cohort membership from the operator.
- On-chain observers see only the SMT root: The root is one 32-byte hash. The on-chain data alone does not show the number of participants, the indexes, or the content of the updates. A CAS Beacon also puts only one 32-byte value on chain: the hash of the Map.
- Non-inclusion proofs: An empty subtree has a known value at each tree level (its "cached zero"), and implementations store these values in a hashed-zero cache. A proof of no update uses one of two leaf values. With a nonce, the leaf is
hash(hash(nonce)). Without a nonce, the leaf is empty, and its value iscachedZero[0]. The verifier goes up to the root with cached zero values for empty sibling subtrees and real hashes for the other siblings. If the calculated root matches the on-chain root, the verifier knows that the DID has no update in that Beacon Signal.
The 256-Level Tree
hash(did) is SHA-256, so the address space of the tree is 2^256. This gives these properties:
- Each DID has one and only one leaf position, and each party can calculate this position in advance.
- The tree is sparse. Only the leaves of cohort DIDs can have values that are not empty. The cached zero values give a precomputed value for each empty subtree, so implementations do not calculate empty branches again.
- The collision resistance comes from SHA-256.
Multi-Party Coordination
CAS Beacons and SMT Beacons need coordination between participants. The btcr2 spec does not require one coordination protocol. It says that a full protocol definition "is out of scope for this specification, but a RECOMMENDED example is provided for illustration" (aggregation section). The example uses MuSig2 (BIP-327) for the aggregated Schnorr signature on the beacon transaction. The spec also says that the service can advertise cohorts with Nostr or DIDComm.
MuSig2 has two rounds: a nonce exchange, and then partial signatures (BIP-327). A beacon round has these steps:
- Cohort formation: The Aggregation Service advertises a cohort and accepts enrollments. When the membership is final, the service calculates an
n-of-nPay-to-Taproot Beacon Address from the Schnorr public keys of the participants. Each participant makes sure that the address includes its key (Aggregate Beacon Address Verification). - Round 1 (nonce exchange): For each update opportunity, each participant sends its update response and a MuSig2 nonce that it made per BIP-327. The service aggregates the nonces.
- Round 2 (partial signatures): The service sends each participant the unsigned Beacon Signal and the aggregated nonce. For a CAS Beacon, the message also contains the Map. For an SMT Beacon, it contains the SMT Proofs of that participant. Each participant makes sure that the signal announces only its own updates, and then it returns a partial signature (Confirm Signal Request).
- Aggregate and broadcast: The service aggregates the partial signatures into one Schnorr signature, completes the transaction, and broadcasts it. The witness of a key-path P2TR spend is a 64-byte Schnorr signature, or 65 bytes with an explicit sighash byte (BIP-341). An observer cannot tell a MuSig2 Taproot output from a single-signer Taproot output (BIP-327). An observer who knows the published Beacon Address can identify the spend as a Beacon Signal and read the Signal Bytes. But the witness does not show whether one party or an
n-of-ncohort holds the key.
How to Select a Beacon Type
| Consideration | Singleton | CAS | SMT |
|---|---|---|---|
| Setup complexity | Low (the controller funds the Beacon Address) | Aggregation Service necessary | Aggregation Service necessary |
| Cost per update | Full transaction fee | Shared (≈1/N) | Shared (≈1/N) |
| Privacy from cohort | Not applicable | The service and each cohort member learn all DIDs in each Map | The service knows the cohort DIDs. With a nonce, it does not know which participant updated. Other members get only their own proofs. |
| Privacy from observers | Update hash visible on chain | Map hash visible on chain | Only the SMT root visible on chain |
| Resolution data necessary | Only the update | The Map and the applicable update | The SMT Proof and the update |
| Failure mode | No cohort dependency (the controller signs alone) | If the cohort fails, the beacon sends no signals | If the cohort fails, the beacon sends no signals |
Conclusion
btcr2 uses several Beacon Types instead of one fixed model. Singleton Beacons are the simplest, and the spec recommends them as a fallback. CAS Beacons share fees across a cohort with a Map of update announcements. SMT Beacons add privacy. The Aggregation Service still knows the cohort DIDs, but a per-leaf nonce can hide which participants updated and what the updates contain.
All three types put 32 bytes of Signal Bytes in an OP_RETURN output, so resolvers process them with one model. The types differ in how update data gets to the verifier (sidecar or CAS) and in how much the aggregator sees. A suitable Beacon Type depends on the threat model of the controller, the update frequency, and the coordination cost that the controller accepts.