From 9b3c37e36edb8f7b1fab76d22bdb8285b19b9bbf Mon Sep 17 00:00:00 2001 From: willieyz Date: Mon, 8 Dec 2025 16:23:03 +0800 Subject: [PATCH 1/4] Backend unit tests: (mld_polyz_unpack/_c) - Add test infrastructure in Makefile and scripts/tests - Update build rules in test/mk/ for component testing - Create test_unit.c and implement unit tests for mld_polyz_unpack and mld_polyz_unpack_c Signed-off-by: willieyz --- Makefile | 34 +++++++--- scripts/tests | 40 +++++++++++ test/mk/components.mk | 41 +++++++++++- test/mk/rules.mk | 31 +++++++++ test/test_unit.c | 151 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 285 insertions(+), 12 deletions(-) create mode 100644 test/test_unit.c diff --git a/Makefile b/Makefile index 99e6b2027..cc945c545 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,14 @@ # Copyright (c) The mldsa-native project authors # SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT -.PHONY: func kat acvp stack \ - func_44 kat_44 acvp_44 stack_44 \ - func_65 kat_65 acvp_65 stack_65 \ - func_87 kat_87 acvp_87 stack_87 \ - run_func run_kat run_acvp run_stack \ - run_func_44 run_kat_44 run_stack_44 \ - run_func_65 run_kat_65 run_stack_65 \ - run_func_87 run_kat_87 run_stack_87 \ +.PHONY: func kat acvp stack unit \ + func_44 kat_44 acvp_44 stack_44 unit_44 \ + func_65 kat_65 acvp_65 stack_65 unit_65 \ + func_87 kat_87 acvp_87 stack_87 unit_87 \ + run_func run_kat run_acvp run_stack run_unit \ + run_func_44 run_kat_44 run_stack_44 run_unit_44 \ + run_func_65 run_kat_65 run_stack_65 run_unit_65 \ + run_func_87 run_kat_87 run_stack_87 run_unit_87 \ bench_44 bench_65 bench_87 bench \ run_bench_44 run_bench_65 run_bench_87 run_bench \ bench_components_44 bench_components_65 bench_components_87 bench_components \ @@ -49,7 +49,7 @@ quickcheck: test build: func kat acvp $(Q)echo " Everything builds fine!" -test: run_kat run_func run_acvp +test: run_kat run_func run_acvp run_unit $(Q)echo " Everything checks fine!" run_kat_44: kat_44 @@ -68,6 +68,14 @@ run_func_87: func_87 $(W) $(MLDSA87_DIR)/bin/test_mldsa87 run_func: run_func_44 run_func_65 run_func_87 +run_unit_44: unit_44 + $(W) $(MLDSA44_DIR)/bin/test_unit44 +run_unit_65: unit_65 + $(W) $(MLDSA65_DIR)/bin/test_unit65 +run_unit_87: unit_87 + $(W) $(MLDSA87_DIR)/bin/test_unit87 +run_unit: run_unit_44 run_unit_65 run_unit_87 + run_acvp: acvp EXEC_WRAPPER="$(EXEC_WRAPPER)" python3 ./test/acvp_client.py $(if $(ACVP_VERSION),--version $(ACVP_VERSION)) @@ -79,6 +87,14 @@ func_87: $(MLDSA87_DIR)/bin/test_mldsa87 $(Q)echo " FUNC ML-DSA-87: $^" func: func_44 func_65 func_87 +unit_44: $(MLDSA44_DIR)/bin/test_unit44 + $(Q)echo " UNIT ML-DSA-44: $^" +unit_65: $(MLDSA65_DIR)/bin/test_unit65 + $(Q)echo " UNIT ML-DSA-65: $^" +unit_87: $(MLDSA87_DIR)/bin/test_unit87 + $(Q)echo " UNIT ML-DSA-87: $^" +unit: unit_44 unit_65 unit_87 + kat_44: $(MLDSA44_DIR)/bin/gen_KAT44 $(Q)echo " KAT ML-DSA-44: $^" kat_65: $(MLDSA65_DIR)/bin/gen_KAT65 diff --git a/scripts/tests b/scripts/tests index e2e18b0cf..2243189f6 100755 --- a/scripts/tests +++ b/scripts/tests @@ -211,6 +211,7 @@ class TEST_TYPES(Enum): CUSTOM_BACKEND = 16 MULTILEVEL_BUILD = 17 MULTILEVEL_BUILD_NATIVE = 18 + UNIT = 19 def is_benchmark(self): return self in [TEST_TYPES.BENCH, TEST_TYPES.BENCH_COMPONENTS] @@ -283,6 +284,8 @@ class TEST_TYPES(Enum): return "Example (multilevel build)" if self == TEST_TYPES.MULTILEVEL_BUILD_NATIVE: return "Example (multilevel build, native)" + if self == TEST_TYPES.UNIT: + return "Unit Test" def make_dir(self): if self == TEST_TYPES.BASIC: @@ -346,6 +349,8 @@ class TEST_TYPES(Enum): return "" if self == TEST_TYPES.MULTILEVEL_BUILD_NATIVE: return "" + if self == TEST_TYPES.UNIT: + return "unit" def make_run_target(self, scheme): t = self.make_target() @@ -632,6 +637,19 @@ class Tests: self.check_fail() + def unit(self): + def _unit(opt): + self._compile_schemes(TEST_TYPES.UNIT, opt) + if self.args.run: + self._run_schemes(TEST_TYPES.UNIT, opt) + + if self.do_no_opt(): + _unit(False) + if self.do_opt(): + _unit(True) + + self.check_fail() + def acvp(self): def _acvp(opt): self._compile_schemes(TEST_TYPES.ACVP, opt) @@ -765,6 +783,7 @@ class Tests: acvp = self.args.acvp examples = self.args.examples stack = self.args.stack + unit = self.args.unit def _all(opt): if func is True: @@ -775,6 +794,8 @@ class Tests: self._compile_schemes(TEST_TYPES.ACVP, opt) if stack is True: self._compile_schemes(TEST_TYPES.STACK, opt) + if unit is True: + self._compile_schemes(TEST_TYPES.UNIT, opt) if self.args.check_namespace is True: p = subprocess.run( @@ -796,6 +817,8 @@ class Tests: self._run_scheme(TEST_TYPES.ACVP, opt, None) if stack is True: self._run_schemes(TEST_TYPES.STACK, opt, suppress_output=False) + if unit is True: + self._run_schemes(TEST_TYPES.UNIT, opt) if self.do_no_opt(): _all(False) @@ -1104,6 +1127,14 @@ def cli(): "--no-acvp", action="store_false", dest="acvp", help="Do not run acvp test" ) + unit_group = all_parser.add_mutually_exclusive_group() + unit_group.add_argument( + "--unit", action="store_true", dest="unit", help="Run unit test", default=True + ) + unit_group.add_argument( + "--no-unit", action="store_false", dest="unit", help="Do not run unit test" + ) + examples_group = all_parser.add_mutually_exclusive_group() examples_group.add_argument( "--examples", @@ -1333,6 +1364,13 @@ def cli(): "kat", help="Run the kat tests for all parameter sets", parents=[common_parser] ) + # unit arguments + unit_parser = cmd_subparsers.add_parser( + "unit", + help="Run the unit tests for all parameter sets", + parents=[common_parser], + ) + # stack arguments stack_parser = cmd_subparsers.add_parser( "stack", @@ -1377,6 +1415,8 @@ def cli(): Tests(args).func() elif args.cmd == "kat": Tests(args).kat() + elif args.cmd == "unit": + Tests(args).unit() elif args.cmd == "stack": Tests(args).stack() elif args.cmd == "size": diff --git a/test/mk/components.mk b/test/mk/components.mk index c605815be..119a0bd5f 100644 --- a/test/mk/components.mk +++ b/test/mk/components.mk @@ -14,7 +14,7 @@ ifeq ($(OPT),1) CFLAGS += -DMLD_CONFIG_USE_NATIVE_BACKEND_ARITH -DMLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 endif -ALL_TESTS = test_mldsa acvp_mldsa bench_mldsa bench_components_mldsa gen_KAT test_stack +ALL_TESTS = test_mldsa test_unit acvp_mldsa bench_mldsa bench_components_mldsa gen_KAT test_stack MLDSA44_DIR = $(BUILD_DIR)/mldsa44 MLDSA65_DIR = $(BUILD_DIR)/mldsa65 @@ -27,6 +27,13 @@ $(MLDSA65_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 MLDSA87_OBJS = $(call MAKE_OBJS,$(MLDSA87_DIR),$(SOURCES) $(FIPS202_SRCS)) $(MLDSA87_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 +# Unit test object files - same sources but with MLD_STATIC_TESTABLE= +MLDSA44_UNIT_OBJS = $(call MAKE_OBJS,$(MLDSA44_DIR)/unit,$(SOURCES) $(FIPS202_SRCS)) +$(MLDSA44_UNIT_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes +MLDSA65_UNIT_OBJS = $(call MAKE_OBJS,$(MLDSA65_DIR)/unit,$(SOURCES) $(FIPS202_SRCS)) +$(MLDSA65_UNIT_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes +MLDSA87_UNIT_OBJS = $(call MAKE_OBJS,$(MLDSA87_DIR)/unit,$(SOURCES) $(FIPS202_SRCS)) +$(MLDSA87_UNIT_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes CFLAGS += -Imldsa @@ -34,6 +41,12 @@ $(BUILD_DIR)/libmldsa44.a: $(MLDSA44_OBJS) $(BUILD_DIR)/libmldsa65.a: $(MLDSA65_OBJS) $(BUILD_DIR)/libmldsa87.a: $(MLDSA87_OBJS) +# Unit libraries with exposed internal functions +$(BUILD_DIR)/libmldsa44_unit.a: $(MLDSA44_UNIT_OBJS) +$(BUILD_DIR)/libmldsa65_unit.a: $(MLDSA65_UNIT_OBJS) +$(BUILD_DIR)/libmldsa87_unit.a: $(MLDSA87_UNIT_OBJS) + + $(BUILD_DIR)/libmldsa.a: $(MLDSA44_OBJS) $(MLDSA65_OBJS) $(MLDSA87_OBJS) $(MLDSA44_DIR)/bin/bench_mldsa44: CFLAGS += -Itest/hal @@ -47,6 +60,16 @@ $(MLDSA44_DIR)/bin/test_stack44: CFLAGS += -Imldsa -fstack-usage $(MLDSA65_DIR)/bin/test_stack65: CFLAGS += -Imldsa -fstack-usage $(MLDSA87_DIR)/bin/test_stack87: CFLAGS += -Imldsa -fstack-usage +$(MLDSA44_DIR)/bin/test_unit44: CFLAGS += -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes +$(MLDSA65_DIR)/bin/test_unit65: CFLAGS += -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes +$(MLDSA87_DIR)/bin/test_unit87: CFLAGS += -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes + +# Unit library object files compiled with MLD_STATIC_TESTABLE= +$(MLDSA44_DIR)/unit_%: CFLAGS += -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes +$(MLDSA65_DIR)/unit_%: CFLAGS += -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes +$(MLDSA87_DIR)/unit_%: CFLAGS += -DMLD_STATIC_TESTABLE= -Wno-missing-prototypes + + $(MLDSA44_DIR)/bin/bench_mldsa44: $(MLDSA44_DIR)/test/hal/hal.c.o $(MLDSA65_DIR)/bin/bench_mldsa65: $(MLDSA65_DIR)/test/hal/hal.c.o $(MLDSA87_DIR)/bin/bench_mldsa87: $(MLDSA87_DIR)/test/hal/hal.c.o @@ -58,18 +81,30 @@ $(MLDSA44_DIR)/bin/%: CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 $(MLDSA65_DIR)/bin/%: CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 $(MLDSA87_DIR)/bin/%: CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 -# Link tests with respective library +# Link tests with respective library (except test_unit which includes sources directly) define ADD_SOURCE $(BUILD_DIR)/$(1)/bin/$(2)$(shell echo $(1) | tr -d -c 0-9): LDLIBS += -L$(BUILD_DIR) -l$(1) $(BUILD_DIR)/$(1)/bin/$(2)$(shell echo $(1) | tr -d -c 0-9): $(BUILD_DIR)/$(1)/test/$(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$(shell echo $(1) | tr -d -c 0-9): LDLIBS += -L$(BUILD_DIR) -l$(1)_unit +$(BUILD_DIR)/$(1)/bin/test_unit$(shell echo $(1) | tr -d -c 0-9): $(BUILD_DIR)/$(1)/test/test_unit.c.o $(BUILD_DIR)/lib$(1)_unit.a $(call MAKE_OBJS, $(BUILD_DIR)/$(1), $(wildcard test/notrandombytes/*.c)) +endef + + $(foreach scheme,mldsa44 mldsa65 mldsa87, \ - $(foreach test,$(ALL_TESTS), \ + $(foreach test,$(filter-out test_unit,$(ALL_TESTS)), \ $(eval $(call ADD_SOURCE,$(scheme),$(test))) \ ) \ ) +$(foreach scheme,mldsa44 mldsa65 mldsa87, \ + $(eval $(call ADD_SOURCE_UNIT,$(scheme))) \ +) + $(ALL_TESTS:%=$(MLDSA44_DIR)/bin/%44): $(call MAKE_OBJS, $(MLDSA44_DIR), $(wildcard test/notrandombytes/*.c) $(EXTRA_SOURCES)) $(ALL_TESTS:%=$(MLDSA65_DIR)/bin/%65): $(call MAKE_OBJS, $(MLDSA65_DIR), $(wildcard test/notrandombytes/*.c) $(EXTRA_SOURCES)) $(ALL_TESTS:%=$(MLDSA87_DIR)/bin/%87): $(call MAKE_OBJS, $(MLDSA87_DIR), $(wildcard test/notrandombytes/*.c) $(EXTRA_SOURCES)) diff --git a/test/mk/rules.mk b/test/mk/rules.mk index 88dd1d1d2..320747ff4 100644 --- a/test/mk/rules.mk +++ b/test/mk/rules.mk @@ -52,3 +52,34 @@ $(BUILD_DIR)/mldsa87/%.S.o: %.S $(CONFIG) $(Q)echo " AS $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) $(Q)$(CC) -c -o $@ $(CFLAGS) $< + + +$(BUILD_DIR)/mldsa44/unit/%.c.o: %.c $(CONFIG) + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa44/unit/%.S.o: %.S $(CONFIG) + $(Q)echo " AS $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa65/unit/%.c.o: %.c $(CONFIG) + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa65/unit/%.S.o: %.S $(CONFIG) + $(Q)echo " AS $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa87/unit/%.c.o: %.c $(CONFIG) + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa87/unit/%.S.o: %.S $(CONFIG) + $(Q)echo " AS $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< diff --git a/test/test_unit.c b/test/test_unit.c new file mode 100644 index 000000000..61a87c428 --- /dev/null +++ b/test/test_unit.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#include +#include +#include +#include "notrandombytes/notrandombytes.h" + +#include "../mldsa/src/poly_kl.h" + +#ifndef NUM_RANDOM_TESTS +#ifdef MLDSA_DEBUG +#define NUM_RANDOM_TESTS 1000 +#else +#define NUM_RANDOM_TESTS 10000 +#endif +#endif /* !NUM_RANDOM_TESTS */ + +#define CHECK(x) \ + do \ + { \ + int r; \ + r = (x); \ + if (!r) \ + { \ + fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +/* Declarations for _c functions exposed by MLD_STATIC_TESTABLE= */ +void mld_polyz_unpack_c(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES]); +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) || \ + defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) + +/* Backend unit test helper functions */ +static void print_i32_array(const char *label, const int32_t *array, size_t len) +{ + size_t i; + fprintf(stderr, "%s:\n", label); + for (i = 0; i < len; i++) + { + if (i % 8 == 0) + { + fprintf(stderr, " "); + } + fprintf(stderr, "%8d", array[i]); + if (i % 8 == 7) + { + fprintf(stderr, "\n"); + } + else + { + fprintf(stderr, " "); + } + } + if (len % 8 != 0) + { + fprintf(stderr, "\n"); + } +} + +static int compare_i32_arrays(const int32_t *a, const int32_t *b, unsigned len, + const char *test_name, const int32_t *input) +{ + unsigned i; + for (i = 0; i < len; i++) + { + if (a[i] != b[i]) + { + fprintf(stderr, "FAIL: %s\n", test_name); + fprintf(stderr, + " First difference at index %u: native=%d, reference=%d\n", i, + a[i], b[i]); + if (input) + { + print_i32_array("Input", input, len); + } + print_i32_array("Native result", a, len); + print_i32_array("Reference result", b, len); + return 0; + } + } + return 1; +} + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) || \ + defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) +static int test_mld_polyz_unpack_core(const uint8_t *input, + const char *test_name) +{ + mld_poly test_poly, ref_poly; + + mld_polyz_unpack(&test_poly, input); + mld_polyz_unpack_c(&ref_poly, input); + + CHECK(compare_i32_arrays(test_poly.coeffs, ref_poly.coeffs, MLDSA_N, + test_name, NULL)); + return 0; +} + +static int test_native_polyz_unpack(void) +{ + MLD_ALIGN uint8_t test_bytes[MLDSA_POLYZ_PACKEDBYTES]; + int i; + + memset(test_bytes, 0, MLDSA_POLYZ_PACKEDBYTES); + CHECK(test_mld_polyz_unpack_core(test_bytes, "polyz_unpack_zeros") == 0); + + + for (i = 0; i < NUM_RANDOM_TESTS; i++) + { + randombytes(test_bytes, MLDSA_POLYZ_PACKEDBYTES); + CHECK(test_mld_polyz_unpack_core(test_bytes, "polyz_unpack_random") == 0); + } + + return 0; +} +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 || MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + + +static int test_backend_units(void) +{ + /* Set fixed seed for reproducible tests */ + randombytes_reset(); + +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) || \ + defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) + CHECK(test_native_polyz_unpack() == 0); +#endif + + return 0; +} +#endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 || MLD_USE_NATIVE_POLYZ_UNPACK_19 */ + +int main(void) +{ + /* WARNING: Test-only + * Normally, you would want to seed a PRNG with trustworthy entropy here. */ + randombytes_reset(); + + /* Run backend unit tests */ +#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) + CHECK(test_backend_units() == 0); +#endif + + + return 0; +} From dd28e535cbd35a5fb9ead327e2f62ed06a8292f8 Mon Sep 17 00:00:00 2001 From: "Matthias J. Kannwischer" Date: Wed, 10 Dec 2025 15:52:45 +0800 Subject: [PATCH 2/4] test: remove MLD_ALIGN Signed-off-by: Matthias J. Kannwischer --- test/test_unit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_unit.c b/test/test_unit.c index 61a87c428..77ff44755 100644 --- a/test/test_unit.c +++ b/test/test_unit.c @@ -103,7 +103,7 @@ static int test_mld_polyz_unpack_core(const uint8_t *input, static int test_native_polyz_unpack(void) { - MLD_ALIGN uint8_t test_bytes[MLDSA_POLYZ_PACKEDBYTES]; + uint8_t test_bytes[MLDSA_POLYZ_PACKEDBYTES]; int i; memset(test_bytes, 0, MLDSA_POLYZ_PACKEDBYTES); From 881027e640139273fbf16e84927a55e9c0b99ded Mon Sep 17 00:00:00 2001 From: "Matthias J. Kannwischer" Date: Thu, 11 Dec 2025 11:18:26 +0800 Subject: [PATCH 3/4] [TEST]: Run unit tests thorugh valgrind Signed-off-by: Matthias J. Kannwischer --- .github/actions/functest/action.yml | 6 ++++- .github/actions/multi-functest/action.yml | 14 +++++++++- .github/workflows/ci.yml | 32 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/.github/actions/functest/action.yml b/.github/actions/functest/action.yml index ec984e5de..5ca70d60f 100644 --- a/.github/actions/functest/action.yml +++ b/.github/actions/functest/action.yml @@ -54,6 +54,9 @@ inputs: stack: description: Determine whether to run stack analysis or not default: "false" + unit: + description: Determine whether to run unit tests or not + default: "true" extra_args: description: Additional arguments to pass to the tests script default: "" @@ -70,6 +73,7 @@ runs: echo ACVP="${{ inputs.acvp == 'true' && 'acvp' || 'no-acvp' }}" >> $GITHUB_ENV echo EXAMPLES="${{ inputs.examples == 'true' && 'examples' || 'no-examples' }}" >> $GITHUB_ENV echo STACK="${{ inputs.stack == 'true' && 'stack' || 'no-stack' }}" >> $GITHUB_ENV + echo UNIT="${{ inputs.unit == 'true' && 'unit' || 'no-unit' }}" >> $GITHUB_ENV - name: Setup nix uses: ./.github/actions/setup-shell with: @@ -104,7 +108,7 @@ runs: shell: ${{ env.SHELL }} run: | make clean - ./scripts/tests all ${{ inputs.check_namespace == 'true' && '--check-namespace' || ''}} --exec-wrapper="${{ inputs.exec_wrapper }}" --cross-prefix="${{ inputs.cross_prefix }}" --cflags="${{ inputs.cflags }}" --ldflags="${{ inputs.ldflags }}" --opt=${{ inputs.opt }} --${{ env.FUNC }} --${{ env.KAT }} --${{ env.ACVP }} --${{ env.EXAMPLES }} --${{ env.STACK }} -v ${{ inputs.extra_args }} + ./scripts/tests all ${{ inputs.check_namespace == 'true' && '--check-namespace' || ''}} --exec-wrapper="${{ inputs.exec_wrapper }}" --cross-prefix="${{ inputs.cross_prefix }}" --cflags="${{ inputs.cflags }}" --ldflags="${{ inputs.ldflags }}" --opt=${{ inputs.opt }} --${{ env.FUNC }} --${{ env.KAT }} --${{ env.ACVP }} --${{ env.EXAMPLES }} --${{ env.STACK }} --${{ env.UNIT }} -v ${{ inputs.extra_args }} - name: Post ${{ env.MODE }} Tests shell: ${{ env.SHELL }} if: success() || failure() diff --git a/.github/actions/multi-functest/action.yml b/.github/actions/multi-functest/action.yml index f1f57716e..52178b6bc 100644 --- a/.github/actions/multi-functest/action.yml +++ b/.github/actions/multi-functest/action.yml @@ -51,6 +51,9 @@ inputs: stack: description: Determine whether to run stack analysis or not default: "false" + unit: + description: Determine whether to run unit tests or not + default: "true" extra_args: description: Additional arguments to pass to the tests script default: "" @@ -75,6 +78,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross x86_64 Tests if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-x86_64') && (success() || failure()) }} @@ -96,6 +100,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross aarch64 Tests if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-aarch64') && (success() || failure()) }} @@ -117,6 +122,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross ppc64le Tests if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-ppc64le') && (success() || failure()) }} @@ -138,6 +144,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross aarch64_be Tests if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-aarch64_be') && (success() || failure()) }} @@ -159,6 +166,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross riscv64 Tests (RVV, VLEN=128) if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv64') && (success() || failure()) }} @@ -180,6 +188,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross riscv64 Tests (RVV, VLEN=256) if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv64') && (success() || failure()) }} @@ -200,6 +209,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross riscv64 Tests (RVV, VLEN=512) if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv64') && (success() || failure()) }} @@ -220,6 +230,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross riscv64 Tests (RVV, VLEN=1024) if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv64') && (success() || failure()) }} @@ -240,6 +251,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - name: Cross riscv32 Tests if: ${{ (inputs.compile_mode == 'all' || inputs.compile_mode == 'cross-riscv32') && (success() || failure()) }} @@ -261,5 +273,5 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + unit: ${{ inputs.unit }} extra_args: ${{ inputs.extra_args }} - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1c770acb..e85a56d50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -438,6 +438,38 @@ jobs: examples: false stack: true check_namespace: false + valgrind_unit: + name: Valgrind unit tests (${{ matrix.target.name }}) + strategy: + fail-fast: false + matrix: + external: + - ${{ github.repository_owner != 'pq-code-package' }} + target: + - runner: ubuntu-latest + name: x86_64 + - runner: ubuntu-24.04-arm + name: aarch64 + runs-on: ${{ matrix.target.runner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Valgrind unit tests + uses: ./.github/actions/multi-functest + with: + gh_token: ${{ secrets.GITHUB_TOKEN }} + compile_mode: native + nix-shell: ci_valgrind-varlat_gcc15 + nix-cache: false + opt: all + cflags: "-O3" + func: false + kat: false + acvp: false + examples: false + stack: false + unit: true + check_namespace: false + extra_args: "--exec-wrapper='valgrind --error-exitcode=1'" config_variations: name: Non-standard configurations strategy: From 5b85d93ffefe19a858b28e374aea8e4e460579f6 Mon Sep 17 00:00:00 2001 From: "Matthias J. Kannwischer" Date: Thu, 11 Dec 2025 11:57:58 +0800 Subject: [PATCH 4/4] switch polyz_unpack unit test to malloc Signed-off-by: Matthias J. Kannwischer --- test/test_unit.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/test/test_unit.c b/test/test_unit.c index 77ff44755..b2ebc59f3 100644 --- a/test/test_unit.c +++ b/test/test_unit.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "notrandombytes/notrandombytes.h" @@ -103,20 +104,35 @@ static int test_mld_polyz_unpack_core(const uint8_t *input, static int test_native_polyz_unpack(void) { - uint8_t test_bytes[MLDSA_POLYZ_PACKEDBYTES]; + uint8_t *test_bytes = malloc(MLDSA_POLYZ_PACKEDBYTES); int i; + int rc = 0; - memset(test_bytes, 0, MLDSA_POLYZ_PACKEDBYTES); - CHECK(test_mld_polyz_unpack_core(test_bytes, "polyz_unpack_zeros") == 0); + if (test_bytes == NULL) + { + return 1; + } + memset(test_bytes, 0, MLDSA_POLYZ_PACKEDBYTES); + if (test_mld_polyz_unpack_core(test_bytes, "polyz_unpack_zeros") != 0) + { + rc = 1; + goto cleanup; + } for (i = 0; i < NUM_RANDOM_TESTS; i++) { randombytes(test_bytes, MLDSA_POLYZ_PACKEDBYTES); - CHECK(test_mld_polyz_unpack_core(test_bytes, "polyz_unpack_random") == 0); + if (test_mld_polyz_unpack_core(test_bytes, "polyz_unpack_random") != 0) + { + rc = 1; + goto cleanup; + } } - return 0; +cleanup: + free(test_bytes); + return rc; } #endif /* MLD_USE_NATIVE_POLYZ_UNPACK_17 || MLD_USE_NATIVE_POLYZ_UNPACK_19 */