Skip to main content
Version: 4.0.0

ML-KEM – Post-Quantum Key Encapsulation (Kyber)

Overview​

ML-KEM (Module-Lattice Key Encapsulation Mechanism) – is a lattice-based key-encapsulation protocol selected by NIST for post-quantum cryptography (FIPS 203).
ML-KEM provides three security categories that correspond to the Kyber512 (Level 1), Kyber768 (Level 3) and Kyber1024 (Level 5) parameter sets.


Byte sizes​

Parameter setPublic keySecret keyCipher-textShared secretEntropy bytesMessage bytesSecurity category
Kyber512800 B1632 B768 B32 B64 B32 BLevel 1
Kyber7681184 B2400 B1088 B32 B64 B32 BLevel 3
Kyber10241568 B3168 B1568 B32 B64 B32 BLevel 5

C++ API​

All three operations are templated by the Kyber parameter set (Kyber512Params, Kyber768Params, Kyber1024Params). The templates are explicitly instantiated by Icicle, so you only have to include the header and link against icicle_pqc.

MlKemConfig struct​

struct MlKemConfig {
icicleStreamHandle stream = nullptr; // Optional async stream
bool is_async = false; // If true – return immediately and synchronize later

// Location hints – set to `true` if the corresponding buffer already resides on the device
bool messages_on_device = false;
bool entropy_on_device = false;
bool public_keys_on_device = false;
bool secret_keys_on_device = false;
bool ciphertexts_on_device = false;
bool shared_secrets_on_device = false;

int batch_size = 1; // Number of independent KEMs processed in parallel

ConfigExtension* ext = nullptr; // Backend-specific tuning knobs (optional)
};

Key pair generation​

template <typename Params /* Kyber512Params | Kyber768Params | Kyber1024Params */>
eIcicleError keygen(
const std::byte* entropy, // [batch_size × ENTROPY_BYTES]
MlKemConfig config,
std::byte* public_keys, // [batch_size × Params::PUBLIC_KEY_BYTES]
std::byte* secret_keys // [batch_size × Params::SECRET_KEY_BYTES]
);

Encapsulation​

template <typename Params>
eIcicleError encapsulate(
const std::byte* message, // [batch_size × MESSAGE_BYTES] arbitrary plaintext
const std::byte* public_keys, // [batch_size × Params::PUBLIC_KEY_BYTES]
MlKemConfig config,
std::byte* ciphertexts, // [batch_size × Params::CIPHERTEXT_BYTES]
std::byte* shared_secrets // [batch_size × Params::SHARED_SECRET_BYTES]
);

Decapsulation​

template <typename Params>
eIcicleError decapsulate(
const std::byte* secret_keys, // [batch_size × Params::SECRET_KEY_BYTES]
const std::byte* ciphertexts, // [batch_size × Params::CIPHERTEXT_BYTES]
MlKemConfig config,
std::byte* shared_secrets // [batch_size × Params::SHARED_SECRET_BYTES]
);

Example: generate & encapsulate (Kyber768)​

#include "icicle/pqc/ml_kem.h"
using namespace icicle::pqc::ml_kem;

int main() {
const int batch_size = 1 << 12;
// Config
MlKemConfig config;
config.batch_size = batch_size;

// Allocate buffers
auto entropy = this->random_entropy(batch_size * ENTROPY_BYTES);
std::vector<std::byte> public_key(batch_size * TypeParam::PUBLIC_KEY_BYTES);
std::vector<std::byte> secret_key(batch_size * TypeParam::SECRET_KEY_BYTES);
std::vector<std::byte> ciphertext(batch_size * TypeParam::CIPHERTEXT_BYTES);
std::vector<std::byte> shared_secret_enc(batch_size * TypeParam::SHARED_SECRET_BYTES);
std::vector<std::byte> shared_secret_dec(batch_size * TypeParam::SHARED_SECRET_BYTES);

auto message = this->random_entropy(batch_size * MESSAGE_BYTES);

// Key generation
auto err = keygen<TypeParam>(entropy.data(), config, public_key.data(), secret_key.data());

// Encapsulation
err = encapsulate<TypeParam>(message.data(), public_key.data(), config, ciphertext.data(), shared_secret_enc.data());

// Decapsulation
err = decapsulate<TypeParam>(secret_key.data(), ciphertext.data(), config, shared_secret_dec.data());
}

References​

• NIST FIPS 203 – Module-Lattice-Based Key-Encapsulation Mechanism Standard.