libcrux-ml-tkem

Crates.iolibcrux-ml-tkem
lib.rslibcrux-ml-tkem
version0.0.3
created_at2025-12-18 06:19:29.581077+00
updated_at2026-01-04 08:11:01.618957+00
descriptionLibcrux ML-KEM & Kyber & tkem implementations
homepagehttps://github.com/OxAndHorse/libcrux
repositoryhttps://github.com/OxAndHorse/libcrux
max_upload_size
id1991780
size973,827
Amliy (OxAndHorse)

documentation

README

ML-TKEM

This crate implements all three ML-KEM (FIPS 203) variants 512, 768, and 1024. And also implements Tag-KEM extended by ML-KEM. For each algorithm, it inlcudes a portable Rust implementation, as well as SIMD implementations for Intel AVX2 and AArch64 Neon platforms.

Verification

verified

The portable and AVX2 code for field arithmetic, NTT polynomial arithmetic, serialization, and the generic code for high-level algorithms is formally verified using hax and F*.

Please refer to this file for detail on the verification of this crate.

Usage

By default, all ML-KEM parameter sets are enabled. If required, they are available individually under feature flags mlkem512, mlkem768, mlkem1024.

Functions in this crate use CPU feature detection to pick the most efficient version on each platform. To use a specific version with your own feature detection use e.g. one of the following

  • mlkem768::avx2::generate_key_pair,
  • mlkem768::neon::generate_key_pair,
  • mlkem768::portable::generate_key_pair,

analogously for encapsulation and decapsulation.

 use rand::{rngs::OsRng, RngCore};

 // Ensure you use good randomness.
 // It is not recommended to use OsRng directly!
 // Instead it is highly encouraged to use RNGs like NISTs DRBG to account for
 // bad system entropy.
 fn random_array<const L: usize>() -> [u8; L] {
     let mut rng = OsRng;
     let mut seed = [0; L];
     rng.try_fill_bytes(&mut seed).unwrap();
     seed
 }

 use libcrux_ml_tkem::*;

 // This example uses ML-KEM 768. The other variants can be used the same way.

 // Generate a key pair.
 let randomness = random_array();
 let key_pair = mlkem768::generate_key_pair(randomness);

 // Encapsulating a shared secret to a public key.
 let randomness = random_array();
 let (ciphertext, shared_secret) = mlkem768::encapsulate(key_pair.public_key(), randomness);

 // Decapsulating a shared secret with a private key.
 let shared_secret_decapsulated = mlkem768::decapsulate(key_pair.private_key(), &ciphertext);


 

use KEM with tag

fn test_tkem768() {

        let mut keygen_randomness = [0u8; KEY_GENERATION_SEED_SIZE];
        OsRng.try_fill_bytes(&mut keygen_randomness).unwrap();

        let key_pair = tkem768::generate_key_pair(keygen_randomness);


        let mut encap_randomness = [0u8; ENCAPS_SEED_SIZE];
        OsRng.try_fill_bytes(&mut encap_randomness).unwrap();


        let test_tag = b"ConsistencyTestTag";


        let (ciphertext, shared_secret_encap) =
            tkem768::encapsulate_with_tag(key_pair.public_key(), encap_randomness, test_tag);

        let shared_secret_decap =
            tkem768::decapsulate_with_tag(key_pair.private_key(), &ciphertext, test_tag);


        assert_eq!(
            shared_secret_encap.as_slice(),
            shared_secret_decap.as_slice(),
            "Encapsulated and Decapsulated shared secrets should be equal."
        );
    }

Kyber Round 3

The kyber flag also gives access to an, as yet, unverified implementation of Kyber as submitted in Round 3 of the NIST PQ competition.

Commit count: 0

cargo fmt