Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions BIBLIOGRAPHY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
6 changes: 6 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions examples/context_parameter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT

build
119 changes: 119 additions & 0 deletions examples/context_parameter/Makefile
Original file line number Diff line number Diff line change
@@ -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)
59 changes: 59 additions & 0 deletions examples/context_parameter/README.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions examples/context_parameter/auto.mk
77 changes: 77 additions & 0 deletions examples/context_parameter/example_context.c
Original file line number Diff line number Diff line change
@@ -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 <stdio.h>
#include <stdlib.h>

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);
}
52 changes: 52 additions & 0 deletions examples/context_parameter/example_context.h
Original file line number Diff line number Diff line change
@@ -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 <stddef.h>
#include <stdint.h>

/* 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 */
1 change: 1 addition & 0 deletions examples/context_parameter/expected_test_vectors.h
Loading
Loading