baml.crypto.ChaCha20Poly1305

ChaCha20-Poly1305 (RFC 8439): authenticated encryption under a 256-bit key with a 96-bit nonce.

Reference version

Signature

class baml.crypto.ChaCha20Poly1305

ChaCha20-Poly1305 (RFC 8439): authenticated encryption under a 256-bit key with a 96-bit nonce.

A stream cipher paired with a one-time authenticator. It runs on ordinary arithmetic rather than table lookups, so it is naturally constant-time and fast in software. Prefer it over the AES ciphers on hardware without AES instructions, and where a peer or format already specifies it (TLS, SSH, WireGuard, age).

let rng = baml.random.SystemRandom.get();
let key = baml.crypto.ChaCha20Poly1305.random_key(rng);
let cipher = baml.crypto.ChaCha20Poly1305.new(key);

let nonce = rng.random(12);
let sealed = cipher.encrypt(nonce, plaintext, aad);
let opened = cipher.decrypt(nonce, sealed, aad);

Never reuse a nonce

Unlike [Aes256GcmSiv], this construction offers nothing when a (key, nonce) pair repeats. Two messages encrypted under the same pair leak the XOR of their plaintexts, and the repetition also exposes the Poly1305 key, which lets an attacker forge ciphertexts that authenticate. One repeat is enough to lose both confidentiality and integrity for that key.

A 96-bit nonce is too small to draw at random for a long-lived key: at random, repeats become likely after roughly 2^48 messages. Derive nonces from a counter you know is unique, or use [XChaCha20Poly1305], whose 192-bit nonce is large enough to draw at random.

The nonce is not part of the ciphertext. Store or transmit it alongside.

Source:<builtin>/baml/ns_crypto/chacha20poly1305.bamlbytes 1548–4367

Fields

_cipher

$rust_type

Opaque, runtime-owned cipher state.

The key lives here rather than in a uint8array field so that a cipher carrying a wrong-length key cannot be constructed, and so key material stays unreachable from BAML. It cannot be read back, rendered by string.from, or serialized by baml.json.from.

Static methods

function

new

(key: uint8array) -> baml.crypto.ChaCha20Poly1305 throws baml.errors.InvalidArgument

Creates a cipher from a 32-byte (256-bit) key.

Throws
  • baml.errors.InvalidArgument if key is not exactly 32 bytes.

Implementations

baml.Concrete for T

Source:<builtin>/baml/core.bamlbytes 763–795

baml.crypto.Aead for baml.crypto.ChaCha20Poly1305

Instance methods

function

decrypt

(
self,
nonce: uint8array,
ciphertext: uint8array,
aad: uint8array

Authenticates and decrypts ciphertext, which must have been produced by encrypt under the same key, nonce, and aad.

Throws
  • baml.errors.InvalidArgument if nonce is not exactly 12 bytes, or ciphertext exceeds the RFC 8439 limit.
  • DecryptionFailure if the ciphertext does not authenticate.
function

encrypt

(
self,
nonce: uint8array,
plaintext: uint8array,
aad: uint8array
) -> uint8array throws baml.errors.InvalidArgument

Encrypts plaintext under nonce, authenticating aad alongside it. The ciphertext is 16 bytes longer than plaintext, which is the appended authentication tag.

nonce must never have been used with this key before. See the class documentation for what a repeat costs.

Throws
  • baml.errors.InvalidArgument if nonce is not exactly 12 bytes, or plaintext exceeds the RFC 8439 limit of 2^38 bytes.

Source:<builtin>/baml/ns_crypto/chacha20poly1305.bamlbytes 2247–3756

baml.crypto.GenerateKey for baml.crypto.ChaCha20Poly1305

Key = uint8array

Static methods

function

random_key

(rng: baml.random.Rng) -> uint8array throws never

Draws a fresh 32-byte key from rng. Pass the result to ChaCha20Poly1305.new. BUG: the return type spells out GenerateKey.Key's concrete value instead of Self.Key, which lowers to an error type here even though Self is the enclosing class and the projection has every input it needs to reduce. Restore Self.Key once concrete-site associated projections resolve.

Source:<builtin>/baml/ns_crypto/chacha20poly1305.bamlbytes 3762–4365