ML-KEM.NetCore 1.0.0

dotnet add package ML-KEM.NetCore --version 1.0.0
                    
NuGet\Install-Package ML-KEM.NetCore -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ML-KEM.NetCore" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ML-KEM.NetCore" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ML-KEM.NetCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ML-KEM.NetCore --version 1.0.0
                    
#r "nuget: ML-KEM.NetCore, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ML-KEM.NetCore@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ML-KEM.NetCore&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ML-KEM.NetCore&version=1.0.0
                    
Install as a Cake Tool

ML-KEM.NetCore

License: MIT nuget

ML-KEM.NetCore is a pure managed .NET implementation of the NIST-standardized ML-KEM (Kyber) post-quantum key encapsulation mechanism.

The library targets .NET 8 and uses PinnedMemory for secret key and shared secret material to improve lifecycle control.


Table of contents


Requirements

  • .NET 8 SDK for building and running tests.
  • Project target framework: net8.0.

Installation

From source

Clone the repository and reference the MLKEM.NetCore project from your solution.

NuGet (when published)

dotnet add package ML-KEM.NetCore

Quick start

Pinned-memory encapsulation flow

using MLKEM.NetCore;

var kem = new MLKem(MLKemParameterSet.MLKem768);
var keyPair = kem.GenerateKeyPair();

using (keyPair.SecretKey)
{
    var encapsulation = kem.Encapsulate(keyPair.PublicKey);
    using (encapsulation.SharedSecret)
    {
        var secretKey = keyPair.SecretKey.Read().AsSpan(0, kem.SecretKeyBytes);
        using var sharedSecretBob = kem.Decapsulate(secretKey, encapsulation.CipherText);

        // Compare or use shared secrets, then dispose to scrub.
    }
}

API reference

MLKemParameterSet

enum MLKemParameterSet
{
    MLKem512,
    MLKem768,
    MLKem1024
}

Selects the NIST parameter set used by an MLKem instance.


MLKem

Constructor

MLKem(MLKemParameterSet parameterSet)

Size properties

int PublicKeyBytes { get; }
int SecretKeyBytes { get; }
int CipherTextBytes { get; }
int SharedSecretBytes { get; } // always 32

Key generation

SecureKeyPair GenerateKeyPair()
SecureKeyPair GenerateKeyPair(ReadOnlySpan<byte> d, ReadOnlySpan<byte> z)
  • Deterministic generation requires d and z to be exactly 32 bytes each.

Encapsulation

EncapsulationResult Encapsulate(ReadOnlySpan<byte> publicKey)
EncapsulationResult EncapsulateDeterministic(ReadOnlySpan<byte> publicKey, ReadOnlySpan<byte> m)
  • EncapsulateDeterministic(...) requires m to be exactly 32 bytes.

Decapsulation

PinnedMemory<byte> Decapsulate(ReadOnlySpan<byte> secretKey, ReadOnlySpan<byte> cipherText)
  • Input lengths are validated and must match the selected parameter set sizes.

Result types

sealed class SecureKeyPair
{
    byte[] PublicKey { get; }
    PinnedMemory<byte> SecretKey { get; }
}

sealed class EncapsulationResult
{
    byte[] CipherText { get; }
    PinnedMemory<byte> SharedSecret { get; }
}

Parameter sizes

Per instantiated MLKem object:

  • MLKem512
    • Public key: 800 bytes
    • Secret key: 1632 bytes
    • Ciphertext: 768 bytes
    • Shared secret: 32 bytes
  • MLKem768
    • Public key: 1184 bytes
    • Secret key: 2400 bytes
    • Ciphertext: 1088 bytes
    • Shared secret: 32 bytes
  • MLKem1024
    • Public key: 1568 bytes
    • Secret key: 3168 bytes
    • Ciphertext: 1568 bytes
    • Shared secret: 32 bytes

Best practices

  1. Use secure APIs for secret-bearing values

    • Use GenerateKeyPair, Encapsulate, and Decapsulate to keep key material in PinnedMemory<byte>.
    • Dispose PinnedMemory<byte> instances promptly.
  2. Treat parameter sets as protocol constants

    • Do not mix parameter sets between peers.
    • Validate all serialized key/ciphertext lengths before use.
  3. Prefer deterministic APIs only for tests/vectors

    • In production, use randomized GenerateKeyPair() and Encapsulate().
  4. Keep secret data lifetime short

    • Zero and dispose sensitive buffers as soon as possible.

Validation and testing

The test suite includes:

  • Deterministic known-answer-style vector checks
  • Encapsulation/decapsulation round-trip checks across parameter sets
  • Ciphertext tamper rejection behavior
  • Secure API behavior and memory handling coverage

Run all tests:

dotnet test MLKEM.sln

Development

Build

dotnet build MLKEM.sln

Test

dotnet test MLKEM.sln

Security notes

This implementation follows ML-KEM constructions in RFC 9936, including a rejection-sampling path that continues SHAKE output generation until enough coefficients are produced.

Current hardening in this repository:

  • Decapsulation uses constant-time ciphertext validation with fallback to z on invalid ciphertext.
  • Sensitive intermediates in decapsulation are explicitly zeroed before returning.
  • All secret key and shared secret APIs expose PinnedMemory<byte> for deterministic cleanup of secret-bearing values.
  • Public keys and ciphertext remain byte[] for interoperability, while key material is pinned.

License

MIT License. See LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 36 3/13/2026