Skip to content

Commit 7b9fa33

Browse files
hanno-beckermkannwischer
authored andcommitted
Allow replacement of memcpy and memset
This commit extends the config to allow customization of mlkem-native's dependencies on the stdlib: memset and memcpy. It follows the same mechanism used for zeroize and randombytes. Custom test configs are added illustrating how the new options work, and they are exercised in CI. Further, STDLIB.md is added, documenting the dependencies on the stdlib and pointing to the customization mechanism. Signed-off-by: Hanno Becker <beckphan@amazon.co.uk>
1 parent 0e121a1 commit 7b9fa33

File tree

17 files changed

+1635
-42
lines changed

17 files changed

+1635
-42
lines changed

.github/workflows/ci.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,36 @@ jobs:
469469
kat: true
470470
acvp: true
471471
examples: false # Some examples use a custom config themselves
472+
- name: "Custom memcpy"
473+
uses: ./.github/actions/multi-functest
474+
with:
475+
gh_token: ${{ secrets.GITHUB_TOKEN }}
476+
compile_mode: native
477+
cflags: "-std=c11 -D_GNU_SOURCE -DMLK_CONFIG_FILE=\\\\\\\"../../test/custom_memcpy_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all"
478+
func: true
479+
kat: true
480+
acvp: true
481+
examples: false # Some examples use a custom config themselves
482+
- name: "Custom memset"
483+
uses: ./.github/actions/multi-functest
484+
with:
485+
gh_token: ${{ secrets.GITHUB_TOKEN }}
486+
compile_mode: native
487+
cflags: "-std=c11 -D_GNU_SOURCE -DMLK_CONFIG_FILE=\\\\\\\"../../test/custom_memset_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all"
488+
func: true
489+
kat: true
490+
acvp: true
491+
examples: false # Some examples use a custom config themselves
492+
- name: "Custom stdlib (memcpy + memset)"
493+
uses: ./.github/actions/multi-functest
494+
with:
495+
gh_token: ${{ secrets.GITHUB_TOKEN }}
496+
compile_mode: native
497+
cflags: "-std=c11 -D_GNU_SOURCE -DMLK_CONFIG_FILE=\\\\\\\"../../test/custom_stdlib_config.h\\\\\\\" -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all"
498+
func: true
499+
kat: true
500+
acvp: true
501+
examples: false # Some examples use a custom config themselves
472502
- name: "MLKEM_GEN_MATRIX_NBLOCKS=1"
473503
uses: ./.github/actions/multi-functest
474504
with:

BIBLIOGRAPHY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ source code and documentation.
5050
- [mlkem/src/config.h](mlkem/src/config.h)
5151
- [mlkem/src/kem.c](mlkem/src/kem.c)
5252
- [test/break_pct_config.h](test/break_pct_config.h)
53+
- [test/custom_memcpy_config.h](test/custom_memcpy_config.h)
54+
- [test/custom_memset_config.h](test/custom_memset_config.h)
5355
- [test/custom_randombytes_config.h](test/custom_randombytes_config.h)
56+
- [test/custom_stdlib_config.h](test/custom_stdlib_config.h)
5457
- [test/custom_zeroize_config.h](test/custom_zeroize_config.h)
5558
- [test/no_asm_config.h](test/no_asm_config.h)
5659

STDLIB.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[//]: # (SPDX-License-Identifier: CC-BY-4.0)
2+
3+
# Standard Library Dependencies
4+
5+
mlkem-native has minimal dependencies on the C standard library. This document lists all stdlib functions used and configuration options for custom replacements.
6+
7+
## Dependencies
8+
9+
### Memory Functions
10+
- **memcpy**: Used extensively for copying data structures, keys, and intermediate values (40+ occurrences)
11+
- **memset**: Used for zeroing state structures and buffers (3 occurrences). **Note**: This is NOT used for security-critical zeroing - that is handled by `mlk_zeroize` which has its own custom replacement mechanism
12+
13+
### Debug Functions (MLKEM_DEBUG builds only)
14+
- **fprintf**: Used in debug.c for error reporting to stderr
15+
- **exit**: Used in debug.c to terminate on assertion failures
16+
17+
## Custom Replacements
18+
19+
Custom replacements can be provided for memory functions using the configuration options in `mlkem/src/config.h`:
20+
21+
### MLK_CONFIG_CUSTOM_MEMCPY
22+
Replaces all `memcpy` calls with a custom implementation. When enabled, you must define a `mlk_memcpy` function with the same signature as the standard `memcpy`.
23+
24+
### MLK_CONFIG_CUSTOM_MEMSET
25+
Replaces all `memset` calls with a custom implementation. When enabled, you must define a `mlk_memset` function with the same signature as the standard `memset`.
26+
27+
See the configuration examples in `mlkem/src/config.h` and test configurations in `test/custom_*_config.h` for usage examples and implementation requirements.

dev/x86_64/src/compress_avx2.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ void mlk_poly_compress_d10_avx2(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D10],
135135
t1 = _mm256_extracti128_si256(f0, 1);
136136
t0 = _mm_blend_epi16(t0, t1, 0xE0);
137137
_mm_storeu_si128((__m128i *)&r[20 * i + 0], t0);
138-
memcpy(&r[20 * i + 16], &t1, 4);
138+
mlk_memcpy(&r[20 * i + 16], &t1, 4);
139139
}
140140
}
141141

@@ -167,7 +167,7 @@ void mlk_poly_decompress_d10_avx2(
167167
}
168168

169169
/* Handle load in last iteration especially to avoid buffer overflow */
170-
memcpy(&f, &a[20 * i], 20);
170+
mlk_memcpy(&f, &a[20 * i], 20);
171171
/* The rest is the same */
172172
f = _mm256_permute4x64_epi64(f, 0x94);
173173
f = _mm256_shuffle_epi8(f, shufbidx);
@@ -219,7 +219,7 @@ void mlk_poly_compress_d5_avx2(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D5],
219219
t1 = _mm256_extracti128_si256(f0, 1);
220220
t0 = _mm_blendv_epi8(t0, t1, _mm256_castsi256_si128(shufbidx));
221221
_mm_storeu_si128((__m128i *)&r[20 * i + 0], t0);
222-
memcpy(&r[20 * i + 16], &t1, 4);
222+
mlk_memcpy(&r[20 * i + 16], &t1, 4);
223223
}
224224
}
225225

@@ -245,7 +245,7 @@ void mlk_poly_decompress_d5_avx2(__m256i *MLK_RESTRICT r,
245245
for (i = 0; i < MLKEM_N / 16; i++)
246246
{
247247
t = _mm_loadl_epi64((__m128i *)&a[10 * i + 0]);
248-
memcpy(&ti, &a[10 * i + 8], 2);
248+
mlk_memcpy(&ti, &a[10 * i + 8], 2);
249249
t = _mm_insert_epi16(t, ti, 4);
250250
f = _mm256_broadcastsi128_si256(t);
251251
f = _mm256_shuffle_epi8(f, shufbidx);
@@ -326,7 +326,7 @@ void mlk_poly_compress_d11_avx2(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_D11],
326326
t0 = _mm_blendv_epi8(t0, t1, _mm256_castsi256_si128(shufbidx));
327327
_mm_storeu_si128((__m128i *)&r[22 * i + 0], t0);
328328
/* Handle store in last iteration especially to avoid overflow */
329-
memcpy(&r[22 * i + 16], &t1, 6);
329+
mlk_memcpy(&r[22 * i + 16], &t1, 6);
330330
}
331331

332332
void mlk_poly_decompress_d11_avx2(
@@ -363,7 +363,7 @@ void mlk_poly_decompress_d11_avx2(
363363
}
364364

365365
/* Handle load of last iteration especially */
366-
memcpy(&f, &a[22 * i], 22);
366+
mlk_memcpy(&f, &a[22 * i], 22);
367367
/* The rest of the iteration is the same */
368368
f = _mm256_permute4x64_epi64(f, 0x94);
369369
f = _mm256_shuffle_epi8(f, shufbidx);

mlkem/mlkem_native.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@
180180
#undef MLK_NAMESPACE_K
181181
#undef MLK_NAMESPACE_PREFIX
182182
#undef MLK_NAMESPACE_PREFIX_K
183+
#undef mlk_memcpy
184+
#undef mlk_memset
183185
/* mlkem/src/indcpa.h */
184186
#undef MLK_INDCPA_H
185187
#undef mlk_gen_matrix

mlkem/mlkem_native.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@
169169
#undef MLK_NAMESPACE_K
170170
#undef MLK_NAMESPACE_PREFIX
171171
#undef MLK_NAMESPACE_PREFIX_K
172+
#undef mlk_memcpy
173+
#undef mlk_memset
172174
/* mlkem/src/indcpa.h */
173175
#undef MLK_INDCPA_H
174176
#undef mlk_gen_matrix

mlkem/src/common.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,19 @@
135135
#define MLK_FIPS202X4_HEADER_FILE MLK_CONFIG_FIPS202X4_CUSTOM_HEADER
136136
#endif
137137

138+
/* Standard library function replacements */
139+
#if !defined(__ASSEMBLER__)
140+
#if !defined(MLK_CONFIG_CUSTOM_MEMCPY)
141+
#include <string.h>
142+
#define mlk_memcpy memcpy
143+
#endif
144+
145+
#if !defined(MLK_CONFIG_CUSTOM_MEMSET)
146+
#include <string.h>
147+
#define mlk_memset memset
148+
#endif
149+
#endif /* !__ASSEMBLER__ */
150+
138151
/* Just in case we want to include mlkem_native.h, set the configuration
139152
* for that header in accordance with the configuration used here. */
140153

mlkem/src/config.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,52 @@
311311
#endif
312312
*/
313313

314+
/******************************************************************************
315+
* Name: MLK_CONFIG_CUSTOM_MEMCPY
316+
*
317+
* Description: Set this option and define `mlk_memcpy` if you want to
318+
* use a custom method to copy memory instead of the standard
319+
* library memcpy function.
320+
*
321+
* The custom implementation must have the same signature and
322+
* behavior as the standard memcpy function:
323+
* void *mlk_memcpy(void *dest, const void *src, size_t n)
324+
*
325+
*****************************************************************************/
326+
/* #define MLK_CONFIG_CUSTOM_MEMCPY
327+
#if !defined(__ASSEMBLER__)
328+
#include <stdint.h>
329+
#include "sys.h"
330+
static MLK_INLINE void *mlk_memcpy(void *dest, const void *src, size_t n)
331+
{
332+
... your implementation ...
333+
}
334+
#endif
335+
*/
336+
337+
/******************************************************************************
338+
* Name: MLK_CONFIG_CUSTOM_MEMSET
339+
*
340+
* Description: Set this option and define `mlk_memset` if you want to
341+
* use a custom method to set memory instead of the standard
342+
* library memset function.
343+
*
344+
* The custom implementation must have the same signature and
345+
* behavior as the standard memset function:
346+
* void *mlk_memset(void *s, int c, size_t n)
347+
*
348+
*****************************************************************************/
349+
/* #define MLK_CONFIG_CUSTOM_MEMSET
350+
#if !defined(__ASSEMBLER__)
351+
#include <stdint.h>
352+
#include "sys.h"
353+
static MLK_INLINE void *mlk_memset(void *s, int c, size_t n)
354+
{
355+
... your implementation ...
356+
}
357+
#endif
358+
*/
359+
314360
/******************************************************************************
315361
* Name: MLK_CONFIG_INTERNAL_API_QUALIFIER
316362
*

mlkem/src/fips202/fips202x4.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ void mlk_shake128x4_absorb_once(mlk_shake128x4ctx *state, const uint8_t *in0,
119119
const uint8_t *in1, const uint8_t *in2,
120120
const uint8_t *in3, size_t inlen)
121121
{
122-
memset(state, 0, sizeof(mlk_shake128x4ctx));
122+
mlk_memset(state, 0, sizeof(mlk_shake128x4ctx));
123123
mlk_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3,
124124
inlen, 0x1F);
125125
}
@@ -145,7 +145,7 @@ static void mlk_shake256x4_absorb_once(mlk_shake256x4_ctx *state,
145145
const uint8_t *in2, const uint8_t *in3,
146146
size_t inlen)
147147
{
148-
memset(state, 0, sizeof(mlk_shake128x4ctx));
148+
mlk_memset(state, 0, sizeof(mlk_shake128x4ctx));
149149
mlk_keccak_absorb_once_x4(state->ctx, SHAKE256_RATE, in0, in1, in2, in3,
150150
inlen, 0x1F);
151151
}
@@ -183,10 +183,10 @@ void mlk_shake256x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3,
183183
if (outlen)
184184
{
185185
mlk_shake256x4_squeezeblocks(tmp0, tmp1, tmp2, tmp3, 1, &statex);
186-
memcpy(out0, tmp0, outlen);
187-
memcpy(out1, tmp1, outlen);
188-
memcpy(out2, tmp2, outlen);
189-
memcpy(out3, tmp3, outlen);
186+
mlk_memcpy(out0, tmp0, outlen);
187+
mlk_memcpy(out1, tmp1, outlen);
188+
mlk_memcpy(out2, tmp2, outlen);
189+
mlk_memcpy(out3, tmp3, outlen);
190190
}
191191

192192
/* Specification: Partially implements

mlkem/src/indcpa.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ static void mlk_pack_pk(uint8_t r[MLKEM_INDCPA_PUBLICKEYBYTES], mlk_polyvec pk,
6464
{
6565
mlk_assert_bound_2d(pk, MLKEM_K, MLKEM_N, 0, MLKEM_Q);
6666
mlk_polyvec_tobytes(r, pk);
67-
memcpy(r + MLKEM_POLYVECBYTES, seed, MLKEM_SYMBYTES);
67+
mlk_memcpy(r + MLKEM_POLYVECBYTES, seed, MLKEM_SYMBYTES);
6868
}
6969

7070
/*************************************************
@@ -87,7 +87,7 @@ static void mlk_unpack_pk(mlk_polyvec pk, uint8_t seed[MLKEM_SYMBYTES],
8787
const uint8_t packedpk[MLKEM_INDCPA_PUBLICKEYBYTES])
8888
{
8989
mlk_polyvec_frombytes(pk, packedpk);
90-
memcpy(seed, packedpk + MLKEM_POLYVECBYTES, MLKEM_SYMBYTES);
90+
mlk_memcpy(seed, packedpk + MLKEM_POLYVECBYTES, MLKEM_SYMBYTES);
9191

9292
/* NOTE: If a modulus check was conducted on the PK, we know at this
9393
* point that the coefficients of `pk` are unsigned canonical. The
@@ -215,7 +215,7 @@ void mlk_gen_matrix(mlk_polymat a, const uint8_t seed[MLKEM_SYMBYTES],
215215

216216
for (j = 0; j < 4; j++)
217217
{
218-
memcpy(seed_ext[j], seed, MLKEM_SYMBYTES);
218+
mlk_memcpy(seed_ext[j], seed, MLKEM_SYMBYTES);
219219
}
220220

221221
/* Sample 4 matrix entries a time. */
@@ -344,7 +344,7 @@ void mlk_indcpa_keypair_derand(uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES],
344344

345345
MLK_ALIGN uint8_t coins_with_domain_separator[MLKEM_SYMBYTES + 1];
346346
/* Concatenate coins with MLKEM_K for domain separation of security levels */
347-
memcpy(coins_with_domain_separator, coins, MLKEM_SYMBYTES);
347+
mlk_memcpy(coins_with_domain_separator, coins, MLKEM_SYMBYTES);
348348
coins_with_domain_separator[MLKEM_SYMBYTES] = MLKEM_K;
349349

350350
mlk_hash_g(buf, coins_with_domain_separator, MLKEM_SYMBYTES + 1);

0 commit comments

Comments
 (0)