@brivora/crypto
Post-quantum cryptography in 3 lines of TypeScript.
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.
Installnpm install @brivora/crypto
pnpm add @brivora/crypto
yarn add @brivora/crypto Quick Start Create an Identityimport { crypto } from '@brivora/crypto' ;
const identity = await crypto. createIdentity ( ) ;
Encrypt & Decrypt
const encrypted = await crypto. encrypt ( 'secret message' , bob. publicKey) ;
const plaintext = await crypto. decrypt ( encrypted, bob. privateKey) ;
Sign & Verify
const signed = await crypto. sign ( 'important data' , alice. privateKey) ;
const { valid, data } = await crypto. verify ( signed, alice. publicKey) ;
Key Rotationconst { newIdentity, migration } = await crypto. rotateKeys ( oldIdentity) ;
Key Derivationconst masterKey = crypto. randomBytes ( 32 ) ;
const encKey = crypto. deriveKey ( masterKey, 'encryption' ) ;
const authKey = crypto. deriveKey ( masterKey, 'authentication' ) ;
Migrate from Ed25519const upgraded = await crypto. upgradeKey ( {
publicKey: existingEd25519PublicKey,
secretKey: existingEd25519SecretKey,
} ) ;
PQC-Only Mode
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)
Generate ephemeral X25519 key pair
Compute classical shared secret via X25519 ECDH
Encapsulate PQC shared secret via ML-KEM-768
Combine both secrets via HKDF-SHA256
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)
Sign data with Ed25519
Sign data with ML-DSA-65
Both signatures must verify for the payload to be valid
An attacker must forge both an Ed25519 and ML-DSA-65 signature.
Tree ShakingImport only what you need:
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
LicenseAGPL-3.0-or-later — Brivora, LLC