Introduction
Last week's post concluded that the practical answer to key compromise in did:btcr2 is structural: authorize more than one key, and hold them under different custody. That is easy to write and less easy to implement, especially for an organization where "the key" needs to survive people leaving, laptops being replaced, and the occasional audit.
This post is about what custody actually looks like for a corporate DID of the kind described in the supply chain and B2B post. It covers the parts with good answers, the parts with workable answers, and the parts where the honest response is that the tooling is not there yet.
Two Keys, Two Problems
The first thing to get right is that an organization running a btcr2 DID has two distinct custody problems, and conflating them produces bad designs.
The document control key signs the Data Integrity proof on a BTCR2 Signed Update. It is a secp256k1 key referenced from the DID document's capabilityInvocation relationship, and it produces a BIP340 Schnorr signature over a digest derived from the JCS-canonicalized payload. This key is what authorizes changes to who you are.
The beacon key signs the Bitcoin transaction that announces the update. It controls a UTXO, it pays a fee, and mechanically it is an ordinary Bitcoin spending key.
These are two different jobs, and they do not need the same custody. They do not start out separate, though. For a key-based (k) did:btcr2 identifier, the deterministically rendered initial document puts the genesis key in capabilityInvocation and derives all three SingletonBeacon service endpoints (the P2PKH, P2WPKH, and P2TR addresses) from that same key. Out of the box they are one key doing both jobs. Splitting the roles is an explicit act: either create a genesis-document-based (x) identifier whose document names a beacon funded by a different key, or publish an update that adds one and rotates the document key.
Once they are split, the compromise cases are not symmetric. An attacker who compromises the beacon key cannot forge an update, but the damage is worse than lost fees. They can broadcast a Beacon Signal whose 32 bytes point at update data that exists nowhere. Every signal from a beacon in the current document must be processed during resolution, an unresolvable one raises MISSING_UPDATE_DATA, and that error is fatal, so a single hostile spend can leave the identifier permanently unresolvable. A plain sweep of the UTXOs only costs you money; it is the spend carrying the OP_RETURN that does the lasting damage. An attacker who compromises the document key can forge updates but has to get one announced, which requires the beacon.
That asymmetry is useful, but it does not make the beacon key a low-stakes key. The spec says controllers SHOULD ensure their Beacon Addresses require appropriate approval to spend, precisely so that no unapproved signal reaches the chain. A small balance is fine; a single key that anyone with access to the host can spend from is not. Script multisig or an n-of-n Taproot address is the right tool here, and the spec also recommends keeping at least one Singleton Beacon as a fallback in case the aggregate beacons that batch many controllers into one signal fail. Most organizations will find their existing Bitcoin custody practices transfer cleanly to the beacon side and not at all to the document side, for reasons the next section makes clear.
The Hardware Signing Gap
Here is the uncomfortable part, and it is the thing to check before committing to an architecture.
Modern hardware wallets support Taproot. They produce BIP340 Schnorr signatures. It is tempting to conclude that a hardware wallet can therefore hold your document control key. In general, it cannot.
The problem is what those devices will sign. A hardware wallet is built to sign Bitcoin transactions. It parses a PSBT, shows the user outputs and amounts, and produces a signature over a transaction sighash. That constraint is the entire security model: the device refuses to sign things it cannot show the user, because a device that signs arbitrary bytes on request is a device that can be tricked into signing a transaction that drains it.
A btcr2 document update is not a transaction. It is a Schnorr signature over a 32-byte digest that the bip340-jcs-2025 cryptosuite builds by hashing the canonicalized document and the canonicalized proof configuration separately, then hashing the concatenation of the two hashes. A device hardened against signing arbitrary data is, by design, poorly suited to signing exactly that.
Some devices expose a message-signing facility, and some support generic signing paths, but coverage is inconsistent across vendors, firmware versions, and derivation paths, and the semantics vary. Before you architect around a specific device, verify empirically that it will produce a BIP340 signature over an arbitrary 32-byte digest at the derivation path you intend to use, and that a library you trust can verify the output. Treat vendor documentation as a starting point rather than an answer.
The same caution applies to HSMs and cloud key services. secp256k1 support in those products has historically meant ECDSA, driven by demand from custody and blockchain applications that predate Taproot. As of this writing, AWS KMS lists ECDSA_SHA_256 as the only signing algorithm for its ECC_SECG_P256K1 key spec, and Google Cloud KMS offers EC_SIGN_SECP256K1_SHA256, again ECDSA. BIP340 Schnorr is a different signature scheme over the same curve, and support for it is neither universal nor safe to assume. If your compliance posture requires an HSM, confirm BIP340 support with the vendor explicitly, and confirm it for the specific product tier you are buying, not the product family.
Where this leaves most organizations today is a software key in a well-controlled environment: a dedicated signing host, an offline machine, or a secure enclave with a custom signing application. That is a weaker story than "it's in an HSM," and pretending otherwise helps nobody. It is also not unusual: plenty of production signing infrastructure works this way, with the controls placed around the host rather than inside a signing chip.
Splitting Authority Across Keys
The simplest thing that meaningfully improves an organization's position costs nothing and requires no special hardware: put more than one key in capabilityInvocation, and hold them differently.
{
"capabilityInvocation": ["#ops-key", "#offline-key"]
}
#ops-key lives on the signing host that performs routine updates. #offline-key lives on an air-gapped machine or in a safe and gets used approximately never. Neither is more powerful than the other in the protocol's eyes, but the operational exposure is very different.
This is a disjunctive relationship, and the distinction matters. Both keys can independently authorize updates. This is or, not and: the update algorithm requires only that the proof's verification method be a member of the capabilityInvocation set, and resolution checks that same single membership. It gives you the property from the rotation post: compromise of the routine key leaves you holding an authorized key the attacker does not have, so you can publish a removal update. It does not give you two-person control, because either key acting alone is sufficient.
If you need genuine two-person control, the protocol does not provide it and you have to build it. Which brings us to the option people reach for first.
Where MuSig2 Fits, and Where It Does Not
MuSig2 appears in this series as the mechanism behind aggregated beacon coordination, and it is reasonable to ask whether it can also serve organizational control. It can, with one significant constraint that determines whether it fits your governance model.
MuSig2, as specified in BIP-327, is an n-of-n scheme. All participants must contribute a partial signature. There is no threshold: a 3-of-5 arrangement is not something MuSig2 provides.
For some organizational structures that is fine, even desirable. Two officers who must both sign off on any change to the corporate identity map cleanly onto 2-of-2. The DID document holds a single aggregated public key, resolution and verification are unchanged, and the multi-party nature is invisible on-chain and in the document. That last property is genuinely nice: verifiers do not need to know or care about your internal governance.
For others it is disqualifying. If your policy is "any three of the five board members," MuSig2 does not express that, and the failure mode of forcing it is severe: in an n-of-n scheme, one unavailable participant means no signature. A key holder on vacation blocks all updates. A key holder who leaves the company acrimoniously blocks all updates permanently.
Threshold Schnorr signing (FROST and related constructions) is the technique that provides t-of-n, and it has real implementations. FROST was published as an IRTF CFRG Informational RFC in 2024, not as a Bitcoin BIP, and the Bitcoin-side tooling is less mature than MuSig2's. If you need thresholds, that is the direction, and you should scope the integration work accordingly rather than assuming it drops in.
One approach that does not work, and is worth naming because it seems like it should: Bitcoin script multisig. A 2-of-3 multisig output secures a Bitcoin transaction. It has no bearing on a signature over a DID document, because the document signature is not a transaction and is never evaluated by Bitcoin script. Multisig is a fine tool for the beacon key. It is not a tool for the document key.
Separation by Verification Relationship
Custody design gets easier once you stop treating "the DID's keys" as one thing. A DID document distinguishes verification relationships, and the different relationships warrant genuinely different handling.
capabilityInvocationauthorizes document updates. Highest value, lowest usage frequency. This is the one that gets the safe.assertionMethodsigns Verifiable Credentials. If you issue credentials at volume, this key is used constantly and must be online in the issuance service.authenticationproves control for login flows. Frequently used, per-session, and the blast radius of compromise is bounded by what those sessions can do.
An issuance service with an online assertionMethod key is a normal and necessary design. The important property is that compromising it does not let the attacker change the document, because that key is not in capabilityInvocation. They can issue fraudulent credentials, which is bad, but you can rotate the assertion key with an update they cannot authorize, and any credential-status mechanism you run stays under your control.
Getting this separation right is the difference between an incident that costs you a revocation event and one that costs you the identifier.
Backup and Derivation
btcr2 document keys are ordinary secp256k1 keys, which means the backup story can reuse existing Bitcoin practice.
Worth knowing for tooling reasons: the bip340-jcs-2025 cryptosuite encodes its Multikey using the secp256k1-pub multicodec with a 33-byte SEC-compressed public key, varint prefix 0xe701. A native x-only bip340-pub codec exists in the multiformats table but the cryptosuite does not use it. Both entries carry draft status, so neither is more settled than the other, and implementers should not read maturity into the choice.
The practical consequence is convenient: a 33-byte compressed public key is exactly what BIP32 hierarchical derivation produces. Document control keys can be derived from a seed phrase on a dedicated derivation path, backed up with the same procedures your organization already uses for Bitcoin seeds, and reconstructed on a replacement machine without inventing a new process.
Two cautions. First, use a dedicated path and document it, because a key you can no longer locate in the tree is a key you have lost. Second, resist the temptation to derive document control keys from the same seed as the beacon spending keys. The entire point of separating the two is that they have different exposure, and a shared seed reunites them at exactly the layer you were trying to split.
An Honest Assessment
Where things stand, in plain terms:
Solid. Multiple authorized keys under different custody. Verification relationship separation. BIP32-derived keys backed up with established seed practices. Beacon Addresses that require approval to spend, which is ordinary Bitcoin multisig custody. Monitoring those addresses for unexpected signals, remembering that monitoring is detection and not prevention.
Workable with effort. MuSig2 n-of-n for two-party control, if n-of-n matches your governance. Software document keys on a hardened dedicated host, if the controls around the host are real.
Not there yet. Broad hardware wallet support for signing arbitrary BIP340 payloads. Reliable BIP340 support across commodity HSMs and cloud key services. Turnkey threshold signing for BIP340 document payloads, specified though FROST itself now is. Off-the-shelf policy engines that enforce approval workflows before a document update is signed.
That last category is not a reason to avoid deploying. It is a reason to design so the gaps can be filled later without re-architecting: keep the signer behind an interface, do not hard-code assumptions about where a key lives, and keep capabilityInvocation small enough that swapping the custody model is a two-update operation rather than a project.
Conclusion
The custody question for organizational DIDs is less about finding one secure vault and more about arranging several keys under different controls, so that compromising any one of them is not enough to take the identifier from you. That applies to the beacon side as much as the document side: an approval requirement on the Beacon Address is part of the custody design, not an operational afterthought. The protocol gives you the primitives: multiple authorized keys, separated verification relationships, and an update mechanism that lets you remove a key you no longer trust. It does not give you thresholds, approval workflows, or a hardware signing ecosystem that has caught up with BIP340 for non-transaction payloads.
Design around what exists. Assume the tooling improves, and keep the seams where you would want them to.
Next week: revocation. Issuing credentials is the easy half, and the mechanism for un-issuing them has privacy properties that are worth understanding before you pick one.