diff --git a/.github/actions/config-variations/action.yml b/.github/actions/config-variations/action.yml index f7ad591d9..dc088afc2 100644 --- a/.github/actions/config-variations/action.yml +++ b/.github/actions/config-variations/action.yml @@ -61,6 +61,7 @@ runs: opt: ${{ inputs.opt }} extra_env: 'ASAN_OPTIONS=detect_leaks=1' examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom zeroization (explicit_bzero)" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-zeroize') }} uses: ./.github/actions/multi-functest @@ -74,6 +75,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom native capability functions (static ON)" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'native-cap-ON') }} uses: ./.github/actions/multi-functest @@ -87,6 +89,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom native capability functions (static OFF)" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'native-cap-OFF') }} uses: ./.github/actions/multi-functest @@ -100,6 +103,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom native capability functions (ID_AA64PFR1_EL1 detection)" if: ${{ (inputs.tests == 'all' || contains(inputs.tests, 'native-cap-ID_AA64PFR1_EL1')) && runner.os == 'Linux' && runner.arch == 'ARM64' }} uses: ./.github/actions/multi-functest @@ -113,6 +117,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom native capability functions (CPUID AVX2 detection)" if: ${{ (inputs.tests == 'all' || contains(inputs.tests, 'native-cap-CPUID_AVX2')) && runner.os == 'Linux' && runner.arch == 'X64' }} uses: ./.github/actions/multi-functest @@ -126,6 +131,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "No ASM" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'no-asm') }} uses: ./.github/actions/multi-functest @@ -139,6 +145,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Serial FIPS202 (no batched Keccak)" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'serial-fips202') }} uses: ./.github/actions/multi-functest @@ -152,6 +159,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom randombytes" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-randombytes') }} uses: ./.github/actions/multi-functest @@ -165,6 +173,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom memcpy" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-memcpy') }} uses: ./.github/actions/multi-functest @@ -178,6 +187,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom memset" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-memset') }} uses: ./.github/actions/multi-functest @@ -191,6 +201,7 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config - name: "Custom stdlib (memcpy + memset)" if: ${{ inputs.tests == 'all' || contains(inputs.tests, 'custom-stdlib') }} uses: ./.github/actions/multi-functest @@ -204,3 +215,4 @@ runs: acvp: true opt: ${{ inputs.opt }} examples: false # Some examples use a custom config themselves + alloc: false # Requires custom config diff --git a/.github/actions/functest/action.yml b/.github/actions/functest/action.yml index 29f41f7e6..dce6b89fb 100644 --- a/.github/actions/functest/action.yml +++ b/.github/actions/functest/action.yml @@ -57,6 +57,9 @@ inputs: stack: description: Determine whether to run stack analysis or not default: "false" + alloc: + description: Determine whether to run alloc tests or not + default: "true" extra_args: description: Additional arguments to pass to the tests script default: "" @@ -77,6 +80,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 ALLOC="${{ inputs.alloc == 'true' && 'alloc' || 'no-alloc' }}" >> $GITHUB_ENV - name: Setup nix uses: ./.github/actions/setup-shell with: @@ -107,11 +111,11 @@ runs: - $(python3 --version) - $(${{ inputs.cross_prefix }}${CC} --version | grep -m1 "") EOF - - name: ${{ env.MODE }} ${{ inputs.opt }} tests (${{ env.FUNC }}, ${{ env.KAT }}, ${{ env.EXAMPLES }}, ${{ env.STACK }}, ${{ env.UNIT }}) + - name: ${{ env.MODE }} ${{ inputs.opt }} tests (${{ env.FUNC }}, ${{ env.KAT }}, ${{ env.EXAMPLES }}, ${{ env.STACK }}, ${{ env.UNIT }}, ${{ env.ALLOC }}) shell: ${{ env.SHELL }} run: | make clean - ${{ inputs.extra_env }} ./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 }} + ${{ inputs.extra_env }} ./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 }} --${{ env.ALLOC }} -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 bb0a0cd00..603dbd1c0 100644 --- a/.github/actions/multi-functest/action.yml +++ b/.github/actions/multi-functest/action.yml @@ -54,6 +54,9 @@ inputs: stack: description: Determine whether to run stack analysis or not default: "false" + alloc: + description: Determine whether to run alloc tests or not + default: "true" extra_args: description: Additional arguments to pass to the tests script default: "" @@ -82,6 +85,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross x86_64 Tests @@ -105,6 +109,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross aarch64 Tests @@ -128,6 +133,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross ppc64le Tests @@ -151,6 +157,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross aarch64_be Tests @@ -174,6 +181,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross riscv64 Tests (RVV, VLEN=128) @@ -197,6 +205,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross riscv64 Tests (RVV, VLEN=256) @@ -219,6 +228,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross riscv64 Tests (RVV, VLEN=512) @@ -241,6 +251,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross riscv64 Tests (RVV, VLEN=1024) @@ -263,6 +274,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} - name: Cross riscv32 Tests @@ -286,6 +298,7 @@ runs: examples: ${{ inputs.examples }} check_namespace: ${{ inputs.check_namespace }} stack: ${{ inputs.stack }} + alloc: ${{ inputs.alloc }} extra_args: ${{ inputs.extra_args }} extra_env: ${{ inputs.extra_env }} diff --git a/.github/workflows/baremetal.yml b/.github/workflows/baremetal.yml index 0d3e1d5a1..4c235e0b6 100644 --- a/.github/workflows/baremetal.yml +++ b/.github/workflows/baremetal.yml @@ -35,3 +35,4 @@ jobs: acvp: true examples: false stack: false + alloc: false diff --git a/BIBLIOGRAPHY.md b/BIBLIOGRAPHY.md index 9730e7919..3b6fd3f5b 100644 --- a/BIBLIOGRAPHY.md +++ b/BIBLIOGRAPHY.md @@ -51,6 +51,7 @@ source code and documentation. - [test/custom_zeroize_config.h](test/custom_zeroize_config.h) - [test/no_asm_config.h](test/no_asm_config.h) - [test/serial_fips202_config.h](test/serial_fips202_config.h) + - [test/test_alloc_config.h](test/test_alloc_config.h) ### `FIPS202` @@ -103,6 +104,7 @@ source code and documentation. - [test/custom_zeroize_config.h](test/custom_zeroize_config.h) - [test/no_asm_config.h](test/no_asm_config.h) - [test/serial_fips202_config.h](test/serial_fips202_config.h) + - [test/test_alloc_config.h](test/test_alloc_config.h) ### `HYBRID` diff --git a/Makefile b/Makefile index d0383bf7a..33bf3f7be 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 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 \ +.PHONY: func kat acvp stack unit alloc \ + func_44 kat_44 acvp_44 stack_44 unit_44 alloc_44 \ + func_65 kat_65 acvp_65 stack_65 unit_65 alloc_65 \ + func_87 kat_87 acvp_87 stack_87 unit_87 alloc_87 \ + run_func run_kat run_acvp run_stack run_unit run_alloc \ + run_func_44 run_kat_44 run_stack_44 run_unit_44 run_alloc_44 \ + run_func_65 run_kat_65 run_stack_65 run_unit_65 run_alloc_65 \ + run_func_87 run_kat_87 run_stack_87 run_unit_87 run_alloc_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 \ @@ -48,7 +48,7 @@ quickcheck: test build: func kat acvp $(Q)echo " Everything builds fine!" -test: run_kat run_func run_acvp run_unit +test: run_kat run_func run_acvp run_unit run_alloc $(Q)echo " Everything checks fine!" # Detect available SHA256 command @@ -115,7 +115,7 @@ acvp_65: $(MLDSA65_DIR)/bin/acvp_mldsa65 acvp_87: $(MLDSA87_DIR)/bin/acvp_mldsa87 $(Q)echo " ACVP ML-DSA-87: $^" acvp: acvp_44 acvp_65 acvp_87 - + ifeq ($(HOST_PLATFORM),Linux-aarch64) # valgrind does not work with the AArch64 SHA3 extension # Use armv8-a as the target architecture, overwriting a @@ -141,6 +141,22 @@ run_stack_87: stack_87 $(Q)python3 scripts/stack $(MLDSA87_DIR)/bin/test_stack87 --build-dir $(MLDSA87_DIR) $(STACK_ANALYSIS_FLAGS) run_stack: run_stack_44 run_stack_65 run_stack_87 +alloc_44: $(MLDSA44_DIR)/bin/test_alloc44 + $(Q)echo " ALLOC ML-DSA-44: $^" +alloc_65: $(MLDSA65_DIR)/bin/test_alloc65 + $(Q)echo " ALLOC ML-DSA-65: $^" +alloc_87: $(MLDSA87_DIR)/bin/test_alloc87 + $(Q)echo " ALLOC ML-DSA-87: $^" +alloc: alloc_44 alloc_65 alloc_87 + +run_alloc_44: alloc_44 + $(W) $(MLDSA44_DIR)/bin/test_alloc44 +run_alloc_65: alloc_65 + $(W) $(MLDSA65_DIR)/bin/test_alloc65 +run_alloc_87: alloc_87 + $(W) $(MLDSA87_DIR)/bin/test_alloc87 +run_alloc: run_alloc_44 run_alloc_65 run_alloc_87 + lib: $(BUILD_DIR)/libmldsa.a $(BUILD_DIR)/libmldsa44.a $(BUILD_DIR)/libmldsa65.a $(BUILD_DIR)/libmldsa87.a # Enforce setting CYCLES make variable when diff --git a/mldsa/src/common.h b/mldsa/src/common.h index 9a7b43709..8ddd2a732 100644 --- a/mldsa/src/common.h +++ b/mldsa/src/common.h @@ -215,16 +215,4 @@ #endif /* !__ASSEMBLER__ */ -/* Just in case we want to include mldsa_native.h, set the configuration - * for that header in accordance with the configuration used here. */ - -/* Double-check that this is not conflicting with pre-existing definitions. */ -#if defined(MLD_CONFIG_API_PARAMETER_SET) || \ - defined(MLD_CONFIG_API_NAMESPACE_PREFIX) || \ - defined(MLD_CONFIG_API_NO_SUPERCOP) || \ - defined(MLD_CONFIG_API_CONSTANTS_ONLY) -#error Pre-existing MLD_CONFIG_API_XXX configuration is neither useful nor allowed during an mldsa-native build -#endif /* MLD_CONFIG_API_PARAMETER_SET || MLD_CONFIG_API_NAMESPACE_PREFIX || \ - MLD_CONFIG_API_NO_SUPERCOP || MLD_CONFIG_API_CONSTANTS_ONLY */ - #endif /* !MLD_COMMON_H */ diff --git a/mldsa/src/sign.c b/mldsa/src/sign.c index 944c9477b..4dfd19c50 100644 --- a/mldsa/src/sign.c +++ b/mldsa/src/sign.c @@ -119,8 +119,8 @@ static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES], cleanup: /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ - MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES); MLD_FREE(pk_test, uint8_t, MLDSA_CRYPTO_PUBLICKEYBYTES); + MLD_FREE(signature, uint8_t, MLDSA_CRYPTO_BYTES); return ret; } @@ -274,9 +274,9 @@ __contract__( cleanup: /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ - MLD_FREE(mat, mld_polymat, 1); - MLD_FREE(s1hat, mld_polyvecl, 1); MLD_FREE(t, mld_polyveck, 1); + MLD_FREE(s1hat, mld_polyvecl, 1); + MLD_FREE(mat, mld_polymat, 1); return ret; } @@ -332,19 +332,24 @@ int crypto_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], /* Constant time: pk is the public key, inherently public data */ MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); - /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ - ret = mld_check_pct(pk, sk); - cleanup: /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ - MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES); - MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2); - MLD_FREE(tr, uint8_t, MLDSA_TRBYTES); - MLD_FREE(s1, mld_polyvecl, 1); - MLD_FREE(s2, mld_polyveck, 1); - MLD_FREE(t1, mld_polyveck, 1); MLD_FREE(t0, mld_polyveck, 1); - return ret; + MLD_FREE(t1, mld_polyveck, 1); + MLD_FREE(s2, mld_polyveck, 1); + MLD_FREE(s1, mld_polyvecl, 1); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES); + MLD_FREE(inbuf, uint8_t, MLDSA_SEEDBYTES + 2); + MLD_FREE(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES); + + if (ret != 0) + { + return ret; + } + + /* Pairwise Consistency Test (PCT) @[FIPS140_3_IG, p.87] */ + /* Do this after freeing all temporaries. */ + return mld_check_pct(pk, sk); } #if !defined(MLD_CONFIG_NO_RANDOMIZED_API) @@ -610,13 +615,13 @@ __contract__( cleanup: /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ - MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES); - MLD_FREE(y, mld_polyvecl, 1); - MLD_FREE(z, mld_polyvecl, 1); - MLD_FREE(w1, mld_polyveck, 1); - MLD_FREE(w0, mld_polyveck, 1); - MLD_FREE(h, mld_polyveck, 1); MLD_FREE(cp, mld_poly, 1); + MLD_FREE(h, mld_polyveck, 1); + MLD_FREE(w0, mld_polyveck, 1); + MLD_FREE(w1, mld_polyveck, 1); + MLD_FREE(z, mld_polyvecl, 1); + MLD_FREE(y, mld_polyvecl, 1); + MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES); return ret; } @@ -735,12 +740,12 @@ int crypto_sign_signature_internal( } /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ - MLD_FREE(seedbuf, uint8_t, - 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES); - MLD_FREE(mat, mld_polymat, 1); - MLD_FREE(s1, mld_polyvecl, 1); MLD_FREE(s2, mld_polyveck, 1); MLD_FREE(t0, mld_polyveck, 1); + MLD_FREE(s1, mld_polyvecl, 1); + MLD_FREE(mat, mld_polymat, 1); + MLD_FREE(seedbuf, uint8_t, + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES); return ret; } @@ -794,8 +799,8 @@ int crypto_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, } /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ - MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES); MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES); + MLD_FREE(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES); return ret; } @@ -971,18 +976,18 @@ int crypto_sign_verify_internal(const uint8_t *sig, size_t siglen, cleanup: /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ - MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)); - MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES); - MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES); - MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES); - MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES); - MLD_FREE(cp, mld_poly, 1); - MLD_FREE(mat, mld_polymat, 1); - MLD_FREE(z, mld_polyvecl, 1); - MLD_FREE(t1, mld_polyveck, 1); - MLD_FREE(w1, mld_polyveck, 1); - MLD_FREE(tmp, mld_polyveck, 1); MLD_FREE(h, mld_polyveck, 1); + MLD_FREE(tmp, mld_polyveck, 1); + MLD_FREE(w1, mld_polyveck, 1); + MLD_FREE(t1, mld_polyveck, 1); + MLD_FREE(z, mld_polyvecl, 1); + MLD_FREE(mat, mld_polymat, 1); + MLD_FREE(cp, mld_poly, 1); + MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES); + MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES); + MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES); + MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)); return ret; } @@ -1350,15 +1355,15 @@ int crypto_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES); /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */ - MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES); - MLD_FREE(tr, uint8_t, MLDSA_TRBYTES); - MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES); - MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES); - MLD_FREE(s1, mld_polyvecl, 1); - MLD_FREE(s2, mld_polyveck, 1); - MLD_FREE(t0, mld_polyveck, 1); - MLD_FREE(t0_computed, mld_polyveck, 1); MLD_FREE(t1, mld_polyveck, 1); + MLD_FREE(t0_computed, mld_polyveck, 1); + MLD_FREE(t0, mld_polyveck, 1); + MLD_FREE(s2, mld_polyveck, 1); + MLD_FREE(s1, mld_polyvecl, 1); + MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES); + MLD_FREE(tr_computed, uint8_t, MLDSA_TRBYTES); + MLD_FREE(tr, uint8_t, MLDSA_TRBYTES); + MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES); return ret; } diff --git a/scripts/tests b/scripts/tests index b3485a8f6..cc28fb752 100755 --- a/scripts/tests +++ b/scripts/tests @@ -212,6 +212,7 @@ class TEST_TYPES(Enum): SIZE = 17 BASIC_DETERMINISTIC = 18 UNIT = 19 + ALLOC = 20 def is_benchmark(self): return self in [TEST_TYPES.BENCH, TEST_TYPES.BENCH_COMPONENTS] @@ -286,6 +287,8 @@ class TEST_TYPES(Enum): return "Measurement Code Size" if self == TEST_TYPES.UNIT: return "Unit Test" + if self == TEST_TYPES.ALLOC: + return "Alloc Test" def make_dir(self): if self == TEST_TYPES.BRING_YOUR_OWN_FIPS202: @@ -351,6 +354,8 @@ class TEST_TYPES(Enum): return "size" if self == TEST_TYPES.UNIT: return "unit" + if self == TEST_TYPES.ALLOC: + return "alloc" def make_run_target(self, scheme): t = self.make_target() @@ -650,6 +655,19 @@ class Tests: self.check_fail() + def alloc(self): + def _alloc(opt): + self._compile_schemes(TEST_TYPES.ALLOC, opt) + if self.args.run: + self._run_schemes(TEST_TYPES.ALLOC, opt) + + if self.do_no_opt(): + _alloc(False) + if self.do_opt(): + _alloc(True) + + self.check_fail() + def acvp(self): def _acvp(opt): self._compile_schemes(TEST_TYPES.ACVP, opt) @@ -784,6 +802,7 @@ class Tests: examples = self.args.examples stack = self.args.stack unit = self.args.unit + alloc = self.args.alloc def _all(opt): if func is True: @@ -796,6 +815,8 @@ class Tests: self._compile_schemes(TEST_TYPES.STACK, opt) if unit is True: self._compile_schemes(TEST_TYPES.UNIT, opt) + if alloc is True: + self._compile_schemes(TEST_TYPES.ALLOC, opt) if self.args.check_namespace is True: p = subprocess.run( @@ -819,6 +840,8 @@ class Tests: self._run_schemes(TEST_TYPES.STACK, opt, suppress_output=False) if unit is True: self._run_schemes(TEST_TYPES.UNIT, opt) + if alloc is True: + self._run_schemes(TEST_TYPES.ALLOC, opt) if self.do_no_opt(): _all(False) @@ -1192,6 +1215,21 @@ def cli(): help="Do not run stack analysis", ) + alloc_group = all_parser.add_mutually_exclusive_group() + alloc_group.add_argument( + "--alloc", + action="store_true", + dest="alloc", + help="Run alloc tests", + default=True, + ) + alloc_group.add_argument( + "--no-alloc", + action="store_false", + dest="alloc", + help="Do not run alloc tests", + ) + # acvp arguments acvp_parser = cmd_subparsers.add_parser( "acvp", help="Run ACVP client", parents=[common_parser] @@ -1398,6 +1436,13 @@ def cli(): default=False, ) + # alloc arguments + alloc_parser = cmd_subparsers.add_parser( + "alloc", + help="Run the alloc tests for all parameter sets", + parents=[common_parser], + ) + args = main_parser.parse_args() if not hasattr(args, "mac_taskpolicy"): @@ -1429,6 +1474,8 @@ def cli(): Tests(args).stack() elif args.cmd == "size": Tests(args).size() + elif args.cmd == "alloc": + Tests(args).alloc() if __name__ == "__main__": diff --git a/test/configs.yml b/test/configs.yml index c6ef1f93d..5fed65f52 100644 --- a/test/configs.yml +++ b/test/configs.yml @@ -396,3 +396,25 @@ configs: MLD_CONFIG_NO_RANDOMIZED_API: true MLD_CONFIG_FILE: comment: "/* No need to set this -- we _are_ already in a custom config */" + + - path: test/test_alloc_config.h + description: "Using custom allocation that can be made fail at specific invocation" + defines: + MLD_CONFIG_NAMESPACE_PREFIX: mld + MLD_CONFIG_KEYGEN_PCT: + content: | + #if !defined(MLD_CONFIG_KEYGEN_PCT) + #define MLD_CONFIG_KEYGEN_PCT + #endif + MLD_CONFIG_CUSTOM_ALLOC_FREE: + content: | + #define MLD_CONFIG_CUSTOM_ALLOC_FREE + #if !defined(__ASSEMBLER__) + #include + void * custom_alloc(size_t sz, const char *file, int line, const char *var, const char *type); + void custom_free(void *p, size_t sz, const char *file, int line, const char *var, const char *type); + #define MLD_CUSTOM_ALLOC(v, T, N) T *v = custom_alloc(sizeof(T)*(N), __FILE__, __LINE__, #v, #T) + #define MLD_CUSTOM_FREE(v, T, N) custom_free(v, sizeof(T)*(N), __FILE__, __LINE__, #v, #T) + #endif /* !__ASSEMBLER__ */ + MLD_CONFIG_FILE: + comment: "/* No need to set this -- we _are_ already in a custom config */" diff --git a/test/mk/components.mk b/test/mk/components.mk index 78abba9c4..c3655fbe1 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 test_unit 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 test_alloc MLDSA44_DIR = $(BUILD_DIR)/mldsa44 MLDSA65_DIR = $(BUILD_DIR)/mldsa65 @@ -35,6 +35,14 @@ $(MLDSA65_UNIT_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 -DMLD_STATIC_TESTA 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 +# Alloc test object files - same sources but with custom alloc config +MLDSA44_ALLOC_OBJS = $(call MAKE_OBJS,$(MLDSA44_DIR)/alloc,$(SOURCES) $(FIPS202_SRCS)) +$(MLDSA44_ALLOC_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 -DMLD_CONFIG_FILE=\"../test/test_alloc_config.h\" +MLDSA65_ALLOC_OBJS = $(call MAKE_OBJS,$(MLDSA65_DIR)/alloc,$(SOURCES) $(FIPS202_SRCS)) +$(MLDSA65_ALLOC_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 -DMLD_CONFIG_FILE=\"../test/test_alloc_config.h\" +MLDSA87_ALLOC_OBJS = $(call MAKE_OBJS,$(MLDSA87_DIR)/alloc,$(SOURCES) $(FIPS202_SRCS)) +$(MLDSA87_ALLOC_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 -DMLD_CONFIG_FILE=\"../test/test_alloc_config.h\" + CFLAGS += -Imldsa @@ -48,6 +56,11 @@ $(BUILD_DIR)/libmldsa44_unit.a: $(MLDSA44_UNIT_OBJS) $(BUILD_DIR)/libmldsa65_unit.a: $(MLDSA65_UNIT_OBJS) $(BUILD_DIR)/libmldsa87_unit.a: $(MLDSA87_UNIT_OBJS) +# Alloc test libraries with custom alloc config +$(BUILD_DIR)/libmldsa44_alloc.a: $(MLDSA44_ALLOC_OBJS) +$(BUILD_DIR)/libmldsa65_alloc.a: $(MLDSA65_ALLOC_OBJS) +$(BUILD_DIR)/libmldsa87_alloc.a: $(MLDSA87_ALLOC_OBJS) + $(BUILD_DIR)/libmldsa.a: $(MLDSA44_OBJS) $(MLDSA65_OBJS) $(MLDSA87_OBJS) @@ -62,6 +75,10 @@ $(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)/test/test_alloc.c.o: CFLAGS += -DMLD_CONFIG_FILE=\"../test/test_alloc_config.h\" +$(MLDSA65_DIR)/test/test_alloc.c.o: CFLAGS += -DMLD_CONFIG_FILE=\"../test/test_alloc_config.h\" +$(MLDSA87_DIR)/test/test_alloc.c.o: CFLAGS += -DMLD_CONFIG_FILE=\"../test/test_alloc_config.h\" + $(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 @@ -96,9 +113,15 @@ $(BUILD_DIR)/$(1)/bin/test_unit$(subst mldsa,,$(1)): LDLIBS += -L$(BUILD_DIR) -l $(BUILD_DIR)/$(1)/bin/test_unit$(subst mldsa,,$(1)): $(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 +# Special rule for test_alloc - link against alloc libraries with custom alloc config +define ADD_SOURCE_ALLOC +$(BUILD_DIR)/$(1)/bin/test_alloc$(subst mldsa,,$(1)): LDLIBS += -L$(BUILD_DIR) -l$(1)_alloc +$(BUILD_DIR)/$(1)/bin/test_alloc$(subst mldsa,,$(1)): $(BUILD_DIR)/$(1)/test/test_alloc.c.o $(BUILD_DIR)/lib$(1)_alloc.a $(call MAKE_OBJS, $(BUILD_DIR)/$(1), $(wildcard test/notrandombytes/*.c)) +endef + $(foreach scheme,mldsa44 mldsa65 mldsa87, \ - $(foreach test,$(filter-out test_unit,$(ALL_TESTS)), \ + $(foreach test,$(filter-out test_unit test_alloc,$(ALL_TESTS)), \ $(eval $(call ADD_SOURCE,$(scheme),$(test))) \ ) \ ) @@ -107,6 +130,10 @@ $(foreach scheme,mldsa44 mldsa65 mldsa87, \ $(eval $(call ADD_SOURCE_UNIT,$(scheme))) \ ) +$(foreach scheme,mldsa44 mldsa65 mldsa87, \ + $(eval $(call ADD_SOURCE_ALLOC,$(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 320747ff4..e4447ebc6 100644 --- a/test/mk/rules.mk +++ b/test/mk/rules.mk @@ -83,3 +83,33 @@ $(BUILD_DIR)/mldsa87/unit/%.S.o: %.S $(CONFIG) $(Q)echo " AS $@" $(Q)[ -d $(@D) ] || mkdir -p $(@D) $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa44/alloc/%.c.o: %.c $(CONFIG) + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa44/alloc/%.S.o: %.S $(CONFIG) + $(Q)echo " AS $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa65/alloc/%.c.o: %.c $(CONFIG) + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa65/alloc/%.S.o: %.S $(CONFIG) + $(Q)echo " AS $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa87/alloc/%.c.o: %.c $(CONFIG) + $(Q)echo " CC $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + +$(BUILD_DIR)/mldsa87/alloc/%.S.o: %.S $(CONFIG) + $(Q)echo " AS $@" + $(Q)[ -d $(@D) ] || mkdir -p $(@D) + $(Q)$(CC) -c -o $@ $(CFLAGS) $< diff --git a/test/test_alloc.c b/test/test_alloc.c new file mode 100644 index 000000000..189fe194d --- /dev/null +++ b/test/test_alloc.c @@ -0,0 +1,571 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ +#include +#include +#include +#include + +/* Expose declaration of allocator (normally internal) */ +#define MLD_BUILD_INTERNAL +#include "../mldsa/mldsa_native.h" +#include "../mldsa/src/common.h" +#include "notrandombytes/notrandombytes.h" + +/* + * This test checks that + * - we handle allocator failures correctly, propagating MLD_ERR_OUT_OF_MEMORY + * and cleaning up all memory, and + * - we leak no memory, and + * - we always de-allocate in the reverse order of allocation, thereby + * allowing the use of a bump allocator. + * + * This is done through a custom bump allocator and tracking of in-flight + * allocations. + */ + +/* + * Allocation tracker + * + * Simple stack of in-flight allocations that's used to test that there are + * no leaks and that we free in reverse order than we allocate. (The absence + * of leaks is also checked through the address sanitizer) + */ + +typedef struct +{ + void *addr; + size_t size; + const char *file; + int line; + const char *var; + const char *type; +} alloc_info_t; + +#define MLD_MAX_IN_FLIGHT_ALLOCS 100 +static alloc_info_t alloc_stack[MLD_MAX_IN_FLIGHT_ALLOCS]; +static int alloc_stack_top = 0; + +static void alloc_tracker_push(void *addr, size_t size, const char *file, + int line, const char *var, const char *type) +{ + if (alloc_stack_top >= MLD_MAX_IN_FLIGHT_ALLOCS) + { + fprintf(stderr, "ERROR: Allocation stack overflow\n"); + exit(1); + } + alloc_stack[alloc_stack_top].addr = addr; + alloc_stack[alloc_stack_top].size = size; + alloc_stack[alloc_stack_top].file = file; + alloc_stack[alloc_stack_top].line = line; + alloc_stack[alloc_stack_top].var = var; + alloc_stack[alloc_stack_top].type = type; + alloc_stack_top++; +} + +static void alloc_tracker_pop(void *addr, size_t size, const char *file, + int line, const char *var) +{ + alloc_info_t *top; + if (alloc_stack_top == 0) + { + fprintf( + stderr, + "ERROR: Attempting to free %s at %s:%d but allocation stack is empty\n", + var, file, line); + exit(1); + } + + top = &alloc_stack[alloc_stack_top - 1]; + if (top->addr != addr || top->size != size) + { + fprintf(stderr, + "ERROR: Free order violation at %s:%d\n" + " Attempting to free: %s (addr=%p, sz %d)\n" + " Expected to free: %s (addr=%p, sz %d) allocated at %s:%d\n", + file, line, var, addr, (int)size, top->var, top->addr, + (int)top->size, top->file, top->line); + exit(1); + } + + alloc_stack_top--; +} + +/* + * Bump allocator + * + * A simple stack-like allocator. We can use it since freeing happens in + * reverse order to allocation. + */ + +#define MLD_BUMP_ALLOC_SIZE (128 * 1024) /* 128KB buffer */ +static uint8_t *bump_buffer = NULL; /* Base address */ +static size_t bump_offset = 0; /* Watermark */ +static size_t bump_high_mark = 0; /* High watermark */ + +static void *bump_alloc(size_t sz) +{ + /* Align to 32 bytes */ + size_t aligned_sz = (sz + 31) & ~((size_t)31); + void *p; + + if (sz > MLD_BUMP_ALLOC_SIZE || + aligned_sz > MLD_BUMP_ALLOC_SIZE - bump_offset) + { + return NULL; + } + + p = bump_buffer + bump_offset; + bump_offset += aligned_sz; + + if (bump_offset > bump_high_mark) + { + bump_high_mark = bump_offset; + } + + return p; +} + +static int bump_free(void *p) +{ + if (p == NULL) + { + return 0; + } + + /* Check that p is within the bump buffer */ + if (p < (void *)bump_buffer || p >= (void *)(bump_buffer + bump_offset)) + { + return -1; + } + + /* Reset bump offset to the freed address */ + bump_offset = (size_t)((uint8_t *)p - bump_buffer); + return 0; +} + +int alloc_counter = 0; +int fail_on_counter = -1; +int print_debug_info = 0; + +static void reset_all(void) +{ + randombytes_reset(); + alloc_counter = 0; + alloc_stack_top = 0; + bump_offset = 0; + fail_on_counter = -1; +} + +void *custom_alloc(size_t sz, const char *file, int line, const char *var, + const char *type) +{ + void *p = NULL; + if (alloc_counter++ == fail_on_counter) + { + return NULL; + } + + p = bump_alloc(sz); + if (p == NULL) + { + fprintf(stderr, + "ERROR: Bump allocator (%d bytes) ran out of memory. " + "%s *%s (%d bytes) at %s:%d\n", + (int)MLD_BUMP_ALLOC_SIZE, type, var, (int)sz, file, line); + exit(1); + } + + if (print_debug_info == 1) + { + fprintf(stderr, "Alloc #%d: %s %s (%d bytes) at %s:%d\n", alloc_counter, + type, var, (int)sz, file, line); + } + + alloc_tracker_push(p, sz, file, line, var, type); + return p; +} + +void custom_free(void *p, size_t sz, const char *file, int line, + const char *var, const char *type) +{ + (void)sz; + (void)type; + + if (p != NULL) + { + alloc_tracker_pop(p, sz, file, line, var); + } + + if (bump_free(p) != 0) + { + fprintf(stderr, "ERROR: Free failed: %s %s (%d bytes) at %s:%d\n", type, + var, (int)sz, file, line); + exit(1); + } +} + +#define TEST_ALLOC_FAILURE(test_name, call) \ + do \ + { \ + int num_allocs, i, rc; \ + /* First pass: count allocations */ \ + bump_high_mark = 0; \ + reset_all(); \ + rc = call; \ + if (rc != 0) \ + { \ + fprintf(stderr, "ERROR: %s failed in counting pass\n", test_name); \ + return 1; \ + } \ + if (alloc_stack_top != 0) \ + { \ + fprintf(stderr, "ERROR: %s leaked %d allocation(s) in counting pass\n", \ + test_name, alloc_stack_top); \ + return 1; \ + } \ + num_allocs = alloc_counter; \ + /* Second pass: test each allocation failure */ \ + for (i = 0; i < num_allocs; i++) \ + { \ + reset_all(); \ + fail_on_counter = i; \ + rc = call; \ + if (rc != MLD_ERR_OUT_OF_MEMORY) \ + { \ + int rc2; \ + /* Re-run dry-run and print debug info */ \ + reset_all(); \ + print_debug_info = 1; \ + rc2 = call; \ + (void)rc2; \ + if (rc == 0) \ + { \ + fprintf(stderr, \ + "ERROR: %s unexpectedly succeeded when allocation %d/%d " \ + "was instrumented to fail\n", \ + test_name, i + 1, num_allocs); \ + } \ + else \ + { \ + fprintf(stderr, \ + "ERROR: %s failed with wrong error code %d " \ + "(expected %d) when allocation %d/%d was instrumented " \ + "to fail\n", \ + test_name, rc, MLD_ERR_OUT_OF_MEMORY, i + 1, num_allocs); \ + } \ + return 1; \ + } \ + if (alloc_stack_top != 0) \ + { \ + fprintf(stderr, \ + "ERROR: %s leaked %d allocation(s) when allocation %d/%d " \ + "was instrumented to fail\n", \ + test_name, alloc_stack_top, i + 1, num_allocs); \ + return 1; \ + } \ + } \ + printf( \ + "Allocation test for %s PASSED.\n" \ + " Max dynamic allocation: %d bytes\n", \ + test_name, (int)bump_high_mark); \ + } while (0) + +static int test_keygen_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + + TEST_ALLOC_FAILURE("mld_keypair", mld_keypair(pk, sk)); + return 0; +} + +static int test_sign_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t msg[32] = {0}; + const uint8_t ctx[] = "test context"; + size_t siglen; + + /* Generate valid keypair first */ + reset_all(); + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, "ERROR: mld_keypair failed in sign test setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE( + "mld_signature", + mld_signature(sig, &siglen, msg, sizeof(msg), ctx, sizeof(ctx) - 1, sk)); + return 0; +} + +static int test_verify_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t msg[32] = {0}; + const uint8_t ctx[] = "test context"; + size_t siglen; + + /* Generate valid keypair and signature first */ + alloc_counter = 0; + alloc_stack_top = 0; + bump_offset = 0; + fail_on_counter = -1; + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, "ERROR: mld_keypair failed in verify test setup\n"); + return 1; + } + + if (mld_signature(sig, &siglen, msg, sizeof(msg), ctx, sizeof(ctx) - 1, sk) != + 0) + { + fprintf(stderr, "ERROR: mld_signature failed in verify test setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE("mld_verify", mld_verify(sig, siglen, msg, sizeof(msg), + ctx, sizeof(ctx) - 1, pk)); + return 0; +} + +static int test_sign_combined_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sm[CRYPTO_BYTES + 32]; + uint8_t msg[32] = {0}; + const uint8_t ctx[] = "test context"; + size_t smlen; + + reset_all(); + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, "ERROR: mld_keypair failed in sign combined test setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE("mld_sign", mld_sign(sm, &smlen, msg, sizeof(msg), ctx, + sizeof(ctx) - 1, sk)); + return 0; +} + +static int test_open_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sm[CRYPTO_BYTES + 32]; + uint8_t msg[32] = {0}; + uint8_t msg_out[CRYPTO_BYTES + 32]; + const uint8_t ctx[] = "test context"; + size_t smlen, mlen; + + reset_all(); + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, "ERROR: mld_keypair failed in open test setup\n"); + return 1; + } + + if (mld_sign(sm, &smlen, msg, sizeof(msg), ctx, sizeof(ctx) - 1, sk) != 0) + { + fprintf(stderr, "ERROR: mld_sign failed in open test setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE("mld_open", mld_open(msg_out, &mlen, sm, smlen, ctx, + sizeof(ctx) - 1, pk)); + return 0; +} + +static int test_signature_extmu_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t mu[64] = {0}; + size_t siglen; + + randombytes_reset(); + alloc_counter = 0; + alloc_stack_top = 0; + bump_offset = 0; + fail_on_counter = -1; + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, + "ERROR: mld_keypair failed in signature_extmu test setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE("mld_signature_extmu", + mld_signature_extmu(sig, &siglen, mu, sk)); + return 0; +} + +static int test_verify_extmu_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t mu[64] = {0}; + size_t siglen; + + reset_all(); + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, "ERROR: mld_keypair failed in verify_extmu test setup\n"); + return 1; + } + + if (mld_signature_extmu(sig, &siglen, mu, sk) != 0) + { + fprintf(stderr, + "ERROR: mld_signature_extmu failed in verify_extmu test setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE("mld_verify_extmu", mld_verify_extmu(sig, siglen, mu, pk)); + return 0; +} + +static int test_signature_pre_hash_shake256_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t msg[32] = {0}; + uint8_t rnd[32] = {0}; + const uint8_t ctx[] = "test context"; + size_t siglen; + + reset_all(); + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, + "ERROR: mld_keypair failed in signature_pre_hash_shake256 test " + "setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE( + "mld_signature_pre_hash_shake256", + mld_signature_pre_hash_shake256(sig, &siglen, msg, sizeof(msg), ctx, + sizeof(ctx) - 1, rnd, sk)); + return 0; +} + +static int test_verify_pre_hash_shake256_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + uint8_t sig[CRYPTO_BYTES]; + uint8_t msg[32] = {0}; + uint8_t rnd[32] = {0}; + const uint8_t ctx[] = "test context"; + size_t siglen; + + reset_all(); + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, + "ERROR: mld_keypair failed in verify_pre_hash_shake256 test " + "setup\n"); + return 1; + } + + if (mld_signature_pre_hash_shake256(sig, &siglen, msg, sizeof(msg), ctx, + sizeof(ctx) - 1, rnd, sk) != 0) + { + fprintf(stderr, + "ERROR: mld_signature_pre_hash_shake256 failed in " + "verify_pre_hash_shake256 test setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE("mld_verify_pre_hash_shake256", + mld_verify_pre_hash_shake256(sig, siglen, msg, sizeof(msg), + ctx, sizeof(ctx) - 1, pk)); + return 0; +} + +static int test_pk_from_sk_alloc_failure(void) +{ + uint8_t pk[CRYPTO_PUBLICKEYBYTES]; + uint8_t sk[CRYPTO_SECRETKEYBYTES]; + + reset_all(); + if (mld_keypair(pk, sk) != 0) + { + fprintf(stderr, "ERROR: mld_keypair failed in pk_from_sk test setup\n"); + return 1; + } + + TEST_ALLOC_FAILURE("mld_pk_from_sk", mld_pk_from_sk(pk, sk)); + return 0; +} + +int main(void) +{ + MLD_ALIGN uint8_t bump_buffer_storage[MLD_BUMP_ALLOC_SIZE]; + bump_buffer = bump_buffer_storage; + + if (test_keygen_alloc_failure() != 0) + { + return 1; + } + + if (test_sign_alloc_failure() != 0) + { + return 1; + } + + if (test_verify_alloc_failure() != 0) + { + return 1; + } + + if (test_sign_combined_alloc_failure() != 0) + { + return 1; + } + + if (test_open_alloc_failure() != 0) + { + return 1; + } + + if (test_signature_extmu_alloc_failure() != 0) + { + return 1; + } + + if (test_verify_extmu_alloc_failure() != 0) + { + return 1; + } + + if (test_signature_pre_hash_shake256_alloc_failure() != 0) + { + return 1; + } + + if (test_verify_pre_hash_shake256_alloc_failure() != 0) + { + return 1; + } + + if (test_pk_from_sk_alloc_failure() != 0) + { + return 1; + } + + return 0; +} diff --git a/test/test_alloc_config.h b/test/test_alloc_config.h new file mode 100644 index 000000000..dfd922253 --- /dev/null +++ b/test/test_alloc_config.h @@ -0,0 +1,701 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* References + * ========== + * + * - [FIPS140_3_IG] + * Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program + * National Institute of Standards and Technology + * https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-ig-announcements + * + * - [FIPS204] + * FIPS 204 Module-Lattice-Based Digital Signature Standard + * National Institute of Standards and Technology + * https://csrc.nist.gov/pubs/fips/204/final + */ + +/* + * WARNING: This file is auto-generated from scripts/autogen + * in the mldsa-native repository. + * Do not modify it directly. + */ + +/* + * Test configuration: Using custom allocation that can be made fail at specific + * invocation + * + * This configuration differs from the default mldsa/mldsa_native_config.h in + * the following places: + * - MLD_CONFIG_NAMESPACE_PREFIX + * - MLD_CONFIG_KEYGEN_PCT + * - MLD_CONFIG_CUSTOM_ALLOC_FREE + */ + + +#ifndef MLD_CONFIG_H +#define MLD_CONFIG_H + +/****************************************************************************** + * Name: MLD_CONFIG_PARAMETER_SET + * + * Description: Specifies the parameter set for ML-DSA + * - MLD_CONFIG_PARAMETER_SET=44 corresponds to ML-DSA-44 + * - MLD_CONFIG_PARAMETER_SET=65 corresponds to ML-DSA-65 + * - MLD_CONFIG_PARAMETER_SET=87 corresponds to ML-DSA-87 + * + * If you want to support multiple parameter sets, build the + * library multiple times and set MLD_CONFIG_MULTILEVEL_BUILD. + * See MLD_CONFIG_MULTILEVEL_BUILD for how to do this while + * minimizing code duplication. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#ifndef MLD_CONFIG_PARAMETER_SET +#define MLD_CONFIG_PARAMETER_SET \ + 44 /* Change this for different security strengths */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FILE + * + * Description: If defined, this is a header that will be included instead + * of the default configuration file mldsa/mldsa_native_config.h. + * + * When you need to build mldsa-native in multiple configurations, + * using varying MLD_CONFIG_FILE can be more convenient + * then configuring everything through CFLAGS. + * + * To use, MLD_CONFIG_FILE _must_ be defined prior + * to the inclusion of any mldsa-native headers. For example, + * it can be set by passing `-DMLD_CONFIG_FILE="..."` + * on the command line. + * + *****************************************************************************/ +/* No need to set this -- we _are_ already in a custom config */ +/* #define MLD_CONFIG_FILE "mldsa_native_config.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_NAMESPACE_PREFIX + * + * Description: The prefix to use to namespace global symbols from mldsa/. + * + * In a multi-level build, level-dependent symbols will + * additionally be prefixed with the parameter set (44/65/87). + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#define MLD_CONFIG_NAMESPACE_PREFIX mld + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_BUILD + * + * Description: Set this if the build is part of a multi-level build supporting + * multiple parameter sets. + * + * If you need only a single parameter set, keep this unset. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * MLD_CONFIG_MULTILEVEL_BUILD should be set for all of them. + * + * See examples/multilevel_build for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_BUILD */ + +/****************************************************************************** + * Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of mldsa-native's + * public API. + * + * The primary use case for this option are single-CU builds + * where the public API exposed by mldsa-native is wrapped by + * another API in the consuming application. In this case, + * even mldsa-native's public API can be marked `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_RANDOMIZED_API + * + * Description: If this option is set, mldsa-native will be built without the + * randomized API functions (crypto_sign_keypair, + * crypto_sign, crypto_sign_signature, and + * crypto_sign_signature_extmu). + * This allows users to build mldsa-native without providing a + * randombytes() implementation if they only need the + * internal deterministic API + * (crypto_sign_keypair_internal, crypto_sign_signature_internal). + * + * NOTE: This option is incompatible with MLD_CONFIG_KEYGEN_PCT + * as the current PCT implementation requires + * crypto_sign_signature(). + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_RANDOMIZED_API */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_SUPERCOP + * + * Description: By default, mldsa_native.h exposes the mldsa-native API in the + * SUPERCOP naming convention (crypto_sign_xxx). If you don't need + * this, set MLD_CONFIG_NO_SUPERCOP. + * + * NOTE: You must set this for a multi-level build as the SUPERCOP + * naming does not disambiguate between the parameter sets. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_SUPERCOP */ + +/****************************************************************************** + * Name: MLD_CONFIG_CONSTANTS_ONLY + * + * Description: If you only need the size constants (MLDSA_PUBLICKEYBYTES, etc.) + * but no function declarations, set MLD_CONFIG_CONSTANTS_ONLY. + * + * This only affects the public header mldsa_native.h, not + * the implementation. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CONSTANTS_ONLY */ + +/****************************************************************************** + * + * Build-only configuration options + * + * The remaining configurations are build-options only. + * They do not affect the API described in mldsa_native.h. + * + *****************************************************************************/ + +#if defined(MLD_BUILD_INTERNAL) +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_WITH_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, all MLD_CONFIG_PARAMETER_SET-independent + * code will be included in the build, including code needed only + * for other parameter sets. + * + * Example: TODO: add example + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_WITH_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MULTILEVEL_NO_SHARED + * + * Description: This is for multi-level builds of mldsa-native only. If you + * need only a single parameter set, keep this unset. + * + * If this is set, no MLD_CONFIG_PARAMETER_SET-independent code + * will be included in the build. + * + * To build mldsa-native with support for all parameter sets, + * build it three times -- once per parameter set -- and set the + * option MLD_CONFIG_MULTILEVEL_WITH_SHARED for exactly one of + * them, and MLD_CONFIG_MULTILEVEL_NO_SHARED for the others. + * + * See examples/multilevel_build_mldsa for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MULTILEVEL_NO_SHARED */ + +/****************************************************************************** + * Name: MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS + * + * Description: This is only relevant for single compilation unit (SCU) + * builds of mldsa-native. In this case, it determines whether + * directives defined in parameter-set-independent headers should + * be #undef'ined or not at the of the SCU file. This is needed + * in multilevel builds. + * + * See examples/multilevel_build_native for an example. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +/* #define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */ + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH + * + * Description: Determines whether an native arithmetic backend should be used. + * + * The arithmetic backend covers performance critical functions + * such as the number-theoretic transform (NTT). + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the arithmetic backend to be use is + * determined by MLD_CONFIG_ARITH_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_ARITH_BACKEND_FILE + * + * Description: The arithmetic backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is unset, this option + * is ignored. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, this option must + * either be undefined or the filename of an arithmetic backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \ + !defined(MLD_CONFIG_ARITH_BACKEND_FILE) +#define MLD_CONFIG_ARITH_BACKEND_FILE "native/meta.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 + * + * Description: Determines whether an native FIPS202 backend should be used. + * + * The FIPS202 backend covers 1x/2x/4x-fold Keccak-f1600, which is + * the performance bottleneck of SHA3 and SHAKE. + * + * If this option is unset, the C backend will be used. + * + * If this option is set, the FIPS202 backend to be use is + * determined by MLD_CONFIG_FIPS202_BACKEND_FILE: If the latter is + * unset, the default backend for your the target architecture + * will be used. If set, it must be the name of a backend metadata + * file. + * + * This can also be set using CFLAGS. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) +/* #define MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */ +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_BACKEND_FILE + * + * Description: The FIPS-202 backend to use. + * + * If MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, this option + * must either be undefined or the filename of a FIPS202 backend. + * If unset, the default backend will be used. + * + * This can be set using CFLAGS. + * + *****************************************************************************/ +#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \ + !defined(MLD_CONFIG_FIPS202_BACKEND_FILE) +#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h" +#endif + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_FIPS202X4_CUSTOM_HEADER + * + * Description: Custom header to use for FIPS-202-X4 + * + * This should only be set if you intend to use a custom + * FIPS-202 implementation, different from the one shipped + * with mldsa-native. + * + * If set, it must be the name of a file serving as the + * replacement for mldsa/src/fips202/fips202x4.h, and exposing + * the same API (see FIPS202.md). + * + *****************************************************************************/ +/* #define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "SOME_FILE.h" */ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ZEROIZE + * + * Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native, + * zeroizes intermediate stack buffers before returning from + * function calls. + * + * Set this option and define `mld_zeroize_native` if you want to + * use a custom method to zeroize intermediate stack buffers. + * The default implementation uses SecureZeroMemory on Windows + * and a memset + compiler barrier otherwise. If neither of those + * is available on the target platform, compilation will fail, + * and you will need to use MLD_CONFIG_CUSTOM_ZEROIZE to provide + * a custom implementation of `mld_zeroize_native()`. + * + * WARNING: + * The explicit stack zeroization conducted by mldsa-native + * reduces the likelihood of data leaking on the stack, but + * does not eliminate it! The C standard makes no guarantee about + * where a compiler allocates structures and whether/where it makes + * copies of them. Also, in addition to entire structures, there + * may also be potentially exploitable leakage of individual values + * on the stack. + * + * If you need bullet-proof zeroization of the stack, you need to + * consider additional measures instead of what this feature + * provides. In this case, you can set mld_zeroize_native to a + * no-op. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_ZEROIZE + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_zeroize_native(void *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_RANDOMBYTES + * + * Description: mldsa-native does not provide a secure randombytes + * implementation. Such an implementation has to provided by the + * consumer. + * + * If this option is not set, mldsa-native expects a function + * void randombytes(uint8_t *out, size_t outlen). + * + * Set this option and define `mld_randombytes` if you want to + * use a custom method to sample randombytes with a different name + * or signature. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void mld_randombytes(uint8_t *ptr, size_t len) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + * + * Description: mldsa-native backends may rely on specific hardware features. + * Those backends will only be included in an mldsa-native build + * if support for the respective features is enabled at + * compile-time. However, when building for a heteroneous set + * of CPUs to run the resulting binary/library on, feature + * detection at _runtime_ is needed to decided whether a backend + * can be used or not. + * + * Set this option and define `mld_sys_check_capability` if you + * want to use a custom method to dispatch between implementations. + * + * If this option is not set, mldsa-native uses compile-time + * feature detection only to decide which backend to use. + * + * If you compile mldsa-native on a system with different + * capabilities than the system that the resulting binary/library + * will be run on, you must use this option. + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC + static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap) + { + ... your implementation ... + } +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_ALLOC_FREE [EXPERIMENTAL] + * + * Description: Set this option and define `MLD_CUSTOM_ALLOC` and + * `MLD_CUSTOM_FREE` if you want to use custom allocation for + * large local structures or buffers. + * + * By default, all buffers/structures are allocated on the stack. + * If this option is set, most of them will be allocated via + * MLD_CUSTOM_ALLOC. + * + * Parameters to MLD_CUSTOM_ALLOC: + * - T* v: Target pointer to declare. + * - T: Type of structure to be allocated + * - N: Number of elements to be allocated. + * + * Parameters to MLD_CUSTOM_FREE: + * - T* v: Target pointer to free. May be NULL. + * - T: Type of structure to be freed. + * - N: Number of elements to be freed. + * + * WARNING: This option is experimental! + * Its scope, configuration and function/macro signatures may + * change at any time. We expect a stable API for v2. + * + * NOTE: Even if this option is set, some allocations further down + * the call stack will still be made from the stack. Those will + * likely be added to the scope of this option in the future. + * + * NOTE: MLD_CUSTOM_ALLOC need not guarantee a successful + * allocation nor include error handling. Upon failure, the + * target pointer should simply be set to NULL. The calling + * code will handle this case and invoke MLD_CUSTOM_FREE. + * + *****************************************************************************/ +#define MLD_CONFIG_CUSTOM_ALLOC_FREE +#if !defined(__ASSEMBLER__) +#include +void *custom_alloc(size_t sz, const char *file, int line, const char *var, + const char *type); +void custom_free(void *p, size_t sz, const char *file, int line, + const char *var, const char *type); +#define MLD_CUSTOM_ALLOC(v, T, N) \ + T *v = custom_alloc(sizeof(T) * (N), __FILE__, __LINE__, #v, #T) +#define MLD_CUSTOM_FREE(v, T, N) \ + custom_free(v, sizeof(T) * (N), __FILE__, __LINE__, #v, #T) +#endif /* !__ASSEMBLER__ */ + + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMCPY + * + * Description: Set this option and define `mld_memcpy` if you want to + * use a custom method to copy memory instead of the standard + * library memcpy function. + * + * The custom implementation must have the same signature and + * behavior as the standard memcpy function: + * void *mld_memcpy(void *dest, const void *src, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMCPY + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_CUSTOM_MEMSET + * + * Description: Set this option and define `mld_memset` if you want to + * use a custom method to set memory instead of the standard + * library memset function. + * + * The custom implementation must have the same signature and + * behavior as the standard memset function: + * void *mld_memset(void *s, int c, size_t n) + * + *****************************************************************************/ +/* #define MLD_CONFIG_CUSTOM_MEMSET + #if !defined(__ASSEMBLER__) + #include + #include "src/src.h" + static MLD_INLINE void *mld_memset(void *s, int c, size_t n) + { + ... your implementation ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_INTERNAL_API_QUALIFIER + * + * Description: If set, this option provides an additional function + * qualifier to be added to declarations of internal API. + * + * The primary use case for this option are single-CU builds, + * in which case this option can be set to `static`. + * + *****************************************************************************/ +/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_CT_TESTING_ENABLED + * + * Description: If set, mldsa-native annotates data as secret / public using + * valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and + * VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret- + * dependent control flow of variable time execution (depending + * on the exact version of valgrind installed). + * + *****************************************************************************/ +/* #define MLD_CONFIG_CT_TESTING_ENABLED */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly. + * + * By default, inline assembly is used to implement value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + * Inline assembly is also used to implement a secure zeroization + * function on non-Windows platforms. If this option is set and + * the target platform is not Windows, you MUST set + * MLD_CONFIG_CUSTOM_ZEROIZE and provide a custom zeroization + * function. + * + * If this option is set, MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 and + * and MLD_CONFIG_USE_NATIVE_BACKEND_ARITH will be ignored, and no + * native backends will be used. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM */ + +/****************************************************************************** + * Name: MLD_CONFIG_NO_ASM_VALUE_BARRIER + * + * Description: If this option is set, mldsa-native will be built without + * use of native code or inline assembly for value barriers. + * + * By default, inline assembly (if available) is used to implement + * value barriers. + * Without inline assembly, mldsa-native will use a global volatile + * 'opt blocker' instead; see ct.h. + * + *****************************************************************************/ +/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */ + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT + * + * Description: Compliance with @[FIPS140_3_IG, p.87] requires a + * Pairwise Consistency Test (PCT) to be carried out on a freshly + * generated keypair before it can be exported. + * + * Set this option if such a check should be implemented. + * In this case, crypto_sign_keypair_internal and + * crypto_sign_keypair will return a non-zero error code if the + * PCT failed. + * + * NOTE: This feature will drastically lower the performance of + * key generation. + * + *****************************************************************************/ +#if !defined(MLD_CONFIG_KEYGEN_PCT) +#define MLD_CONFIG_KEYGEN_PCT +#endif + + +/****************************************************************************** + * Name: MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + * + * Description: If this option is set, the user must provide a runtime + * function `static inline int mld_break_pct() { ... }` to + * indicate whether the PCT should be made fail. + * + * This option only has an effect if MLD_CONFIG_KEYGEN_PCT is set. + * + *****************************************************************************/ +/* #define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST + #if !defined(__ASSEMBLER__) + #include "src/src.h" + static MLD_INLINE int mld_break_pct(void) + { + ... return 0/1 depending on whether PCT should be broken ... + } + #endif +*/ + +/****************************************************************************** + * Name: MLD_CONFIG_SERIAL_FIPS202_ONLY + * + * Description: Set this to use a FIPS202 implementation with global state + * that supports only one active Keccak computation at a time + * (e.g. some hardware accelerators). + * + * If this option is set, ML-DSA will use FIPS202 operations + * serially, ensuring that only one SHAKE context is active + * at any given time. + * + * This allows offloading Keccak computations to a hardware + * accelerator that holds only a single Keccak state locally, + * rather than requiring support for multiple concurrent + * Keccak states. + * + * NOTE: Depending on the target CPU, this may reduce + * performance when using software FIPS202 implementations. + * Only enable this when you have to. + * + *****************************************************************************/ +/* #define MLD_CONFIG_SERIAL_FIPS202_ONLY */ + +/************************* Config internals ********************************/ + +#endif /* MLD_BUILD_INTERNAL */ + +/* Default namespace + * + * Don't change this. If you need a different namespace, re-define + * MLD_CONFIG_NAMESPACE_PREFIX above instead, and remove the following. + * + * The default MLDSA namespace is + * + * PQCP_MLDSA_NATIVE_MLDSA_ + * + * e.g., PQCP_MLDSA_NATIVE_MLDSA44_ + */ + +#if MLD_CONFIG_PARAMETER_SET == 44 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA44 +#elif MLD_CONFIG_PARAMETER_SET == 65 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA65 +#elif MLD_CONFIG_PARAMETER_SET == 87 +#define MLD_DEFAULT_NAMESPACE_PREFIX PQCP_MLDSA_NATIVE_MLDSA87 +#endif + +#endif /* !MLD_CONFIG_H */