silk.crypto.ml_kem.

Agree on a shared secret with ML-KEM (FIPS 203), the module-lattice key encapsulation mechanism, at the levels ML-KEM-512, ML-KEM-768, and ML-KEM-1024.

When to use#

Use MlKem when a shared secret must stay secret also against an attacker with a large quantum computer, for example in a hybrid TLS 1.3 group such as X25519MLKEM768. One side makes a key pair with MlKem.keyPairFromSeed and sends the encapsulation key. The other side calls MlKem.encapsulate, keeps the 32-byte shared secret, and sends the ciphertext back. The first side gets the same secret with MlKem.decapsulate. Use silk.crypto.ml_key to read and write the keys in PKCS #8 and SubjectPublicKeyInfo.

Details#

The caller gives every buffer, so nothing allocates. A key pair comes from a 64-byte seed d || z, the form that PKCS #8 stores; the functions of MlKemParameters give the sizes. Decapsulation runs in constant time for the secret values and returns the implicit-rejection secret for a ciphertext that does not match, as FIPS 203 says, so it never fails for a ciphertext of the right length. The NTT uses 16-bit Montgomery products with lazy reduction. The encapsulation and decapsulation keys are checked as FIPS 203 section 7 asks.

Errors#

  • MlKemError for a buffer of the wrong length, or for a key that fails the checks of FIPS 203.

Gotchas#

ML-KEM does not tell you who the other side is; authenticate the exchange, for example with a signature. Secrets are not erased.

Examples#

Agree on a secret#

silk
import silk.core.result { Result }
import silk.crypto.ml_kem { MlKem, MlKemError, MlKemParameters }

pub fn main() -> i32 {
  let parameters = MlKemParameters.MlKem768
  // Real programs fill the seed and the message from a secure `Random` provider.
  let seed: [u8; 64] = [1; 64]
  let mut encapsulationKey: [u8; 1184] = [0; 1184]
  let mut decapsulationKey: [u8; 2400] = [0; 2400]
  match MlKem.keyPairFromSeed(parameters, &seed, &mut encapsulationKey, &mut decapsulationKey) {
    Result<(), MlKemError>.Success { .. } => {}
    Result<(), MlKemError>.Failure { error: _ } => {
      return 1
    }
  }
  let message: [u8; 32] = [2; 32]
  let mut ciphertext: [u8; 1088] = [0; 1088]
  let sent = match MlKem.encapsulateWith(parameters, &encapsulationKey, &message, &mut ciphertext) {
    Result<[u8; 32], MlKemError>.Success { value } => value
    Result<[u8; 32], MlKemError>.Failure { error: _ } => {
      return 1
    }
  }
  let received = match MlKem.decapsulate(parameters, &decapsulationKey, &ciphertext) {
    Result<[u8; 32], MlKemError>.Success { value } => value
    Result<[u8; 32], MlKemError>.Failure { error: _ } => {
      return 1
    }
  }
  if sent[0] != received[0] || sent[31] != received[31] {
    return 1
  }
  return 0
}

Import as MlKem with import silk.crypto.ml_kem { MlKem }.

Public declarations: 3.

MlKemParameters#

silk
pub enum MlKemParameters

A parameter set of FIPS 203.

MlKem512#

silk
MlKem512

ML-KEM-512, security category 1.

MlKem768#

silk
MlKem768

ML-KEM-768, security category 3.

MlKem1024#

silk
MlKem1024

ML-KEM-1024, security category 5.

Implementation MlKemParameters#

silk
impl MlKemParameters

Method encapsulationKeyLength#

silk
pub fn encapsulationKeyLength(self: &Self) -> usize

Returns the length of an encapsulation key in bytes: 800, 1184, or 1568.

Method decapsulationKeyLength#

silk
pub fn decapsulationKeyLength(self: &Self) -> usize

Returns the length of a decapsulation key in bytes: 1632, 2400, or 3168.

Method ciphertextLength#

silk
pub fn ciphertextLength(self: &Self) -> usize

Returns the length of a ciphertext in bytes: 768, 1088, or 1568.

Method objectIdentifier#

silk
pub fn objectIdentifier(self: &Self) -> &[u8]

Returns the content bytes of the object identifier that names the parameter set, without the tag and length: id-alg-ml-kem-512 is 2.16.840.1.101.3.4.4.1, and the others end in 2 and 3.

Implementation Debug for MlKemParameters#

silk
impl Debug for MlKemParameters

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as MlKem768.

MlKemError#

silk
pub enum MlKemError

The reason that an ML-KEM call failed. It holds no secret bytes.

InvalidLength#

silk
InvalidLength

A seed, key, message, ciphertext, or output buffer does not have the length of the parameter set.

InvalidEncapsulationKey#

silk
InvalidEncapsulationKey

The encapsulation key fails the modulus check of FIPS 203 section 7.2: a coefficient is not below q.

InvalidDecapsulationKey#

silk
InvalidDecapsulationKey

The decapsulation key fails the hash check of FIPS 203 section 7.3: it does not hold the hash of its encapsulation key.

Implementation Debug for MlKemError#

silk
impl Debug for MlKemError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as InvalidLength.

MlKem#

silk
pub struct MlKem

The functions of ML-KEM.

When to use#

Make a key pair with MlKem.keyPairFromSeed, encapsulate with MlKem.encapsulate, and decapsulate with MlKem.decapsulate.

Details#

Each function takes the parameter set and the caller's buffers, which must have the lengths of MlKemParameters. The decapsulation key holds the encapsulation key; see MlKem.encapsulationKeyOf.

Implementation MlKem#

silk
impl MlKem

Associated function keyPairFromSeed#

silk
pub fn keyPairFromSeed(
    parameters: MlKemParameters,
    seed: &[u8],
    encapsulationKey: &mut [u8],
    decapsulationKey: &mut [u8],
  ) -> Result<(), MlKemError>

Writes the key pair of ML-KEM.KeyGen_internal for the 64-byte seed, d followed by z, into encapsulationKey and decapsulationKey.

Errors#

  • InvalidLength if seed is not 64 bytes, or a key buffer does not have the length of the parameter set. The buffers do not change.

Associated function generateSeed#

silk
pub effect fn generateSeed() -> [u8; 64] ? &mut Random

Returns a new 64-byte seed from the ambient Random, for MlKem.keyPairFromSeed.

The Random provider must be cryptographically secure.

Associated function encapsulationKeyOf#

silk
pub fn encapsulationKeyOf<'a>(parameters: MlKemParameters, decapsulationKey: &'a [u8]) -> Result<
    &'a [u8],
    MlKemError,
  >

Returns the encapsulation key inside decapsulationKey, a view that does not copy.

Errors#

  • InvalidLength if decapsulationKey does not have the length of the parameter set.

Associated function checkEncapsulationKey#

silk
pub fn checkEncapsulationKey(parameters: MlKemParameters, encapsulationKey: &[u8]) -> Result<
    (),
    MlKemError,
  >

Checks an encapsulation key as FIPS 203 section 7.2 asks: the length, and that every coefficient is below q.

Errors#

  • InvalidLength or InvalidEncapsulationKey.

Associated function checkDecapsulationKey#

silk
pub fn checkDecapsulationKey(parameters: MlKemParameters, decapsulationKey: &[u8]) -> Result<
    (),
    MlKemError,
  >

Checks a decapsulation key as FIPS 203 section 7.3 asks: the length, and that it holds the SHA3-256 hash of its encapsulation key.

Errors#

  • InvalidLength or InvalidDecapsulationKey.

Associated function encapsulate#

silk
pub effect fn encapsulate(
    parameters: MlKemParameters,
    encapsulationKey: &[u8],
    ciphertext: &mut [u8],
  ) -> Result<[u8; 32], MlKemError> ? &mut Random

Writes a ciphertext for encapsulationKey into ciphertext and returns the 32-byte shared secret, with a 32-byte message from the ambient Random.

Errors#

  • InvalidLength if encapsulationKey or ciphertext does not have the length of the parameter set.

  • InvalidEncapsulationKey if the key fails the modulus check.

ciphertext does not change on an error.

Associated function encapsulateWith#

silk
pub fn encapsulateWith(
    parameters: MlKemParameters,
    encapsulationKey: &[u8],
    message: &[u8],
    ciphertext: &mut [u8],
  ) -> Result<[u8; 32], MlKemError>

Writes the ciphertext of ML-KEM.Encaps_internal for encapsulationKey and the 32-byte message into ciphertext, and returns the shared secret.

Errors#

  • InvalidLength for a key, message, or ciphertext buffer of the wrong length.

  • InvalidEncapsulationKey if the key fails the modulus check.

Gotchas#

It is for test vectors. A message that is not fresh random bytes breaks the security, so use MlKem.encapsulate.

Associated function decapsulate#

silk
pub fn decapsulate(parameters: MlKemParameters, decapsulationKey: &[u8], ciphertext: &[u8]) -> Result<
    [u8; 32],
    MlKemError,
  >

Returns the 32-byte shared secret of ML-KEM.Decaps for ciphertext.

A ciphertext of the right length that was not made for this key gives the implicit-rejection secret of FIPS 203, a value that the sender cannot predict, and not an error. The time does not depend on the secret values or on whether the ciphertext matched.

Errors#

  • InvalidLength if decapsulationKey or ciphertext does not have the length of the parameter set.

  • InvalidDecapsulationKey if the key fails the hash check.

Category: Cryptography.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.

View the source of this page