Ciphersuites

Each registry is a closed OCaml variant, not an integer. Unknown codepoints cannot be constructed at all; of_int is the only way in from the wire, and it returns Unsupported_algorithm for anything outside the tables below.

let suite =
  Suite.create ~kem:Kem.X25519 ~kdf:Kdf.Hkdf_sha256
    ~aead:Aead.Aes_128_gcm

let exporter =
  Suite.export_only ~kem:Kem.P384 ~kdf:Kdf.Hkdf_sha384

Five KEMs, three KDFs, and three AEADs give 45 encryption suites; every one of them is round-tripped by the test suite in Base mode. Dropping the AEAD gives 15 further export-only suites.

KEM

Key encapsulation mechanisms, all DHKEM
Constructor RFC 9180 name ID Public / enc Private Secret
Kem.P256DHKEM(P-256, HKDF-SHA256)0x0010653232
Kem.P384DHKEM(P-384, HKDF-SHA384)0x0011974848
Kem.P521DHKEM(P-521, HKDF-SHA512)0x00121336664
Kem.X25519DHKEM(X25519, HKDF-SHA256)0x0020323232
Kem.X448DHKEM(X448, HKDF-SHA512)0x0021565664

Sizes are bytes. An encapsulated key has the same size as a public key, because it is one. Kem.public_key_size, Kem.private_key_size, and Kem.encapsulated_key_size report these at run time.

KDF

Key derivation functions
Constructor Name ID Hash size Longest export
Kdf.Hkdf_sha256HKDF-SHA2560x0001328,160
Kdf.Hkdf_sha384HKDF-SHA3840x00024812,240
Kdf.Hkdf_sha512HKDF-SHA5120x00036416,320

The export ceiling is HKDF's own: 255 times the hash size. Asking for more, or for a negative length, returns Export_length_out_of_range rather than a truncated answer.

AEAD

Authenticated encryption
Constructor Name ID Key Nonce Tag Longest plaintext
Aead.Aes_128_gcmAES-128-GCM0x0001161216236 − 31
Aead.Aes_256_gcmAES-256-GCM0x0002321216236 − 31
Aead.Chacha20_poly1305ChaCha20-Poly13050x0003321216238 − 64
Suite.export_onlyExport-only0xFFFF

Export-only is a distinct suite type rather than an AEAD value, so it cannot be passed to seal or open_: the capability parameter on Suite.t makes that a type error. Its 0xFFFF codepoint still enters the key schedule's suite identifier, as RFC 9180 requires, so export secrets are domain-separated from encryption suites.

Modes

RFC 9180 modes
ModeIDStatus
Base0x00Implemented.
PSK0x01Implemented. Secrets of at least 32 bytes, non-empty identifier.
Auth0x02Implemented. The sender seals with its static private key; the recipient opens with that key's public half.
AuthPSK0x03Implemented. Auth and PSK together.

Deliberate omissions

Validation

What is checked, and where
Public keysExact encoded length. NIST keys must start with the uncompressed SEC1 marker and lie on the curve. X25519 and X448 low-order values are rejected when the key is used.
Private keysExact encoded length. NIST scalars must be non-zero and below the curve order, compared in constant time. X25519 and X448 scalars are clamped on parse and on output.
Encapsulated keysParsed as a public key for the suite's KEM. Context-level setup reports the failure structurally; single-shot opens normalize it.
Suite agreementA recipient or sender key whose KEM differs from the suite's KEM yields Key_mismatch before any cryptography.
PSKsSecret of at least 32 bytes and a non-empty identifier. A length check cannot establish entropy.
Derivationderive_key_pair follows RFC 9180, including rejection sampling for the NIST curves; exhausting it yields Derive_key_pair_failure.

Limits

Versioning

Wire behavior lives under Hpke.Rfc9180 and will not be changed by a future HPKE standard. A successor standard can be added as a second versioned module, so applications choose when to move rather than discovering that an upgrade changed what their peers see.

The successor draft, draft-ietf-hpke-hpke, removes the Auth and AuthPSK modes and reserves their identifiers. They stay in Hpke.Rfc9180; a module for the successor standard would not offer them.