Skip to content

Commit e1f2117

Browse files
committed
Example: add the multilevel_build_no_stdlib example
- This commit add an example demonstrating how to build mlkem-native without the standard library (-nostdlib) - Create an example folder named `multilevel_build_no_stdlib` - Add the `example_no_stdlib_config.h` reference from `test/custom_stdlib_config.h`, this config provide custom implementations for mlk_memcpy and mlk_memset - Add the `-nostdlib` cflag during generating objects file. - Integrate this example to the `tests` script and ./Makefile - Add this example to the `base.yml` for CI testing Signed-off-by: willieyz <[email protected]>
1 parent 91f1927 commit e1f2117

File tree

16 files changed

+910
-2
lines changed

16 files changed

+910
-2
lines changed

.github/workflows/base.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,9 @@ jobs:
254254
- name: multilevel_build_native
255255
run: |
256256
CFLAGS="-O0" make run -C examples/multilevel_build_native
257+
- name: multilevel_build_no_stdlib
258+
run: |
259+
CFLAGS="-O0" make run -C examples/multilevel_build_no_stdlib
257260
simpasm:
258261
strategy:
259262
fail-fast: false

BIBLIOGRAPHY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ source code and documentation.
2727
* URL: https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements
2828
* Referenced from:
2929
- [examples/basic_deterministic/mlkem_native/custom_no_randomized_config.h](examples/basic_deterministic/mlkem_native/custom_no_randomized_config.h)
30+
- [examples/multilevel_build_no_stdlib/mlkem_native/example_no_stdlib_config.h](examples/multilevel_build_no_stdlib/mlkem_native/example_no_stdlib_config.h)
3031
- [integration/liboqs/config_aarch64.h](integration/liboqs/config_aarch64.h)
3132
- [integration/liboqs/config_c.h](integration/liboqs/config_c.h)
3233
- [integration/liboqs/config_x86_64.h](integration/liboqs/config_x86_64.h)

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,4 @@ clean:
225225
-make clean -C examples/monolithic_build_multilevel_native >/dev/null
226226
-make clean -C examples/multilevel_build >/dev/null
227227
-make clean -C examples/multilevel_build_native >/dev/null
228+
-make clean -C examples/multilevel_build_no_stdlib > /dev/null

examples/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ See [basic_deterministic](basic_deterministic) for a basic example of how to bui
1616
See [multilevel_build](multilevel_build) for an example of how to build one instance of mlkem-native per security level,
1717
in such a way that level-independent code is shared.
1818

19+
## Multi-level build without the standard library (C only)
20+
21+
See multilevel_build_no_stdlib for an example of how to build one instance of mlkem-native per security level without the standard library.
22+
In this example, `mlk_memcpy` and `mlk_memset` are replaced with custom implementations through [custom_no_stdlib_config.h](../test/custom_stdlib_config.h).
23+
1924
## Multi-level build (with native code)
2025

2126
See [multilevel_build_native](multilevel_build_native) for an example of how to build one instance of mlkem-native per

examples/multilevel_build/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ CFLAGS := \
8989
-Wno-unknown-pragmas \
9090
-Wno-unused-command-line-argument \
9191
-fomit-frame-pointer \
92-
-DMLK_CONFIG_NAMESPACE_PREFIX=mlkem \
92+
-DMLK_CONFIG_NAMESPACE_PREFIX=mlkem \
9393
-std=c99 \
9494
-pedantic \
9595
-MMD \
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
2+
3+
build
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# (SPDX-License-Identifier: CC-BY-4.0)
2+
3+
.PHONY: build run clean mlkem512_objs mlkem768_objs mlkem1024_objs mlkem_objs size size_objs
4+
.DEFAULT_GOAL := all
5+
6+
Q ?= @
7+
# Append cross-prefix for cross compilation
8+
# Remove or ignore for native builds
9+
CC ?= gcc
10+
SIZE ?= size
11+
# When called from the root Makefile, CROSS_PREFIX has already been added here
12+
ifeq (,$(findstring $(CROSS_PREFIX),$(CC)))
13+
CC := $(CROSS_PREFIX)$(CC)
14+
endif
15+
16+
ifeq (,$(findstring $(CROSS_PREFIX),$(SIZE)))
17+
SIZE := $(CROSS_PREFIX)$(SIZE)
18+
endif
19+
20+
# Part A:
21+
#
22+
# mlkem-native source and header files
23+
#
24+
# If you are not concerned about minimizing for a specific backend,
25+
# you can just include _all_ source files into your build.
26+
MLK_SOURCE_ALL := $(wildcard \
27+
mlkem_native/mlkem/src/*.c \
28+
mlkem_native/mlkem/src/**/*.c \
29+
mlkem_native/mlkem/src/**/**/*.c \
30+
mlkem_native/mlkem/src/**/**/**/*.c)
31+
MLK_SOURCE:=$(foreach S,$(MLK_SOURCE_ALL),\
32+
$(if $(findstring /native/,$S),,$S))
33+
34+
INC=-Imlkem_native -Imlkem_native/mlkem -Imlkem_native/mlkem/src
35+
36+
BUILD_DIR=build
37+
MLKEM512_DIR = $(BUILD_DIR)/mlkem512
38+
MLKEM768_DIR = $(BUILD_DIR)/mlkem768
39+
MLKEM1024_DIR = $(BUILD_DIR)/mlkem1024
40+
41+
MLKEM512_OBJS=$(patsubst %,$(MLKEM512_DIR)/%.o,$(MLK_SOURCE))
42+
MLKEM768_OBJS=$(patsubst %,$(MLKEM768_DIR)/%.o,$(MLK_SOURCE))
43+
MLKEM1024_OBJS=$(patsubst %,$(MLKEM1024_DIR)/%.o,$(MLK_SOURCE))
44+
45+
$(MLKEM512_OBJS): $(MLKEM512_DIR)/%.c.o: %.c
46+
$(Q)[ -d $(@D) ] || mkdir -p $(@D)
47+
$(Q)$(CC) -nostdlib -DMLK_CONFIG_MULTILEVEL_WITH_SHARED -DMLK_CONFIG_PARAMETER_SET=512 $(INC) $(CFLAGS) -c $^ -o $@
48+
49+
$(MLKEM768_OBJS): $(MLKEM768_DIR)/%.c.o: %.c
50+
$(Q)[ -d $(@D) ] || mkdir -p $(@D)
51+
$(Q)$(CC) -nostdlib -DMLK_CONFIG_MULTILEVEL_NO_SHARED -DMLK_CONFIG_PARAMETER_SET=768 $(INC) $(CFLAGS) -c $^ -o $@
52+
53+
$(MLKEM1024_OBJS): $(MLKEM1024_DIR)/%.c.o: %.c
54+
$(Q)[ -d $(@D) ] || mkdir -p $(@D)
55+
$(Q)$(CC) -nostdlib -DMLK_CONFIG_MULTILEVEL_NO_SHARED -DMLK_CONFIG_PARAMETER_SET=1024 $(INC) $(CFLAGS) -c $^ -o $@
56+
57+
mlkem512_objs: $(MLKEM512_OBJS)
58+
mlkem768_objs: $(MLKEM768_OBJS)
59+
mlkem1024_objs: $(MLKEM1024_OBJS)
60+
mlkem_objs: mlkem512_objs mlkem768_objs mlkem1024_objs
61+
62+
# Part B:
63+
#
64+
# Random number generator
65+
#
66+
# !!! WARNING !!!
67+
#
68+
# The randombytes() implementation used here is for TESTING ONLY.
69+
# You MUST NOT use this implementation outside of testing.
70+
#
71+
# !!! WARNING !!!
72+
RNG_SOURCE=$(wildcard test_only_rng/*.c)
73+
74+
# Part C:
75+
#
76+
# Your application source code
77+
APP_SOURCE=$(wildcard *.c)
78+
79+
BIN=test_binary
80+
81+
CFLAGS := \
82+
-Wall \
83+
-Wextra \
84+
-Werror \
85+
-Wmissing-prototypes \
86+
-Wshadow \
87+
-Werror \
88+
-Wpointer-arith \
89+
-Wredundant-decls \
90+
-Wno-long-long \
91+
-Wno-unknown-pragmas \
92+
-Wno-unused-command-line-argument \
93+
-fomit-frame-pointer \
94+
-DMLK_CONFIG_NAMESPACE_PREFIX=mlkem \
95+
-std=c99 \
96+
-pedantic \
97+
-MMD \
98+
-O3 \
99+
$(CFLAGS)
100+
101+
BINARY_NAME_FULL=$(BUILD_DIR)/$(BIN)
102+
103+
CFLAGS += -DMLK_CONFIG_FILE="\"example_no_stdlib_config.h\""
104+
105+
$(BINARY_NAME_FULL): $(APP_SOURCE) $(RNG_SOURCE) $(MLKEM512_OBJS) $(MLKEM768_OBJS) $(MLKEM1024_OBJS)
106+
echo "$@"
107+
mkdir -p $(BUILD_DIR)
108+
$(CC) $(CFLAGS) $(INC) $^ -o $@
109+
110+
all: build size_objs
111+
112+
build: $(BINARY_NAME_FULL)
113+
114+
run: $(BINARY_NAME_FULL)
115+
$(EXEC_WRAPPER) ./$(BINARY_NAME_FULL)
116+
117+
size: build
118+
@echo "=== Size info for $(BINARY_NAME_FULL) ==="
119+
$(Q)$(SIZE) $(BINARY_NAME_FULL)
120+
121+
size_objs: size
122+
$(Q)echo "=== Object size summary ==="
123+
$(Q)$(SIZE) $(shell find $(BUILD_DIR)/mlkem512 -name '*.o') | (read header; echo "$$header"; awk '$$5 != 0' | sort -k5 -n -r)
124+
$(Q)$(SIZE) $(shell find $(BUILD_DIR)/mlkem768 -name '*.o') | (read header; echo "$$header"; awk '$$5 != 0' | sort -k5 -n -r)
125+
$(Q)$(SIZE) $(shell find $(BUILD_DIR)/mlkem1024 -name '*.o') | (read header; echo "$$header"; awk '$$5 != 0' | sort -k5 -n -r)
126+
127+
clean:
128+
rm -rf $(BUILD_DIR)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[//]: # (SPDX-License-Identifier: CC-BY-4.0)
2+
3+
# Multi-level build with no standard library
4+
5+
This directory contains a minimal example for how to build mlkem-native with support for all 3 security levels
6+
MLKEM-512, MLKEM-768, and MLKEM-1024, and so that level-independent code is shared. In this example, only the C-backend
7+
of mlkem-native is used.
8+
9+
The library is built 3 times in different build directories `build/mlkem{512,768,1024}`. For the MLKEM-512 build, we set
10+
`MLK_CONFIG_MULTILEVEL_WITH_SHARED` to force the inclusion of all level-independent code in the
11+
MLKEM512-build. For MLKEM-768 and MLKEM-1024, we set `MLK_CONFIG_MULTILEVEL_NO_SHARED` to not include any
12+
level-independent code, beside this, this example replace the `mlk_memcpy`, `mlk_memset` with the custom implementation memcpy and memset instead of using the stdlib by adding `example_no_stdlib_config.h`, and add the `-nostdlib` during objects file building,
13+
Finally, we use the common namespace prefix `mlkem` as `MLK_CONFIG_NAMESPACE_PREFIX` for all three builds;
14+
the suffix 512/768/1024 will be added to level-dependent functions automatically.
15+
16+
## Usage
17+
18+
Build this example with `make build`, run with `make run`.

0 commit comments

Comments
 (0)