Embeddable, dependency-free C11 implementation of ML-KEM from the FIPS 203 initial public draft (IPD).
FIPS 203 is (or will be) NIST's standardized version of Kyber, a post-quantum key encapsulation mechanism (KEM).
Notes on this implementation:
- Coefficients are reduced modulo Q during polynomial deserialization, as per this discussion.
- This implementation is focused on correctness and is not optimized. In particular, there is no SIMD optimization.
- Randomness for
keygen()
and encaps()
is specified as a function parameter.
- Uses my SHA-3 implementation.
- Full Doxygen API documentation.
- Test suite is built-in to
fips203ipd.c
(see bottom of file).
Use make
to build a minimal self test application, make doc
to build the HTML-formatted API documentation, and make test
to run the test suite.
Example
Minimal example of Alice and Bob exchanging a shared secret with KEM512:
#include <stdio.h>
#include <string.h>
#include "hex.h"
#include "rand-bytes.h"
int main(void) {
{
uint8_t keygen_seed[64] = { 0 };
rand_bytes(keygen_seed, sizeof(keygen_seed));
fputs("alice: keygen random (64 bytes) = ", stdout);
hex_write(stdout, keygen_seed, sizeof(keygen_seed));
fputs("\n", stdout);
}
fputs("alice: generated encapsulation key `ek` and decapsulation key `dk`:\n", stdout);
hex_write(stdout, ek, sizeof(ek));
hex_write(stdout, dk, sizeof(dk));
fputs("\n", stdout);
fputs("alice: sending encapsulation key `ek` to bob\n\n", stdout);
uint8_t b_key[32] = { 0 };
{
uint8_t encaps_seed[32] = { 0 };
rand_bytes(encaps_seed, sizeof(encaps_seed));
fputs("bob: encaps random (32 bytes) = ", stdout);
hex_write(stdout, encaps_seed, sizeof(encaps_seed));
fputs("\n", stdout);
}
fputs("bob: generated secret `b_key` and ciphertext `ct`:\nbob: b_key (32 bytes) = ", stdout);
hex_write(stdout, b_key, sizeof(b_key));
hex_write(stdout, ct, sizeof(ct));
fputs("\n", stdout);
fputs("bob: sending ciphertext `ct` to alice\n\n", stdout);
uint8_t a_key[32] = { 0 };
fputs("alice: used `dk` to decapsulate secret from `ct` into `a_key`:\nalice: a_key (32 bytes) = ", stdout);
hex_write(stdout, a_key, sizeof(a_key));
fputs("\n\n", stdout);
if (!memcmp(a_key, b_key, sizeof(a_key))) {
fputs("SUCCESS! alice secret `a_key` and bob secret `b_key` match.\n", stdout);
return 0;
} else {
fputs("FAILURE! alice secret `a_key` and bob secret `b_key` do not match.\n", stdout);
return -1;
}
}
C11 implementation of ML-KEM from the FIPS 203 initial public draft.
#define FIPS203IPD_KEM512_DK_SIZE
Size of KEM512 decapsulation key, in bytes (768 * K + 96).
Definition: fips203ipd.h:35
#define FIPS203IPD_KEM512_CT_SIZE
Size of KEM512 ciphertext, in bytes (32 * (DU * K + DV)).
Definition: fips203ipd.h:41
#define FIPS203IPD_KEM512_EK_SIZE
Size of KEM512 encapsulation key, in bytes (384 * K + 32).
Definition: fips203ipd.h:29
void fips203ipd_kem512_keygen(uint8_t ek[static FIPS203IPD_KEM512_EK_SIZE], uint8_t dk[static FIPS203IPD_KEM512_DK_SIZE], const uint8_t seed[static 64])
Generate KEM512 encapsulation key ek and decapsulation key dk from 64 byte random seed seed.
void fips203ipd_kem512_decaps(uint8_t key[static 32], const uint8_t ct[static FIPS203IPD_KEM512_CT_SIZE], const uint8_t dk[static FIPS203IPD_KEM512_DK_SIZE])
Decapsulate shared key key from ciphertext ct using KEM512 decapsulation key dk with implicit rejecti...
void fips203ipd_kem512_encaps(uint8_t key[static 32], uint8_t ct[static FIPS203IPD_KEM512_CT_SIZE], const uint8_t ek[static FIPS203IPD_KEM512_EK_SIZE], const uint8_t seed[static 32])
Generate KEM512 shared key key and ciphertext ct from given encapsulation key ek and randomness seed.
See examples/0-hello-kem/
for the full buildable example, including a Makefile
and support files.
Documentation
API documentation is available online here and also in fips203ipd.h
. If you have Doxygen installed, you can build HTML-formatted API documentation by typing make doc
.
Tests
Use make test
to build and run the test suite.
The test suite checks each component of this implementation for expected answers and is built with common sanitizers supported by both GCC and Clang. The source code for the test suite is embedded at the bottom of fips203ipd.c
behind a TEST_FIPS203IPD
define.
You can also build a quick test application by typing make
in the top-level directory. The test application does the following 1000 times for each parameter set:
- Generate a random encapsulation/decapsulation key pair.
- Encapsulate a secret using the encapsulation key.
- Decapsulate the secret using the decapsulation key.
- Verify that the secrets generated in steps #2 and #3 match.
Usage
There are safer and faster alternatives, but if you want to use this library anyway:
- Copy the following files into your source tree:
fips203ipd.c
, fips203ipd.h
, sha3.h
, and sha3.c
.
- Update your build system to compile
fips203ipd.o
and sha3.o
.
- Include
fips203ipd.h
in your application.
- Use
fips203ipd_*()
functions in your code.
References
License
MIT No Attribution (MIT-0)
Copyright 2023 Paul Duncan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.