diff --git a/.github/workflows/all.yml b/.github/workflows/all.yml index f28879790..bd607ec59 100644 --- a/.github/workflows/all.yml +++ b/.github/workflows/all.yml @@ -108,3 +108,9 @@ jobs: needs: [ base ] uses: ./.github/workflows/baremetal.yml secrets: inherit + zephyr: + name: Zephyr + permissions: + contents: 'read' + needs: [ base ] + uses: ./.github/workflows/zephyr.yml diff --git a/.github/workflows/baremetal.yml b/.github/workflows/baremetal.yml index 5be619b38..2c83c7b7a 100644 --- a/.github/workflows/baremetal.yml +++ b/.github/workflows/baremetal.yml @@ -16,27 +16,6 @@ jobs: fail-fast: false matrix: target: - - runner: ubuntu-latest - name: 'M55-AN547' - makefile: test/baremetal/platform/m55-an547/platform.mk - nix-shell: cross-arm-embedded - func: true - kat: true - acvp: true - wycheproof: false - alloc: true - bench: true - opt: all - - runner: ubuntu-latest - name: 'M33-AN524' - makefile: test/baremetal/platform/m33-an524/platform.mk - nix-shell: cross-arm-embedded - func: true - kat: true - acvp: true - alloc: true - bench: true - opt: no_opt - runner: ubuntu-latest name: 'AVR ATmega128RFR2 (modified for 32K RAM)' makefile: test/baremetal/platform/avr/platform.mk diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml new file mode 100644 index 000000000..c9f8dd0f9 --- /dev/null +++ b/.github/workflows/zephyr.yml @@ -0,0 +1,57 @@ +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +name: Zephyr +permissions: + contents: read +on: + workflow_call: + workflow_dispatch: + +jobs: + zephyr_tests: + name: Zephyr tests (${{ matrix.target.board }}, ${{ matrix.target.cpu }}) + strategy: + fail-fast: false + matrix: + target: + - { board: mps2-an385, cpu: Cortex-M3, opt: no_opt } + - { board: mps2-an386, cpu: Cortex-M4, opt: no_opt } + - { board: mps2-an500, cpu: Cortex-M7, opt: no_opt } + - { board: mps2-an521, cpu: Cortex-M33, opt: no_opt } + - { board: mps3-an547, cpu: Cortex-M55, opt: all } + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - name: zephyr build + test + uses: ./.github/actions/functest + env: + EXTRA_MAKEFILE: test/zephyr/platform.mk + ZEPHYR_TARGET: ${{ matrix.target.board }} + with: + nix-shell: zephyr + gh_token: ${{ secrets.GITHUB_TOKEN }} + opt: ${{ matrix.target.opt }} + func: true + kat: true + acvp: true + wycheproof: false + examples: false + unit: false + stack: false + alloc: false + rng_fail: false + check_namespace: false + # Zephyr's CMake selects the target arch; disable the host-arch + # auto-detection that would otherwise leak into the forwarded CFLAGS. + extra_args: --no-auto + # Smoke only: QEMU doesn't model cycle counts (real numbers come from the + # FPGA); this just exercises the bench build + run. + - name: bench (smoke) + env: + EXTRA_MAKEFILE: test/zephyr/platform.mk + ZEPHYR_TARGET: ${{ matrix.target.board }} + run: | + opt=${{ matrix.target.opt == 'all' && 'opt' || 'no_opt' }} + nix develop .#zephyr --command ./scripts/tests bench --no-auto -c PMU --opt=$opt + nix develop .#zephyr --command ./scripts/tests bench --no-auto --components -c PMU --opt=$opt diff --git a/dev/fips202/armv81m/mve.h b/dev/fips202/armv81m/mve.h index a86dc156d..f2a4b5626 100644 --- a/dev/fips202/armv81m/mve.h +++ b/dev/fips202/armv81m/mve.h @@ -17,6 +17,7 @@ #if !defined(__ASSEMBLER__) #include "../api.h" +#include "src/fips202_native_armv81m.h" /* * Native x4 permutation @@ -35,42 +36,27 @@ static MLK_INLINE int mlk_keccak_f1600_x4_native(uint64_t *state) /* * Native x4 XOR bytes (with on-the-fly bit interleaving) */ -#define mlk_keccak_f1600_x4_state_xor_bytes \ - MLK_NAMESPACE(keccak_f1600_x4_state_xor_bytes_asm) -void mlk_keccak_f1600_x4_state_xor_bytes(void *state, const uint8_t *data0, - const uint8_t *data1, - const uint8_t *data2, - const uint8_t *data3, unsigned offset, - unsigned length); - MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_keccakf1600_xor_bytes_x4_native( uint64_t *state, const uint8_t *data0, const uint8_t *data1, const uint8_t *data2, const uint8_t *data3, unsigned offset, unsigned length) { - mlk_keccak_f1600_x4_state_xor_bytes(state, data0, data1, data2, data3, offset, - length); + mlk_keccak_f1600_x4_state_xor_bytes_asm(state, data0, data1, data2, data3, + offset, length); return MLK_NATIVE_FUNC_SUCCESS; } /* * Native x4 extract bytes (with on-the-fly bit de-interleaving) */ -#define mlk_keccak_f1600_x4_state_extract_bytes \ - MLK_NAMESPACE(keccak_f1600_x4_state_extract_bytes_asm) -void mlk_keccak_f1600_x4_state_extract_bytes(void *state, uint8_t *data0, - uint8_t *data1, uint8_t *data2, - uint8_t *data3, unsigned offset, - unsigned length); - MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_keccakf1600_extract_bytes_x4_native( uint64_t *state, uint8_t *data0, uint8_t *data1, uint8_t *data2, uint8_t *data3, unsigned offset, unsigned length) { - mlk_keccak_f1600_x4_state_extract_bytes(state, data0, data1, data2, data3, - offset, length); + mlk_keccak_f1600_x4_state_extract_bytes_asm(state, data0, data1, data2, data3, + offset, length); return MLK_NATIVE_FUNC_SUCCESS; } diff --git a/flake.nix b/flake.nix index 1e6d3b3f3..5a9a96e25 100644 --- a/flake.nix +++ b/flake.nix @@ -148,15 +148,16 @@ ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isAarch64 [ config.packages.toolchain_x86_64 ]; }; - # arm-none-eabi-gcc + platform files from pqmx - devShells.cross-arm-embedded = util.mkShell { + # Zephyr build environment (board chosen at make time via EXTRA_MAKEFILE) + packages.zephyr = util.zephyr; + devShells.zephyr = util.mkShell { packages = builtins.attrValues { - inherit (util) pqmx; - inherit (config.packages) linters; - inherit (pkgs) gcc-arm-embedded qemu coreutils git; - }; + inherit (util) zephyr; + inherit (pkgs) gcc-arm-embedded qemu cmake ninja dtc gperf coreutils git; + } ++ [ util.zephyrPythonEnv ]; }; + devShells.cross-aarch64-embedded = util.mkShell { packages = builtins.attrValues { diff --git a/mlkem/mlkem_native.c b/mlkem/mlkem_native.c index d8b0fd539..e2c49cffa 100644 --- a/mlkem/mlkem_native.c +++ b/mlkem/mlkem_native.c @@ -508,8 +508,6 @@ #undef MLK_USE_FIPS202_X4_NATIVE #undef MLK_USE_FIPS202_X4_XOR_BYTES_NATIVE #undef mlk_keccak_f1600_x4_native_impl -#undef mlk_keccak_f1600_x4_state_extract_bytes -#undef mlk_keccak_f1600_x4_state_xor_bytes /* mlkem/src/fips202/native/armv81m/src/fips202_native_armv81m.h */ #undef MLK_FIPS202_NATIVE_ARMV81M_SRC_FIPS202_NATIVE_ARMV81M_H #undef mlk_keccak_f1600_x4_mve_asm diff --git a/mlkem/mlkem_native_asm.S b/mlkem/mlkem_native_asm.S index c2edd2b16..18adf0be0 100644 --- a/mlkem/mlkem_native_asm.S +++ b/mlkem/mlkem_native_asm.S @@ -532,8 +532,6 @@ #undef MLK_USE_FIPS202_X4_NATIVE #undef MLK_USE_FIPS202_X4_XOR_BYTES_NATIVE #undef mlk_keccak_f1600_x4_native_impl -#undef mlk_keccak_f1600_x4_state_extract_bytes -#undef mlk_keccak_f1600_x4_state_xor_bytes /* mlkem/src/fips202/native/armv81m/src/fips202_native_armv81m.h */ #undef MLK_FIPS202_NATIVE_ARMV81M_SRC_FIPS202_NATIVE_ARMV81M_H #undef mlk_keccak_f1600_x4_mve_asm diff --git a/mlkem/src/fips202/native/armv81m/mve.h b/mlkem/src/fips202/native/armv81m/mve.h index e2f19ec24..3b595e476 100644 --- a/mlkem/src/fips202/native/armv81m/mve.h +++ b/mlkem/src/fips202/native/armv81m/mve.h @@ -17,6 +17,7 @@ #if !defined(__ASSEMBLER__) #include "../api.h" +#include "src/fips202_native_armv81m.h" /* * Native x4 permutation @@ -35,42 +36,27 @@ static MLK_INLINE int mlk_keccak_f1600_x4_native(uint64_t *state) /* * Native x4 XOR bytes (with on-the-fly bit interleaving) */ -#define mlk_keccak_f1600_x4_state_xor_bytes \ - MLK_NAMESPACE(keccak_f1600_x4_state_xor_bytes_asm) -void mlk_keccak_f1600_x4_state_xor_bytes(void *state, const uint8_t *data0, - const uint8_t *data1, - const uint8_t *data2, - const uint8_t *data3, unsigned offset, - unsigned length); - MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_keccakf1600_xor_bytes_x4_native( uint64_t *state, const uint8_t *data0, const uint8_t *data1, const uint8_t *data2, const uint8_t *data3, unsigned offset, unsigned length) { - mlk_keccak_f1600_x4_state_xor_bytes(state, data0, data1, data2, data3, offset, - length); + mlk_keccak_f1600_x4_state_xor_bytes_asm(state, data0, data1, data2, data3, + offset, length); return MLK_NATIVE_FUNC_SUCCESS; } /* * Native x4 extract bytes (with on-the-fly bit de-interleaving) */ -#define mlk_keccak_f1600_x4_state_extract_bytes \ - MLK_NAMESPACE(keccak_f1600_x4_state_extract_bytes_asm) -void mlk_keccak_f1600_x4_state_extract_bytes(void *state, uint8_t *data0, - uint8_t *data1, uint8_t *data2, - uint8_t *data3, unsigned offset, - unsigned length); - MLK_MUST_CHECK_RETURN_VALUE static MLK_INLINE int mlk_keccakf1600_extract_bytes_x4_native( uint64_t *state, uint8_t *data0, uint8_t *data1, uint8_t *data2, uint8_t *data3, unsigned offset, unsigned length) { - mlk_keccak_f1600_x4_state_extract_bytes(state, data0, data1, data2, data3, - offset, length); + mlk_keccak_f1600_x4_state_extract_bytes_asm(state, data0, data1, data2, data3, + offset, length); return MLK_NATIVE_FUNC_SUCCESS; } diff --git a/nix/pqmx/default.nix b/nix/pqmx/default.nix deleted file mode 100644 index 7794c5c79..000000000 --- a/nix/pqmx/default.nix +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) The mldsa-native project authors -# Copyright (c) The mlkem-native project authors -# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT - -{ stdenvNoCC -, fetchFromGitHub -, writeText -}: - -stdenvNoCC.mkDerivation { - pname = "mlkem-native-pqmx"; - version = "main-2026-02-10"; - - - # Fetch platform files from pqmx - src = fetchFromGitHub { - owner = "slothy-optimizer"; - repo = "pqmx"; - rev = "904451a615dc7926eba07b4f3d1a4137c368bb4a"; - hash = "sha256-BjsToEWGlykKIKRfPom84BkD5RfetUKKwRAw3PecebU="; - }; - - dontBuild = true; - - installPhase = '' - mkdir -p $out/platform/m33-an524/src/platform/ - cp -r envs/m33-an524/src/platform/. $out/platform/m33-an524/src/platform/ - cp integration/*.c $out/platform/m33-an524/src/platform/ - - mkdir -p $out/platform/m55-an547/src/platform/ - cp -r envs/m55-an547/src/platform/. $out/platform/m55-an547/src/platform/ - cp integration/*.c $out/platform/m55-an547/src/platform/ - ''; - - setupHook = writeText "setup-hook.sh" '' - export M33_AN524_PATH="$1/platform/m33-an524/src/platform/" - export M55_AN547_PATH="$1/platform/m55-an547/src/platform/" - ''; - - meta = { - description = "Platform files from pqmx for baremetal targets"; - homepage = "https://github.com/slothy-optimizer/pqmx"; - }; -} diff --git a/nix/util.nix b/nix/util.nix index bbe0d8688..0a70ab47c 100644 --- a/nix/util.nix +++ b/nix/util.nix @@ -107,7 +107,17 @@ rec { hol_server = pkgs.callPackage ./hol_light/hol_server.nix { inherit hol_light'; }; s2n_bignum = pkgs.callPackage ./s2n_bignum { }; slothy = pkgs.callPackage ./slothy { }; - pqmx = pkgs.callPackage ./pqmx { }; + zephyr = pkgs.callPackage ./zephyr { }; + zephyrPythonEnv = pkgs.python3.withPackages (ps: with ps; [ + pyelftools + pyyaml + packaging + pykwalify + jsonschema + anytree + intelhex + colorama + ]); avr-toolchain = pkgs.callPackage ./avr { }; # Helper function to build individual cross toolchains diff --git a/nix/zephyr/default.nix b/nix/zephyr/default.nix new file mode 100644 index 000000000..4f5e8fdf3 --- /dev/null +++ b/nix/zephyr/default.nix @@ -0,0 +1,53 @@ +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +{ stdenvNoCC +, fetchFromGitHub +, gcc-arm-embedded +, writeText +}: + +# Board-agnostic Zephyr build environment: a pinned Zephyr tree plus the +# modules needed by the boards we target, exposed via a setup hook so a plain +# `cmake` build works with no west workspace. CMSIS-6 covers the Cortex-M +# boards; add further modules here as more boards are wired up. +let + zephyr = fetchFromGitHub { + owner = "zephyrproject-rtos"; + repo = "zephyr"; + rev = "v4.4.1"; + hash = "sha256-8bzykJs6fFGiofCxRKh8M9jdXr5R8FM0lAbA28yanGk="; + }; + + # Revision pinned by the Zephyr v4.4.1 manifest (west.yml). + cmsis_6 = fetchFromGitHub { + owner = "zephyrproject-rtos"; + repo = "CMSIS_6"; + rev = "30a859f44ef8ab4dc8f84b03ed586fd16ccf9d74"; + hash = "sha256-nTehISN0pu9gnOZMpGaBQ3DFmNxAqAZPGpvbKfEM35o="; + }; +in +stdenvNoCC.mkDerivation { + pname = "mlkem-native-zephyr"; + version = "4.4.1"; + + dontUnpack = true; + + installPhase = '' + mkdir -p $out + ln -s ${zephyr} $out/zephyr + ln -s ${cmsis_6} $out/cmsis_6 + ''; + + setupHook = writeText "setup-hook.sh" '' + export ZEPHYR_BASE="$1/zephyr" + export ZEPHYR_MODULES="$1/cmsis_6" + export ZEPHYR_TOOLCHAIN_VARIANT=gnuarmemb + export GNUARMEMB_TOOLCHAIN_PATH=${gcc-arm-embedded} + ''; + + meta = { + description = "Pinned Zephyr tree and modules for the Zephyr-based test flows"; + homepage = "https://www.zephyrproject.org/"; + }; +} diff --git a/scripts/lint b/scripts/lint index d85b9134a..4e96405d9 100755 --- a/scripts/lint +++ b/scripts/lint @@ -268,7 +268,7 @@ gh_group_end check-tabs() { - for file in $(git ls-files -- ":/" ":/!:Makefile" ":/!:**/Makefile" ":/!:**/Makefile.*" ":/!:Makefile.*" ":/!:*.mk" ":/!:*.patch" ":/!:*.S" ":/!:*.inc" ":/!:nix/valgrind/*.txt"); do + for file in $(git ls-files -- ":/" ":/!:Makefile" ":/!:**/Makefile" ":/!:**/Makefile.*" ":/!:Makefile.*" ":/!:**/Kconfig" ":/!:*.mk" ":/!:*.patch" ":/!:*.S" ":/!:*.inc" ":/!:nix/valgrind/*.txt"); do if [[ ! -L $file ]] && grep -Pq '\t' "$file"; then l=$(grep -Pn '\t' "$file" | head -1 | cut -d: -f1) echo "$file $l" diff --git a/test/acvp/acvp_mlkem.c b/test/acvp/acvp_mlkem.c index df2622f4e..df52700eb 100644 --- a/test/acvp/acvp_mlkem.c +++ b/test/acvp/acvp_mlkem.c @@ -192,6 +192,11 @@ static MLK_NOINLINE void acvp_mlkem_keyGen_AFT( print_hex("dk", dk, sizeof(dk)); } +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(int argc, char *argv[]); +#endif int main(int argc, char *argv[]) { acvp_mode mode; diff --git a/test/baremetal/platform/m33-an524/exec_wrapper.py b/test/baremetal/platform/m33-an524/exec_wrapper.py deleted file mode 100755 index 28493a539..000000000 --- a/test/baremetal/platform/m33-an524/exec_wrapper.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) The mldsa-native project authors -# Copyright (c) The mlkem-native project authors -# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT - -"""QEMU wrapper for executing Cortex-M33 bare-metal ELF binaries (mps3-an524).""" - -import struct as st -import sys -import subprocess -import tempfile -import os - - -def err(msg, **kwargs): - print(msg, file=sys.stderr, **kwargs) - - -binpath = sys.argv[1] -args = sys.argv[1:] - -# Memory layout: [argc] [offset1] [offset2] ... [string1\0] [string2\0] ... -# M33-AN524 RAM: 0x20000000-0x2001FFFF (128KB) -# Heap ends at: ~0x20000b20 -# Stack: 0x20008000-0x2001FFFF (96KB, grows downward) -# Use address after heap but before stack -# cmdline.c CMDLINE_ADDR must match this value -cmdline_offset = 0x20007000 -arg0_offset = cmdline_offset + 4 + len(args) * 4 -arg_offsets = [sum(map(len, args[:i])) + i + arg0_offset for i in range(len(args))] - -binargs = st.pack( - f"<{1 + len(args)}I" + "".join(f"{len(a) + 1}s" for a in args), - len(args), - *arg_offsets, - *map(lambda x: x.encode("utf-8"), args), -) - -with tempfile.NamedTemporaryFile(mode="wb", delete=False, suffix=".bin") as fd: - args_file = fd.name - fd.write(binargs) - -try: - qemu_cmd = f"qemu-system-arm -M mps3-an524 -cpu cortex-m33 -nographic -semihosting -kernel {binpath} -device loader,file={args_file},addr=0x{cmdline_offset:x}".split() - result = subprocess.run(qemu_cmd, encoding="utf-8", capture_output=True) -finally: - os.unlink(args_file) -if result.returncode != 0: - err("FAIL!") - err(f"{qemu_cmd} failed with error code {result.returncode}") - err(result.stderr) - exit(1) - -for line in result.stdout.splitlines(): - print(line) diff --git a/test/baremetal/platform/m33-an524/platform.mk b/test/baremetal/platform/m33-an524/platform.mk deleted file mode 100644 index 7c51c5a45..000000000 --- a/test/baremetal/platform/m33-an524/platform.mk +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) The mldsa-native project authors -# Copyright (c) The mlkem-native project authors -# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT - -PLATFORM_PATH:=test/baremetal/platform/m33-an524 - -CROSS_PREFIX=arm-none-eabi- -CC=gcc - -# Use PMU cycle counting by default -CYCLES ?= PMU - -# Reduce iterations for benchmarking and functional tests -CFLAGS += -DMLK_BENCHMARK_NTESTS=10 -DMLK_BENCHMARK_NITERATIONS=10 -DMLK_BENCHMARK_NWARMUP=10 -CFLAGS += -DNTESTS_FUNC=100 - - -CFLAGS += -DMLK_BUMP_ALLOC_SIZE=65536 -CFLAGS += \ - -O3 \ - -Wall -Wextra -Wshadow \ - -Wno-pedantic \ - -Wno-redundant-decls \ - -Wno-missing-prototypes \ - -Wno-conversion \ - -Wno-sign-conversion \ - -fno-common \ - -ffunction-sections \ - -fdata-sections \ - --sysroot=$(SYSROOT) \ - -DDEVICE=an524 \ - -I$(M33_AN524_PATH) \ - -I$(M33_AN524_PATH)/m-profile \ - -DARMCM33 \ - -DSEMIHOSTING \ - -DCMDLINE_BASE_ADDR=0x20007000 - -ARCH_FLAGS += \ - -mcpu=cortex-m33+nodsp \ - -mthumb \ - -mfloat-abi=soft - -CFLAGS += \ - $(ARCH_FLAGS) \ - --specs=nosys.specs - -CFLAGS += $(CFLAGS_EXTRA) - -LDSCRIPT = $(M33_AN524_PATH)/m33-an524.ld - -LDFLAGS += \ - -Wl,--gc-sections \ - -Wl,--no-warn-rwx-segments \ - -L. - -LDFLAGS += \ - --specs=nosys.specs \ - -Wl,--wrap=_open \ - -Wl,--wrap=_close \ - -Wl,--wrap=_read \ - -Wl,--wrap=_write \ - -Wl,--wrap=_fstat \ - -Wl,--wrap=_getpid \ - -Wl,--wrap=_isatty \ - -Wl,--wrap=_kill \ - -Wl,--wrap=_lseek \ - -Wl,--wrap=main \ - -ffreestanding \ - -T$(LDSCRIPT) \ - $(ARCH_FLAGS) - -# Extra sources to be included in test binaries -EXTRA_SOURCES = $(wildcard $(M33_AN524_PATH)/*.c) -# The CMSIS files fail compilation if conversion warnings are enabled -EXTRA_SOURCES_CFLAGS = -Wno-conversion -Wno-sign-conversion - -EXEC_WRAPPER := $(realpath $(PLATFORM_PATH)/exec_wrapper.py) diff --git a/test/baremetal/platform/m55-an547/exec_wrapper.py b/test/baremetal/platform/m55-an547/exec_wrapper.py deleted file mode 100755 index 820674b34..000000000 --- a/test/baremetal/platform/m55-an547/exec_wrapper.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) The mldsa-native project authors -# Copyright (c) The mlkem-native project authors -# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT - -import struct as st -import sys -import subprocess -import tempfile -import os - - -def err(msg, **kwargs): - print(msg, file=sys.stderr, **kwargs) - - -binpath = sys.argv[1] -args = sys.argv[1:] -cmdline_offset = 0x70000 - -arg0_offset = cmdline_offset + 4 + len(args) * 4 - -arg_offsets = [sum(map(len, args[:i])) + i + arg0_offset for i in range(len(args))] - -binargs = st.pack( - f"<{1 + len(args)}I" + "".join(f"{len(a) + 1}s" for a in args), - len(args), - *arg_offsets, - *map(lambda x: x.encode("utf-8"), args), -) - -with tempfile.NamedTemporaryFile(mode="wb", delete=False, suffix=".bin") as fd: - args_file = fd.name - fd.write(binargs) - -try: - qemu_cmd = f"qemu-system-arm -M mps3-an547 -monitor none -nographic -semihosting -kernel {binpath} -device loader,file={args_file},addr=0x{cmdline_offset:x}".split() - result = subprocess.run(qemu_cmd, encoding="utf-8", capture_output=True) -finally: - os.unlink(args_file) -if result.returncode != 0: - err("FAIL!") - err(f"{qemu_cmd} failed with error code {result.returncode}") - err(result.stderr) - exit(1) - -for line in result.stdout.splitlines(): - print(line) diff --git a/test/baremetal/platform/m55-an547/platform.mk b/test/baremetal/platform/m55-an547/platform.mk deleted file mode 100644 index 85985c907..000000000 --- a/test/baremetal/platform/m55-an547/platform.mk +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) The mldsa-native project authors -# Copyright (c) The mlkem-native project authors -# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT - -PLATFORM_PATH:=test/baremetal/platform/m55-an547 - -CROSS_PREFIX=arm-none-eabi- -CC=gcc - -# Use PMU cycle counting by default -CYCLES ?= PMU - -# Reduce iterations for benchmarking and functional tests -CFLAGS += -DMLK_BENCHMARK_NTESTS=10 -DMLK_BENCHMARK_NITERATIONS=10 -DMLK_BENCHMARK_NWARMUP=10 -CFLAGS += -DNTESTS_FUNC=100 - -# Explicitly include experimental Armv8.1-M + MVE backend -# Remove this once backend is finalized and enabled by default. -CFLAGS += "-DMLK_CONFIG_FIPS202_BACKEND_FILE=\"fips202/native/armv81m/mve.h\"" - -CFLAGS += \ - -O3 \ - -Wall -Wextra -Wshadow \ - -Wno-pedantic \ - -Wno-redundant-decls \ - -Wno-missing-prototypes \ - -Wno-conversion \ - -Wno-sign-conversion \ - -fno-common \ - -ffunction-sections \ - -fdata-sections \ - --sysroot=$(SYSROOT) \ - -DDEVICE=an547 \ - -I$(M55_AN547_PATH) \ - -DARMCM55 \ - -DSEMIHOSTING - -ARCH_FLAGS += \ - -march=armv8.1-m.main+mve.fp \ - -mcpu=cortex-m55 \ - -mthumb \ - -mfloat-abi=hard -mfpu=fpv4-sp-d16 - -CFLAGS += \ - $(ARCH_FLAGS) \ - --specs=nosys.specs - -CFLAGS += $(CFLAGS_EXTRA) - -LDSCRIPT = $(M55_AN547_PATH)/mps3.ld - -LDFLAGS += \ - -Wl,--gc-sections \ - -Wl,--no-warn-rwx-segments \ - -L. - -LDFLAGS += \ - --specs=nosys.specs \ - -Wl,--wrap=_open \ - -Wl,--wrap=_close \ - -Wl,--wrap=_read \ - -Wl,--wrap=_write \ - -Wl,--wrap=_fstat \ - -Wl,--wrap=_getpid \ - -Wl,--wrap=_isatty \ - -Wl,--wrap=_kill \ - -Wl,--wrap=_lseek \ - -Wl,--wrap=main \ - -ffreestanding \ - -T$(LDSCRIPT) \ - $(ARCH_FLAGS) - -# Extra sources to be included in test binaries -EXTRA_SOURCES = $(wildcard $(M55_AN547_PATH)/*.c) -# The CMSIS files fail compilation if conversion warnings are enabled -EXTRA_SOURCES_CFLAGS = -Wno-conversion -Wno-sign-conversion - -EXEC_WRAPPER := $(realpath $(PLATFORM_PATH)/exec_wrapper.py) diff --git a/test/bench/bench_components_mlkem.c b/test/bench/bench_components_mlkem.c index 8accc27b4..6247f2ee7 100644 --- a/test/bench/bench_components_mlkem.c +++ b/test/bench/bench_components_mlkem.c @@ -362,6 +362,11 @@ static int bench(void) return 0; } +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(void); +#endif int main(void) { enable_cyclecounter(); diff --git a/test/bench/bench_mlkem.c b/test/bench/bench_mlkem.c index ee5c346fb..e2d884a90 100644 --- a/test/bench/bench_mlkem.c +++ b/test/bench/bench_mlkem.c @@ -157,6 +157,11 @@ static int bench(void) return 0; } +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(void); +#endif int main(void) { enable_cyclecounter(); diff --git a/test/hal/hal.c b/test/hal/hal.c index 0a1b9f23f..9dfc73d95 100644 --- a/test/hal/hal.c +++ b/test/hal/hal.c @@ -42,7 +42,16 @@ #include "hal.h" -#if defined(PMU_CYCLES) +#if defined(__ZEPHYR__) + +/* Zephyr: use the kernel cycle counter. */ +#include + +void enable_cyclecounter(void) {} +void disable_cyclecounter(void) {} +uint64_t get_cyclecounter(void) { return k_cycle_get_32(); } + +#elif defined(PMU_CYCLES) #if defined(__x86_64__) @@ -368,10 +377,10 @@ uint64_t get_cyclecounter(void) return g_counters[2]; } -#else /* !PMU_CYCLES && !PERF_CYCLES && MAC_CYCLES */ +#else /* !__ZEPHYR__ && !PMU_CYCLES && !PERF_CYCLES && MAC_CYCLES */ void enable_cyclecounter(void) { return; } void disable_cyclecounter(void) { return; } uint64_t get_cyclecounter(void) { return (0); } -#endif /* !PMU_CYCLES && !PERF_CYCLES && !MAC_CYCLES */ +#endif /* !__ZEPHYR__ && !PMU_CYCLES && !PERF_CYCLES && !MAC_CYCLES */ diff --git a/test/mk/components.mk b/test/mk/components.mk index a12c6750d..2833914d1 100644 --- a/test/mk/components.mk +++ b/test/mk/components.mk @@ -3,15 +3,25 @@ FIPS202_SRCS = $(wildcard mlkem/src/fips202/*.c) ifeq ($(OPT),1) - FIPS202_SRCS += $(wildcard mlkem/src/fips202/native/aarch64/src/*.S) $(wildcard mlkem/src/fips202/native/aarch64/src/*.c) $(wildcard mlkem/src/fips202/native/x86_64/src/*.c) $(wildcard mlkem/src/fips202/native/x86_64/src/*.S) $(wildcard mlkem/src/fips202/native/armv81m/src/*.[csS]) + FIPS202_SRCS += $(wildcard mlkem/src/fips202/native/aarch64/src/*.S) \ + $(wildcard mlkem/src/fips202/native/aarch64/src/*.c) \ + $(wildcard mlkem/src/fips202/native/x86_64/src/*.c) \ + $(wildcard mlkem/src/fips202/native/x86_64/src/*.S) \ + $(wildcard mlkem/src/fips202/native/armv81m/src/*.[csS]) endif SOURCES += $(wildcard mlkem/src/*.c) ifeq ($(OPT),1) - SOURCES += $(wildcard mlkem/src/native/aarch64/src/*.[csS]) $(wildcard mlkem/src/native/x86_64/src/*.[csS]) $(wildcard mlkem/src/native/riscv64/src/*.[csS]) $(wildcard mlkem/src/native/ppc64le/src/*.[csS]) - CFLAGS += -DMLK_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 + SOURCES += $(wildcard mlkem/src/native/aarch64/src/*.[csS]) \ + $(wildcard mlkem/src/native/x86_64/src/*.[csS]) \ + $(wildcard mlkem/src/native/riscv64/src/*.[csS]) \ + $(wildcard mlkem/src/native/ppc64le/src/*.[csS]) + CFLAGS += -DMLK_CONFIG_USE_NATIVE_BACKEND_ARITH \ + -DMLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 endif +LIB_SRCS := $(SOURCES) $(FIPS202_SRCS) + BASIC_TESTS = test_mlkem gen_KAT test_stack ACVP_TESTS = acvp_mlkem WYCHEPROOF_TESTS = wycheproof_mlkem @@ -25,29 +35,29 @@ MLKEM512_DIR = $(BUILD_DIR)/mlkem512 MLKEM768_DIR = $(BUILD_DIR)/mlkem768 MLKEM1024_DIR = $(BUILD_DIR)/mlkem1024 -MLKEM512_OBJS = $(call MAKE_OBJS,$(MLKEM512_DIR),$(SOURCES) $(FIPS202_SRCS)) +MLKEM512_OBJS = $(call MAKE_OBJS,$(MLKEM512_DIR),$(LIB_SRCS)) $(MLKEM512_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=512 -MLKEM768_OBJS = $(call MAKE_OBJS,$(MLKEM768_DIR),$(SOURCES) $(FIPS202_SRCS)) +MLKEM768_OBJS = $(call MAKE_OBJS,$(MLKEM768_DIR),$(LIB_SRCS)) $(MLKEM768_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=768 -MLKEM1024_OBJS = $(call MAKE_OBJS,$(MLKEM1024_DIR),$(SOURCES) $(FIPS202_SRCS)) +MLKEM1024_OBJS = $(call MAKE_OBJS,$(MLKEM1024_DIR),$(LIB_SRCS)) $(MLKEM1024_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=1024 # Unit test object files - same sources but with MLK_STATIC_TESTABLE= UNIT_CFLAGS = -DMLK_STATIC_TESTABLE= -Wno-missing-prototypes -MLKEM512_UNIT_OBJS = $(call MAKE_OBJS,$(MLKEM512_DIR)/unit,$(SOURCES) $(FIPS202_SRCS)) +MLKEM512_UNIT_OBJS = $(call MAKE_OBJS,$(MLKEM512_DIR)/unit,$(LIB_SRCS)) $(MLKEM512_UNIT_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=512 $(UNIT_CFLAGS) -MLKEM768_UNIT_OBJS = $(call MAKE_OBJS,$(MLKEM768_DIR)/unit,$(SOURCES) $(FIPS202_SRCS)) +MLKEM768_UNIT_OBJS = $(call MAKE_OBJS,$(MLKEM768_DIR)/unit,$(LIB_SRCS)) $(MLKEM768_UNIT_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=768 $(UNIT_CFLAGS) -MLKEM1024_UNIT_OBJS = $(call MAKE_OBJS,$(MLKEM1024_DIR)/unit,$(SOURCES) $(FIPS202_SRCS)) +MLKEM1024_UNIT_OBJS = $(call MAKE_OBJS,$(MLKEM1024_DIR)/unit,$(LIB_SRCS)) $(MLKEM1024_UNIT_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=1024 $(UNIT_CFLAGS) # Alloc test object files - same sources but with custom alloc config -MLKEM512_ALLOC_OBJS = $(call MAKE_OBJS,$(MLKEM512_DIR)/alloc,$(SOURCES) $(FIPS202_SRCS)) +MLKEM512_ALLOC_OBJS = $(call MAKE_OBJS,$(MLKEM512_DIR)/alloc,$(LIB_SRCS)) $(MLKEM512_ALLOC_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=512 -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" -MLKEM768_ALLOC_OBJS = $(call MAKE_OBJS,$(MLKEM768_DIR)/alloc,$(SOURCES) $(FIPS202_SRCS)) +MLKEM768_ALLOC_OBJS = $(call MAKE_OBJS,$(MLKEM768_DIR)/alloc,$(LIB_SRCS)) $(MLKEM768_ALLOC_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=768 -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" -MLKEM1024_ALLOC_OBJS = $(call MAKE_OBJS,$(MLKEM1024_DIR)/alloc,$(SOURCES) $(FIPS202_SRCS)) +MLKEM1024_ALLOC_OBJS = $(call MAKE_OBJS,$(MLKEM1024_DIR)/alloc,$(LIB_SRCS)) $(MLKEM1024_ALLOC_OBJS): CFLAGS += -DMLK_CONFIG_PARAMETER_SET=1024 -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" CFLAGS += -Imlkem @@ -79,50 +89,36 @@ $(MLKEM512_DIR)/bin/test_stack512: CFLAGS += -Imlkem/src -fstack-usage $(MLKEM768_DIR)/bin/test_stack768: CFLAGS += -Imlkem/src -fstack-usage $(MLKEM1024_DIR)/bin/test_stack1024: CFLAGS += -Imlkem/src -fstack-usage -$(MLKEM512_DIR)/test/src/test_alloc.c.o: CFLAGS += -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" -$(MLKEM768_DIR)/test/src/test_alloc.c.o: CFLAGS += -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" -$(MLKEM1024_DIR)/test/src/test_alloc.c.o: CFLAGS += -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" - -$(MLKEM512_DIR)/test/src/test_unit.c.o: CFLAGS += $(UNIT_CFLAGS) -$(MLKEM768_DIR)/test/src/test_unit.c.o: CFLAGS += $(UNIT_CFLAGS) -$(MLKEM1024_DIR)/test/src/test_unit.c.o: CFLAGS += $(UNIT_CFLAGS) - +# Per-test CFLAGS. Attach to the binary so it automatically propagates to all +# dependencies. Applying to .o files would prevent propagation to custom builds. $(MLKEM512_DIR)/bin/test_unit512: CFLAGS += $(UNIT_CFLAGS) $(MLKEM768_DIR)/bin/test_unit768: CFLAGS += $(UNIT_CFLAGS) $(MLKEM1024_DIR)/bin/test_unit1024: CFLAGS += $(UNIT_CFLAGS) +$(MLKEM512_DIR)/bin/test_alloc512: CFLAGS += -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" +$(MLKEM768_DIR)/bin/test_alloc768: CFLAGS += -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" +$(MLKEM1024_DIR)/bin/test_alloc1024: CFLAGS += -DMLK_CONFIG_FILE=\"../test/configs/test_alloc_config.h\" + # Unit library object files compiled with MLK_STATIC_TESTABLE= $(MLKEM512_DIR)/unit_%: CFLAGS += -DMLK_STATIC_TESTABLE= -Wno-missing-prototypes $(MLKEM768_DIR)/unit_%: CFLAGS += -DMLK_STATIC_TESTABLE= -Wno-missing-prototypes $(MLKEM1024_DIR)/unit_%: CFLAGS += -DMLK_STATIC_TESTABLE= -Wno-missing-prototypes -$(MLKEM512_DIR)/bin/bench_mlkem512: $(MLKEM512_DIR)/test/hal/hal.c.o -$(MLKEM768_DIR)/bin/bench_mlkem768: $(MLKEM768_DIR)/test/hal/hal.c.o -$(MLKEM1024_DIR)/bin/bench_mlkem1024: $(MLKEM1024_DIR)/test/hal/hal.c.o -$(MLKEM512_DIR)/bin/bench_components_mlkem512: $(MLKEM512_DIR)/test/hal/hal.c.o -$(MLKEM768_DIR)/bin/bench_components_mlkem768: $(MLKEM768_DIR)/test/hal/hal.c.o -$(MLKEM1024_DIR)/bin/bench_components_mlkem1024: $(MLKEM1024_DIR)/test/hal/hal.c.o - $(MLKEM512_DIR)/bin/%: CFLAGS += -DMLK_CONFIG_PARAMETER_SET=512 $(MLKEM768_DIR)/bin/%: CFLAGS += -DMLK_CONFIG_PARAMETER_SET=768 $(MLKEM1024_DIR)/bin/%: CFLAGS += -DMLK_CONFIG_PARAMETER_SET=1024 -# Link tests with respective library (except test_unit which includes sources directly) define ADD_SOURCE -$(BUILD_DIR)/$(1)/bin/$(2)$(subst mlkem,,$(1)): LDLIBS += -L$(BUILD_DIR) -l$(1) -$(BUILD_DIR)/$(1)/bin/$(2)$(subst mlkem,,$(1)): $(BUILD_DIR)/$(1)/test/$(3)/$(2).c.o $(BUILD_DIR)/lib$(1).a -endef - -# Special rule for test_unit - link against unit libraries with exposed internal functions -define ADD_SOURCE_UNIT -$(BUILD_DIR)/$(1)/bin/test_unit$(subst mlkem,,$(1)): LDLIBS += -L$(BUILD_DIR) -l$(1)_unit -$(BUILD_DIR)/$(1)/bin/test_unit$(subst mlkem,,$(1)): $(BUILD_DIR)/$(1)/test/src/test_unit.c.o $(BUILD_DIR)/lib$(1)_unit.a $(call MAKE_OBJS, $(BUILD_DIR)/$(1), $(wildcard test/notrandombytes/*.c)) -endef - -# Special rule for test_alloc - link against alloc libraries with custom alloc config -define ADD_SOURCE_ALLOC -$(BUILD_DIR)/$(1)/bin/test_alloc$(subst mlkem,,$(1)): LDLIBS += -L$(BUILD_DIR) -l$(1)_alloc -$(BUILD_DIR)/$(1)/bin/test_alloc$(subst mlkem,,$(1)): $(BUILD_DIR)/$(1)/test/src/test_alloc.c.o $(BUILD_DIR)/lib$(1)_alloc.a $(call MAKE_OBJS, $(BUILD_DIR)/$(1), $(wildcard test/notrandombytes/*.c)) +# Record each test binary's test sources in the per-binary TEST_SRCS variable: +# its entrypoint test/$(3)/$(2).c plus any extra test sources $(4). +# TEST_SRCS is the source of truth for "which sources does this test need". +$(BUILD_DIR)/$(1)/bin/$(2)$(subst mlkem,,$(1)): TEST_SRCS += test/$(3)/$(2).c $(4) +# In a normal build, the library sources are compiled into a .a and linked in. +# A custom build (CUSTOM_BUILD set, see test/mk/rules.mk) may do it differently. +ifndef CUSTOM_BUILD +$(BUILD_DIR)/$(1)/bin/$(2)$(subst mlkem,,$(1)): LDLIBS += -L$(BUILD_DIR) -l$(1)$(5) +$(BUILD_DIR)/$(1)/bin/$(2)$(subst mlkem,,$(1)): $(BUILD_DIR)/lib$(1)$(5).a +endif endef $(foreach scheme,mlkem512 mlkem768 mlkem1024, \ @@ -133,25 +129,44 @@ $(foreach scheme,mlkem512 mlkem768 mlkem1024, \ $(eval $(call ADD_SOURCE,$(scheme),$(test),wycheproof)) \ ) \ $(foreach test,$(BENCH_TESTS), \ - $(eval $(call ADD_SOURCE,$(scheme),$(test),bench)) \ + $(eval $(call ADD_SOURCE,$(scheme),$(test),bench,test/hal/hal.c)) \ ) \ $(foreach test,$(BASIC_TESTS), \ $(eval $(call ADD_SOURCE,$(scheme),$(test),src)) \ ) \ $(eval $(call ADD_SOURCE,$(scheme),test_rng_fail,src)) \ - $(eval $(call ADD_SOURCE_UNIT,$(scheme))) \ - $(eval $(call ADD_SOURCE_ALLOC,$(scheme))) \ + $(eval $(call ADD_SOURCE,$(scheme),test_unit,src,,_unit)) \ + $(eval $(call ADD_SOURCE,$(scheme),test_alloc,src,,_alloc)) \ ) -# All tests get EXTRA_SOURCES -$(ALL_TESTS:%=$(MLKEM512_DIR)/bin/%512): $(call MAKE_OBJS, $(MLKEM512_DIR), $(EXTRA_SOURCES)) -$(ALL_TESTS:%=$(MLKEM768_DIR)/bin/%768): $(call MAKE_OBJS, $(MLKEM768_DIR), $(EXTRA_SOURCES)) -$(ALL_TESTS:%=$(MLKEM1024_DIR)/bin/%1024): $(call MAKE_OBJS, $(MLKEM1024_DIR), $(EXTRA_SOURCES)) - -# All tests except rng_fail get notrandombytes (rng_fail provides its own) -$(filter-out %test_rng_fail512,$(ALL_TESTS:%=$(MLKEM512_DIR)/bin/%512)): $(call MAKE_OBJS, $(MLKEM512_DIR), $(wildcard test/notrandombytes/*.c)) -$(filter-out %test_rng_fail768,$(ALL_TESTS:%=$(MLKEM768_DIR)/bin/%768)): $(call MAKE_OBJS, $(MLKEM768_DIR), $(wildcard test/notrandombytes/*.c)) -$(filter-out %test_rng_fail1024,$(ALL_TESTS:%=$(MLKEM1024_DIR)/bin/%1024)): $(call MAKE_OBJS, $(MLKEM1024_DIR), $(wildcard test/notrandombytes/*.c)) +# All tests get EXTRA_SOURCES; all except rng_fail get notrandombytes (rng_fail +# provides its own). Both are just more test sources, so record them in +# TEST_SRCS alongside the entrypoints set by ADD_SOURCE. +NOTRANDOMBYTES_SRCS := $(wildcard test/notrandombytes/*.c) + +$(ALL_TESTS:%=$(MLKEM512_DIR)/bin/%512): TEST_SRCS += $(EXTRA_SOURCES) +$(ALL_TESTS:%=$(MLKEM768_DIR)/bin/%768): TEST_SRCS += $(EXTRA_SOURCES) +$(ALL_TESTS:%=$(MLKEM1024_DIR)/bin/%1024): TEST_SRCS += $(EXTRA_SOURCES) + +$(filter-out %test_rng_fail512,$(ALL_TESTS:%=$(MLKEM512_DIR)/bin/%512)): TEST_SRCS += $(NOTRANDOMBYTES_SRCS) +$(filter-out %test_rng_fail768,$(ALL_TESTS:%=$(MLKEM768_DIR)/bin/%768)): TEST_SRCS += $(NOTRANDOMBYTES_SRCS) +$(filter-out %test_rng_fail1024,$(ALL_TESTS:%=$(MLKEM1024_DIR)/bin/%1024)): TEST_SRCS += $(NOTRANDOMBYTES_SRCS) + +# Turn each binary's TEST_SRCS into its prerequisites (resolved via +# .SECONDEXPANSION, as TEST_SRCS is a per-target variable). In a normal build +# this is redundant: a dependency is implicitly created via .a -> .o -> .c. +# Nontheless, we explicitly register the source files as dependencies to allow +# custom platforms to implement a separate build +.SECONDEXPANSION: +ifndef CUSTOM_BUILD +$(ALL_TESTS:%=$(MLKEM512_DIR)/bin/%512): $$(call MAKE_OBJS,$(MLKEM512_DIR),$$(TEST_SRCS)) +$(ALL_TESTS:%=$(MLKEM768_DIR)/bin/%768): $$(call MAKE_OBJS,$(MLKEM768_DIR),$$(TEST_SRCS)) +$(ALL_TESTS:%=$(MLKEM1024_DIR)/bin/%1024): $$(call MAKE_OBJS,$(MLKEM1024_DIR),$$(TEST_SRCS)) +else +$(ALL_TESTS:%=$(MLKEM512_DIR)/bin/%512): $$(TEST_SRCS) $(LIB_SRCS) +$(ALL_TESTS:%=$(MLKEM768_DIR)/bin/%768): $$(TEST_SRCS) $(LIB_SRCS) +$(ALL_TESTS:%=$(MLKEM1024_DIR)/bin/%1024): $$(TEST_SRCS) $(LIB_SRCS) +endif # Apply EXTRA_CFLAGS to EXTRA_SOURCES object files ifneq ($(EXTRA_SOURCES),) diff --git a/test/mk/rules.mk b/test/mk/rules.mk index 51c8c84dc..feff75942 100644 --- a/test/mk/rules.mk +++ b/test/mk/rules.mk @@ -1,20 +1,27 @@ # Copyright (c) The mlkem-native project authors # SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +# Final step that turns a binary's prerequisites into the bin at $@. By default +# this links the prerequisite objects, but a platform may override it by setting +# CUSTOM_BUILD -- e.g. the Zephyr platform builds a firmware image from the +# binary's sources instead. When CUSTOM_BUILD is set, test/mk/components.mk also +# attaches the binary's sources (rather than prebuilt objects/libraries) as its +# prerequisites. CUSTOM_BUILD is expanded in the recipe context, so it can use +# the target's automatic variables ($@) and target-specific variables (e.g. +# TEST_SRCS, set per bin in test/mk/components.mk). +LINK = $(if $(strip $(CUSTOM_BUILD)),$(CUSTOM_BUILD),echo " LD $@" && $(LD) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS)) + $(BUILD_DIR)/mlkem512/bin/%: $(CONFIG) - $(Q)echo " LD $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) - $(Q)$(LD) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) + $(Q)$(LINK) $(BUILD_DIR)/mlkem768/bin/%: $(CONFIG) - $(Q)echo " LD $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) - $(Q)$(LD) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) + $(Q)$(LINK) $(BUILD_DIR)/mlkem1024/bin/%: $(CONFIG) - $(Q)echo " LD $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) - $(Q)$(LD) $(LDFLAGS) -o $@ $(filter %.o,$^) $(LDLIBS) + $(Q)$(LINK) $(BUILD_DIR)/%.a: $(CONFIG) $(Q)echo " AR $@" diff --git a/test/src/gen_KAT.c b/test/src/gen_KAT.c index 494267e2c..af656b932 100644 --- a/test/src/gen_KAT.c +++ b/test/src/gen_KAT.c @@ -42,6 +42,11 @@ static void print_hex(const char *label, const uint8_t *data, size_t size) printf("\n"); } +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(void); +#endif int main(void) { unsigned i; diff --git a/test/src/test_alloc.c b/test/src/test_alloc.c index 3fcdaa4e1..16bc09a08 100644 --- a/test/src/test_alloc.c +++ b/test/src/test_alloc.c @@ -436,6 +436,11 @@ static int test_check_sk_alloc_failure(test_ctx_t *ctx) } \ } while (0) +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(void); +#endif int main(void) { MLK_ALIGN uint8_t bump_buffer[MLK_BUMP_ALLOC_SIZE]; diff --git a/test/src/test_mlkem.c b/test/src/test_mlkem.c index 88564b4df..c9a0cf5fb 100644 --- a/test/src/test_mlkem.c +++ b/test/src/test_mlkem.c @@ -160,6 +160,11 @@ static int test_invalid_ciphertext(void) return 0; } +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(void); +#endif int main(void) { unsigned i; diff --git a/test/src/test_rng_fail.c b/test/src/test_rng_fail.c index 407a86b83..b0d0320a8 100644 --- a/test/src/test_rng_fail.c +++ b/test/src/test_rng_fail.c @@ -199,6 +199,11 @@ static int test_check_sk_rng_failure(void) return 0; } +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(void); +#endif int main(void) { if (test_keygen_rng_failure() != 0) diff --git a/test/src/test_stack.c b/test/src/test_stack.c index 4472d39b3..9b3149469 100644 --- a/test/src/test_stack.c +++ b/test/src/test_stack.c @@ -43,6 +43,11 @@ static void test_decaps_only(void) (void)ret; /* Ignore return value - we only care about stack measurement */ } +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(int argc, char *argv[]); +#endif int main(int argc, char *argv[]) { if (argc != 2) diff --git a/test/src/test_unit.c b/test/src/test_unit.c index 55430a546..e87793e03 100644 --- a/test/src/test_unit.c +++ b/test/src/test_unit.c @@ -30,6 +30,13 @@ #endif #endif /* !NUM_RANDOM_TESTS_REJ_UNIFORM */ +/* Largest absolute constant-coefficient value the invNTT overflow test sweeps. + * Defaults to a full INT16 sweep; an emulated target (e.g. QEMU) can lower it + * to keep the run within its time budget. */ +#ifndef MAX_INTT_CONSTANT_COEFF +#define MAX_INTT_CONSTANT_COEFF INT16_MAX +#endif + /* Declarations for _c functions exposed by MLK_STATIC_TESTABLE= */ void mlk_poly_reduce_c(mlk_poly *r); @@ -540,7 +547,7 @@ static int test_native_intt(void) * * Gradually increase absolute value to find smallest failure first. */ - for (coeff = 0; coeff <= INT16_MAX; coeff++) + for (coeff = 0; coeff <= MAX_INTT_CONSTANT_COEFF; coeff++) { generate_i16_array_constant(test_data, MLKEM_N, (int16_t)coeff); CHECK(test_intt_core(test_data, "intt_constant") == 0); @@ -1216,6 +1223,11 @@ static int test_poly_rej_uniform_consistency(void) +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(void); +#endif int main(void) { /* WARNING: Test-only diff --git a/test/wycheproof/wycheproof_mlkem.c b/test/wycheproof/wycheproof_mlkem.c index b1f762241..4af40dc27 100644 --- a/test/wycheproof/wycheproof_mlkem.c +++ b/test/wycheproof/wycheproof_mlkem.c @@ -100,6 +100,11 @@ static void print_hex(const char *name, const unsigned char *raw, size_t len) printf("\n"); } +/* Ensure main has a prototype even if re-#define'd, avoiding + * -Wmissing-prototypes failure */ +#if defined(main) +int main(int argc, char *argv[]); +#endif int main(int argc, char *argv[]) { if (argc < 2) diff --git a/test/zephyr/README.md b/test/zephyr/README.md new file mode 100644 index 000000000..fa9f117e5 --- /dev/null +++ b/test/zephyr/README.md @@ -0,0 +1,68 @@ +[//]: # (SPDX-License-Identifier: CC-BY-4.0) + +# Zephyr test platform + +This is a test platform that builds the mlkem-native test applications as +[Zephyr](https://www.zephyrproject.org/) applications, so they can run on +QEMU-emulated Arm MPS boards. It covers Cortex-M3/M4/M7/M33/M55 through a +single platform, without the need for per-board hardware abstraction layers. + +## Usage + +The platform is selected through the `EXTRA_MAKEFILE` environment variable and +driven by the usual test targets from the top-level `Makefile`. It must run +inside the `zephyr` Nix development shell, which provides the Arm toolchain, +QEMU, and the Zephyr SDK (`ZEPHYR_BASE`). The board is chosen with the +`ZEPHYR_TARGET` environment variable (default `mps3-an547`): + +``` +export EXTRA_MAKEFILE=test/zephyr/platform.mk +export ZEPHYR_TARGET=mps3-an547 +nix develop .#zephyr --command ./scripts/tests func --opt=opt +``` + +Supported targets: + +| `ZEPHYR_TARGET` | Zephyr board | QEMU machine | Core | +| --------------- | --------------------- | ------------ | ---------- | +| `mps2-an385` | `mps2/an385` | `mps2-an385` | Cortex-M3 | +| `mps2-an386` | `mps2/an386` | `mps2-an386` | Cortex-M4 | +| `mps2-an500` | `mps2/an500` | `mps2-an500` | Cortex-M7 | +| `mps2-an521` | `mps2/an521/cpu0` | `mps2-an521` | Cortex-M33 | +| `mps3-an547` | `mps3/corstone300/an547` | `mps3-an547` | Cortex-M55 | + +The Armv8.1-M MVE FIPS202 backend is an `OPT=1` feature and is built for +`mps3-an547` only (the only listed core with MVE). + +## How it works + +The test binaries are built by Zephyr's CMake rather than the generic +`test/mk/rules.mk` link rule. This is wired through two generic hooks in the +test build (see `test/mk/components.mk` and `test/mk/rules.mk`): + +- `CUSTOM_BUILD` -- a recipe that replaces the default link step. When set, the + generic rules also attach each binary's *sources* (rather than prebuilt + objects/libraries) as its prerequisites, via the per-binary `TEST_SRCS` + variable. Setting it is the only thing that makes a platform "source-driven"; + adding a new test binary in `components.mk` needs no change here. + +- `TEST_SRCS` -- the per-binary list of test sources (entrypoint plus support + sources such as `notrandombytes` and, for the benchmarks, the cycle HAL). + `platform.mk`'s `CUSTOM_BUILD` passes it to CMake as `ZEPHYR_TEST_SRCS`. + +The Zephyr application lives in `app/`: + +- `app/CMakeLists.txt` compiles the `mlkem_native.c` amalgamation, the test + sources, and `shim.c`. The test's `main()` is renamed to `mlk_test_main` via + `-Dmain=mlk_test_main` so the shim can own `main()`. +- `app/shim.c` fetches argv via semihosting, calls `mlk_test_main`, and exits + QEMU with the test's return code (again via semihosting). +- `app/Kconfig` force-selects the FPU/MVE features for Corstone-300, whose + Zephyr SoC does not otherwise advertise MVE. + +`platform.mk` forwards the test binary's full `CFLAGS` to the CMake build, so +the firmware is compiled with the project's own warning/optimization/standard +policy and feature defines rather than a divergent Zephyr default. + +`exec_wrapper.py` runs a built ELF under QEMU (`-nographic`, semihosting on), +forwarding the guest's exit code; it is wired in as `EXEC_WRAPPER`. diff --git a/test/zephyr/app/CMakeLists.txt b/test/zephyr/app/CMakeLists.txt new file mode 100644 index 000000000..a7745f1b3 --- /dev/null +++ b/test/zephyr/app/CMakeLists.txt @@ -0,0 +1,70 @@ +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(mlkem_native_zephyr) + +# Parameters supplied via -D from platform.mk: +# ZEPHYR_NATIVE_ROOT - mlkem-native checkout the test is built from +# ZEPHYR_TEST_SRCS - test sources (entrypoint + support, e.g. notrandombytes +# and -- for bench -- the HAL), relative to +# ZEPHYR_NATIVE_ROOT, space separated +# ZEPHYR_TEST_CFLAGS - the test binary's CFLAGS (see below); includes the +# parameter set (-DMLK_CONFIG_PARAMETER_SET=...) +set(R ${ZEPHYR_NATIVE_ROOT}) + +separate_arguments(_test_srcs UNIX_COMMAND "${ZEPHYR_TEST_SRCS}") +list(TRANSFORM _test_srcs PREPEND ${R}/) + +target_sources(app PRIVATE + ${R}/mlkem/mlkem_native.c + ${_test_srcs} + ${CMAKE_CURRENT_SOURCE_DIR}/shim.c +) + +target_include_directories(app PRIVATE + ${R}/mlkem + ${R}/test/notrandombytes + ${R}/test/hal + # So a test that sets MLK_CONFIG_FILE (e.g. test_alloc) finds its config by + # name; the flag is forwarded in ZEPHYR_TEST_CFLAGS (see test/zephyr/platform.mk). + ${R}/test/configs +) + +# The test binary's CFLAGS, forwarded from the build (test/zephyr/platform.mk) +# and applied to the mlkem amalgamation and the test sources alike, so they are +# built with the project's own warning/opt/std policy and feature defines. This +# includes the per-test defines -- e.g. -DMLK_STATIC_TESTABLE= (test_unit) or +# -DMLK_CONFIG_FILE= (test_alloc; angle brackets so the +# header, found via the test/configs include dir, needs no quoting to survive +# the make/shell/CMake layers). +if(ZEPHYR_TEST_CFLAGS) + separate_arguments(_cflags UNIX_COMMAND "${ZEPHYR_TEST_CFLAGS}") + target_compile_options(app PRIVATE ${_cflags}) +endif() + +# The benchmark HAL is the only test source that pulls in Zephyr SDK headers +# ( for the cycle counter). Those headers are not clean under +# the project's strict, -Werror'd warning set forwarded above (e.g. +# -Wconversion, -Wsign-conversion, -pedantic), so drop -Werror just for this +# file -- our own sources stay strict. +set_source_files_properties(${R}/test/hal/hal.c + PROPERTIES COMPILE_OPTIONS "-Wno-error") + +# Optional native FIPS202 backend (e.g. Armv8.1-M MVE on Cortex-M55). The +# monolithic mlkem_native.c already includes the backend C sources; its +# assembly counterpart comes from mlkem_native_asm.S. +if(ZEPHYR_FIPS202_BACKEND) + target_sources(app PRIVATE ${R}/mlkem/mlkem_native_asm.S) + target_compile_definitions(app PRIVATE + MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202 + "MLK_CONFIG_FIPS202_BACKEND_FILE=\"${ZEPHYR_FIPS202_BACKEND}\"") +endif() + +# Each test brings its own int main(void); rename it so the Zephyr shim +# (shim.c) owns main() and can stop QEMU with the test's exit code. Only the +# test entrypoint in ZEPHYR_TEST_SRCS defines main(); the support sources +# (notrandombytes, hal) don't, so applying the define to all is harmless. +set_source_files_properties(${_test_srcs} + PROPERTIES COMPILE_DEFINITIONS "main=mlk_test_main") diff --git a/test/zephyr/app/Kconfig b/test/zephyr/app/Kconfig new file mode 100644 index 000000000..444b088ac --- /dev/null +++ b/test/zephyr/app/Kconfig @@ -0,0 +1,14 @@ +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Corstone-300's Zephyr SoC doesn't advertise MVE, but its Cortex-M55 (and +# QEMU's mps3-an547) has it. Force-select it to build the Armv8.1-M MVE FIPS202 +# backend. Enabled per target by platform.mk. +config FIPS202_MVE_BACKEND + bool "Build with the Armv8.1-M MVE FIPS202 backend" + select FPU + select ARMV8_M_DSP + select ARMV8_1_M_MVEI + select ARMV8_1_M_MVEF + +source "Kconfig.zephyr" diff --git a/test/zephyr/app/prj.conf b/test/zephyr/app/prj.conf new file mode 100644 index 000000000..0e42e22a6 --- /dev/null +++ b/test/zephyr/app/prj.conf @@ -0,0 +1,4 @@ +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT +CONFIG_MAIN_STACK_SIZE=32768 +CONFIG_BOOT_BANNER=n diff --git a/test/zephyr/app/shim.c b/test/zephyr/app/shim.c new file mode 100644 index 000000000..b87a21391 --- /dev/null +++ b/test/zephyr/app/shim.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) The mlkem-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * Zephyr entrypoint shim for the mlkem-native tests. + * + * Each test's main() is renamed to mlk_test_main (-Dmain=mlk_test_main) and + * called from here. argv is fetched from the host via semihosting (needed by + * the acvp/wycheproof tests); on return we exit QEMU with the test's return + * code, again via semihosting. + */ + +#include + +extern int mlk_test_main(int argc, char **argv); + +/* Arm semihosting operations, trapped by QEMU via `bkpt 0xab`. */ +#define SYS_GET_CMDLINE 0x15 +#define SYS_EXIT_EXTENDED 0x20 +#define ADP_STOPPED_APPLICATION_EXIT 0x20026UL + +#define MAX_ARGS 32 +#define CMDLINE_BUF_SIZE 65536 + +static long semihost(unsigned op, void *arg) +{ + register unsigned r0 __asm__("r0") = op; + register void *r1 __asm__("r1") = arg; + __asm__ volatile("bkpt 0xab" : "+r"(r0) : "r"(r1) : "memory"); + return (long)r0; +} + +static char cmdline[CMDLINE_BUF_SIZE]; +static char *argv_buf[MAX_ARGS + 1]; + +/* Fetch the host command line via semihosting and split it into argv. */ +static int get_args(char ***argv_out) +{ + struct + { + char *buf; + size_t len; + } block = {cmdline, sizeof(cmdline) - 1}; + int argc = 0; + char *p = cmdline; + + *argv_out = argv_buf; + if (semihost(SYS_GET_CMDLINE, &block) != 0) + { + argv_buf[0] = "test"; + argv_buf[1] = NULL; + return 1; + } + + while (*p != '\0' && argc < MAX_ARGS) + { + while (*p == ' ' || *p == '\t') + { + p++; + } + if (*p == '\0') + { + break; + } + argv_buf[argc++] = p; + while (*p != '\0' && *p != ' ' && *p != '\t') + { + p++; + } + if (*p != '\0') + { + *p++ = '\0'; + } + } + argv_buf[argc] = NULL; + return argc; +} + +static void semihost_exit(int code) +{ + unsigned long block[2] = {ADP_STOPPED_APPLICATION_EXIT, (unsigned long)code}; + semihost(SYS_EXIT_EXTENDED, block); +} + +int main(void) +{ + char **argv; + int argc = get_args(&argv); + int rc = mlk_test_main(argc, argv); + semihost_exit(rc); + return rc; +} diff --git a/test/zephyr/exec_wrapper.py b/test/zephyr/exec_wrapper.py new file mode 100755 index 000000000..d4fd686e8 --- /dev/null +++ b/test/zephyr/exec_wrapper.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Runs a Zephyr ELF under QEMU (machine from QEMU_MACHINE, set in platform.mk). +# Extra args reach the guest via semihosting (see app/shim.c), the UART console +# goes to stdout via -nographic, and the guest's semihosting exit sets QEMU's +# return code. + +import os +import sys +import subprocess + +binpath = sys.argv[1] +args = sys.argv[2:] +machine = os.environ.get("QEMU_MACHINE", "mps3-an547") + +semihosting_args = [binpath] + args +semihosting_config = "enable=on," + ",".join(f"arg={a}" for a in semihosting_args) + +qemu_cmd = [ + "qemu-system-arm", + "-M", + machine, + "-monitor", + "none", + "-nographic", + "-semihosting-config", + semihosting_config, + "-kernel", + binpath, +] + +result = subprocess.run(qemu_cmd, encoding="utf-8", capture_output=True, timeout=300) +sys.stdout.write(result.stdout) +if result.returncode != 0: + sys.stderr.write(result.stderr) +sys.exit(result.returncode) diff --git a/test/zephyr/platform.mk b/test/zephyr/platform.mk new file mode 100644 index 000000000..3b84a9608 --- /dev/null +++ b/test/zephyr/platform.mk @@ -0,0 +1,111 @@ +# Copyright (c) The mlkem-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +# Zephyr test platform for QEMU-emulated Arm MPS boards. +# +# Each test binary is built as a Zephyr application by CMake (which owns the arm +# toolchain, the per-board arch flags and libc via the .#zephyr dev shell). The +# generic make rules don't link these binaries; instead CUSTOM_BUILD (see +# test/mk/rules.mk) drives the CMake build. The list of test sources for each +# binary comes from TEST_SRCS, a target-specific variable set by the generic +# test/mk/components.mk -- adding a new test binary there needs no change here. + +PLATFORM_PATH := test/zephyr + +# BUILD_DIR is set by the top-level Makefile after this file is included; +# define it here too so CUSTOM_BUILD below expands to the right path. +BUILD_DIR ?= test/build + +# ZEPHYR_TARGET= selects a target. Each key maps to a Zephyr board and the +# QEMU machine emulating it; add a board with a row below. +ZEPHYR_TARGET ?= mps3-an547 + +ZEPHYR_BOARD_mps2-an385 := mps2/an385 +ZEPHYR_QEMU_mps2-an385 := mps2-an385 # Cortex-M3 +ZEPHYR_BOARD_mps2-an386 := mps2/an386 +ZEPHYR_QEMU_mps2-an386 := mps2-an386 # Cortex-M4 +ZEPHYR_BOARD_mps2-an500 := mps2/an500 +ZEPHYR_QEMU_mps2-an500 := mps2-an500 # Cortex-M7 +ZEPHYR_BOARD_mps2-an521 := mps2/an521/cpu0 +ZEPHYR_QEMU_mps2-an521 := mps2-an521 # Cortex-M33 +ZEPHYR_BOARD_mps3-an547 := mps3/corstone300/an547 +ZEPHYR_QEMU_mps3-an547 := mps3-an547 # Cortex-M55 + +ZEPHYR_FIPS202_BACKEND_mps3-an547 := fips202/native/armv81m/mve.h + +ZEPHYR_TARGETS := mps2-an385 mps2-an386 mps2-an500 mps2-an521 mps3-an547 + +ZEPHYR_BOARD := $(ZEPHYR_BOARD_$(ZEPHYR_TARGET)) +export QEMU_MACHINE := $(strip $(ZEPHYR_QEMU_$(ZEPHYR_TARGET))) + +ifeq ($(ZEPHYR_BOARD),) +$(error Unknown ZEPHYR_TARGET '$(ZEPHYR_TARGET)'. Supported: $(ZEPHYR_TARGETS)) +endif + +# The test binaries are built by Zephyr's CMake, not the generic Make rules, so +# each binary depends on its sources rather than on objects/libraries built (and +# then discarded) here. Setting CUSTOM_BUILD (below) switches test/mk/components.mk +# to attach source prerequisites, and overrides the link step to consume them via +# TEST_SRCS. It must be defined before components.mk is included (it is: the +# top-level Makefile includes this platform file first). +OPT ?= 0 + +# Native backends are an OPT=1 feature (an547 builds the Armv8.1-M MVE backend). +ZEPHYR_FIPS202_BACKEND := $(if $(filter 1,$(OPT)),$(strip $(ZEPHYR_FIPS202_BACKEND_$(ZEPHYR_TARGET)))) + +ZEPHYR_APP := $(PLATFORM_PATH)/app +ZEPHYR_BUILD_DIR := $(BUILD_DIR)/zephyr/$(ZEPHYR_TARGET) + +# Build the binary at $@ as a Zephyr application and drop the resulting ELF +# there. The bin's parameter set is the trailing digits of its name; its test +# sources come from the binary's TEST_SRCS (set by test/mk/components.mk); the +# mlkem sources are also prerequisites but are built by the app's own +# mlkem_native.c amalgamation, so they are not passed here. This is expanded in +# the recipe context, so $@ and $(TEST_SRCS) resolve to the specific bin being +# built -- a per-binary build dir keyed on $(notdir $@) lets binaries build in +# parallel. +# $@ the bin path being built +# $(TEST_SRCS) test entrypoint + notrandombytes (+ hal) sources for this bin +ZEPHYR_OUT = $(ZEPHYR_BUILD_DIR)/$(notdir $@) + +# Test-tuning defines. The test sources default these (via #ifndef) to values +# sized for native hardware; QEMU is far slower, so shrink the iteration counts. +# Amended onto CFLAGS so they forward with everything else below. +CFLAGS += -DNTESTS_FUNC=3 -DNTESTS_KAT=100 \ + -DMLK_BENCHMARK_NTESTS=10 -DMLK_BENCHMARK_NITERATIONS=10 -DMLK_BENCHMARK_NWARMUP=10 \ + -DNUM_RANDOM_TESTS=100 -DNUM_RANDOM_TESTS_REJ_UNIFORM=100 -DMAX_INTT_CONSTANT_COEFF=512 + +# Forward the test binary's CFLAGS to the Zephyr CMake build, which applies them +# (via target_compile_options) to the mlkem amalgamation and the test sources -- +# the same flags the normal build uses, so the firmware is built with the +# project's own warning/opt/std policy and feature defines (including the +# parameter set) rather than a divergent Zephyr default. This uses '=' (not ':=') +# and is evaluated in the CUSTOM_BUILD recipe context, so $(CFLAGS) includes the +# binary's target-specific additions (e.g. -DMLK_STATIC_TESTABLE= for test_unit, +# -DMLK_CONFIG_FILE="..." for test_alloc). Two rewrites: +# - -Imlkem -> absolute, as the CMake build runs from its own build dir, not +# the repo root (and the alloc config path is relative to -Imlkem); +# - the embedded quotes of -DMLK_CONFIG_FILE="..." would be eaten twice on the +# way to the compiler (once by the recipe shell, once by CMake's +# separate_arguments), leaving a bare token #include rejects; doubling the +# backslash escaping (\" -> \\") makes one level survive each layer. +# The platform is run with AUTO=0 (see .github/workflows/zephyr.yml), so the +# host-arch flags that AUTO=1 would add to CFLAGS -- which the Zephyr toolchain +# must not see, as it selects the target arch itself -- are not present. +ZEPHYR_TEST_CFLAGS = $(subst \",\\\",$(patsubst -Imlkem,-I$(abspath mlkem),$(CFLAGS))) + +CUSTOM_BUILD = \ + echo " ZEPHYR $(ZEPHYR_TARGET): $(notdir $@)" && \ + cmake -GNinja -S $(ZEPHYR_APP) -B $(ZEPHYR_OUT) \ + -DBOARD=$(ZEPHYR_BOARD) \ + -DZEPHYR_NATIVE_ROOT=$(CURDIR) \ + -DZEPHYR_TEST_SRCS="$(strip $(TEST_SRCS))" \ + -DZEPHYR_TEST_CFLAGS="$(ZEPHYR_TEST_CFLAGS)" \ + -DZEPHYR_FIPS202_BACKEND=$(ZEPHYR_FIPS202_BACKEND) \ + $(if $(ZEPHYR_FIPS202_BACKEND),-DCONFIG_FIPS202_MVE_BACKEND=y) \ + -DUSER_CACHE_DIR=$(abspath $(ZEPHYR_OUT)/.cache) \ + >/dev/null && \ + cmake --build $(ZEPHYR_OUT) >/dev/null && \ + cp $(ZEPHYR_OUT)/zephyr/zephyr.elf $@ + +EXEC_WRAPPER := $(abspath $(PLATFORM_PATH)/exec_wrapper.py)