diff --git a/.github/workflows/baremetal.yml b/.github/workflows/baremetal.yml index b74d572ce2..95b35090e3 100644 --- a/.github/workflows/baremetal.yml +++ b/.github/workflows/baremetal.yml @@ -23,6 +23,7 @@ jobs: func: true kat: true acvp: true + alloc: true - runner: ubuntu-latest name: 'AVR ATmega128RFR2 (modified for 32K RAM)' makefile: test/baremetal/platform/avr/platform.mk @@ -30,6 +31,7 @@ jobs: func: true kat: true acvp: true + alloc: false runs-on: ${{ matrix.target.runner }} steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -46,4 +48,4 @@ jobs: acvp: ${{ matrix.target.acvp }} examples: false stack: false - alloc: false + alloc: ${{ matrix.target.alloc }} diff --git a/examples/monolithic_build_multilevel/mlkem_native/mlkem_native_config.h b/examples/monolithic_build_multilevel/mlkem_native/mlkem_native_config.h index ae3efcff13..6e6393c131 100644 --- a/examples/monolithic_build_multilevel/mlkem_native/mlkem_native_config.h +++ b/examples/monolithic_build_multilevel/mlkem_native/mlkem_native_config.h @@ -29,6 +29,7 @@ * * This configuration differs from the default mlkem/mlkem_native_config.h in * the following places: + * - MLK_CONFIG_NO_SUPERCOP * - MLK_CONFIG_MULTILEVEL_BUILD * - MLK_CONFIG_NAMESPACE_PREFIX * - MLK_CONFIG_INTERNAL_API_QUALIFIER @@ -156,7 +157,7 @@ * naming does not disambiguate between the parameter sets. * *****************************************************************************/ -/* #define MLK_CONFIG_NO_SUPERCOP */ +#define MLK_CONFIG_NO_SUPERCOP /****************************************************************************** * Name: MLK_CONFIG_CONSTANTS_ONLY diff --git a/examples/monolithic_build_multilevel_native/mlkem_native/mlkem_native_config.h b/examples/monolithic_build_multilevel_native/mlkem_native/mlkem_native_config.h index a36cacdd0f..ce5ddcf111 100644 --- a/examples/monolithic_build_multilevel_native/mlkem_native/mlkem_native_config.h +++ b/examples/monolithic_build_multilevel_native/mlkem_native/mlkem_native_config.h @@ -29,6 +29,7 @@ * * This configuration differs from the default mlkem/mlkem_native_config.h in * the following places: + * - MLK_CONFIG_NO_SUPERCOP * - MLK_CONFIG_MULTILEVEL_BUILD * - MLK_CONFIG_NAMESPACE_PREFIX * - MLK_CONFIG_USE_NATIVE_BACKEND_ARITH @@ -160,7 +161,7 @@ * naming does not disambiguate between the parameter sets. * *****************************************************************************/ -/* #define MLK_CONFIG_NO_SUPERCOP */ +#define MLK_CONFIG_NO_SUPERCOP /****************************************************************************** * Name: MLK_CONFIG_CONSTANTS_ONLY diff --git a/examples/multilevel_build/mlkem_native/mlkem_native_config.h b/examples/multilevel_build/mlkem_native/mlkem_native_config.h index de6a080f3f..0d6d959a82 100644 --- a/examples/multilevel_build/mlkem_native/mlkem_native_config.h +++ b/examples/multilevel_build/mlkem_native/mlkem_native_config.h @@ -29,6 +29,7 @@ * * This configuration differs from the default mlkem/mlkem_native_config.h in * the following places: + * - MLK_CONFIG_NO_SUPERCOP * - MLK_CONFIG_MULTILEVEL_BUILD * - MLK_CONFIG_NAMESPACE_PREFIX */ @@ -155,7 +156,7 @@ * naming does not disambiguate between the parameter sets. * *****************************************************************************/ -/* #define MLK_CONFIG_NO_SUPERCOP */ +#define MLK_CONFIG_NO_SUPERCOP /****************************************************************************** * Name: MLK_CONFIG_CONSTANTS_ONLY diff --git a/examples/multilevel_build_native/mlkem_native/mlkem_native_config.h b/examples/multilevel_build_native/mlkem_native/mlkem_native_config.h index f574a6597a..88fbc4cf61 100644 --- a/examples/multilevel_build_native/mlkem_native/mlkem_native_config.h +++ b/examples/multilevel_build_native/mlkem_native/mlkem_native_config.h @@ -29,6 +29,7 @@ * * This configuration differs from the default mlkem/mlkem_native_config.h in * the following places: + * - MLK_CONFIG_NO_SUPERCOP * - MLK_CONFIG_MULTILEVEL_BUILD * - MLK_CONFIG_NAMESPACE_PREFIX * - MLK_CONFIG_USE_NATIVE_BACKEND_ARITH @@ -157,7 +158,7 @@ * naming does not disambiguate between the parameter sets. * *****************************************************************************/ -/* #define MLK_CONFIG_NO_SUPERCOP */ +#define MLK_CONFIG_NO_SUPERCOP /****************************************************************************** * Name: MLK_CONFIG_CONSTANTS_ONLY diff --git a/mlkem/mlkem_native.S b/mlkem/mlkem_native.S index 7450551b06..4aea390401 100644 --- a/mlkem/mlkem_native.S +++ b/mlkem/mlkem_native.S @@ -168,6 +168,25 @@ #undef MLK_ERR_FAIL #undef MLK_ERR_OUT_OF_MEMORY #undef MLK_H +#undef MLK_MAX3_ +#undef MLK_TOTAL_ALLOC_1024 +#undef MLK_TOTAL_ALLOC_1024_DECAPS +#undef MLK_TOTAL_ALLOC_1024_ENCAPS +#undef MLK_TOTAL_ALLOC_1024_KEYPAIR +#undef MLK_TOTAL_ALLOC_1024_KEYPAIR_NO_PCT +#undef MLK_TOTAL_ALLOC_1024_KEYPAIR_PCT +#undef MLK_TOTAL_ALLOC_512 +#undef MLK_TOTAL_ALLOC_512_DECAPS +#undef MLK_TOTAL_ALLOC_512_ENCAPS +#undef MLK_TOTAL_ALLOC_512_KEYPAIR +#undef MLK_TOTAL_ALLOC_512_KEYPAIR_NO_PCT +#undef MLK_TOTAL_ALLOC_512_KEYPAIR_PCT +#undef MLK_TOTAL_ALLOC_768 +#undef MLK_TOTAL_ALLOC_768_DECAPS +#undef MLK_TOTAL_ALLOC_768_ENCAPS +#undef MLK_TOTAL_ALLOC_768_KEYPAIR +#undef MLK_TOTAL_ALLOC_768_KEYPAIR_NO_PCT +#undef MLK_TOTAL_ALLOC_768_KEYPAIR_PCT #undef crypto_kem_check_pk #undef crypto_kem_check_sk #undef crypto_kem_dec diff --git a/mlkem/mlkem_native.c b/mlkem/mlkem_native.c index 6f118e442a..73190a2dc5 100644 --- a/mlkem/mlkem_native.c +++ b/mlkem/mlkem_native.c @@ -157,6 +157,25 @@ #undef MLK_ERR_FAIL #undef MLK_ERR_OUT_OF_MEMORY #undef MLK_H +#undef MLK_MAX3_ +#undef MLK_TOTAL_ALLOC_1024 +#undef MLK_TOTAL_ALLOC_1024_DECAPS +#undef MLK_TOTAL_ALLOC_1024_ENCAPS +#undef MLK_TOTAL_ALLOC_1024_KEYPAIR +#undef MLK_TOTAL_ALLOC_1024_KEYPAIR_NO_PCT +#undef MLK_TOTAL_ALLOC_1024_KEYPAIR_PCT +#undef MLK_TOTAL_ALLOC_512 +#undef MLK_TOTAL_ALLOC_512_DECAPS +#undef MLK_TOTAL_ALLOC_512_ENCAPS +#undef MLK_TOTAL_ALLOC_512_KEYPAIR +#undef MLK_TOTAL_ALLOC_512_KEYPAIR_NO_PCT +#undef MLK_TOTAL_ALLOC_512_KEYPAIR_PCT +#undef MLK_TOTAL_ALLOC_768 +#undef MLK_TOTAL_ALLOC_768_DECAPS +#undef MLK_TOTAL_ALLOC_768_ENCAPS +#undef MLK_TOTAL_ALLOC_768_KEYPAIR +#undef MLK_TOTAL_ALLOC_768_KEYPAIR_NO_PCT +#undef MLK_TOTAL_ALLOC_768_KEYPAIR_PCT #undef crypto_kem_check_pk #undef crypto_kem_check_sk #undef crypto_kem_dec diff --git a/mlkem/mlkem_native.h b/mlkem/mlkem_native.h index 3fec85a2de..63f305826a 100644 --- a/mlkem/mlkem_native.h +++ b/mlkem/mlkem_native.h @@ -465,4 +465,69 @@ int MLK_API_NAMESPACE(check_sk)( #endif /* MLK_CONFIG_API_NO_SUPERCOP */ #endif /* !MLK_CONFIG_API_CONSTANTS_ONLY */ + +/***************************** Memory Usage **********************************/ + +/* + * By default mlkem-native performs all memory allocations on the stack. + * Alternatively, mlkem-native supports custom allocation of large structures + * through the `MLK_CONFIG_CUSTOM_ALLOC_FREE` configuration option. + * See mlkem_native_config.h for details. + * + * `MLK_TOTAL_ALLOC_{512,768,1024}_{KEYPAIR,ENCAPS,DECAPS}` indicates the + * maximum (accumulative) allocation via MLK_ALLOC for each parameter set and + * operation. Note that some stack allocation remains even when using custom + * allocators, so these values are lower than total stack usage with the default + * stack-only allocation. + * + * These constants may be used to implement custom allocations using a + * fixed-sized buffer and a simple allocator (e.g., bump allocator). + */ +/* check-magic: off */ +#define MLK_TOTAL_ALLOC_512_KEYPAIR_NO_PCT 5824 +#define MLK_TOTAL_ALLOC_512_KEYPAIR_PCT 10048 +#define MLK_TOTAL_ALLOC_512_ENCAPS 8384 +#define MLK_TOTAL_ALLOC_512_DECAPS 9152 +#define MLK_TOTAL_ALLOC_768_KEYPAIR_NO_PCT 10176 +#define MLK_TOTAL_ALLOC_768_KEYPAIR_PCT 15552 +#define MLK_TOTAL_ALLOC_768_ENCAPS 13248 +#define MLK_TOTAL_ALLOC_768_DECAPS 14336 +#define MLK_TOTAL_ALLOC_1024_KEYPAIR_NO_PCT 15552 +#define MLK_TOTAL_ALLOC_1024_KEYPAIR_PCT 22400 +#define MLK_TOTAL_ALLOC_1024_ENCAPS 19136 +#define MLK_TOTAL_ALLOC_1024_DECAPS 20704 +/* check-magic: on */ + +/* + * MLK_TOTAL_ALLOC_*_KEYPAIR adapts based on MLK_CONFIG_KEYGEN_PCT. + * For legacy config, we don't know which options are used, so assume + * the worst case (PCT enabled). + */ +#if defined(MLK_API_LEGACY_CONFIG) || defined(MLK_CONFIG_KEYGEN_PCT) +#define MLK_TOTAL_ALLOC_512_KEYPAIR MLK_TOTAL_ALLOC_512_KEYPAIR_PCT +#define MLK_TOTAL_ALLOC_768_KEYPAIR MLK_TOTAL_ALLOC_768_KEYPAIR_PCT +#define MLK_TOTAL_ALLOC_1024_KEYPAIR MLK_TOTAL_ALLOC_1024_KEYPAIR_PCT +#else +#define MLK_TOTAL_ALLOC_512_KEYPAIR MLK_TOTAL_ALLOC_512_KEYPAIR_NO_PCT +#define MLK_TOTAL_ALLOC_768_KEYPAIR MLK_TOTAL_ALLOC_768_KEYPAIR_NO_PCT +#define MLK_TOTAL_ALLOC_1024_KEYPAIR MLK_TOTAL_ALLOC_1024_KEYPAIR_NO_PCT +#endif + +#define MLK_MAX3_(a, b, c) \ + ((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c))) + +/* + * `MLK_TOTAL_ALLOC_{512,768,1024}` is the maximum across all operations for + * each parameter set. + */ +#define MLK_TOTAL_ALLOC_512 \ + MLK_MAX3_(MLK_TOTAL_ALLOC_512_KEYPAIR, MLK_TOTAL_ALLOC_512_ENCAPS, \ + MLK_TOTAL_ALLOC_512_DECAPS) +#define MLK_TOTAL_ALLOC_768 \ + MLK_MAX3_(MLK_TOTAL_ALLOC_768_KEYPAIR, MLK_TOTAL_ALLOC_768_ENCAPS, \ + MLK_TOTAL_ALLOC_768_DECAPS) +#define MLK_TOTAL_ALLOC_1024 \ + MLK_MAX3_(MLK_TOTAL_ALLOC_1024_KEYPAIR, MLK_TOTAL_ALLOC_1024_ENCAPS, \ + MLK_TOTAL_ALLOC_1024_DECAPS) + #endif /* !MLK_H */ diff --git a/scripts/autogen b/scripts/autogen index 16130c7117..4fc6163555 100755 --- a/scripts/autogen +++ b/scripts/autogen @@ -2025,6 +2025,10 @@ def check_macro_typos(): if m in macros: return True + # Ignore alloc macros only defined in mlkem_native.h + if m.startswith("MLK_TOTAL_ALLOC") or m.startswith("MLK_MAX_TOTAL_ALLOC"): + return True + is_autogen = filename == "scripts/autogen" # Exclude system capabilities, which are enum values diff --git a/test/configs/configs.yml b/test/configs/configs.yml index a2a1062a79..e88e2d7e09 100644 --- a/test/configs/configs.yml +++ b/test/configs/configs.yml @@ -301,6 +301,7 @@ configs: - path: examples/monolithic_build_multilevel/mlkem_native/mlkem_native_config.h description: "Multilevel monolithic build config" defines: + MLK_CONFIG_NO_SUPERCOP: true MLK_CONFIG_MULTILEVEL_BUILD: true MLK_CONFIG_NAMESPACE_PREFIX: mlkem MLK_CONFIG_INTERNAL_API_QUALIFIER: static @@ -310,6 +311,7 @@ configs: - path: examples/multilevel_build/mlkem_native/mlkem_native_config.h description: "Multilevel build config" defines: + MLK_CONFIG_NO_SUPERCOP: true MLK_CONFIG_MULTILEVEL_BUILD: true MLK_CONFIG_NAMESPACE_PREFIX: mlkem MLK_CONFIG_FILE: @@ -318,6 +320,7 @@ configs: - path: examples/multilevel_build_native/mlkem_native/mlkem_native_config.h description: "Multilevel build config" defines: + MLK_CONFIG_NO_SUPERCOP: true MLK_CONFIG_MULTILEVEL_BUILD: true MLK_CONFIG_NAMESPACE_PREFIX: mlkem MLK_CONFIG_USE_NATIVE_BACKEND_ARITH: true @@ -328,6 +331,7 @@ configs: - path: examples/monolithic_build_multilevel_native/mlkem_native/mlkem_native_config.h description: "Multilevel monolithic build config with native backends" defines: + MLK_CONFIG_NO_SUPERCOP: true MLK_CONFIG_MULTILEVEL_BUILD: true MLK_CONFIG_NAMESPACE_PREFIX: mlkem MLK_CONFIG_USE_NATIVE_BACKEND_ARITH: true @@ -430,11 +434,6 @@ configs: description: "Using custom allocation that can be made fail at specific invocation" defines: MLK_CONFIG_NAMESPACE_PREFIX: mlk - MLK_CONFIG_KEYGEN_PCT: - content: | - #if !defined(MLK_CONFIG_KEYGEN_PCT) - #define MLK_CONFIG_KEYGEN_PCT - #endif MLK_CONFIG_CONTEXT_PARAMETER: true MLK_CONFIG_CONTEXT_PARAMETER_TYPE: struct test_ctx_t * MLK_CONFIG_CUSTOM_ALLOC_FREE: diff --git a/test/configs/test_alloc_config.h b/test/configs/test_alloc_config.h index bc6c4ce29e..7f1550fb85 100644 --- a/test/configs/test_alloc_config.h +++ b/test/configs/test_alloc_config.h @@ -31,7 +31,6 @@ * This configuration differs from the default mlkem/mlkem_native_config.h in * the following places: * - MLK_CONFIG_NAMESPACE_PREFIX - * - MLK_CONFIG_KEYGEN_PCT * - MLK_CONFIG_CONTEXT_PARAMETER * - MLK_CONFIG_CONTEXT_PARAMETER_TYPE * - MLK_CONFIG_CUSTOM_ALLOC_FREE @@ -635,10 +634,7 @@ void custom_free(struct test_ctx_t *ctx, void *p, size_t sz, const char *file, * key generation. * *****************************************************************************/ -#if !defined(MLK_CONFIG_KEYGEN_PCT) -#define MLK_CONFIG_KEYGEN_PCT -#endif - +/* #define MLK_CONFIG_KEYGEN_PCT */ /****************************************************************************** * Name: MLK_CONFIG_KEYGEN_PCT_BREAKAGE_TEST diff --git a/test/src/test_alloc.c b/test/src/test_alloc.c index 79b604fdba..bc4f0d03c7 100644 --- a/test/src/test_alloc.c +++ b/test/src/test_alloc.c @@ -12,6 +12,33 @@ #include "../../mlkem/src/common.h" #include "../notrandombytes/notrandombytes.h" +/* + * Level-dependent allocation limit macros. + * These expand to the right MLK_TOTAL_ALLOC_{512,768,1024}_* constant + * based on MLK_CONFIG_API_PARAMETER_SET. + * + * Note: MLK_TOTAL_ALLOC_*_KEYPAIR in the header automatically adapts + * based on MLK_CONFIG_KEYGEN_PCT. + */ +#define MLK_TOTAL_ALLOC_KEYPAIR__(LVL) MLK_TOTAL_ALLOC_##LVL##_KEYPAIR +#define MLK_TOTAL_ALLOC_KEYPAIR_(LVL) MLK_TOTAL_ALLOC_KEYPAIR__(LVL) +#define MLK_TOTAL_ALLOC_KEYPAIR \ + MLK_TOTAL_ALLOC_KEYPAIR_(MLK_CONFIG_API_PARAMETER_SET) + +#define MLK_TOTAL_ALLOC_ENCAPS__(LVL) MLK_TOTAL_ALLOC_##LVL##_ENCAPS +#define MLK_TOTAL_ALLOC_ENCAPS_(LVL) MLK_TOTAL_ALLOC_ENCAPS__(LVL) +#define MLK_TOTAL_ALLOC_ENCAPS \ + MLK_TOTAL_ALLOC_ENCAPS_(MLK_CONFIG_API_PARAMETER_SET) + +#define MLK_TOTAL_ALLOC_DECAPS__(LVL) MLK_TOTAL_ALLOC_##LVL##_DECAPS +#define MLK_TOTAL_ALLOC_DECAPS_(LVL) MLK_TOTAL_ALLOC_DECAPS__(LVL) +#define MLK_TOTAL_ALLOC_DECAPS \ + MLK_TOTAL_ALLOC_DECAPS_(MLK_CONFIG_API_PARAMETER_SET) + +#define MLK_TOTAL_ALLOC__(LVL) MLK_TOTAL_ALLOC_##LVL +#define MLK_TOTAL_ALLOC_(LVL) MLK_TOTAL_ALLOC__(LVL) +#define MLK_TOTAL_ALLOC MLK_TOTAL_ALLOC_(MLK_CONFIG_API_PARAMETER_SET) + /* * This test checks that * - we handle allocator failures correctly, propagating MLK_ERR_OUT_OF_MEMORY @@ -51,6 +78,10 @@ struct test_ctx_t uint8_t *buffer; size_t offset; size_t high_mark; + size_t global_high_mark; + size_t global_high_mark_keypair; + size_t global_high_mark_encaps; + size_t global_high_mark_decaps; /* Allocation tracker */ alloc_info_t alloc_stack[MLK_MAX_IN_FLIGHT_ALLOCS]; @@ -207,79 +238,93 @@ void custom_free(test_ctx_t *ctx, void *p, size_t sz, const char *file, } } -#define TEST_ALLOC_FAILURE(test_name, call) \ - do \ - { \ - int num_allocs, i, rc; \ - /* First pass: count allocations */ \ - ctx->high_mark = 0; \ - reset_all(ctx); \ - rc = call; \ - if (rc != 0) \ - { \ - fprintf(stderr, "ERROR: %s failed with %d in counting pass\n", \ - test_name, rc); \ - return 1; \ - } \ - if (ctx->alloc_stack_top != 0) \ - { \ - fprintf(stderr, "ERROR: %s leaked %d allocation(s) in counting pass\n", \ - test_name, ctx->alloc_stack_top); \ - return 1; \ - } \ - num_allocs = ctx->alloc_counter; \ - /* Second pass: test each allocation failure */ \ - for (i = 0; i < num_allocs; i++) \ - { \ - reset_all(ctx); \ - ctx->fail_on_counter = i; \ - rc = call; \ - if (rc != MLK_ERR_OUT_OF_MEMORY) \ - { \ - int rc2; \ - /* Re-run dry-run and print debug info */ \ - ctx->print_debug_info = 1; \ - reset_all(ctx); \ - 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, MLK_ERR_OUT_OF_MEMORY, i + 1, num_allocs); \ - } \ - return 1; \ - } \ - if (ctx->alloc_stack_top != 0) \ - { \ - fprintf(stderr, \ - "ERROR: %s leaked %d allocation(s) when allocation %d/%d " \ - "was instrumented to fail\n", \ - test_name, ctx->alloc_stack_top, i + 1, num_allocs); \ - return 1; \ - } \ - if (ctx->offset != 0) \ - { \ - fprintf(stderr, \ - "ERROR: %s leaked %d bytes when allocation %d/%d " \ - "was instrumented to fail\n", \ - test_name, (int)ctx->offset, i + 1, num_allocs); \ - return 1; \ - } \ - } \ - printf( \ - "Allocation test for %s PASSED.\n" \ - " Max dynamic allocation: %d bytes\n", \ - test_name, (int)ctx->high_mark); \ +#define TEST_ALLOC_FAILURE(test_name, call, alloc_limit, global_high_mark_ptr) \ + do \ + { \ + int num_allocs, i, rc; \ + /* First pass: count allocations */ \ + ctx->high_mark = 0; \ + reset_all(ctx); \ + rc = call; \ + if (rc != 0) \ + { \ + fprintf(stderr, "ERROR: %s failed with %d in counting pass\n", \ + test_name, rc); \ + return 1; \ + } \ + if (ctx->alloc_stack_top != 0) \ + { \ + fprintf(stderr, "ERROR: %s leaked %d allocation(s) in counting pass\n", \ + test_name, ctx->alloc_stack_top); \ + return 1; \ + } \ + num_allocs = ctx->alloc_counter; \ + /* Second pass: test each allocation failure */ \ + for (i = 0; i < num_allocs; i++) \ + { \ + reset_all(ctx); \ + ctx->fail_on_counter = i; \ + rc = call; \ + if (rc != MLK_ERR_OUT_OF_MEMORY) \ + { \ + int rc2; \ + /* Re-run dry-run and print debug info */ \ + ctx->print_debug_info = 1; \ + reset_all(ctx); \ + 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, MLK_ERR_OUT_OF_MEMORY, i + 1, num_allocs); \ + } \ + return 1; \ + } \ + if (ctx->alloc_stack_top != 0) \ + { \ + fprintf(stderr, \ + "ERROR: %s leaked %d allocation(s) when allocation %d/%d " \ + "was instrumented to fail\n", \ + test_name, ctx->alloc_stack_top, i + 1, num_allocs); \ + return 1; \ + } \ + if (ctx->offset != 0) \ + { \ + fprintf(stderr, \ + "ERROR: %s leaked %d bytes when allocation %d/%d " \ + "was instrumented to fail\n", \ + test_name, (int)ctx->offset, i + 1, num_allocs); \ + return 1; \ + } \ + } \ + if (ctx->high_mark > (alloc_limit)) \ + { \ + fprintf(stderr, "ERROR: max allocation %u in %s exceeded limit %d\n", \ + (unsigned)ctx->high_mark, test_name, (int)(alloc_limit)); \ + return 1; \ + } \ + printf( \ + "Allocation test for %s PASSED.\n" \ + " Max dynamic allocation: %d bytes\n", \ + test_name, (int)ctx->high_mark); \ + if (ctx->high_mark > ctx->global_high_mark) \ + { \ + ctx->global_high_mark = ctx->high_mark; \ + } \ + if (ctx->high_mark > *(global_high_mark_ptr)) \ + { \ + *(global_high_mark_ptr) = ctx->high_mark; \ + } \ } while (0) static int test_keygen_alloc_failure(test_ctx_t *ctx) @@ -287,7 +332,8 @@ static int test_keygen_alloc_failure(test_ctx_t *ctx) uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; - TEST_ALLOC_FAILURE("crypto_kem_keypair", crypto_kem_keypair(pk, sk, ctx)); + TEST_ALLOC_FAILURE("crypto_kem_keypair", crypto_kem_keypair(pk, sk, ctx), + MLK_TOTAL_ALLOC_KEYPAIR, &ctx->global_high_mark_keypair); return 0; } @@ -306,7 +352,8 @@ static int test_enc_alloc_failure(test_ctx_t *ctx) return 1; } - TEST_ALLOC_FAILURE("crypto_kem_enc", crypto_kem_enc(ct, key, pk, ctx)); + TEST_ALLOC_FAILURE("crypto_kem_enc", crypto_kem_enc(ct, key, pk, ctx), + MLK_TOTAL_ALLOC_ENCAPS, &ctx->global_high_mark_encaps); return 0; } @@ -332,7 +379,8 @@ static int test_dec_alloc_failure(test_ctx_t *ctx) return 1; } - TEST_ALLOC_FAILURE("crypto_kem_dec", crypto_kem_dec(key_dec, ct, sk, ctx)); + TEST_ALLOC_FAILURE("crypto_kem_dec", crypto_kem_dec(key_dec, ct, sk, ctx), + MLK_TOTAL_ALLOC_DECAPS, &ctx->global_high_mark_decaps); return 0; } @@ -349,7 +397,8 @@ static int test_check_pk_alloc_failure(test_ctx_t *ctx) return 1; } - TEST_ALLOC_FAILURE("crypto_kem_check_pk", crypto_kem_check_pk(pk, ctx)); + TEST_ALLOC_FAILURE("crypto_kem_check_pk", crypto_kem_check_pk(pk, ctx), + MLK_TOTAL_ALLOC_KEYPAIR, &ctx->global_high_mark_keypair); return 0; } @@ -366,10 +415,25 @@ static int test_check_sk_alloc_failure(test_ctx_t *ctx) return 1; } - TEST_ALLOC_FAILURE("crypto_kem_check_sk", crypto_kem_check_sk(sk, ctx)); + TEST_ALLOC_FAILURE("crypto_kem_check_sk", crypto_kem_check_sk(sk, ctx), + MLK_TOTAL_ALLOC_KEYPAIR, &ctx->global_high_mark_keypair); return 0; } +/* + * Helper macro to check allocation high watermark matches expected limit. + */ +#define CHECK_ALLOC_MATCH(high_mark, expected) \ + do \ + { \ + if ((expected) != (high_mark)) \ + { \ + fprintf(stderr, "ERROR: %s = %u does not match %s = %d\n", #high_mark, \ + (unsigned)(high_mark), #expected, (int)(expected)); \ + return 1; \ + } \ + } while (0) + int main(void) { MLK_ALIGN uint8_t bump_buffer[MLK_BUMP_ALLOC_SIZE]; @@ -378,6 +442,10 @@ int main(void) NULL, /* buffer (set below) */ 0, /* offset */ 0, /* high_mark */ + 0, /* global_high_mark */ + 0, /* global_high_mark_keypair */ + 0, /* global_high_mark_encaps */ + 0, /* global_high_mark_decaps */ {{0}}, /* alloc_stack */ 0, /* alloc_stack_top */ 0, /* alloc_counter */ @@ -411,5 +479,11 @@ int main(void) return 1; } + /* Check per-operation high watermarks match the declared limits */ + CHECK_ALLOC_MATCH(ctx.global_high_mark_keypair, MLK_TOTAL_ALLOC_KEYPAIR); + CHECK_ALLOC_MATCH(ctx.global_high_mark_encaps, MLK_TOTAL_ALLOC_ENCAPS); + CHECK_ALLOC_MATCH(ctx.global_high_mark_decaps, MLK_TOTAL_ALLOC_DECAPS); + CHECK_ALLOC_MATCH(ctx.global_high_mark, MLK_TOTAL_ALLOC); + return 0; }