diff --git a/.github/workflows/base.yml b/.github/workflows/base.yml index 5edc5c0e76..c93f43f9e7 100644 --- a/.github/workflows/base.yml +++ b/.github/workflows/base.yml @@ -237,6 +237,9 @@ jobs: - name: basic run: | CFLAGS="-O0" make run -C examples/basic + - name: context_parameter + run: | + CFLAGS="-O0" make run -C examples/context_parameter - name: basic_deterministic run: | CFLAGS="-O0" make run -C examples/basic_deterministic diff --git a/BIBLIOGRAPHY.md b/BIBLIOGRAPHY.md index d69700bec7..1c226b1c6c 100644 --- a/BIBLIOGRAPHY.md +++ b/BIBLIOGRAPHY.md @@ -75,6 +75,7 @@ source code and documentation. - [examples/basic_lowram/mldsa_native/mldsa_native_config.h](examples/basic_lowram/mldsa_native/mldsa_native_config.h) - [examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h) - [examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h) + - [examples/context_parameter/mldsa_native/mldsa_native_config.h](examples/context_parameter/mldsa_native/mldsa_native_config.h) - [examples/custom_backend/mldsa_native/mldsa_native_config.h](examples/custom_backend/mldsa_native/mldsa_native_config.h) - [examples/monolithic_build/mldsa_native/mldsa_native_config.h](examples/monolithic_build/mldsa_native/mldsa_native_config.h) - [examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h](examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h) @@ -128,6 +129,7 @@ source code and documentation. - [examples/basic_lowram/mldsa_native/mldsa_native_config.h](examples/basic_lowram/mldsa_native/mldsa_native_config.h) - [examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h) - [examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h) + - [examples/context_parameter/mldsa_native/mldsa_native_config.h](examples/context_parameter/mldsa_native/mldsa_native_config.h) - [examples/custom_backend/mldsa_native/mldsa_native_config.h](examples/custom_backend/mldsa_native/mldsa_native_config.h) - [examples/monolithic_build/mldsa_native/mldsa_native_config.h](examples/monolithic_build/mldsa_native/mldsa_native_config.h) - [examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h](examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h) @@ -183,6 +185,7 @@ source code and documentation. - [examples/basic_lowram/mldsa_native/mldsa_native_config.h](examples/basic_lowram/mldsa_native/mldsa_native_config.h) - [examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202/mldsa_native/mldsa_native_config.h) - [examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h](examples/bring_your_own_fips202_static/mldsa_native/mldsa_native_config.h) + - [examples/context_parameter/mldsa_native/mldsa_native_config.h](examples/context_parameter/mldsa_native/mldsa_native_config.h) - [examples/custom_backend/mldsa_native/mldsa_native_config.h](examples/custom_backend/mldsa_native/mldsa_native_config.h) - [examples/monolithic_build/mldsa_native/mldsa_native_config.h](examples/monolithic_build/mldsa_native/mldsa_native_config.h) - [examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h](examples/monolithic_build_multilevel/mldsa_native/mldsa_native_config.h) diff --git a/Makefile b/Makefile index 89e5f19feb..9da7a013d9 100644 --- a/Makefile +++ b/Makefile @@ -314,6 +314,7 @@ EXAMPLE_DIRS := \ examples/bring_your_own_fips202_static \ examples/custom_backend \ examples/basic \ + examples/context_parameter \ examples/basic_deterministic \ examples/basic_lowram \ examples/monolithic_build \ diff --git a/examples/README.md b/examples/README.md index 0739a27583..ebd77afb21 100644 --- a/examples/README.md +++ b/examples/README.md @@ -49,6 +49,12 @@ custom FIPS-202 implementation using a static state. This variant demonstrates t See [custom_backend](custom_backend) for an example of how to use mldsa-native with a custom configuration file and a custom FIPS-202 backend. +## Context parameter + +See [context_parameter](context_parameter) for an example of adding an application context to the public API and using it +to pass a bump allocator to the custom allocation callbacks (`MLD_CONFIG_CONTEXT_PARAMETER`, +`MLD_CONFIG_CUSTOM_ALLOC_FREE`). + ## Monobuild (C only) See [monolithic_build](monolithic_build) for an example of how to build mldsa-native (with C backend) from a single diff --git a/examples/context_parameter/.gitignore b/examples/context_parameter/.gitignore new file mode 100644 index 0000000000..eb98a94f12 --- /dev/null +++ b/examples/context_parameter/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +build diff --git a/examples/context_parameter/Makefile b/examples/context_parameter/Makefile new file mode 100644 index 0000000000..274ad8ed39 --- /dev/null +++ b/examples/context_parameter/Makefile @@ -0,0 +1,119 @@ +# Copyright (c) The mlkem-native project authors +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +.PHONY: build run clean +.DEFAULT_GOAL := all + +CC ?= gcc + +# Adjust CFLAGS if needed +CFLAGS := \ + -Wall \ + -Wextra \ + -Werror=unused-result \ + -Wpedantic \ + -Werror \ + -Wmissing-prototypes \ + -Wshadow \ + -Wpointer-arith \ + -Wredundant-decls \ + -Wconversion \ + -Wsign-conversion \ + -Wno-long-long \ + -Wno-unknown-pragmas \ + -Wno-unused-command-line-argument \ + -O3 \ + -fomit-frame-pointer \ + -std=c99 \ + -pedantic \ + -MMD \ + $(CFLAGS) + +# If you want to use the native backends, the compiler needs to know about +# the target architecture. Here, we import the default host detection from +# mldsa-native's tests, but you can write your own or specialize accordingly. +AUTO ?= 1 +include auto.mk + +# The following only concerns the cross-compilation tests. +# You can likely ignore the following for your application. +# +# Append cross-prefix for cross compilation +# When called from the root Makefile, CROSS_PREFIX has already been added here +ifeq (,$(findstring $(CROSS_PREFIX),$(CC))) +CC := $(CROSS_PREFIX)$(CC) +endif + +# Part A: +# +# mldsa-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. +# +# In this example, we compile the individual mldsa-native source files directly. +# Alternatively, you can compile the 'monobuild' source file mldsa_native.c. +# See examples/monolithic_build for that. +MLD_SOURCE=$(wildcard \ + mldsa_native/src/*.c \ + mldsa_native/src/**/*.c \ + mldsa_native/src/**/**/*.c \ + mldsa_native/src/**/**/**/*.c) + +INC=-Imldsa_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=$(MLD_SOURCE) $(RNG_SOURCE) $(APP_SOURCE) + +BUILD_DIR=build +BIN=test_binary + +# +# Configuration adjustments +# + +# Pick prefix +CFLAGS += -DMLD_CONFIG_NAMESPACE_PREFIX=mldsa + +BINARY_NAME_FULL_44=$(BUILD_DIR)/$(BIN)44 +BINARY_NAME_FULL_65=$(BUILD_DIR)/$(BIN)65 +BINARY_NAME_FULL_87=$(BUILD_DIR)/$(BIN)87 +BINARIES_FULL=$(BINARY_NAME_FULL_44) $(BINARY_NAME_FULL_65) $(BINARY_NAME_FULL_87) + +$(BINARY_NAME_FULL_44): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 +$(BINARY_NAME_FULL_65): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 +$(BINARY_NAME_FULL_87): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 + +$(BINARIES_FULL): $(ALL_SOURCE) + echo "$@" + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(INC) $^ -o $@ + +all: build + +build: $(BINARIES_FULL) + +run: $(BINARIES_FULL) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_44) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_65) + $(EXEC_WRAPPER) ./$(BINARY_NAME_FULL_87) + +clean: + rm -rf $(BUILD_DIR) diff --git a/examples/context_parameter/README.md b/examples/context_parameter/README.md new file mode 100644 index 0000000000..9c894826a6 --- /dev/null +++ b/examples/context_parameter/README.md @@ -0,0 +1,59 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Context parameter + +This example shows how to add an application context to the mldsa-native public +API and pass it through to custom allocation callbacks. + +The example has the same functional coverage as `examples/basic`: it exercises +the randomized and deterministic key-generation and signing APIs, plus +verification, for all three ML-DSA parameter sets. + +## Configuration + +The generated configuration in +[`mldsa_native_config.h`](mldsa_native/mldsa_native_config.h) enables: + +- `MLD_CONFIG_CONTEXT_PARAMETER` +- `MLD_CONFIG_CONTEXT_PARAMETER_TYPE` +- `MLD_CONFIG_CUSTOM_ALLOC_FREE` + +Note that `MLD_CONFIG_CUSTOM_ALLOC_FREE` is marked experimental: its scope and +the signatures of `MLD_CUSTOM_ALLOC`/`MLD_CUSTOM_FREE` may still change. + +## The allocator + +The context in [`example_context.h`](example_context.h) holds a bump allocator +over a statically declared buffer. Two properties of mldsa-native's allocation +behavior keep it this simple: + +- **Deallocation happens in reverse order of allocation**, including when + unwinding after a failed allocation. So a single cursor suffices, and freeing + a block just moves the cursor back to its address; no per-allocation + bookkeeping is needed. See [`test_alloc.c`](../../test/src/test_alloc.c), + which empirically validates this contract for every allocation-failure point. +- **The total allocation per operation is known at compile time.** The buffer + is sized from `MLD_TOTAL_ALLOC_{44,65,87}`, published by + [`mldsa_native.h`](../../mldsa/mldsa_native.h) for exactly this purpose. + +### Alignment + +Memory handed to mldsa-native has to meet the alignment requirements of the +types it allocates. The strictest of those is 32 bytes, needed by the AVX2 +backend for its aligned loads (`vmovdqa`); the other backends need less. Rather +than track which backend is in use, this example is conservative and aligns +every allocation to 32 bytes. + +The buffer itself is declared with `EXAMPLE_ALIGN`, which mirrors the library's +internal `MLD_ALIGN` (see [`sys.h`](../../mldsa/src/sys.h)) — including its +fallback to no alignment on a toolchain that cannot express the constraint. + +## Usage + +```bash +make build +make run +``` + +The `randombytes()` implementation in `test_only_rng/` is for testing only. +Applications must provide a cryptographically secure RNG. diff --git a/examples/context_parameter/auto.mk b/examples/context_parameter/auto.mk new file mode 120000 index 0000000000..ce5c161cbf --- /dev/null +++ b/examples/context_parameter/auto.mk @@ -0,0 +1 @@ +../../test/mk/auto.mk \ No newline at end of file diff --git a/examples/context_parameter/example_context.c b/examples/context_parameter/example_context.c new file mode 100644 index 0000000000..65e4f6d45d --- /dev/null +++ b/examples/context_parameter/example_context.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include "example_context.h" + +#include +#include + +static size_t example_align_up(size_t n) +{ + return (n + (EXAMPLE_ALLOC_ALIGN - 1)) & ~(size_t)(EXAMPLE_ALLOC_ALIGN - 1); +} + +void example_context_init(example_context *context, uint8_t *buffer, + size_t buffer_size) +{ + if (buffer_size % EXAMPLE_ALLOC_ALIGN != 0) + { + fprintf(stderr, "ERROR: buffer size %u is not a multiple of %d\n", + (unsigned)buffer_size, EXAMPLE_ALLOC_ALIGN); + exit(1); + } + + context->buffer = buffer; + context->size = buffer_size; + context->used = 0; +} + +void *example_context_malloc(example_context *context, size_t size) +{ + size_t need; + uint8_t *ptr; + + /* Reject allocations that cannot even be accommodated by an empty + * allocator. Since `context->size` is aligned, this rules out overflow in + * the alignment below. */ + if (size > context->size) + { + return NULL; + } + + /* Round the request up so that every block stays aligned. */ + need = example_align_up(size); + + /* `used <= size` is an invariant, so the subtraction cannot underflow. + * Exhaustion is not an error here: returning NULL makes mldsa-native unwind + * and report MLD_ERR_OUT_OF_MEMORY. */ + if (need > context->size - context->used) + { + return NULL; + } + + ptr = context->buffer + context->used; + context->used += need; + return ptr; +} + +void example_context_free(example_context *context, void *ptr, size_t size) +{ + if (ptr == NULL) + { + return; + } + + /* mldsa-native frees in LIFO order, so the to-be-freed region must be a + * tail of the used memory region. To free it, we merely move the pointer. */ + if ((uint8_t *)ptr + example_align_up(size) != + context->buffer + context->used) + { + fprintf(stderr, "ERROR: free is not the most recent allocation\n"); + exit(1); + } + + context->used -= example_align_up(size); +} diff --git a/examples/context_parameter/example_context.h b/examples/context_parameter/example_context.h new file mode 100644 index 0000000000..0c5e6fcb70 --- /dev/null +++ b/examples/context_parameter/example_context.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#ifndef EXAMPLE_CONTEXT_H +#define EXAMPLE_CONTEXT_H + +#include +#include + +/* Alignment used for every allocation. 32 bytes is the strictest requirement + * of any type mldsa-native allocates -- the AVX2 backend needs it for its + * aligned loads, other backends need less -- and we are conservative and apply + * it throughout. mldsa-native's own MLD_DEFAULT_ALIGN carries the same value, + * but is internal to the library, so we restate it here. */ +#define EXAMPLE_ALLOC_ALIGN 32 + +/* This mirrors MLD_ALIGN from mldsa/src/sys.h, including the fallback to no + * alignment at all: on a toolchain that cannot express the constraint, the + * library's own buffers are equally unaligned, so we are no worse off. */ +#if defined(__GNUC__) +#define EXAMPLE_ALIGN __attribute__((aligned(EXAMPLE_ALLOC_ALIGN))) +#elif defined(_MSC_VER) +#define EXAMPLE_ALIGN __declspec(align(EXAMPLE_ALLOC_ALIGN)) +#else +#define EXAMPLE_ALIGN /* No known support for alignment constraints */ +#endif + +/* + * Application context threaded through the mldsa-native API. + * + * Here it holds a bump allocator: `buffer` is the base of the region, and + * `used` is the cursor bounding the part currently handed out. Since + * mldsa-native deallocates in reverse order of allocation, freeing is just a + * matter of moving the cursor back; no per-allocation bookkeeping is needed. + */ +typedef struct +{ + uint8_t *buffer; + size_t size; + size_t used; +} example_context; + +/* `buffer` must be declared with EXAMPLE_ALIGN, and `buffer_size` must be a + * multiple of EXAMPLE_ALLOC_ALIGN. */ +void example_context_init(example_context *context, uint8_t *buffer, + size_t buffer_size); + +void *example_context_malloc(example_context *context, size_t size); +void example_context_free(example_context *context, void *ptr, size_t size); + +#endif /* !EXAMPLE_CONTEXT_H */ diff --git a/examples/context_parameter/expected_test_vectors.h b/examples/context_parameter/expected_test_vectors.h new file mode 120000 index 0000000000..5c5d41ccb3 --- /dev/null +++ b/examples/context_parameter/expected_test_vectors.h @@ -0,0 +1 @@ +../../test/test_vectors/expected_test_vectors.h \ No newline at end of file diff --git a/examples/context_parameter/main.c b/examples/context_parameter/main.c new file mode 100644 index 0000000000..52fd4ff641 --- /dev/null +++ b/examples/context_parameter/main.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include +#include + +/* Import public mldsa-native API. This also pulls in example_context.h, + * which mldsa_native_config.h includes for the context parameter type. */ +#include +#include "expected_test_vectors.h" +#include "test_only_rng/notrandombytes.h" + +/* Convenience abbreviations for the key and signature sizes. + * + * Ordinarily you know the parameter set you're working with, so you would + * just use the level-specific constants directly, e.g. MLDSA44_PUBLICKEYBYTES, + * MLDSA65_BYTES, or MLDSA87_SECRETKEYBYTES. + * + * These examples, however, are compiled for all three parameter sets (44, 65, + * 87), so we keep things generic by deriving the sizes from the configured + * MLD_CONFIG_PARAMETER_SET. */ +#define MLDSA_PK_BYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#define MLDSA_SK_BYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET) +#define MLDSA_SIG_BYTES MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET) + +/* Size of the region the bump allocator hands out. + * + * MLD_TOTAL_ALLOC_{44,65,87} is published by mldsa_native.h precisely for this + * purpose: it is the maximum accumulated MLD_ALLOC usage across key generation, + * signing and verification, and it already accounts for the alignment rounding + * the allocator applies. So this buffer is exactly large enough, and no + * operation can run out of memory. */ +#if MLD_CONFIG_PARAMETER_SET == 44 +#define EXAMPLE_ALLOC_SIZE MLD_TOTAL_ALLOC_44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define EXAMPLE_ALLOC_SIZE MLD_TOTAL_ALLOC_65 +#else +#define EXAMPLE_ALLOC_SIZE MLD_TOTAL_ALLOC_87 +#endif + +static EXAMPLE_ALIGN uint8_t alloc_buffer[EXAMPLE_ALLOC_SIZE]; + +#define CHECK(x) \ + do \ + { \ + int rc; \ + rc = (x); \ + if (!rc) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +#if !defined(MLD_CONFIG_NO_KEYPAIR_API) +static int example_keygen(example_context *context) +{ + uint8_t pk[MLDSA_PK_BYTES]; + uint8_t sk[MLDSA_SK_BYTES]; + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) + printf("Generating keypair (randomized)... "); + CHECK(mldsa_keypair(pk, sk, context) == 0); + CHECK(memcmp(pk, test_vector_pk, MLDSA_PK_BYTES) == 0); + CHECK(memcmp(sk, test_vector_sk, MLDSA_SK_BYTES) == 0); + printf("DONE\n"); +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + + printf("Generating keypair (deterministic)... "); + CHECK(mldsa_keypair_internal(pk, sk, test_vector_rnd, context) == 0); + CHECK(memcmp(pk, test_vector_pk, MLDSA_PK_BYTES) == 0); + CHECK(memcmp(sk, test_vector_sk, MLDSA_SK_BYTES) == 0); + printf("DONE\n"); + return 0; +} +#else /* !MLD_CONFIG_NO_KEYPAIR_API */ +static int example_keygen(example_context *context) +{ + (void)context; + printf("Generating keypair... SKIPPED (keygen API disabled)\n"); + return 0; +} +#endif /* MLD_CONFIG_NO_KEYPAIR_API */ + +#if !defined(MLD_CONFIG_NO_SIGN_API) +static int example_sign(example_context *context) +{ + uint8_t sig[MLDSA_SIG_BYTES]; + uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES]; + size_t pre_len; + +#if !defined(MLD_CONFIG_NO_RANDOMIZED_API) + printf("Signing message (randomized)... "); + CHECK(mldsa_signature(sig, (const uint8_t *)TEST_VECTOR_MSG, + TEST_VECTOR_MSG_LEN, (const uint8_t *)TEST_VECTOR_CTX, + TEST_VECTOR_CTX_LEN, test_vector_sk, context) == 0); + CHECK(memcmp(sig, test_vector_sig, sizeof(test_vector_sig)) == 0); + printf("DONE\n"); +#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */ + + printf("Signing message (deterministic)... "); + /* prepare_domain_separation_prefix does not allocate and takes no context. */ + pre_len = mldsa_prepare_domain_separation_prefix( + pre, NULL, 0, (const uint8_t *)TEST_VECTOR_CTX, TEST_VECTOR_CTX_LEN, + MLD_PREHASH_NONE); + CHECK(pre_len != 0); + CHECK(mldsa_signature_internal( + sig, (const uint8_t *)TEST_VECTOR_MSG, TEST_VECTOR_MSG_LEN, pre, + pre_len, test_vector_rnd, test_vector_sk, 0, context) == 0); + CHECK(memcmp(sig, test_vector_sig, sizeof(test_vector_sig)) == 0); + printf("DONE\n"); + return 0; +} +#else /* !MLD_CONFIG_NO_SIGN_API */ +static int example_sign(example_context *context) +{ + (void)context; + printf("Signing message... SKIPPED (sign API disabled)\n"); + return 0; +} +#endif /* MLD_CONFIG_NO_SIGN_API */ + +#if !defined(MLD_CONFIG_NO_VERIFY_API) +static int example_verify(example_context *context) +{ + printf("Verifying signature... "); + CHECK(mldsa_verify(test_vector_sig, (const uint8_t *)TEST_VECTOR_MSG, + TEST_VECTOR_MSG_LEN, (const uint8_t *)TEST_VECTOR_CTX, + TEST_VECTOR_CTX_LEN, test_vector_pk, context) == 0); + printf("DONE\n"); + return 0; +} +#else /* !MLD_CONFIG_NO_VERIFY_API */ +static int example_verify(example_context *context) +{ + (void)context; + printf("Verifying signature... SKIPPED (verify API disabled)\n"); + return 0; +} +#endif /* MLD_CONFIG_NO_VERIFY_API */ + +int main(void) +{ + int r = 0; + example_context context; + + printf("ML-DSA-%d, %d byte allocation buffer\n", MLD_CONFIG_PARAMETER_SET, + (int)EXAMPLE_ALLOC_SIZE); + example_context_init(&context, alloc_buffer, sizeof(alloc_buffer)); + + /* WARNING: Test-only + * Normally, you would seed a PRNG _once_ with trustworthy entropy and not + * reseed it afterwards. Here, we reseed before each API call to make each + * test independent and reproducible even when some API is disabled. */ + randombytes_reset(); + r |= example_keygen(&context); + CHECK(context.used == 0); + randombytes_reset(); + r |= example_sign(&context); + CHECK(context.used == 0); + r |= example_verify(&context); + CHECK(context.used == 0); + + return r; +} diff --git a/examples/context_parameter/mldsa_native/mldsa_native.h b/examples/context_parameter/mldsa_native/mldsa_native.h new file mode 120000 index 0000000000..f251913364 --- /dev/null +++ b/examples/context_parameter/mldsa_native/mldsa_native.h @@ -0,0 +1 @@ +../../../mldsa/mldsa_native.h \ No newline at end of file diff --git a/examples/context_parameter/mldsa_native/mldsa_native_config.h b/examples/context_parameter/mldsa_native/mldsa_native_config.h new file mode 100644 index 0000000000..49f2d2de85 --- /dev/null +++ b/examples/context_parameter/mldsa_native/mldsa_native_config.h @@ -0,0 +1,876 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + * + * - [FIPS204_UPDATES] + * FIPS 204 Potential Updates (Errata) + * National Institute of Standards and Technology + * https://csrc.nist.gov/files/pubs/fips/204/final/docs/fips-204-potential-updates.xlsx + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Configuration with a context parameter and custom + * allocation + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_CONTEXT_PARAMETER + * - MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * - MLD_CONFIG_CUSTOM_ALLOC_FREE + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/** + * MLD_CONFIG_PARAMETER_SET + * + * Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + */ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/** + * MLD_CONFIG_FILE + * + * If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * than configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + */ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/** + * MLD_CONFIG_NAMESPACE_PREFIX + * + * The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + */ +#define MLD_CONFIG_NAMESPACE_PREFIX mldsa + +/** + * MLD_CONFIG_MULTILEVEL_BUILD + * + * Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + */ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/** + * MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + */ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/** + * MLD_CONFIG_NO_KEYPAIR_API + * + * By default, mldsa-native includes support for generating key + * pairs. If you don't need this, set MLD_CONFIG_NO_KEYPAIR_API + * to exclude keypair, keypair_internal, + * pk_from_sk, and all internal APIs only needed by + * those functions. + */ +/* #define MLD_CONFIG_NO_KEYPAIR_API */ + +/** + * MLD_CONFIG_NO_SIGN_API + * + * By default, mldsa-native includes support for creating + * signatures. If you don't need this, set MLD_CONFIG_NO_SIGN_API + * to exclude signature, + * signature_extmu, signature_internal, + * signature_pre_hash_internal, + * signature_pre_hash_shake256, and all internal APIs + * only needed by those functions. + */ +/* #define MLD_CONFIG_NO_SIGN_API */ + +/** + * MLD_CONFIG_NO_VERIFY_API + * + * By default, mldsa-native includes support for verifying + * signatures. If you don't need this, set + * MLD_CONFIG_NO_VERIFY_API to exclude verify, + * verify_extmu, verify_internal, + * verify_pre_hash_internal, + * verify_pre_hash_shake256, and all internal APIs + * only needed by those functions. + */ +/* #define MLD_CONFIG_NO_VERIFY_API */ + +/** + * MLD_CONFIG_CORE_API_ONLY + * + * Set this to remove all public APIs except + * keypair_internal, signature_internal, + * and verify_internal. + */ +/* #define MLD_CONFIG_CORE_API_ONLY */ + +/** + * MLD_CONFIG_NO_RANDOMIZED_API + * + * If this option is set, mldsa-native will be built without the + * randomized API functions (keypair, + * signature, and signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (keypair_internal, signature_internal). + * + * @note This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * signature(). + */ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/** + * MLD_CONFIG_CONSTANTS_ONLY + * + * If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + */ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/** + * MLD_CONFIG_KEYGEN_PCT + * + * Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, keypair_internal and + * keypair will return MLD_ERR_PCT_FAIL if the + * PCT failed. + * + * @note This feature will drastically lower the performance of + * key generation. + * + * @note This option is incompatible with MLD_CONFIG_NO_SIGN_API + * and MLD_CONFIG_NO_VERIFY_API as the current PCT implementation + * requires signature() and verify(). + */ +/* #define MLD_CONFIG_KEYGEN_PCT */ + +/** + * MLD_CONFIG_CONTEXT_PARAMETER + * + * Set this to add a caller-supplied context parameter to the public API + * functions, which is then forwarded unchanged to the custom callbacks + * (allocation, and signing hooks below). + * + * When this option is set, every public API function gains a trailing + * parameter + * + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE context + * + * as its last argument; its type is configured via + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE (see below). mldsa-native treats this + * value as opaque: it never dereferences it and only passes it on to the + * configurable hook macros. It is meant to carry per-caller state -- e.g. a + * pointer to a memory pool for the allocation hooks, or the resume state for + * the signing hooks -- into those hooks. + * + * When this option is unset (the default), no extra parameter is added and + * the hook macros never receive a context argument. + * + * The hooks that receive the context are the allocation hooks (see + * MLD_CONFIG_CUSTOM_ALLOC_FREE) and the signing hooks (see + * MLD_CONFIG_SIGN_HOOK_RESUME / _ATTEMPT / _FINISH); each is documented with + * its own option below. + */ +#define MLD_CONFIG_CONTEXT_PARAMETER +#if !defined(__ASSEMBLER__) +#include "../example_context.h" +#endif + + +/** + * MLD_CONFIG_CONTEXT_PARAMETER_TYPE + * + * Set this to define the type of the context parameter added by + * MLD_CONFIG_CONTEXT_PARAMETER. It can be any C type usable as a function + * parameter, e.g. `void *` or a pointer to a caller-defined struct such as + * `struct my_ctx *`. + * + * This option must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is + * defined; defining one without the other is a compile-time error. + */ +#define MLD_CONFIG_CONTEXT_PARAMETER_TYPE example_context * + +/** + * MLD_CONFIG_REDUCE_RAM + * + * Set this to reduce RAM usage. This trades memory for performance. + * + * For expected memory usage, see the MLD_TOTAL_ALLOC_* constants defined in + * mldsa_native.h. + * + * This option is useful for embedded systems with tight RAM constraints but + * relaxed performance requirements. + * + */ +/* #define MLD_CONFIG_REDUCE_RAM */ +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ +#if defined(MLD_BUILD_INTERNAL) + +/** + * MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: mld_polyw1_pack_88 is only needed for + * MLD_CONFIG_PARAMETER_SET == 44. Yet, if this option is set for a + * build with MLD_CONFIG_PARAMETER_SET == 65/87, it would be included. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + */ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/** + * MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + */ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/** + * MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the end of the SCU file. This is + * needed in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + */ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/** + * MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Determines whether a native arithmetic backend should be used. + * + * The arithmetic backend covers performance-critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be used is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + */ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/** + * MLD_CONFIG_ARITH_BACKEND_FILE + * + * The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + */ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/** + * MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Determines whether a native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be used is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + */ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/** + * MLD_CONFIG_FIPS202_BACKEND_FILE + * + * The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + */ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/** + * MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + */ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/** + * MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + */ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/** + * MLD_CONFIG_CUSTOM_ZEROIZE + * + * In compliance with @[FIPS204, Section 3.6.3], mldsa-native zeroizes + * intermediate buffers before returning from function calls. By default, + * those buffers are allocated from the stack; if MLD_CONFIG_CUSTOM_ALLOC_FREE + * is set, they are (mostly -- few exceptions remain at present) allocated from + * the configured custom allocator. + * + * mldsa-native also zeroizes caller-owned output buffers as needed to uphold + * the API convention that outputs be either unmodified or zeroized upon + * failure. + * + * Set this option and define `mld_zeroize` if you want to use a custom + * method to zeroize intermediate and output buffers. + * + * The default implementation uses SecureZeroMemory on Windows and a + * memset + compiler barrier otherwise. If neither of those is available on + * the target platform, compilation will fail, and you will need to use + * MLD_CONFIG_CUSTOM_ZEROIZE to provide a custom implementation of + * `mld_zeroize()`. + * + * @warning + * The zeroization conducted by mldsa-native reduces the likelihood of data + * leaking on the stack or custom allocators, but it does not eliminate it. + * For example, the C standard makes no guarantee about where a compiler + * allocates local structures and whether/where it makes copies of them. + * Also, in addition to entire structures, there may also be potentially + * exploitable leakage of individual values on the stack. If you need + * bullet-proof zeroization of the stack, you need to consider additional + * measures instead of what this feature provides. In this case, you can + * set mld_zeroize to a no-op. Note that in this case you are also responsible + * for zeroizing output buffers upon failure. + */ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/** + * MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to be provided by + * the consumer. + * + * If this option is not set, mldsa-native expects a function + * int randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + */ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + return 0; + } + #endif +*/ + +/** + * MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heterogeneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decide whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * Return value 1 indicates that a capability is supported. + * Return value 0 indicates that a capability is not supported. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + */ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/** + * MLD_CONFIG_CUSTOM_ALLOC_FREE + * + * Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * @warning This option is experimental. Its scope, configuration and + * function/macro signatures may change at any time. We expect a + * stable API in a future version. + * + * @note Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * @note MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + */ +#define MLD_CONFIG_CUSTOM_ALLOC_FREE +#if !defined(__ASSEMBLER__) +#define MLD_CUSTOM_ALLOC(v, T, N, context) \ + T *v = example_context_malloc((context), sizeof(T) * (N)) +#define MLD_CUSTOM_FREE(v, T, N, context) \ + example_context_free((context), (v), sizeof(T) * (N)) +#endif /* !__ASSEMBLER__ */ + + +/** + * MLD_CONFIG_CUSTOM_MEMCPY + * + * Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + */ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/** + * MLD_CONFIG_CUSTOM_MEMSET + * + * Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + */ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/** + * MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * If set, this option provides an additional qualifier + * to be added to declarations of internal API functions and data. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + */ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/** + * MLD_CONFIG_CT_TESTING_ENABLED + * + * If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + */ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/** + * MLD_CONFIG_NO_ASM + * + * If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + */ +/* #define MLD_CONFIG_NO_ASM */ + +/** + * MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + */ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/** + * MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + */ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/** + * MLD_CONFIG_MAX_SIGNING_ATTEMPTS + * + * Upper bound on the number of rejection-sampling iterations + * performed by ML-DSA signing (@[FIPS204, Algorithm 7]). + * + * If a valid signature is not produced within this many + * attempts, signing returns MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED. + * This is useful in timing-sensitive environments that + * require a deterministic worst-case bound on signing time. + * + * For FIPS 204 compliance, this value MUST be at least 821, + * cf. @[FIPS204, Appendix C] and @[FIPS204_UPDATES], which is + * chosen so that the signing failure rate is < 2^{-256}. + * + * Default: Largest possible value before internal counters + * would overflow. This is larger than the FIPS204 bound. + * + * In particular, in the default configuration, the signing + * failure rate is < 2^{-256}. + */ +/* #define MLD_CONFIG_MAX_SIGNING_ATTEMPTS 821 */ + +/** + * MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * @note Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + */ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/** + * Signing hooks: MLD_CONFIG_SIGN_HOOK_RESUME / _ATTEMPT / _FINISH + * + * Three optional, independent hooks into the ML-DSA signing rejection-sampling + * loop. Each is enabled by defining the matching option, in which case the + * integration must provide the corresponding function. If a hook needs + * per-operation state, enable MLD_CONFIG_CONTEXT_PARAMETER; the context is then + * appended as the last argument. + * + * @warning This feature is experimental. Its scope, configuration and + * function signatures may change at any time, including after v2. + * + * Enabling any of the hooks requires MLD_CONFIG_NO_RANDOMIZED_API (restricting + * the public API to deterministic operations). This is because the restartable + * signing as enabled by the signing hooks only produces the uninterrupted + * signature when the randomness is fixed across calls. A logging-only use + * (attempt always returns 0; resume/finish merely observe) would be safe with + * the randomized API too, but for now the requirement is imposed uniformly on + * all three hooks. + * + * Note: Randomized signing is a shim wrapper around deterministic signing, and + * all helper functions you need to build it are exposed publicly. Thus, if you + * need a restartable, randomized signing operation, you can build your own by + * replicating the logic and adding the RNG seed to the restart context. In this + * case, please also consider letting the mldsa-native maintainers know of your + * need for randomized, restartable signing, so the feature can be appropriately + * prioritized. + * + * - MLD_CONFIG_SIGN_HOOK_ATTEMPT: int mld_sign_hook_attempt(attempt[, ctxt]) + * Called before each attempt. Returns 0 to proceed, or non-zero to pause: + * signing then returns MLD_ERR_SIGNING_PAUSED with `attempt` as the resume + * point (needs MLD_CONFIG_SIGN_HOOK_RESUME to resume; otherwise just aborts). + * Always returning 0 makes it a logging/benchmarking hook. + * + * - MLD_CONFIG_SIGN_HOOK_RESUME: uint16_t mld_sign_hook_resume([ctxt]) + * Returns the attempt to resume from (0 for a fresh operation), i.e. the one + * recorded when a previous call paused. + * + * - MLD_CONFIG_SIGN_HOOK_FINISH: void mld_sign_hook_finish(attempt[, ctxt]) + * Called on success with the succeeding attempt. Observe-only. + * + * When an option is unset, the hook is a no-op (resume to 0, attempt proceeds), + * i.e. ordinary one-shot signing. + * + * Independent of MLD_CONFIG_MAX_SIGNING_ATTEMPTS, which is a static upper bound + * on the number of signing attempts. + * + * See test/src/test_sign_hook.c for a worked example using all three. + */ +/* #define MLD_CONFIG_SIGN_HOOK_RESUME + #define MLD_CONFIG_SIGN_HOOK_ATTEMPT + #define MLD_CONFIG_SIGN_HOOK_FINISH + #if !defined(__ASSEMBLER__) + #include + #include "src/sys.h" + static MLD_INLINE uint16_t mld_sign_hook_resume(void) + { + ... return the attempt to resume from ... + } + static MLD_INLINE int mld_sign_hook_attempt(uint16_t attempt) + { + ... return non-zero to pause here; for resume, store attempt ... + return 0; + } + static MLD_INLINE void mld_sign_hook_finish(uint16_t attempt) + { + ... mark the operation complete (attempt = successful attempt) ... + } + #endif +*/ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if defined(MLD_CONFIG_MULTILEVEL_BUILD) +/* In a multi-level build the parameter set is appended by the namespacing + * machinery, so the default prefix must not embed it. */ +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA +#elif MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */ diff --git a/examples/context_parameter/mldsa_native/src b/examples/context_parameter/mldsa_native/src new file mode 120000 index 0000000000..3fd9af3d70 --- /dev/null +++ b/examples/context_parameter/mldsa_native/src @@ -0,0 +1 @@ +../../../mldsa/src/ \ No newline at end of file diff --git a/examples/context_parameter/test_only_rng/notrandombytes.c b/examples/context_parameter/test_only_rng/notrandombytes.c new file mode 120000 index 0000000000..65b7801b83 --- /dev/null +++ b/examples/context_parameter/test_only_rng/notrandombytes.c @@ -0,0 +1 @@ +../../../test/notrandombytes/notrandombytes.c \ No newline at end of file diff --git a/examples/context_parameter/test_only_rng/notrandombytes.h b/examples/context_parameter/test_only_rng/notrandombytes.h new file mode 120000 index 0000000000..e72c12b9cd --- /dev/null +++ b/examples/context_parameter/test_only_rng/notrandombytes.h @@ -0,0 +1 @@ +../../../test/notrandombytes/notrandombytes.h \ No newline at end of file diff --git a/mldsa/mldsa_native.h b/mldsa/mldsa_native.h index a38a2c4154..0118ab7c17 100644 --- a/mldsa/mldsa_native.h +++ b/mldsa/mldsa_native.h @@ -128,11 +128,7 @@ * string longer than 255 bytes. */ #define MLD_ERR_INVALID_ARG (-9) -/********************* Namespacing and Qualifiers *****************************/ - -#define MLD_API_CONCAT_(x, y) x##y -#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) -#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) +/****************************** Configuration *********************************/ /* You need to make sure the config file is in the include path. */ #if defined(MLD_CONFIG_FILE) @@ -141,6 +137,32 @@ #include "mldsa_native_config.h" #endif +/* Hash algorithm constants for domain separation */ +#define MLD_PREHASH_NONE 0 +#define MLD_PREHASH_SHA2_224 1 +#define MLD_PREHASH_SHA2_256 2 +#define MLD_PREHASH_SHA2_384 3 +#define MLD_PREHASH_SHA2_512 4 +#define MLD_PREHASH_SHA2_512_224 5 +#define MLD_PREHASH_SHA2_512_256 6 +#define MLD_PREHASH_SHA3_224 7 +#define MLD_PREHASH_SHA3_256 8 +#define MLD_PREHASH_SHA3_384 9 +#define MLD_PREHASH_SHA3_512 10 +#define MLD_PREHASH_SHAKE_128 11 +#define MLD_PREHASH_SHAKE_256 12 + +/* Maximum formatted domain separation message length */ +#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) + +/********************* Namespacing and Qualifiers *****************************/ + +#if !defined(MLD_CONFIG_CONSTANTS_ONLY) + +#define MLD_API_CONCAT_(x, y) x##y +#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y) +#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y) + /* Namespace prefix for the public API symbols. For multi-level builds, the * parameter set is appended to disambiguate the security levels. */ #if defined(MLD_CONFIG_MULTILEVEL_BUILD) @@ -165,28 +187,8 @@ #define MLD_API_QUALIFIER #endif -/* Hash algorithm constants for domain separation */ -#define MLD_PREHASH_NONE 0 -#define MLD_PREHASH_SHA2_224 1 -#define MLD_PREHASH_SHA2_256 2 -#define MLD_PREHASH_SHA2_384 3 -#define MLD_PREHASH_SHA2_512 4 -#define MLD_PREHASH_SHA2_512_224 5 -#define MLD_PREHASH_SHA2_512_256 6 -#define MLD_PREHASH_SHA3_224 7 -#define MLD_PREHASH_SHA3_256 8 -#define MLD_PREHASH_SHA3_384 9 -#define MLD_PREHASH_SHA3_512 10 -#define MLD_PREHASH_SHAKE_128 11 -#define MLD_PREHASH_SHAKE_256 12 - -/* Maximum formatted domain separation message length */ -#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64) - /****************************** Function API **********************************/ -#if !defined(MLD_CONFIG_CONSTANTS_ONLY) - #include #include diff --git a/scripts/tests b/scripts/tests index 59a512acb0..696519cb1a 100755 --- a/scripts/tests +++ b/scripts/tests @@ -219,6 +219,7 @@ class TEST_TYPES(Enum): ABICHECK = 24 SIGN_HOOK = 25 RESTARTABLE_SIGN = 26 + CONTEXT_PARAMETER = 27 def is_benchmark(self): return self in [TEST_TYPES.BENCH, TEST_TYPES.BENCH_COMPONENTS] @@ -233,6 +234,7 @@ class TEST_TYPES(Enum): TEST_TYPES.BRING_YOUR_OWN_FIPS202_STATIC, TEST_TYPES.CUSTOM_BACKEND, TEST_TYPES.BASIC, + TEST_TYPES.CONTEXT_PARAMETER, TEST_TYPES.MONOLITHIC_BUILD, TEST_TYPES.MONOLITHIC_BUILD_NATIVE, TEST_TYPES.MONOLITHIC_BUILD_MULTILEVEL, @@ -279,6 +281,8 @@ class TEST_TYPES(Enum): return "Example (Custom Backend)" if self == TEST_TYPES.BASIC: return "Example (mldsa-native as code package)" + if self == TEST_TYPES.CONTEXT_PARAMETER: + return "Example (context parameter)" if self == TEST_TYPES.BASIC_DETERMINISTIC: return "Example (mldsa-native as code package without randombytes() implementation)" if self == TEST_TYPES.BASIC_LOWRAM: @@ -319,6 +323,8 @@ class TEST_TYPES(Enum): return "examples/custom_backend" if self == TEST_TYPES.BASIC: return "examples/basic" + if self == TEST_TYPES.CONTEXT_PARAMETER: + return "examples/context_parameter" if self == TEST_TYPES.BASIC_DETERMINISTIC: return "examples/basic_deterministic" if self == TEST_TYPES.BASIC_LOWRAM: @@ -362,6 +368,8 @@ class TEST_TYPES(Enum): return "" if self == TEST_TYPES.BASIC: return "" + if self == TEST_TYPES.CONTEXT_PARAMETER: + return "" if self == TEST_TYPES.BASIC_DETERMINISTIC: return "" if self == TEST_TYPES.BASIC_LOWRAM: @@ -1321,6 +1329,7 @@ def cli(): "bring_your_own_fips202_static", "custom_backend", "basic", + "context_parameter", "basic_deterministic", "basic_lowram", "restartable_sign", @@ -1438,6 +1447,7 @@ def cli(): "bring_your_own_fips202_static", "custom_backend", "basic", + "context_parameter", "basic_deterministic", "basic_lowram", "restartable_sign", diff --git a/test/configs/configs.yml b/test/configs/configs.yml index 1bcfbd88c1..234db63080 100644 --- a/test/configs/configs.yml +++ b/test/configs/configs.yml @@ -418,6 +418,29 @@ configs: MLD_CONFIG_FILE: comment: "/* No need to set this -- we _are_ already in a custom config */" + - path: examples/context_parameter/mldsa_native/mldsa_native_config.h + description: "Configuration with a context parameter and custom allocation" + defines: + MLD_CONFIG_NAMESPACE_PREFIX: mldsa + MLD_CONFIG_CONTEXT_PARAMETER: + content: | + #define MLD_CONFIG_CONTEXT_PARAMETER + #if !defined(__ASSEMBLER__) + #include "../example_context.h" + #endif /* !__ASSEMBLER__ */ + MLD_CONFIG_CONTEXT_PARAMETER_TYPE: example_context * + MLD_CONFIG_CUSTOM_ALLOC_FREE: + content: | + #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #define MLD_CUSTOM_ALLOC(v, T, N, context) \ + T *v = example_context_malloc((context), sizeof(T) * (N)) + #define MLD_CUSTOM_FREE(v, T, N, context) \ + example_context_free((context), (v), sizeof(T) * (N)) + #endif /* !__ASSEMBLER__ */ + MLD_CONFIG_FILE: + comment: "/* No need to set this -- we _are_ already in a custom config */" + - path: examples/basic_lowram/mldsa_native/mldsa_native_config.h description: "Configuration for low RAM build of mldsa-native" defines: @@ -492,14 +515,18 @@ configs: description: "Using custom allocation that can be made fail at specific invocation" defines: MLD_CONFIG_NAMESPACE_PREFIX: mld - MLD_CONFIG_CONTEXT_PARAMETER: true + MLD_CONFIG_CONTEXT_PARAMETER: + content: | + #define MLD_CONFIG_CONTEXT_PARAMETER + #if !defined(__ASSEMBLER__) + struct test_ctx_t; /* Forward declaration */ + #endif /* !__ASSEMBLER__ */ MLD_CONFIG_CONTEXT_PARAMETER_TYPE: struct test_ctx_t * MLD_CONFIG_CUSTOM_ALLOC_FREE: content: | #define MLD_CONFIG_CUSTOM_ALLOC_FREE #if !defined(__ASSEMBLER__) #include - struct test_ctx_t; /* Forward declaration */ void * custom_alloc(struct test_ctx_t *ctx, size_t sz, const char *file, int line, const char *var, const char *type); void custom_free(struct test_ctx_t *ctx, void *p, size_t sz, const char *file, int line, const char *var, const char *type); #define MLD_CUSTOM_ALLOC(v, T, N, ctx) T *v = custom_alloc(ctx, sizeof(T)*(N), __FILE__, __LINE__, #v, #T) diff --git a/test/configs/test_alloc_config.h b/test/configs/test_alloc_config.h index 0478efa983..09973b86eb 100644 --- a/test/configs/test_alloc_config.h +++ b/test/configs/test_alloc_config.h @@ -252,6 +252,10 @@ * its own option below. */ #define MLD_CONFIG_CONTEXT_PARAMETER +#if !defined(__ASSEMBLER__) +struct test_ctx_t; /* Forward declaration */ +#endif + /** * MLD_CONFIG_CONTEXT_PARAMETER_TYPE @@ -599,7 +603,6 @@ #define MLD_CONFIG_CUSTOM_ALLOC_FREE #if !defined(__ASSEMBLER__) #include -struct test_ctx_t; /* Forward declaration */ void *custom_alloc(struct test_ctx_t *ctx, size_t sz, const char *file, int line, const char *var, const char *type); void custom_free(struct test_ctx_t *ctx, void *p, size_t sz, const char *file,