did-btcr2-js

@did-btcr2/keypair

TypeScript implementation of secp256k1 key pairs and three signing schemes used by did:btcr2.

Part of the did-btcr2-js monorepo.

Summary

This package wraps the secp256k1 primitives from @noble/curves into the key types and signing abstraction used by every higher-level package (@did-btcr2/cryptosuite, @did-btcr2/key-manager, @did-btcr2/method).

Signing schemes

Scheme Wire format Used for
'ecdsa' DER-encoded, low-S, no prehash P2PKH / P2WPKH / P2SH-P2WPKH input signatures (BIP-143 sighash)
'bip340' 64-byte raw Schnorr Data Integrity proofs over DID updates (untweaked)
'bip341' 64-byte Schnorr over taproot-tweaked key P2TR input signatures (BIP-341 key-path)

The bip341 path applies taprootTweakPrivKey(secret, merkleRoot) before signing so the produced signature verifies against the tweaked output internal key Q = P + tG.

Install

npm install @did-btcr2/keypair

Or with pnpm:

pnpm add @did-btcr2/keypair

Requires Node >= 22. Ships both ESM (dist/esm/) and CJS (dist/cjs/) with TypeScript declarations.

Key Exports

Concern Entry point
Generate a fresh keypair SchnorrKeyPair.generate()
Import from bytes / hex / JSON SchnorrKeyPair.fromSecret(), .fromJSON()
Watch-only pair (pubkey only) new SchnorrKeyPair({ publicKey })
Sign with explicit scheme LocalSigner, signWithScheme(secret, data, scheme)
Signer interface Signer, SigningScheme, SignOptions
Public key types CompressedSecp256k1PublicKey, PublicKey, Point
Secret key type Secp256k1SecretKey, SecretKey
Multibase prefix BIP340_PUBLIC_KEY_MULTIBASE_PREFIX ([0xe7, 0x01])

Quick Start

import { LocalSigner, SchnorrKeyPair, signWithScheme } from '@did-btcr2/keypair';

// Generate a fresh keypair.
const kp = SchnorrKeyPair.generate();

// Compressed pubkey + x-only pubkey + multibase form.
const compressed = kp.publicKey.compressed;          // 33 bytes
const xOnly      = kp.publicKey.xOnly;               // 32 bytes
const multibase  = kp.publicKey.multibase.encoded;   // 'zQ3s...'

// Build a Signer and sign with the appropriate scheme.
const signer = new LocalSigner(kp.secretKey.bytes);
const data   = new Uint8Array(32);

const sigEcdsa  = signer.sign(data, 'ecdsa');    // for P2PKH/P2WPKH/P2SH inputs
const sigBip340 = signer.sign(data, 'bip340');   // for DI proofs
const sigBip341 = signer.sign(data, 'bip341', { merkleRoot: new Uint8Array(0) });

Architecture Principles

Build & Test

# From packages/keypair/
pnpm build              # Compile ESM + CJS + type declarations
pnpm build:tests        # Compile tests to tests/compiled/
pnpm test               # Run the test suite with coverage
pnpm lint               # ESLint (zero warnings tolerated)

Documentation

License

MPL-2.0