npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@btc-vision/ecpair

v4.0.5

Published

Universal Bitcoin signer library with branded types and pluggable CryptoBackend

Readme

@btc-vision/ecpair

Bitcoin TypeScript NodeJS NPM

code style: prettier

Overview

Universal Bitcoin signer library with branded types and a pluggable CryptoBackend. Written in TypeScript with zero CommonJS. Ships with a pure-JS backend (@noble/curves) and a legacy adapter for tiny-secp256k1.

What is ecpair?

@btc-vision/ecpair provides secp256k1 key management, ECDSA signing, BIP-340 Schnorr signing, Taproot-style key tweaking, and WIF import/export. It is designed for use with @btc-vision/bitcoin and the broader OPNet ecosystem, but works with any Bitcoin library that consumes standard key types.

Why branded types?

PrivateKey, PublicKey, XOnlyPublicKey, Signature, and other key types are nominal (branded) Uint8Array subtypes. This prevents accidentally passing a raw hash where a private key is expected, or mixing up compressed and x-only public keys. Mistakes are caught at compile time, not at runtime in production.

Why pluggable backends?

CryptoBackend is an interface. The library ships two implementations:

  • NobleBackend: pure JavaScript via @noble/curves/secp256k1, zero native dependencies
  • LegacyBackend: adapter for existing tiny-secp256k1 installations (WASM or ASM.js)

Swap backends without changing application code.

No hardcoded networks

The library does not ship Bitcoin, testnet, or regtest constants. Consumers must provide a Network object to every factory method. This keeps the library network-agnostic and avoids accidental mainnet usage in test environments.

Installation

npm install @btc-vision/ecpair

Requires Node.js >= 24.0.0. The package is ESM-only ("type": "module").

Quick Start

import {
  ECPairSigner,
  createNobleBackend,
  createPrivateKey,
  createMessageHash,
  verifyCryptoBackend,
} from '@btc-vision/ecpair';
import type { Network } from '@btc-vision/ecpair';

// Define your network
const bitcoin: Network = {
  messagePrefix: '\x18Bitcoin Signed Message:\n',
  bech32: 'bc',
  bech32Opnet: 'op',
  bip32: { public: 0x0488b21e, private: 0x0488ade4 },
  pubKeyHash: 0x00,
  scriptHash: 0x05,
  wif: 0x80,
};

// Create backend and verify integrity
const backend = createNobleBackend();
verifyCryptoBackend(backend);

// Generate a random signer (FIPS 186-5 B.4.2 key generation)
const signer = ECPairSigner.makeRandom(backend, bitcoin);
console.log(signer.toWIF());

// Sign and verify
const hash = createMessageHash(new Uint8Array(32));
const sig = signer.sign(hash);
console.log(signer.verify(hash, sig)); // true

// Schnorr (BIP-340)
const schnorrSig = signer.signSchnorr(hash);
console.log(signer.verifySchnorr(hash, schnorrSig)); // true

API Comparison

| Old API (v3) | New API (v4) | |-------------------------------------|-----------------------------------------------------------------| | ECPairFactory(tinysecp) | createNobleBackend() or createLegacyBackend(tinysecp) | | ECPair.makeRandom() | ECPairSigner.makeRandom(backend, network) | | ECPair.fromPrivateKey(buf, opts) | ECPairSigner.fromPrivateKey(backend, privateKey, network) | | ECPair.fromPublicKey(buf, opts) | ECPairSigner.fromPublicKey(backend, publicKey, network) | | ECPair.fromWIF(str, network) | ECPairSigner.fromWIF(backend, str, network) | | keyPair.network (optional) | signer.network (always set, required parameter) | | { network } in options | Separate network parameter on every factory method | | Set<SignerCapability> | number bitmask of SignerCapability flags |

Usage

Import from WIF

const signer = ECPairSigner.fromWIF(backend, 'KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn', bitcoin);
console.log(signer.compressed); // true
console.log(signer.toWIF());

From raw private key

const signer = ECPairSigner.fromPrivateKey(
  backend,
  createPrivateKey(new Uint8Array(32).fill(1)),
  bitcoin,
);

Public-key-only signer (verify only, cannot sign)

import { createPublicKey } from '@btc-vision/ecpair';

const pubOnly = ECPairSigner.fromPublicKey(backend, createPublicKey(pubKeyBytes), bitcoin);
console.log(pubOnly.privateKey); // undefined
console.log(pubOnly.verify(hash, sig)); // true

Taproot-style tweaking

import type { Bytes32 } from '@btc-vision/ecpair';

const tweakScalar = new Uint8Array(32).fill(2) as Bytes32;
const tweaked = signer.tweak(tweakScalar);
console.log(tweaked.toWIF());

Legacy backend (tiny-secp256k1)

import { createLegacyBackend } from '@btc-vision/ecpair';
import type { TinySecp256k1Interface } from '@btc-vision/ecpair';
import * as tinysecp from 'tiny-secp256k1';

const legacy = createLegacyBackend(tinysecp as unknown as TinySecp256k1Interface);
const kp = ECPairSigner.makeRandom(legacy, bitcoin);

Custom RNG

import { randomBytes } from 'node:crypto';

const kp = ECPairSigner.makeRandom(backend, bitcoin, {
  rng: (size: number) => new Uint8Array(randomBytes(size).buffer),
});

The rng function receives 48 bytes (FIPS 186-5 seed length) and must return exactly size bytes.

Multiple networks

const testnet: Network = {
  messagePrefix: '\x18Bitcoin Signed Message:\n',
  bech32: 'tb',
  bech32Opnet: 'opt',
  bip32: { public: 0x043587cf, private: 0x04358394 },
  pubKeyHash: 0x6f,
  scriptHash: 0xc4,
  wif: 0xef,
};

// fromWIF accepts an array of candidate networks
const kp = ECPairSigner.fromWIF(backend, wifString, [bitcoin, testnet]);
console.log(kp.network === bitcoin); // true if mainnet WIF

Capabilities

import { SignerCapability } from '@btc-vision/ecpair';

const kp = ECPairSigner.makeRandom(backend, bitcoin);

if (kp.capabilities & SignerCapability.SchnorrSign) {
  console.log('Schnorr signing available');
}

// Or use the convenience method
kp.hasCapability(SignerCapability.EcdsaSign);      // true
kp.hasCapability(SignerCapability.PrivateKeyExport); // true

WIF encode/decode (standalone)

import { encodeWIF, decodeWIF, createPrivateKey } from '@btc-vision/ecpair';

const wif = encodeWIF(createPrivateKey(keyBytes), true, bitcoin);
const decoded = decodeWIF(wif, bitcoin);
// decoded.privateKey, decoded.compressed, decoded.network

Documentation

Visit our API documentation generated by TypeDoc.

Running Tests

npm test
npm run lint
npm run lint:tests
npm run format:ci

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: npm test
  5. Submit a pull request

See CONTRIBUTING.md for details.

Reporting Issues

  • Bugs: Open an issue
  • Security: See SECURITY.md - do not open public issues for vulnerabilities

License

MIT

Links