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

@brivora/crypto

v0.1.0

Published

Post-quantum cryptography in 3 lines of TypeScript. The Stripe for PQC.

Readme

@brivora/crypto

Post-quantum cryptography in 3 lines of TypeScript.

License: AGPL v3 Node.js


import { crypto } from '@brivora/crypto';
const keys = await crypto.createIdentity();
const signed = await crypto.sign(data, keys.privateKey);

What is this?

@brivora/crypto is an opinionated, batteries-included post-quantum cryptography library for JavaScript/TypeScript. The "Stripe for PQC."

  • Hybrid by default — Classical (Ed25519 + X25519) + Post-Quantum (ML-DSA-65 + ML-KEM-768). Both must be broken to compromise security.
  • NIST FIPS compliant — ML-KEM-768 (FIPS 203), ML-DSA-65 (FIPS 204), finalized August 2024.
  • Self-describing payloads — Every encrypted/signed payload includes version and algorithm metadata.
  • Zero configuration — Sensible defaults. No crypto PhD required.
  • Pure TypeScript — No native modules. No WASM. Works everywhere: Node.js, Deno, Bun, browsers.
  • Zero telemetry — No analytics. No network calls. Pure local computation.

Install

npm install @brivora/crypto
# or
pnpm add @brivora/crypto
# or
yarn add @brivora/crypto

Quick Start

Create an Identity

import { crypto } from '@brivora/crypto';

const identity = await crypto.createIdentity();
// {
//   publicKey: { classical: { signing, encryption }, pqc: { signing, encryption } },
//   privateKey: { classical: { signing, encryption }, pqc: { signing, encryption } },
//   fingerprint: 'a1b2c3d4...',
//   algorithm: 'hybrid-pqc-v1',
//   createdAt: '2026-02-13T...'
// }

Encrypt & Decrypt

// Alice encrypts a message for Bob
const encrypted = await crypto.encrypt('secret message', bob.publicKey);

// Bob decrypts
const plaintext = await crypto.decrypt(encrypted, bob.privateKey);
// Uint8Array → use new TextDecoder().decode(plaintext) for strings

Sign & Verify

// Sign data
const signed = await crypto.sign('important data', alice.privateKey);

// Verify signature
const { valid, data } = await crypto.verify(signed, alice.publicKey);
// valid: true, data: Uint8Array of original data

Key Rotation

const { newIdentity, migration } = await crypto.rotateKeys(oldIdentity);
// migration is a signed proof linking old key → new key

Key Derivation

const masterKey = crypto.randomBytes(32);
const encKey = crypto.deriveKey(masterKey, 'encryption');
const authKey = crypto.deriveKey(masterKey, 'authentication');
// Different contexts → different deterministic keys

Migrate from Ed25519

const upgraded = await crypto.upgradeKey({
  publicKey: existingEd25519PublicKey,
  secretKey: existingEd25519SecretKey,
});
// upgraded.identity is now a hybrid PQC identity
// upgraded.migration is a signed proof of the upgrade

PQC-Only Mode

// Disable classical crypto (PQC-only)
const encrypted = await crypto.encrypt(data, pubKey, { hybrid: false });
const signed = await crypto.sign(data, privKey, { hybrid: false });

API Reference

Identity

| Method | Description | |--------|-------------| | crypto.createIdentity(options?) | Create a new hybrid identity | | crypto.exportKey(identity, format?) | Serialize identity for storage | | crypto.importKey(serialized) | Restore identity from serialized form | | crypto.exportPublicKey(identity) | Export only the public key (safe to share) | | crypto.importPublicKey(encoded) | Import a shared public key |

Encryption

| Method | Description | |--------|-------------| | crypto.encrypt(data, recipientPublicKey, options?) | Hybrid encrypt (X25519 + ML-KEM-768 + AES-256-GCM) | | crypto.decrypt(encrypted, privateKey) | Decrypt with your private key |

Signatures

| Method | Description | |--------|-------------| | crypto.sign(data, privateKey, options?) | Hybrid sign (Ed25519 + ML-DSA-65) | | crypto.verify(signed, publicKey?) | Verify a signed payload |

Key Management

| Method | Description | |--------|-------------| | crypto.rotateKeys(oldIdentity, newIdentity?) | Rotate keys with migration proof | | crypto.deriveKey(masterKey, context, length?) | HKDF-SHA256 key derivation |

Migration

| Method | Description | |--------|-------------| | crypto.upgradeKey(ed25519KeyPair) | Upgrade Ed25519 → hybrid PQC |

Utilities

| Method | Description | |--------|-------------| | crypto.hash(data, algorithm?) | SHA-256 (default), SHA-384/512, SHA3-256/512 | | crypto.randomBytes(length) | CSPRNG random bytes | | crypto.fingerprint(...keys) | SHA-256 fingerprint of public keys |

Algorithms

| Algorithm | Standard | Usage | |-----------|----------|-------| | ML-KEM-768 | FIPS 203 | Key encapsulation (encryption) | | ML-DSA-65 | FIPS 204 | Digital signatures | | X25519 | RFC 7748 | Classical key exchange (hybrid) | | Ed25519 | RFC 8032 | Classical signatures (hybrid) | | AES-256-GCM | FIPS 197 | Symmetric encryption | | HKDF-SHA256 | RFC 5869 | Key derivation | | SHA-256 | FIPS 180-4 | Hashing, fingerprinting |

How Hybrid Mode Works

Encryption (X25519 + ML-KEM-768)

  1. Generate ephemeral X25519 key pair
  2. Compute classical shared secret via X25519 ECDH
  3. Encapsulate PQC shared secret via ML-KEM-768
  4. Combine both secrets via HKDF-SHA256
  5. Encrypt plaintext with AES-256-GCM

An attacker must break both X25519 and ML-KEM-768 to recover the plaintext.

Signing (Ed25519 + ML-DSA-65)

  1. Sign data with Ed25519
  2. Sign data with ML-DSA-65
  3. Both signatures must verify for the payload to be valid

An attacker must forge both an Ed25519 and ML-DSA-65 signature.

Tree Shaking

Import only what you need:

// Only signing — no encryption code in your bundle
import { sign, verify, createIdentity } from '@brivora/crypto';

Security

  • Constant-time comparisons — All byte comparisons use constant-time algorithms to prevent timing side-channels.
  • CSPRNG — All random bytes from crypto.getRandomValues() (OS-level CSPRNG).
  • No network calls — Everything runs locally. Zero telemetry. Zero analytics.
  • Audited primitives — Built on @noble/post-quantum (audited by Cure53).

See SECURITY.md for our security policy and responsible disclosure process.

Requirements

  • Node.js 20+ (also works in Deno, Bun, and modern browsers)
  • Web Crypto API (globalThis.crypto.subtle)

Built On

License

AGPL-3.0-or-laterBrivora, LLC