32 KiB
@suaveplan/crypto - Universal cryptographic primitives — AEAD (AES-256-GCM, ChaCha20-Poly1305, XChaCha20-Poly1305), Ed25519 / X25519 / ECDSA-P256, sealed-box, auth-box, constant-time compare, zeroize. Engine-pluggable via noble defaults.
Summary
Universal cryptographic primitives — engine-pluggable AEAD, Ed25519/ECDSA-P256 signing, X25519 key agreement, sealed-box, and auth-box. Built on audited @noble/* libraries with zero WASM.
Documentation tree
- streaming-aead —
streaming-aead.tsis the high-level streaming AEAD façade in@suaveplan/crypto. It accepts analgorithmstring (`… - web-streams —
web-streams.tsadapts the async-generator streaming AEAD entry points (encryptStreamAead/decryptStreamAead) int… - authority — (no submodules)
- authority — (no submodules)
- chain-bundle — (no submodules)
- chain-bundle — (no submodules)
- public-bundle — (no submodules)
- public-bundle — (no submodules)
- coordinate — (no submodules)
- coordinate — (no submodules)
- layouts — (no submodules)
- layouts — (no submodules)
- purposes — (no submodules)
- purposes — (no submodules)
- domain-tags — (no submodules)
- domain-tags — (no submodules)
- codes — (no submodules)
- codes — (no submodules)
- crypto-error — (no submodules)
- crypto-error — (no submodules)
- codes — (no submodules)
- codes — (no submodules)
- crypto-keys-error — (no submodules)
- crypto-keys-error — (no submodules)
- codes — (no submodules)
- codes — (no submodules)
- crypto-vault-error — (no submodules)
- crypto-vault-error — (no submodules)
- keychain — (no submodules) - algorithms — _(no submodule…
- algorithms — (no submodules)
- algorithms — (no submodules)
- key-slot — (no submodules)
- key-slot — (no submodules)
- generate — (no submodules)
- generate — (no submodules)
- validate — (no submodules)
- validate — (no submodules)
- memory — (no submodules)
- memory — (no submodules)
- serialized — (no submodules)
- serialized — (no submodules)
- validity — (no submodules)
- validity — (no submodules)
- keychain — (no submodules) - algorithms — _(no submodule…
- algorithms — (no submodules)
- derive-key-from-password —
derive-key-from-password.tsis the low-level password-to-key derivation helper in@suaveplan/crypto. It accepts a p… - encrypt-with-password —
encrypt-with-password.tsis the high-level password-based encryption helper in@suaveplan/crypto. It accepts a pass… - trust-anchors — (no submodules)
- trust-anchor — (no submodules)
- mnemonic — (no submodules)
- mnemonic — (no submodules)
- encrypt-with-password —
encrypt-with-password.tsis the high-level password-based encryption helper in@suaveplan/crypto. It accepts a pass… - trust-anchors — (no submodules)- trust-anchor — (no submodules)- mnemonic — (no submodules)- mnemonic — (no submodules)- authority — (no submodules)- chain-bundle — (no submodules)- chain-bundle — (no submodules)- public-bundle — (no submodules)- public-bundle — (no submodules)- coordinate — (no submodules)- coordinate — (no submodules)- layouts — (no submodules)- layouts — (no submodules)- purposes — (no submodules)- purposes — (no submodules)- domain-tags — (no submodules)- domain-tags — (no submodules)- codes — (no submodules)- codes — (no submodules)- crypto-error — (no submodules)- crypto-error — (no submodules)- codes — (no submodules)- codes — (no submodules)- crypto-keys-error — (no submodules)- crypto-keys-error — (no submodules)- codes — (no submodules)- codes — (no submodules)- crypto-vault-error — (no submodules)- crypto-vault-error — (no submodules)- keychain — (no submodules)- algorithms — <!-- begin:auto…
- algorithms — (no submodules)- algorithms — (no submodules)- key-slot — (no submodules)- key-slot — (no submodules)- generate — (no submodules)- generate — (no submodules)- validate — (no submodules)- validate — (no submodules)- memory — (no submodules)- memory — (no submodules)- serialized — (no submodules)- serialized — (no submodules)- validity — (no submodules)- validity — (no submodules)- keychain — (no submodules)- algorithms — <!-- begin:auto…
- derive-key-from-password —
derive-key-from-password.tsis the low-level password-to-key derivation helper in@suaveplan/crypto. It accepts a p… - encrypt-with-password —
encrypt-with-password.tsis the high-level password-based encryption helper in@suaveplan/crypto. It accepts a pass… - trust-anchors — (no submodules)- trust-anchor — (no submodules)- mnemonic — (no submodules)- mnemonic — (no submodules)- authority — (no submodules)- chain-bundle — (no submodules)- chain-bundle — (no submodules)- public-bundle — (no submodules)- public-bundle — (no submodules)- coordinate — (no submodules)- coordinate — (no submodules)- layouts — (no submodules)- layouts — (no submodules)- purposes — (no submodules)- purposes — (no submodules)- domain-tags — (no submodules)- domain-tags — (no submodules)- codes — (no submodules)- codes — (no submodules)- crypto-error — (no submodules)- crypto-error — (no submodules)- codes — (no submodules)- codes — (no submodules)- crypto-keys-error — (no submodules)- crypto-keys-error — (no submodules)- codes — (no submodules)- codes — (no submodules)- crypto-vault-error — (no submodules)- crypto-vault-error — (no submodules)- keychain — (no submodules)- algorithms — _(no submodul…
- algorithms — (no submodules)- algorithms — (no submodules)- key-slot — (no submodules)- key-slot — (no submodules)- generate — (no submodules)- generate — (no submodules)- validate — (no submodules)- validate — (no submodules)- memory — (no submodules)- memory — (no submodules)- serialized — (no submodules)- serialized — (no submodules)- validity — (no submodules)- validity — (no submodules)- keychain — (no submodules)- algorithms — _(no submodul…
- derive-key-from-password —
derive-key-from-password.tsis the low-level password-to-key derivation helper in@suaveplan/crypto. It accepts a p… - encrypt-with-password —
encrypt-with-password.tsis the high-level password-based encryption helper in@suaveplan/crypto. It accepts a pass… - trust-anchors — (no submodules)- trust-anchor — (no submodules)- mnemonic — (no submodules)- mnemonic — (no submodules)- authority — (no submodules)- chain-bundle — (no submodules) - chain-bundle — (no submodules)- public-bundle — (no submodules) - public-bundle — (no submodules)- coordinate — (no submodules) - coordinate — (no submodules)- layouts — (no submodules) - layouts — (no submodules)- purposes — (no submodules) - purposes — (no submodules)- domain-tags — (no submodules) - domain-tags — (no submodules)- codes — (no submodules) - codes — (no submodules)- crypto-error — (no submodules) - crypto-error — (no submodules)- codes — (no submodules) - codes — (no submodules)- crypto-keys-error — (no submodules) - crypto-keys-error — (no submodules)- codes — (no submodules) - codes — (no submodules)- crypto-vault-error — (no submodules) - crypto-vault-error — (no submodules)- keychain — (no submodules) - algorithms — (no submodules) - algorithms — (no submodules) - key-slot — (no submodules) - key-slot — (no submodules) - generate — (no submodules) - generate — (no submodules) - validate — (no submodules) - validate — (no submodules) - memory — (no submodules) - memory — (no submodules) - serialized — (no submodules) - serialized — (no submodules) - validity — (no submodules) - validity — (no submodules) - keychain — (no submodules)- derive-key-from-password —
derive-key-from-password.tsis the low-level password-to-key derivation helper in@suaveplan/crypto. It accepts a p… - encrypt-with-password —
encrypt-with-password.tsis the high-level password-based encryption helper in@suaveplan/crypto. It accepts a pass… - trust-anchors — (no submodules) - trust-anchor — (no submodules)- mnemonic — (no submodules) - mnemonic — (no submodules)
Install
bun add @suaveplan/crypto
Primitives
| Surface | What |
|---|---|
randomBytes(n, { byteSource? }) |
CSPRNG bytes (WebCrypto default; injectable for tests) |
constantTimeEqual(a, b) |
Constant-time byte comparison |
zeroize(buf) |
Fill a Uint8Array with zeros |
aeadEncrypt / aeadDecrypt |
AES-256-GCM, ChaCha20-Poly1305, XChaCha20-Poly1305 |
ed25519.{generateKeypair, sign, verify} |
Ed25519 signing |
ecdsaP256.{generateKeypair, sign, verify} |
ECDSA-P256 signing |
x25519.{generateKeypair, agree} |
X25519 ECDH key agreement |
sealedBox.{seal, open} |
Anonymous-sender sealed box (X25519 + XChaCha20-Poly1305) |
authBox.{seal, open} |
Authenticated box (X25519 + XChaCha20-Poly1305) |
Hashing (SHA-2, HMAC, HKDF, PBKDF2, Argon2id) lives in
@suaveplan/crypto-hash.
Engine interfaces
Every operation accepts an optional { engine?: <EngineType> } argument. The default engines use @noble/ciphers and @noble/curves. Swap in a WebCrypto-backed or libsodium-backed engine without changing call sites.
import type { AeadEngine } from "@suaveplan/crypto/engines";
const webCryptoEngine: AeadEngine = { /* ... */ };
aeadEncrypt("AES-256-GCM", key, plaintext, { nonce }, { engine: webCryptoEngine });
ByteSource
ByteSource = (n: number) => Uint8Array — the injected randomness type used for key generation. Replaces the old Rng alias (which conflicted with @suaveplan/types's Rng).
import { randomBytes, type ByteSource } from "@suaveplan/crypto";
// Production
const key = randomBytes(32);
// Tests — deterministic
const seeded: ByteSource = (n) => new Uint8Array(n).fill(0x42);
const kp = ed25519.generateKeypair({ byteSource: seeded });
AEAD
import { aeadEncrypt, aeadDecrypt, randomBytes } from "@suaveplan/crypto";
const key = randomBytes(32);
const nonce = randomBytes(12); // 12 for AES-GCM/ChaCha20, 24 for XChaCha20
const plaintext = new TextEncoder().encode("hello");
const ct = aeadEncrypt("AES-256-GCM", key, plaintext, { nonce });
const pt = aeadDecrypt("AES-256-GCM", key, ct, { nonce });
Signing
import { ed25519, ecdsaP256 } from "@suaveplan/crypto";
const kp = ed25519.generateKeypair();
const sig = ed25519.sign(kp.secretKey, message);
ed25519.verify(kp.publicKey, sig, message); // true
Key Agreement + Sealed Box
import { x25519, sealedBox, authBox, randomBytes } from "@suaveplan/crypto";
const alice = x25519.generateKeypair();
const bob = x25519.generateKeypair();
// Anonymous sender (sealed box)
const sealed = sealedBox.seal(bob.publicKey, plaintext);
const opened = sealedBox.open(bob.secretKey, bob.publicKey, sealed);
// Authenticated (auth box)
const nonce = randomBytes(24);
const ct = authBox.seal(alice.secretKey, bob.publicKey, plaintext, nonce);
const pt = authBox.open(alice.publicKey, bob.secretKey, ct, nonce);
Error surface
Every failure surfaces as CryptoError (extends SuaveplanError) with a stable CRYPTO.* code. Error context never includes raw key bytes, plaintext, or authentication tags.
| Code | When |
|---|---|
CRYPTO.KEY.INVALID_LENGTH |
Key is not 32 bytes |
CRYPTO.AEAD.INVALID_NONCE |
Nonce length wrong for algorithm |
CRYPTO.AEAD.DECRYPT_FAILED |
Authentication tag mismatch |
CRYPTO.SIGN.INVALID_KEY |
Key is malformed |
CRYPTO.SIGN.VERIFY_FAILED |
Signature verification failed |
CRYPTO.RNG.INVALID_LENGTH |
randomBytes(n) called with negative/non-integer n |
CRYPTO.RNG.UNAVAILABLE |
No CSPRNG available |
Subpath exports
import { randomBytes } from "@suaveplan/crypto/primitives/random-bytes";
import { constantTimeEqual } from "@suaveplan/crypto/primitives/constant-time-equal";
import { zeroize } from "@suaveplan/crypto/primitives/zeroize";
import { aeadEncrypt, aeadDecrypt } from "@suaveplan/crypto/aead";
import { ed25519, ecdsaP256 } from "@suaveplan/crypto/sign";
import { x25519 } from "@suaveplan/crypto/agree";
import { sealedBox } from "@suaveplan/crypto/sealed-box";
import { authBox } from "@suaveplan/crypto/auth-box";
import type { AeadEngine, SignEngine } from "@suaveplan/crypto/engines";
import { CryptoError, CRYPTO_CODES } from "@suaveplan/crypto/errors";
Co-located docs
src/primitives/random-bytes.mdsrc/primitives/constant-time-equal.mdsrc/primitives/zeroize.mdsrc/aead/aead.mdsrc/sign/ed25519.mdsrc/sign/ecdsa-p256.mdsrc/agree/x25519.mdsrc/sealed-box/sealed-box.mdsrc/auth-box/auth-box.md
Foundation rules
- Runtime deps:
@noble/ciphers,@noble/curves,@suaveplan/crypto-hash,@suaveplan/error,@suaveplan/types,tslib,zod sideEffects: false, per-primitive subpath exports- Zero
Math.random,Date.now, orcrypto.getRandomValuesoutsidesrc/primitives/random-bytes.ts(guarded bytests/no-disallowed.test.ts) - 100% statement / branch / function / line coverage (Layer 1/2 foundation rule)
- fast-check property tests for every primitive
Testing
bunx turbo lint typecheck test:coverage --filter=@suaveplan/crypto