Introduction
Every DID method needs a way to sign and verify data: DID document updates, Verifiable Credentials, authentication challenges. The W3C-recommended Data Integrity cryptosuites cover Ed25519 and ECDSA over NIST P-256/P-384, neither of which is what Bitcoin signs with. For a Bitcoin-native DID method, that lineup is a missed opportunity. btcr2 uses BIP-340 Schnorr signatures, the scheme Bitcoin uses for Taproot (BIP-341) outputs, and packages them as a W3C Data Integrity cryptosuite: bip340-jcs-2025.
Why a Custom Cryptosuite?
W3C VC Data Integrity is one of two W3C-track frameworks for attaching cryptographic proofs to credentials (the other being VC-JOSE-COSE, which envelopes credentials with JWS for JSON or COSE for CBOR rather than embedding a proof). Data Integrity defines how proofs are structured, how documents are canonicalized, and how verification works, but it's algorithm-agnostic. You need a cryptosuite that specifies the concrete signature scheme.
Existing cryptosuites cover:
eddsa-jcs-2022: Ed25519 (W3C Recommendation, May 2025)ecdsa-jcs-2019: ECDSA scoped to NIST P-256 / P-384 only; the W3C Recommendation explicitly notes secp256k1 "is not used by this specification"EcdsaSecp256k1Signature2019: an older CCG draft that does cover secp256k1, but uses ECDSA, not Schnorr, and isn't on the Recommendation track
Nothing in the existing W3C lineup uses BIP-340 Schnorr. btcr2 needed a cryptosuite that:
- Uses the exact same signature algorithm as Bitcoin Taproot
- Signs with BIP-340's 32-byte x-only public keys (the form Bitcoin uses for Taproot)
- Embeds verification keys in DID documents via the W3C Multikey format
- Composes with MuSig2 (BIP-327) for multi-party signatures
So one was built.
How bip340-jcs-2025 Works
Document Canonicalization
Before signing, the document must be serialized deterministically. Two logically identical JSON objects might have different byte representations (key ordering, whitespace). The bip340-jcs-2025 variant uses JSON Canonicalization Scheme (JCS, RFC 8785) to produce a canonical byte sequence; a companion bip340-rdfc-2025 variant uses RDF Dataset Canonicalization for JSON-LD-heavy stacks.
JCS is the focus of this post because:
- It works on plain JSON: no JSON-LD context resolution required
- It's simpler to implement and audit
- It doesn't introduce external dependencies on context documents
Hashing
The cryptosuite follows the W3C Data Integrity hashing pattern up to the concatenation step: SHA-256 the canonicalized document; SHA-256 the canonicalized proof configuration (the proof options minus proofValue); concatenate the two 32-byte digests. Where eddsa-jcs-2022 and ecdsa-jcs-2019 sign that 64-byte concatenation directly, bip340-jcs-2025 applies one more SHA-256 to reduce it to a single 32-byte digest. Earlier revisions of BIP-340 required exactly 32-byte messages, and although that restriction has since been lifted, the cryptosuite still pre-hashes to a fixed 32-byte value before signing. The final 32-byte hash is what gets signed. (This is not the same as Bitcoin's double-SHA-256 used for transaction hashing: it's three independent single-round SHA-256 calls, not SHA-256(SHA-256(x)) over the same input.)
Signing
The 32-byte hash is signed using BIP-340 Schnorr:
- The signing key is a standard secp256k1 private key (32 bytes)
- The corresponding public key, in BIP-340's algorithm form, is 32 bytes: the x-coordinate alone, with implicit even y (see the Multikey section below for how that key is published in DID documents, where the wire format is the 33-byte SEC-compressed form)
- The signature is 64 bytes per BIP-340: 32 bytes encoding the x-coordinate of the nonce point
R, followed by the 32-byte scalars - BIP-340 recommends an auxiliary 32-byte random input at signing time as protection against fault-injection and side-channel attacks; if randomness is unavailable, the spec permits constants or counters in its place: the security of the signature itself does not depend on the auxiliary value
Proof Structure
The resulting proof follows W3C Data Integrity conventions. For a btcr2 DID update, the proof object looks like:
{
"type": "DataIntegrityProof",
"cryptosuite": "bip340-jcs-2025",
"verificationMethod": "did:btcr2:k1...#key-0",
"proofPurpose": "capabilityInvocation",
"capability": "urn:zcap:root:did%3Abtcr2%3Ak1...",
"capabilityAction": "Write",
"proofValue": "z..."
}
The required fields here (type, cryptosuite, verificationMethod, proofPurpose, and proofValue) are inherited from W3C VC Data Integrity, not added by the cryptosuite. The bip340-jcs-2025 spec's job is to define the encoding of those values (notably: the proofValue is the 64-byte BIP-340 signature, base58-btc multibase-encoded, hence the leading z). The capability and capabilityAction fields aren't part of the cryptosuite at all; they're added on top by btcr2's update algorithm, which layers ZCAP-LD authorization onto the proof. Together they mean the proof doesn't just demonstrate that a key signed the document; it demonstrates that the key was authorized to perform the specific action (Write, in this case) against a specific target capability URN.
Key Representation: Multikey
BIP-340 signs and verifies with 32-byte x-only public keys, a departure from the 33-byte SEC-compressed form typical of secp256k1 ECDSA. The cryptosuite still publishes verification keys via the standard W3C Multikey format, with one practical wrinkle worth knowing about: the spec mandates the 0xe701 multicodec prefix (the varint encoding of 0xe7, the in-use secp256k1-pub codec) followed by the 33-byte SEC-compressed key, then multibase base58-btc encoded with a leading z. The multicodec table also lists a bip340-pub codec (0x1340) for native 32-byte x-only keys, but bip340-jcs-2025 instead reuses the compressed-key codec, letting the same Multikey carry material usable by both BIP-340 Schnorr and traditional secp256k1 ECDSA tooling. Implementations recover the 32-byte x-coordinate from the 33-byte form for the BIP-340 algorithm, handling y-parity per the BIP-340 specification.
The Multikey can be embedded in DID documents as a verificationMethod, referenced from Verifiable Credential proofs, and resolved during verification.
A practical implementation note: the same secp256k1 private-key bytes can drive both BIP-340 Schnorr signing and traditional secp256k1 ECDSA: the curve is the same, and the Multikey form (33-byte compressed) round-trips across both schemes. There's a subtlety worth knowing about, though: BIP-340 normalizes its keys to even y-parity, so if a key derives a public point with odd y, the BIP-340 signing primitive itself negates the secret scalar to produce the canonical even-y form, so callers never do it manually (the reference code calls the @noble/curves Schnorr implementation, which handles this). In the reference implementation the dual-scheme signing lives in @did-btcr2/keypair, whose Signer accepts an ecdsa, bip340, or bip341 scheme, while @did-btcr2/cryptosuite wraps a key as a SchnorrMultikey that produces BIP-340 Schnorr signatures only. The shared curve underneath is what makes interoperating with systems that haven't adopted Schnorr practical.
Verification Flow
- Extract the proof from the document
- Resolve the
verificationMethodDID to obtain the public key (Multikey) - (For a btcr2 update) verify the ZCAP-LD capability invocation: the
capabilityURN points at a root capability whosecontrollershould authorize thisverificationMethodfor the declaredcapabilityAction - Reconstruct the canonical document and the canonical proof configuration via JCS
- Apply the same hash construction as signing (SHA-256 each, concatenate, SHA-256 the concatenation)
- Verify the 64-byte BIP-340 Schnorr signature in
proofValueagainst the resolved public key over that 32-byte hash
If any step fails, the proof is invalid. The verification is fully deterministic: any implementation that follows the spec will reach the same conclusion.
Standardization Status
The cryptosuite is published as a public draft at dcdpr.github.io/data-integrity-schnorr-secp256k1, with an accompanying test-vector suite and reference implementations. As of this writing, work continues in the open under the W3C Credentials Community Group's public-credentials mailing list; track the W3C CCG work-items page for formal adoption status.
The point of taking it through this process is so BIP-340 Schnorr signatures aren't locked into btcr2: any DID method or credential issuer can use this cryptosuite to align their cryptography with Bitcoin's.
Conclusion
The bip340-jcs-2025 cryptosuite brings Bitcoin's signature scheme into the W3C verifiable data ecosystem. By using the same algorithm that secures Bitcoin transactions, btcr2 avoids introducing a parallel cryptographic system with its own assumptions and attack surface. One curve, one signature scheme, one security model: from Bitcoin transactions to DID updates to Verifiable Credentials.
