KEM (quantum_safe.kem)¶
Key encapsulation mechanisms. The high-level entry point is
HybridKEM.
- class quantum_safe.kem.hybrid.HybridKEM(classical='X25519', pqc='ML-KEM-768', backend='auto', validate=True)[source]¶
Bases:
objectHybrid KEM: classical Diffie-Hellman + post-quantum KEM.
Default configuration: X25519 + ML-KEM-768. This matches the TLS 1.3 hybrid group X25519MLKEM768 and is recommended by all major standards bodies for the current transition period.
- Parameters:
classical (
str) – Classical KEM algorithm. Currently “X25519” or “P-256”. Default: “X25519”.pqc (
str) – PQC KEM algorithm. Default: “ML-KEM-768”.backend (
str) – Backend for PQC operations: “auto”, “liboqs”, “rustcrypto”. Default: “auto”.validate (
bool) – If True (default), validate that the classical+pqc combination is an approved hybrid. Set False only if you’re testing a non-standard combination.
Example:
from quantum_safe import HybridKEM kem = HybridKEM() # X25519 + ML-KEM-768 kp = kem.generate_keypair() ct, ss = kem.encapsulate(kp.public) ss2 = kem.decapsulate(kp.secret, ct) assert ss == ss2
- generate_keypair()[source]¶
Generate a hybrid key pair.
The public key contains both the X25519 public key and the ML-KEM public key, packed with a length prefix. The secret key is similarly structured.
The migration_state is set to HYBRID_TRANSITION by default — this key participates in the current hybrid deployment.
- Return type:
- Returns:
KeyPair where both .public and .secret contain hybrid key material.
- encapsulate(public_key)[source]¶
Encapsulate a shared secret under the recipient’s hybrid public key.
- Parameters:
public_key (
PublicKey) – The recipient’s HybridKEM public key.- Return type:
- Returns:
(ct, ss) –
- HybridCipherText to send to the recipient, SharedSecret
for the sender’s use.
Note
The HybridCipherText.to_bytes() gives you the wire-format bytes to transmit. The SharedSecret is 32 bytes of combined key material derived from both the classical and PQC exchanges.
- decapsulate(secret_key, ciphertext)[source]¶
Decapsulate: recover the shared secret from a hybrid ciphertext.
- Parameters:
secret_key (
SecretKey) – The recipient’s HybridKEM secret key.ciphertext (
HybridCipherText) – HybridCipherText from the sender.
- Return type:
- Returns:
SharedSecret matching the sender’s.
- Raises:
DecapsulationError – on structural failures. Note that ML-KEM uses implicit rejection, so a bad ML-KEM ciphertext returns a pseudorandom value rather than failing — this is by design.
- class quantum_safe.kem.core.KEM(algorithm='ML-KEM-768', backend='auto', allow_low_security=False, strict=False)[source]¶
Bases:
objectSingle-algorithm KEM.
Wraps a backend and presents a typed, safe interface. Key decisions:
Key generation always returns a KeyPair (not raw bytes).
Encapsulate takes a PublicKey, returns (CipherText, SharedSecret).
Decapsulate takes (SecretKey, CipherText), returns SharedSecret.
All inputs/outputs are typed — you can’t accidentally pass a shared secret where a ciphertext is expected.
- Parameters:
algorithm (
str) – PQC algorithm name. Defaults to ML-KEM-768.backend (
str) – Backend name: “auto”, “liboqs”, “rustcrypto”. “auto” tries rustcrypto first, then liboqs.allow_low_security (
bool) – If True, allows NIST level 1 algorithms without warning. Default False (warns on L1).strict (
bool) – If True, raises instead of warning for non-standard configurations. Default False.
- generate_keypair()[source]¶
Generate a fresh key pair for this algorithm.
- Return type:
- Returns:
KeyPair with .public (PublicKey) and .secret (SecretKey).
Example:
kp = kem.generate_keypair() print(kp.public.fingerprint())
- encapsulate(public_key)[source]¶
Encapsulate a shared secret under the recipient’s public key.
- Parameters:
public_key (
PublicKey) – The recipient’s public key. Must be for the same algorithm as this KEM instance.- Return type:
- Returns:
(ct, ss) –
- CipherText to send to the recipient, SharedSecret
for the sender to use.
- Raises:
UnsupportedAlgorithm – if the key’s algorithm doesn’t match.
- decapsulate(secret_key, ciphertext)[source]¶
Decapsulate: recover the shared secret from a ciphertext.
- Parameters:
secret_key (
SecretKey) – The recipient’s secret key.ciphertext (
CipherText) – The CipherText from the sender.
- Return type:
- Returns:
SharedSecret matching the one the sender derived.
- Raises:
DecapsulationError – if decapsulation fails. Note that ML-KEM implements implicit rejection (FIPS 203 §6.3), so malformed ciphertexts produce a pseudorandom value rather than raising. The error is raised only for structural failures.
Algorithm registry¶
- quantum_safe.kem.algorithms.get_algorithm_spec(name)[source]¶
Return the spec for a PQC algorithm, raising UnsupportedAlgorithm if unknown.
- Parameters:
name (
str)- Return type:
KEMAlgorithmSpec
- quantum_safe.kem.algorithms.canonical_hybrid_name(classical, pqc)[source]¶
Return the canonical algorithm string for a hybrid combination.
Example: canonical_hybrid_name(“X25519”, “ML-KEM-768”) -> “X25519+ML-KEM-768”
- quantum_safe.kem.algorithms.parse_hybrid_name(name)[source]¶
Parse a hybrid algorithm name into (classical, pqc) components.
Raises ValueError if the name doesn’t look like a hybrid name.
- quantum_safe.kem.algorithms.validate_hybrid_combination(classical, pqc)[source]¶
Raise ValueError if the combination is not approved.
We don’t block unapproved combinations entirely (a researcher might have a legitimate reason), but we raise by default so callers have to be explicit about using a non-standard combination.