@sovereignbase/cryptosuite
    Preparing search index...

    @sovereignbase/cryptosuite

    npm version JSR CI codecov license

    cryptosuite

    JS/TS runtime-agnostic, quantum-safe, and agile cryptography toolkit with a declarative API for cipher messaging, message authentication, digital signatures, and key agreement.

    • Runtimes: Tested on browsers, Bun, Cloudflare Workers, Deno, Edge Runtime, and Node.js.
    • Module format: ESM or CJS
    • Required globals / APIs: crypto, crypto.subtle, crypto.getRandomValues
    • Types: bundled .d.ts
    • Runtime-agnostic across modern JavaScript and TypeScript environments
    • Post-quantum by default
    • Crypto-agile, with room to add or replace algorithms as recommendations evolve while keeping already issued keys backwards compatible
    • Declarative API surface that expresses cryptographic intent clearly
    • Cipher messaging: AES-GCM-256
    • Message authentication: HMAC-SHA-256
    • Key agreement: X25519-ML-KEM-768
    • Digital signatures: Ed25519-ML-DSA-65
    npm install @sovereignbase/cryptosuite
    # or
    pnpm add @sovereignbase/cryptosuite
    # or
    yarn add @sovereignbase/cryptosuite
    # or
    bun add @sovereignbase/cryptosuite
    # or
    deno add jsr:@sovereignbase/cryptosuite
    # or
    vlt install jsr:@sovereignbase/cryptosuite
    import { Cryptographic } from '@sovereignbase/cryptosuite'
    import { Bytes } from '@sovereignbase/bytecodec'

    const messageBytes = Bytes.fromString('hello world') // Uint8Array

    const cipherKey = await Cryptographic.cipherMessage.generateKey() // JsonWebKey

    const sourceKeyMaterial = Bytes.fromString('deterministic key source') // Uint8Array
    const salt = Bytes.fromString('deterministic salt source') // Uint8Array
    const cipherKey = await Cryptographic.cipherMessage.deriveKey(
    sourceKeyMaterial,
    salt
    ) // JsonWebKey

    const cipherMessage = await Cryptographic.cipherMessage.encrypt(
    cipherKey,
    messageBytes
    ) // {ciphertext: Uint8Array, iv: Uint8Array}
    const roundtrip = await Cryptographic.cipherMessage.decrypt(
    cipherKey,
    cipherMessage
    ) // Uint8Array

    const plainMessage = Bytes.toString(roundtrip) // 'hello world'
    import { Cryptographic } from '@sovereignbase/cryptosuite'
    import { Bytes } from '@sovereignbase/bytecodec'

    const messageBytes = Bytes.fromString('authenticated payload') // Uint8Array

    const generatedMessageAuthenticationKey =
    await Cryptographic.messageAuthentication.generateKey() // JsonWebKey

    const sourceKeyMaterial = Bytes.fromString('deterministic key source') // Uint8Array
    const salt = Bytes.fromString('deterministic salt source') // Uint8Array

    const messageAuthenticationKey =
    await Cryptographic.messageAuthentication.deriveKey(sourceKeyMaterial, salt) // JsonWebKey

    const tag = await Cryptographic.messageAuthentication.sign(
    generatedMessageAuthenticationKey,
    messageBytes
    ) // Uint8Array

    const verified = await Cryptographic.messageAuthentication.verify(
    generatedMessageAuthenticationKey,
    messageBytes,
    tag
    ) // boolean
    import { Cryptographic } from '@sovereignbase/cryptosuite'
    import { Bytes } from '@sovereignbase/bytecodec'

    const sourceKeyMaterial = Bytes.fromString('k'.repeat(32)) // Uint8Array, exactly 32 bytes

    const { encapsulateKey, decapsulateKey } =
    await Cryptographic.keyAgreement.generateKeypair() // {encapsulateKey: JsonWebKey, decapsulateKey: JsonWebKey}

    const deterministicKeypair =
    await Cryptographic.keyAgreement.deriveKeypair(sourceKeyMaterial) // {encapsulateKey: JsonWebKey, decapsulateKey: JsonWebKey}

    const { keyOffer, cipherKey: senderCipherKey } =
    await Cryptographic.keyAgreement.encapsulate(encapsulateKey) // {keyOffer: {ciphertext: Uint8Array}, cipherKey: JsonWebKey}

    const { cipherKey: receiverCipherKey } =
    await Cryptographic.keyAgreement.decapsulate(keyOffer, decapsulateKey) // {cipherKey: JsonWebKey}
    import { Cryptographic } from '@sovereignbase/cryptosuite'
    import { Bytes } from '@sovereignbase/bytecodec'

    const sourceKeyMaterial = Bytes.fromString('s'.repeat(64)) // Uint8Array, exactly 64 bytes
    const bytes = Bytes.fromString('signed payload') // Uint8Array
    const { signKey, verifyKey } =
    await Cryptographic.digitalSignature.generateKeypair() // {signKey: JsonWebKey, verifyKey: JsonWebKey}

    const deterministicKeypair =
    await Cryptographic.digitalSignature.deriveKeypair(sourceKeyMaterial) // {signKey: JsonWebKey, verifyKey: JsonWebKey}

    const signature = await Cryptographic.digitalSignature.sign(signKey, bytes) // Uint8Array
    const verified = await Cryptographic.digitalSignature.verify(
    verifyKey,
    bytes,
    signature
    ) // boolean
    • symmetric operations use WebCrypto
    • symmetric key derivation accepts an optional salt and always uses a key-type-specific HKDF info value for domain separation
    • key agreement and digital signatures use noble hybrid primitives
    • all byte inputs and outputs are normalized to Uint8Array
    • unsupported crypto primitives throw typed CryptosuiteError codes
    • AES-GCM provides confidentiality and message integrity for each ciphertext
    • authenticate peers and session setup at the protocol layer
    • never reuse a (key, iv) pair
    • treat JWKs and derived key material as secrets
    • sign a canonical byte representation, not loosely structured objects

    Latest local npm run test run on 2026-08-29 with Node v24.16.0 (win32 x64):

    • 63/63 unit and integration tests passed
    • Coverage passed at 100% for statements, branches, functions, and lines
    • End-to-end runtime suites all passed in:
      • Node ESM
      • Node CJS
      • Bun ESM
      • Bun CJS
      • Deno ESM
      • Edge Runtime ESM
      • Cloudflare Workers ESM
      • Chromium
      • Firefox
      • WebKit
      • Mobile Chromium emulation
      • Mobile Firefox emulation
      • Mobile WebKit emulation
    • The runtime suite currently exercises 17/17 public API scenarios per runtime:
      • 1 static wiring check
      • 16 public methods

    Latest local npm run bench run on 2026-08-29 with Node v24.16.0 (win32 x64).

    Benchmark ops ms ms/op ops/sec
    cipherMessage.generateKey 100 17.36 0.1736 5759.77
    cipherMessage.deriveKey 100 41.96 0.4196 2383.23
    cipherMessage.encrypt 100 18.99 0.1899 5264.71
    cipherMessage.decrypt 100 18.93 0.1893 5282.15
    messageAuthentication.generateKey 100 18.20 0.1820 5494.17
    messageAuthentication.deriveKey 100 38.44 0.3844 2601.46
    messageAuthentication.sign 100 8.57 0.0857 11672.70
    messageAuthentication.verify 100 7.58 0.0758 13199.93
    keyAgreement.generateKeypair 100 312.30 3.1230 320.20
    keyAgreement.deriveKeypair 100 244.60 2.4460 408.84
    keyAgreement.encapsulate 100 990.29 9.9029 100.98
    keyAgreement.decapsulate 100 803.80 8.0380 124.41
    digitalSignature.generateKeypair 100 500.13 5.0013 199.95
    digitalSignature.deriveKeypair 100 384.87 3.8487 259.83
    digitalSignature.sign 100 1922.69 19.2269 52.01
    digitalSignature.verify 100 626.36 6.2636 159.65

    Results vary by machine and Node version.

    Post-quantum primitives are built on top of noble.

    Thanks to Paul Miller for an unusually clear, well-engineered, and genuinely awesome project.

    Apache-2.0