ciphersuite - xero/leviathan-crypto GitHub Wiki

CipherSuite

The extension point for the streaming AEAD layer. Seal, SealStream, OpenStream, and SealStreamPool are all cipher-agnostic. You provide the cipher by passing a CipherSuite object at construction.


Three implementations are included: SerpentCipher, XChaCha20Cipher, and KyberSuite. The first two are symmetric cipher suites. KyberSuite wraps either of them with an ML-KEM layer for hybrid post-quantum encryption.


Symmetric implementations

SerpentCipher XChaCha20Cipher
Cipher Serpent-256 CBC + HMAC-SHA-256 XChaCha20-Poly1305
formatEnum 0x02 0x01
hkdfInfo serpent-sealstream-v2 xchacha20-sealstream-v2
keySize 32 bytes 32 bytes
tagSize 32 bytes 16 bytes
padded true (PKCS7) false
wasmChunkSize 65552 65536
wasmModules ['serpent', 'sha2'] ['chacha20', 'sha2']
Auth construction Encrypt-then-MAC AEAD

SerpentCipher

import { init, SerpentCipher } from 'leviathan-crypto'
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
import { sha2Wasm }    from 'leviathan-crypto/sha2/embedded'

await init({ serpent: serpentWasm, sha2: sha2Wasm })

const key = SerpentCipher.keygen()  // 32 bytes

SerpentCipher uses Encrypt-then-MAC: Serpent-256-CBC for encryption and HMAC-SHA-256 for authentication. HKDF-SHA-256 derives three keys from the master key and stream nonce: an encryption key, a MAC key, and an IV key. The CBC IV is derived deterministically per chunk and never transmitted.

See serpent.md for the full Serpent-256 primitive reference.

XChaCha20Cipher

import { init, XChaCha20Cipher } from 'leviathan-crypto'
import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
import { sha2Wasm }     from 'leviathan-crypto/sha2/embedded'

await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })

const key = XChaCha20Cipher.keygen()  // 32 bytes

XChaCha20Cipher uses XChaCha20-Poly1305 AEAD per chunk. HKDF-SHA-256 derives a stream key, then HChaCha20 derives a per-chunk subkey. The intermediate stream key is wiped immediately after derivation.

See chacha20.md for the full ChaCha20 primitive reference.


KyberSuite

KyberSuite is a factory that wraps a MlKemBase instance and an inner CipherSuite into a hybrid KEM+AEAD suite. The result satisfies the CipherSuite interface and plugs into Seal, SealStream, OpenStream, and SealStreamPool identically to the symmetric suites.

import { KyberSuite, MlKem768 } from 'leviathan-crypto/kyber'
import { XChaCha20Cipher }      from 'leviathan-crypto/chacha20'

const suite = KyberSuite(new MlKem768(), XChaCha20Cipher)
const { encapsulationKey: ek, decapsulationKey: dk } = suite.keygen()

On encrypt, ML-KEM encapsulates a fresh shared secret. HKDF binds the KEM ciphertext into key derivation. On decrypt, the KEM ciphertext is recovered from the preamble and decapsulated. The inner cipher runs on the derived key material. Neither party ever transmits the shared secret.

formatEnum encodes both the KEM parameter set and inner cipher in a single byte. This allows OpenStream to infer the full suite from the preamble alone.

Suite formatEnum Preamble size
MlKem512 + XChaCha20Cipher 0x11 788 bytes
MlKem512 + SerpentCipher 0x12 788 bytes
MlKem768 + XChaCha20Cipher 0x21 1108 bytes
MlKem768 + SerpentCipher 0x22 1108 bytes
MlKem1024 + XChaCha20Cipher 0x31 1588 bytes
MlKem1024 + SerpentCipher 0x32 1588 bytes

See kyber.md for the full ML-KEM reference and key management guidance.


Interface reference

CipherSuite is an interface, not a class. SerpentCipher and XChaCha20Cipher are plain const objects. You can implement your own by satisfying the interface.

Fields

Field Type Description
formatEnum number Wire format ID. Bits 0-3 cipher nibble (0x1=xchacha20, 0x2=serpent); bits 4-5 KEM selector (0x00=none, 0x10=ML-KEM-512, 0x20=ML-KEM-768, 0x30=ML-KEM-1024); bit 6 reserved; max 0x3f.
formatName string Human-readable label, e.g. 'xchacha20', 'serpent'. Used in hybrid suite names ('mlkem768+xchacha20').
hkdfInfo string HKDF info string for domain separation between cipher suites.
keySize number Required master key length in bytes. For KEM suites this is the encapsulation key (ek) size.
decKeySize? number | undefined Decryption key size in bytes. Absent for symmetric suites (defaults to keySize). For KEM suites this is the decapsulation key (dk) size.
kemCtSize number KEM ciphertext size in bytes. 0 for symmetric suites; set to the KEM ciphertext length for hybrid suites.
tagSize number Authentication tag size in bytes per chunk.
padded boolean Whether ciphertext includes block padding. Affects pool chunk splitting.
wasmChunkSize number WASM buffer capacity for one padded chunk. Pool validates paddedFull ≤ wasmChunkSize at creation for padded ciphers. Must match the CHUNK_SIZE constant in the cipher's WASM module.
wasmModules readonly string[] WASM modules this suite requires.

Methods

Method Description
deriveKeys(masterKey, nonce, kemCt?) HKDF key derivation. kemCt is the KEM ciphertext — present only for hybrid suites, absent for symmetric. Returns opaque DerivedKeys.
sealChunk(keys, counterNonce, chunk, aad?) Encrypt one chunk. Returns ciphertext with tag appended.
openChunk(keys, counterNonce, chunk, aad?) Decrypt one chunk. Throws AuthenticationError on failure.
wipeKeys(keys) Zero all derived key material. Called after finalize().
createPoolWorker() Create a Web Worker for pool use. Default implementations spawn a classic worker from a blob URL over an IIFE source bundled at lib build time. Override via spread ({ ...XChaCha20Cipher, createPoolWorker: () => new Worker(myUrl) }) for strict-CSP environments that disallow blob: in worker-src.

Implementing a custom CipherSuite

Your formatEnum must not conflict with the built-in values (0x01, 0x02, 0x11 through 0x32). Bits 6 and 7 of header byte 0 are reserved. The hkdfInfo string must be unique to your cipher to prevent key reuse across suites. wipeKeys must zero every byte of derived key material — the stream layer calls it unconditionally after finalize.


Cross-References

Document Description
index Project Documentation index
architecture architecture overview, module relationships, buffer layouts, and build pipeline
lexicon Glossary of cryptographic terms
authenticated encryption Seal, SealStream, OpenStream, SealStreamPool
serpent Serpent-256 TypeScript API and raw primitives
chacha20 ChaCha20 TypeScript API and raw primitives
kyber ML-KEM key encapsulation and KyberSuite
types TypeScript interfaces