diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0c7e65e7..e63ce068b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,6 +119,9 @@ jobs: - name: bring_your_own_fips202 run: | make run -C examples/bring_your_own_fips202 + - name: custom_backend + run: | + make run -C examples/custom_backend build_kat: needs: [quickcheck, quickcheck-windows] strategy: diff --git a/examples/README.md b/examples/README.md index 3412042d1..ba73ec584 100644 --- a/examples/README.md +++ b/examples/README.md @@ -12,3 +12,8 @@ See [mlkem_native_as_code_package](mlkem_native_as_code_package). See [bring_your_own_fips202](bring_your_own_fips202) for an example of how to use mlkem-native with your own FIPS-202 implementation. + +## Using mlkem-native as a code package, custom config + custom FIPS-202 backend + +See [custom_backend](custom_backend) for an example of how to use mlkem-native with a custom configuration file and a +custom FIPS-202 backend. diff --git a/examples/custom_backend/Makefile b/examples/custom_backend/Makefile new file mode 100644 index 000000000..b1dad8549 --- /dev/null +++ b/examples/custom_backend/Makefile @@ -0,0 +1,64 @@ +# (SPDX-License-Identifier: CC-BY-4.0) + +.PHONY: build run clean + +# Part A: +# +# mlkem-native source and header files +# +# If you are not concerned about minimizing for a specific backend, +# you can just include _all_ source files into your build. +MLKEM_NATIVE_SOURCE=$(wildcard \ + mlkem_native/**/*.c \ + mlkem_native/**/*.c \ + mlkem_native/**/**/*.c \ + mlkem_native/**/**/**/*.c \ + mlkem_native/**/**/**/**/*.c) + +INC= +INC+=-Imlkem_native/ +INC+=-Imlkem_native/mlkem +INC+=-Imlkem_native/mlkem/native +INC+=-Imlkem_native/fips202 +INC+=-Imlkem_native/fips202/native + +# Part B: +# +# Random number generator +# +# !!! WARNING !!! +# +# The randombytes() implementation used here is for TESTING ONLY. +# You MUST NOT use this implementation outside of testing. +# +# !!! WARNING !!! +RNG_SOURCE=$(wildcard test_only_rng/*.c) + +# Part C: +# +# Your application source code +APP_SOURCE=$(wildcard *.c) + +ALL_SOURCE=$(MLKEM_NATIVE_SOURCE) $(RNG_SOURCE) $(APP_SOURCE) + +BUILD_DIR=build +BIN=test_binary + +CFLAGS=-DMLKEM_NATIVE_CONFIG_FILE="\"custom_config.h\"" + +BINARY_NAME_FULL=$(BUILD_DIR)/$(BIN) + +$(BINARY_NAME_FULL): $(ALL_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: run + +build: $(BINARY_NAME_FULL) + +run: $(BINARY_NAME_FULL) + ./$(BINARY_NAME_FULL) + +clean: + rm -rf $(BUILD_DIR) diff --git a/examples/custom_backend/README.md b/examples/custom_backend/README.md new file mode 100644 index 000000000..b93ea95ad --- /dev/null +++ b/examples/custom_backend/README.md @@ -0,0 +1,34 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Using a custom configuration and FIPS-202 backend + +This directory contains a minimal example for how to use mlkem-native as a code package, with a custom FIPS-202 +backend and a custom configuration. We use the [tiny_sha3](https://github.com/mjosaarinen/tiny_sha3/) by Markku-J. O. +Saarinen as an example. + +## Components + +An application using mlkem-native with a custom FIPS-202 backend and custom configuration needs the following: + +1. Arithmetic part of the mlkem-native source tree: [`mlkem/`](../../mlkem). In this example, we disable arithmetic + backends, hence it is safe to remove the entire `native` subfolder. +2. A secure pseudo random number generator, implementing [`randombytes.h`](../../mlkem/randombytes.h). +3. FIPS-202 part of the mlkem-native source tree, [`fips/`](../../fips202). If you only want to use your backend, + you can remove all existing backends; that's what this example does. +4. A custom FIPS-202 backend. In this example, the metadata file is + [custom.h](mlkem_native/fips202/native/custom/custom.h), the implementation shim is + [custom_impl.h](mlkem_native/fips202/native/custom/src/custom_impl.h), wrapping the + [sha3.c](mlkem_native/fips202/native/custom/src/sha3.c) and setting `MLKEM_USE_FIPS101_X1_NATIVE` to indicate that we + replace 1-fold Keccak-F1600. +5. Either modify the existing [config.h](mlkem_native/mlkem/config.h), or register a new config. In this example, we add + a new config [custom_config.h](mlkem_native/custom_config.h) and register it from the command line for + `-DMLKEM_NATIVE_CONFIG_FILE="custom_config.h"` -- no further changes to the build are needed. For the sake of + demonstration, we set a custom namespace. We set `MLKEM_NATIVE_FIPS202_BACKEND` to point to our custom FIPS-202 + backend, but leave `MLKEM_NATIVE_ARITH_BACKEND` undefined to indicate that we wish to use the C backend. + +**WARNING:** The `randombytes()` implementation used here is for TESTING ONLY. You MUST NOT use this implementation +outside of testing. + +## Usage + +Build this example with `make build`, run with `make run`. diff --git a/examples/custom_backend/main.c b/examples/custom_backend/main.c new file mode 100644 index 000000000..d6bb92888 --- /dev/null +++ b/examples/custom_backend/main.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +int main(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t ct[CRYPTO_CIPHERTEXTBYTES]; + uint8_t key_a[CRYPTO_BYTES]; + uint8_t key_b[CRYPTO_BYTES]; + + printf("Generating keypair ... "); + + /* Alice generates a public key */ + crypto_kem_keypair(pk, sk); + + printf("DONE\n"); + printf("Encaps... "); + + /* Bob derives a secret key and creates a response */ + crypto_kem_enc(ct, key_b, pk); + + printf("DONE\n"); + printf("Decaps... "); + + /* Alice uses Bobs response to get her shared key */ + crypto_kem_dec(key_a, ct, sk); + + printf("DONE\n"); + printf("Compare... "); + + if (memcmp(key_a, key_b, CRYPTO_BYTES)) + { + printf("ERROR\n"); + return 1; + } + + printf("OK\n"); + + printf("Shared secret: "); + { + int i; + for (i = 0; i < sizeof(key_a); i++) + printf("%02x", key_a[i]); + } + printf("\n"); + + return 0; +} diff --git a/examples/custom_backend/mlkem_native/custom_config.h b/examples/custom_backend/mlkem_native/custom_config.h new file mode 100644 index 000000000..d9ecfa9fa --- /dev/null +++ b/examples/custom_backend/mlkem_native/custom_config.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024 The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef MLKEM_NATIVE_CONFIG_H +#define MLKEM_NATIVE_CONFIG_H + +/****************************************************************************** + * Name: MLKEM_K + * + * Description: Determines the security level for ML-KEM + * - MLKEM_K=2 corresponds to ML-KEM-512 + * - MLKEM_K=3 corresponds to ML-KEM-768 + * - MLKEM_K=4 corresponds to ML-KEM-1024 + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLKEM_K 4 /* We want MLKEM-1024 */ + +/****************************************************************************** + * Name: MLKEM_NATIVE_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of mlkem/config.h. + * + * When you need to build mlkem-native in multiple configurations, + * this can be a convenient alternative to configuration via + * CFLAGS. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLKEM_NATIVE_CONFIG_FILE "config.h" */ + +/****************************************************************************** + * Name: MLKEM_NAMESPACE + * _MLKEM_NAMESPACE + * + * Description: The macros to use to namespace global symbols + * from mlkem/. + *****************************************************************************/ +#define __CONC(a, b) a##b +#define CONC(a, b) __CONC(a, b) + +#define MLKEM_NAMESPACE(sym) CONC(CUSTOM_TINY_SHA3_, sym) +#define _MLKEM_NAMESPACE(sym) CONC(_CUSTOM_TINY_SHA3_, sym) + +/****************************************************************************** + * Name: FIPS202_NAMESPACE + * _FIPS202_NAMESPACE + * + * Description: The macros to use to namespace global symbols + * from fips202/. + *****************************************************************************/ +#define FIPS202_NAMESPACE(sym) CONC(CUSTOM_TINY_SHA3_, sym) +#define _FIPS202_NAMESPACE(sym) CONC(_CUSTOM_TINY_SHA3_, sym) + +/****************************************************************************** + * Name: MLKEM_USE_NATIVE + * + * Description: Determines whether a native backend should + * be used, if available. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLKEM_USE_NATIVE + +/****************************************************************************** + * Name: MLKEM_NATIVE_ARITH_BACKEND + * + * Description: The arithmetic backend to use. + * + * This must be the filename of an arithmetic + * backend. The backend is expected to define + * + * - MLKEM_NATIVE_ARITH_BACKEND_NAME + * + * The name of the backend as used in the default namespace. + * + * - MLKEM_NATIVE_ARITH_BACKEND_IMPL + * + * The filename of the implementation of the arithmetic backend. + * + * See the existing backends for more information. + * + *****************************************************************************/ +/* Let's pretend we don't want an arithmetic backend */ +/* #define MLKEM_NATIVE_ARITH_BACKEND "native/default.h" */ + +/****************************************************************************** + * Name: MLKEM_NATIVE_FIPS202_BACKEND + * + * Description: The FIPS-202 backend to use. + * + * This must be the filename of an FIPS-202 + * backend. The backend is expected to define + * + * - MLKEM_NATIVE_FIPS202_BACKEND_NAME + * + * The name of the backend as used in the default namespace. + * + * - MLKEM_NATIVE_FIPS202_BACKEND_IMPL + * + * The filename of the implementation of the FIPS-202 backend. + * + * See the existing backends for more information. + * + *****************************************************************************/ +#define MLKEM_NATIVE_FIPS202_BACKEND "fips202/native/custom/custom.h" + +#endif /* MLkEM_NATIVE_CONFIG_H */ diff --git a/examples/custom_backend/mlkem_native/fips202/LICENSE b/examples/custom_backend/mlkem_native/fips202/LICENSE new file mode 120000 index 000000000..bcebb16c1 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/LICENSE @@ -0,0 +1 @@ +../../../../fips202/LICENSE \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/fips202.c b/examples/custom_backend/mlkem_native/fips202/fips202.c new file mode 120000 index 000000000..34cf3813b --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/fips202.c @@ -0,0 +1 @@ +../../../../fips202/fips202.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/fips202.h b/examples/custom_backend/mlkem_native/fips202/fips202.h new file mode 120000 index 000000000..164a3b7b8 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/fips202.h @@ -0,0 +1 @@ +../../../../fips202/fips202.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/fips202_backend.h b/examples/custom_backend/mlkem_native/fips202/fips202_backend.h new file mode 120000 index 000000000..5397725dc --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/fips202_backend.h @@ -0,0 +1 @@ +../../../../fips202/fips202_backend.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/fips202x4.c b/examples/custom_backend/mlkem_native/fips202/fips202x4.c new file mode 120000 index 000000000..fd9ec60d1 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/fips202x4.c @@ -0,0 +1 @@ +../../../../fips202/fips202x4.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/fips202x4.h b/examples/custom_backend/mlkem_native/fips202/fips202x4.h new file mode 120000 index 000000000..4dc5c3b80 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/fips202x4.h @@ -0,0 +1 @@ +../../../../fips202/fips202x4.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/keccakf1600.c b/examples/custom_backend/mlkem_native/fips202/keccakf1600.c new file mode 120000 index 000000000..53a5e8617 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/keccakf1600.c @@ -0,0 +1 @@ +../../../../fips202/keccakf1600.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/keccakf1600.h b/examples/custom_backend/mlkem_native/fips202/keccakf1600.h new file mode 120000 index 000000000..fe6e51a4c --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/keccakf1600.h @@ -0,0 +1 @@ +../../../../fips202/keccakf1600.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/native/api.h b/examples/custom_backend/mlkem_native/fips202/native/api.h new file mode 120000 index 000000000..b255ddf09 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/native/api.h @@ -0,0 +1 @@ +../../../../../fips202/native/api.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/fips202/native/custom/custom.h b/examples/custom_backend/mlkem_native/fips202/native/custom/custom.h new file mode 100644 index 000000000..2ef194461 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/native/custom/custom.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Default FIPS202 assembly profile for AArch64 systems */ + +#ifdef FIPS202_NATIVE_PROFILE_H +#error Only one FIPS202 assembly profile can be defined -- did you include multiple profiles? +#else +#define FIPS202_NATIVE_PROFILE_H + +/* Identifier for this backend so that source and assembly files + * in the build can be appropriately guarded. */ +#define MLKEM_NATIVE_FIPS202_BACKEND_CUSTOM_TINY_SHA3 + +#define MLKEM_NATIVE_FIPS202_BACKEND_NAME TINY_SHA3 + +/* Filename of the C backend implementation. + * This is not inlined here because this header is included in assembly + * files as well. */ +#define MLKEM_NATIVE_FIPS202_BACKEND_IMPL \ + "fips202/native/custom/src/custom_impl.h" + +#endif /* FIPS202_NATIVE_PROFILE_H */ diff --git a/examples/custom_backend/mlkem_native/fips202/native/custom/src/LICENSE b/examples/custom_backend/mlkem_native/fips202/native/custom/src/LICENSE new file mode 100644 index 000000000..35741e52a --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/native/custom/src/LICENSE @@ -0,0 +1,23 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +The MIT License (MIT) + +Copyright (c) 2015 Markku-Juhani O. Saarinen + +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, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/examples/custom_backend/mlkem_native/fips202/native/custom/src/Makefile b/examples/custom_backend/mlkem_native/fips202/native/custom/src/Makefile new file mode 100644 index 000000000..e855f986f --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/native/custom/src/Makefile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT + +# Makefile +# 19-Nov-11 Markku-Juhani O. Saarinen + +BINARY = sha3test +OBJS = sha3.o main.o +DIST = tiny_sha3 + +CC = gcc +CFLAGS = -Wall -O3 +LIBS = +LDFLAGS = +INCLUDES = + +$(BINARY): $(OBJS) + $(CC) $(LDFLAGS) -o $(BINARY) $(OBJS) $(LIBS) + +.c.o: + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +clean: + rm -rf $(DIST)-*.txz $(OBJS) $(BINARY) *~ + +dist: clean + cd ..; \ + tar cfvJ $(DIST)/$(DIST)-`date -u "+%Y%m%d%H%M00"`.txz \ + $(DIST)/* diff --git a/examples/custom_backend/mlkem_native/fips202/native/custom/src/README.md b/examples/custom_backend/mlkem_native/fips202/native/custom/src/README.md new file mode 100644 index 000000000..66684bec2 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/native/custom/src/README.md @@ -0,0 +1,63 @@ +[//]: # (SPDX-License-Identifier: MIT) + +# tiny_sha3 +Very small, readable implementation of the FIPS 202 and SHA3 hash function. +Public domain. + +### Updated 27-Dec-15: + +Added SHAKE128 and SHAKE256 code and test vectors. The code can actually do +a XOF of arbitrary size (like "SHAKE512"). + + +### Updated 03-Sep-15: + +Made the implementation portable. The API is now pretty much the +same that OpenSSL uses. + + +### Updated 07-Aug-15: + +Now that SHA3 spec is out, I've updated the package to match with the +new padding rules. There is literally one line difference between +Keccak 3.0 and SHA-3 implementations: + +``` + temp[inlen++] = 0x06; // XXX Padding Changed from Keccak 3.0 +``` + +The 0x06 constant there used to be 0x01. But this of course totally +breaks compatibility and test vectors had to be revised. + +SHA-3 Spec: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf + +Cheers, +- markku + + +### Original README.TXT from 19-Nov-11: + +Hi. + +The SHA-3 competition is nearing it's end and I would personally like +to support Keccak as the winner. I have a PhD in hash function cryptanalysis +so don't take my word for it, go ahead and look into the code ! + +Since I couldn't find a *compact* and/or *readable* implementation of Keccak +anywhere, here's one I cooked up as a service to the curious. + +This implementation is intended for study of the algorithm, not for +production use. + +The code works correctly on 64-bit little-endian platforms with gcc. +Like your Linux box. The main.c module contains self-tests for all +officially supported hash sizes. + +If you're looking for production code, the official multi-megabyte package +covers everyting you could possibly need and too much much more: +http://keccak.noekeon.org/ + +Cheers, +- Markku 19-Nov-11 + +Dr. Markku-Juhani O. Saarinen diff --git a/examples/custom_backend/mlkem_native/fips202/native/custom/src/custom_impl.h b/examples/custom_backend/mlkem_native/fips202/native/custom/src/custom_impl.h new file mode 100644 index 000000000..242d6b7f4 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/native/custom/src/custom_impl.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Default FIPS202 assembly profile for AArch64 systems */ + +#ifdef FIPS202_NATIVE_PROFILE_IMPL_H +#error Only one FIPS202 assembly profile can be defined -- did you include multiple profiles? +#else +#define FIPS202_NATIVE_PROFILE_IMPL_H + +#include "sha3.h" + +/* Replace (single) Keccak-F1600 by tiny-SHA3's */ +#define MLKEM_USE_FIPS202_X1_NATIVE +static INLINE void keccak_f1600_x1_native(uint64_t *state) +{ + sha3_keccakf(state); +} + +#endif /* FIPS202_NATIVE_PROFILE_H */ diff --git a/examples/custom_backend/mlkem_native/fips202/native/custom/src/sha3.c b/examples/custom_backend/mlkem_native/fips202/native/custom/src/sha3.c new file mode 100644 index 000000000..c21684ae5 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/native/custom/src/sha3.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +// +// sha3.c +// 19-Nov-11 Markku-Juhani O. Saarinen + +// Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3" +// Revised 03-Sep-15 for portability + OpenSSL - style API + +#include "sha3.h" + +// update the state with given number of rounds + +void sha3_keccakf(uint64_t st[25]) +{ + // constants + const uint64_t keccakf_rndc[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}; + const int keccakf_rotc[24] = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44}; + const int keccakf_piln[24] = {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1}; + + // variables + int i, j, r; + uint64_t t, bc[5]; + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + uint8_t *v; + + // endianess conversion. this is redundant on little-endian targets + for (i = 0; i < 25; i++) + { + v = (uint8_t *)&st[i]; + st[i] = ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8) | + (((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24) | + (((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40) | + (((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56); + } +#endif + + // actual iteration + for (r = 0; r < KECCAKF_ROUNDS; r++) + { + // Theta + for (i = 0; i < 5; i++) + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + + for (i = 0; i < 5; i++) + { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + st[j + i] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; i++) + { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) + { + for (i = 0; i < 5; i++) + bc[i] = st[j + i]; + for (i = 0; i < 5; i++) + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + + // Iota + st[0] ^= keccakf_rndc[r]; + } + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + // endianess conversion. this is redundant on little-endian targets + for (i = 0; i < 25; i++) + { + v = (uint8_t *)&st[i]; + t = st[i]; + v[0] = t & 0xFF; + v[1] = (t >> 8) & 0xFF; + v[2] = (t >> 16) & 0xFF; + v[3] = (t >> 24) & 0xFF; + v[4] = (t >> 32) & 0xFF; + v[5] = (t >> 40) & 0xFF; + v[6] = (t >> 48) & 0xFF; + v[7] = (t >> 56) & 0xFF; + } +#endif +} + +// Initialize the context for SHA3 + +int sha3_init(sha3_ctx_t *c, int mdlen) +{ + int i; + + for (i = 0; i < 25; i++) + c->st.q[i] = 0; + c->mdlen = mdlen; + c->rsiz = 200 - 2 * mdlen; + c->pt = 0; + + return 1; +} + +// update state with more data + +int sha3_update(sha3_ctx_t *c, const void *data, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) + { + c->st.b[j++] ^= ((const uint8_t *)data)[i]; + if (j >= c->rsiz) + { + sha3_keccakf(c->st.q); + j = 0; + } + } + c->pt = j; + + return 1; +} + +// finalize and output a hash + +int sha3_final(void *md, sha3_ctx_t *c) +{ + int i; + + c->st.b[c->pt] ^= 0x06; + c->st.b[c->rsiz - 1] ^= 0x80; + sha3_keccakf(c->st.q); + + for (i = 0; i < c->mdlen; i++) + { + ((uint8_t *)md)[i] = c->st.b[i]; + } + + return 1; +} + +// compute a SHA-3 hash (md) of given byte length from "in" + +void *sha3(const void *in, size_t inlen, void *md, int mdlen) +{ + sha3_ctx_t sha3; + + sha3_init(&sha3, mdlen); + sha3_update(&sha3, in, inlen); + sha3_final(md, &sha3); + + return md; +} + +// SHAKE128 and SHAKE256 extensible-output functionality + +void shake_xof(sha3_ctx_t *c) +{ + c->st.b[c->pt] ^= 0x1F; + c->st.b[c->rsiz - 1] ^= 0x80; + sha3_keccakf(c->st.q); + c->pt = 0; +} + +void shake_out(sha3_ctx_t *c, void *out, size_t len) +{ + size_t i; + int j; + + j = c->pt; + for (i = 0; i < len; i++) + { + if (j >= c->rsiz) + { + sha3_keccakf(c->st.q); + j = 0; + } + ((uint8_t *)out)[i] = c->st.b[j++]; + } + c->pt = j; +} diff --git a/examples/custom_backend/mlkem_native/fips202/native/custom/src/sha3.h b/examples/custom_backend/mlkem_native/fips202/native/custom/src/sha3.h new file mode 100644 index 000000000..fb5276059 --- /dev/null +++ b/examples/custom_backend/mlkem_native/fips202/native/custom/src/sha3.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +// +// sha3.h +// 19-Nov-11 Markku-Juhani O. Saarinen + +#ifndef SHA3_H +#define SHA3_H + +#include +#include + +#ifndef KECCAKF_ROUNDS +#define KECCAKF_ROUNDS 24 +#endif + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +// state context +typedef struct +{ + union + { // state: + uint8_t b[200]; // 8-bit bytes + uint64_t q[25]; // 64-bit words + } st; + int pt, rsiz, mdlen; // these don't overflow +} sha3_ctx_t; + +// Compression function. +void sha3_keccakf(uint64_t st[25]); + +// OpenSSL - like interfece +int sha3_init(sha3_ctx_t *c, int mdlen); // mdlen = hash output in bytes +int sha3_update(sha3_ctx_t *c, const void *data, size_t len); +int sha3_final(void *md, sha3_ctx_t *c); // digest goes to md + +// compute a sha3 hash (md) of given byte length from "in" +void *sha3(const void *in, size_t inlen, void *md, int mdlen); + +// SHAKE128 and SHAKE256 extensible-output functions +#define shake128_init(c) sha3_init(c, 16) +#define shake256_init(c) sha3_init(c, 32) +#define shake_update sha3_update + +void shake_xof(sha3_ctx_t *c); +void shake_out(sha3_ctx_t *c, void *out, size_t len); + +#endif diff --git a/examples/custom_backend/mlkem_native/mlkem/LICENSE b/examples/custom_backend/mlkem_native/mlkem/LICENSE new file mode 120000 index 000000000..8fae44d93 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/LICENSE @@ -0,0 +1 @@ +../../../../mlkem/LICENSE \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/arith_backend.h b/examples/custom_backend/mlkem_native/mlkem/arith_backend.h new file mode 120000 index 000000000..c7abf8ecd --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/arith_backend.h @@ -0,0 +1 @@ +../../../../mlkem/arith_backend.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/cbd.c b/examples/custom_backend/mlkem_native/mlkem/cbd.c new file mode 120000 index 000000000..66131480c --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/cbd.c @@ -0,0 +1 @@ +../../../../mlkem/cbd.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/cbd.h b/examples/custom_backend/mlkem_native/mlkem/cbd.h new file mode 120000 index 000000000..941b8bd44 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/cbd.h @@ -0,0 +1 @@ +../../../../mlkem/cbd.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/cbmc.h b/examples/custom_backend/mlkem_native/mlkem/cbmc.h new file mode 120000 index 000000000..1d7ad6bf2 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/cbmc.h @@ -0,0 +1 @@ +../../../../mlkem/cbmc.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/common.h b/examples/custom_backend/mlkem_native/mlkem/common.h new file mode 120000 index 000000000..f6ec75f66 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/common.h @@ -0,0 +1 @@ +../../../../mlkem/common.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/config.h b/examples/custom_backend/mlkem_native/mlkem/config.h new file mode 120000 index 000000000..a71bed830 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/config.h @@ -0,0 +1 @@ +../../../../mlkem/config.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/debug b/examples/custom_backend/mlkem_native/mlkem/debug new file mode 120000 index 000000000..cd511d740 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/debug @@ -0,0 +1 @@ +../../../../mlkem/debug \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/indcpa.c b/examples/custom_backend/mlkem_native/mlkem/indcpa.c new file mode 120000 index 000000000..56b7fc666 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/indcpa.c @@ -0,0 +1 @@ +../../../../mlkem/indcpa.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/indcpa.h b/examples/custom_backend/mlkem_native/mlkem/indcpa.h new file mode 120000 index 000000000..6bec2894b --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/indcpa.h @@ -0,0 +1 @@ +../../../../mlkem/indcpa.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/kem.c b/examples/custom_backend/mlkem_native/mlkem/kem.c new file mode 120000 index 000000000..2677344d2 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/kem.c @@ -0,0 +1 @@ +../../../../mlkem/kem.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/kem.h b/examples/custom_backend/mlkem_native/mlkem/kem.h new file mode 120000 index 000000000..6f74e1af6 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/kem.h @@ -0,0 +1 @@ +../../../../mlkem/kem.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/namespace.h b/examples/custom_backend/mlkem_native/mlkem/namespace.h new file mode 120000 index 000000000..c41101c01 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/namespace.h @@ -0,0 +1 @@ +../../../../mlkem/namespace.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/ntt.c b/examples/custom_backend/mlkem_native/mlkem/ntt.c new file mode 120000 index 000000000..693bc94f2 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/ntt.c @@ -0,0 +1 @@ +../../../../mlkem/ntt.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/ntt.h b/examples/custom_backend/mlkem_native/mlkem/ntt.h new file mode 120000 index 000000000..5ea1982c5 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/ntt.h @@ -0,0 +1 @@ +../../../../mlkem/ntt.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/params.h b/examples/custom_backend/mlkem_native/mlkem/params.h new file mode 120000 index 000000000..f9fc45bfb --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/params.h @@ -0,0 +1 @@ +../../../../mlkem/params.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/poly.c b/examples/custom_backend/mlkem_native/mlkem/poly.c new file mode 120000 index 000000000..8f37481c9 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/poly.c @@ -0,0 +1 @@ +../../../../mlkem/poly.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/poly.h b/examples/custom_backend/mlkem_native/mlkem/poly.h new file mode 120000 index 000000000..6aa17ed35 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/poly.h @@ -0,0 +1 @@ +../../../../mlkem/poly.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/polyvec.c b/examples/custom_backend/mlkem_native/mlkem/polyvec.c new file mode 120000 index 000000000..358c967ff --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/polyvec.c @@ -0,0 +1 @@ +../../../../mlkem/polyvec.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/polyvec.h b/examples/custom_backend/mlkem_native/mlkem/polyvec.h new file mode 120000 index 000000000..b3a001d95 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/polyvec.h @@ -0,0 +1 @@ +../../../../mlkem/polyvec.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/randombytes.h b/examples/custom_backend/mlkem_native/mlkem/randombytes.h new file mode 120000 index 000000000..d1b4aeb9e --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/randombytes.h @@ -0,0 +1 @@ +../../../../mlkem/randombytes.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/reduce.h b/examples/custom_backend/mlkem_native/mlkem/reduce.h new file mode 120000 index 000000000..6b2408820 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/reduce.h @@ -0,0 +1 @@ +../../../../mlkem/reduce.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/rej_uniform.c b/examples/custom_backend/mlkem_native/mlkem/rej_uniform.c new file mode 120000 index 000000000..bcc45b521 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/rej_uniform.c @@ -0,0 +1 @@ +../../../../mlkem/rej_uniform.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/rej_uniform.h b/examples/custom_backend/mlkem_native/mlkem/rej_uniform.h new file mode 120000 index 000000000..1d2f26cdb --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/rej_uniform.h @@ -0,0 +1 @@ +../../../../mlkem/rej_uniform.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/symmetric.h b/examples/custom_backend/mlkem_native/mlkem/symmetric.h new file mode 120000 index 000000000..a44e26f71 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/symmetric.h @@ -0,0 +1 @@ +../../../../mlkem/symmetric.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/sys.h b/examples/custom_backend/mlkem_native/mlkem/sys.h new file mode 120000 index 000000000..c6b25c7f2 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/sys.h @@ -0,0 +1 @@ +../../../../mlkem/sys.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/verify.c b/examples/custom_backend/mlkem_native/mlkem/verify.c new file mode 120000 index 000000000..d49e9df42 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/verify.c @@ -0,0 +1 @@ +../../../../mlkem/verify.c \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/verify.h b/examples/custom_backend/mlkem_native/mlkem/verify.h new file mode 120000 index 000000000..82ae31329 --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/verify.h @@ -0,0 +1 @@ +../../../../mlkem/verify.h \ No newline at end of file diff --git a/examples/custom_backend/mlkem_native/mlkem/zetas.c b/examples/custom_backend/mlkem_native/mlkem/zetas.c new file mode 120000 index 000000000..4e1a91dda --- /dev/null +++ b/examples/custom_backend/mlkem_native/mlkem/zetas.c @@ -0,0 +1 @@ +../../../../mlkem/zetas.c \ No newline at end of file diff --git a/examples/custom_backend/test_only_rng/notrandombytes.c b/examples/custom_backend/test_only_rng/notrandombytes.c new file mode 100644 index 000000000..93807622d --- /dev/null +++ b/examples/custom_backend/test_only_rng/notrandombytes.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 The mlkem-native project authors + * SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MI + * Based on https://cr.yp.to/papers.html#surf by Daniel. J. Bernstein + */ + +/** + * WARNING + * + * The randombytes() implementation in this file is for TESTING ONLY. + * You MUST NOT use this implementation outside of testing. + * + */ + +#warning !!! WARNING !!! +#warning THIS BUILD IS USING A TEST-ONLY RANDOM NUMBER GENERATOR WHICH MUST NOT BE USED IN PRODUCTION + +#include +#include "randombytes.h" + +static uint32_t seed[32] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, + 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5}; +static uint32_t in[12]; +static uint32_t out[8]; +static int32_t outleft = 0; + +#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); + +static void surf(void) +{ + uint32_t t[12]; + uint32_t x; + uint32_t sum = 0; + int32_t r; + int32_t i; + int32_t loop; + + for (i = 0; i < 12; ++i) + { + t[i] = in[i] ^ seed[12 + i]; + } + for (i = 0; i < 8; ++i) + { + out[i] = seed[24 + i]; + } + x = t[11]; + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { + sum += 0x9e3779b9; + MUSH(0, 5) + MUSH(1, 7) + MUSH(2, 9) + MUSH(3, 13) + MUSH(4, 5) + MUSH(5, 7) + MUSH(6, 9) + MUSH(7, 13) + MUSH(8, 5) + MUSH(9, 7) + MUSH(10, 9) + MUSH(11, 13) + } + for (i = 0; i < 8; ++i) + { + out[i] ^= t[i + 4]; + } + } +} + +void randombytes(uint8_t *buf, size_t n) +{ + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { + ++in[3]; + } + } + } + surf(); + outleft = 8; + } + *buf = (uint8_t)out[--outleft]; + ++buf; + --n; + } +} diff --git a/scripts/ci/lint b/scripts/ci/lint index 406f00526..879ad13b2 100755 --- a/scripts/ci/lint +++ b/scripts/ci/lint @@ -85,7 +85,7 @@ check-spdx() success=false fi done - for file in $(git ls-files -- "*.[chsS]" "*.py" ":/!cbmc/*.py" ":/!examples/bring_your_own_fips202/custom_fips202/tiny_sha3/*"); do + for file in $(git ls-files -- "*.[chsS]" "*.py" ":/!cbmc/*.py" ":/!examples/bring_your_own_fips202/custom_fips202/tiny_sha3/*" ":/!examples/custom_backend/mlkem_native/fips202/native/custom/src/*"); do # Ignore symlinks if [[ ! -L $file && $(grep "Copyright (c) 2024 The mlkem-native project authors" $file | wc -l) == 0 ]]; then echo "::error file=$file,line=${line:-1},title=Missing copyright header error::$file is missing copyright header"