Skip to content

Commit e9b12dd

Browse files
committed
FIPS202: Provide alignment constraints for in/out buffers
mlkem-native will only call the FIPS202 API with aligned buffers, which can be useful for users providing their own FIPS202 implementation. This commit extends the documentation and CBMC contracts accordingly, and adds debug assertions for checking alignment. Note that CBMC does, to the best of my knowledge, not support talking about absolute pointer alignment, so we cannot rely on proof here. We also take the opportunity to align internal buffers used in the default C implementation of mlk_shake256x4. Signed-off-by: Hanno Becker <[email protected]>
1 parent 6048cab commit e9b12dd

File tree

8 files changed

+203
-5
lines changed

8 files changed

+203
-5
lines changed

mlkem/mlkem_native.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,10 @@
280280
#undef mlk_assert
281281
#undef mlk_assert_abs_bound
282282
#undef mlk_assert_abs_bound_2d
283+
#undef mlk_assert_alignment
283284
#undef mlk_assert_bound
284285
#undef mlk_assert_bound_2d
286+
#undef mlk_debug_check_alignment
285287
#undef mlk_debug_check_assert
286288
#undef mlk_debug_check_bounds
287289
/* mlkem/src/poly.h */

mlkem/mlkem_native.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,10 @@
269269
#undef mlk_assert
270270
#undef mlk_assert_abs_bound
271271
#undef mlk_assert_abs_bound_2d
272+
#undef mlk_assert_alignment
272273
#undef mlk_assert_bound
273274
#undef mlk_assert_bound_2d
275+
#undef mlk_debug_check_alignment
274276
#undef mlk_debug_check_assert
275277
#undef mlk_debug_check_bounds
276278
/* mlkem/src/poly.h */

mlkem/src/debug.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,28 @@
1616

1717
#define MLK_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] "
1818

19+
void mlk_debug_check_alignment(const char *file, int line, const void *ptr,
20+
size_t ptr_len, unsigned alignment)
21+
{
22+
uintptr_t ptr_uint = (uintptr_t)ptr;
23+
if (ptr_uint % alignment != 0)
24+
{
25+
fprintf(stderr,
26+
MLK_DEBUG_ERROR_HEADER
27+
"Alignment assertion failed for address %p)\n",
28+
file, line, ptr);
29+
exit(1);
30+
}
31+
32+
if (ptr_len % alignment != 0)
33+
{
34+
fprintf(stderr,
35+
MLK_DEBUG_ERROR_HEADER
36+
"Alignment assertion failed for length %u)\n",
37+
file, line, (unsigned)ptr_len);
38+
exit(1);
39+
}
40+
}
1941
void mlk_debug_check_assert(const char *file, int line, const int val)
2042
{
2143
if (val == 0)

mlkem/src/debug.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,31 @@ void mlk_debug_check_bounds(const char *file, int line, const int16_t *ptr,
4545
unsigned len, int lower_bound_exclusive,
4646
int upper_bound_exclusive);
4747

48+
/*************************************************
49+
* Name: mlk_debug_check_alignment
50+
*
51+
* Description: Check whether a pointer has the specified alignment.
52+
*
53+
* Prints an error message to stderr and calls
54+
* exit(1) if not.
55+
*
56+
* Arguments: - file: filename
57+
* - line: line number
58+
* - ptr: pointer to be checked for alignment
59+
* - alignment: alignment to check for (e.g. 8, 16)
60+
**************************************************/
61+
#define mlk_debug_check_alignment MLK_NAMESPACE(mlkem_debug_check_alignment)
62+
void mlk_debug_check_alignment(const char *file, int line, const void *ptr,
63+
size_t ptr_len, unsigned alignment);
64+
65+
66+
/* Check that pointer and length is aligned to given alignment. */
67+
#define mlk_assert_alignment(ptr, len, alignment) \
68+
do \
69+
{ \
70+
mlk_debug_check_alignment(__FILE__, __LINE__, (ptr), (len), (alignment)); \
71+
} while (0)
72+
4873
/* Check assertion, calling exit() upon failure
4974
*
5075
* val: Value that's asserted to be non-zero
@@ -79,6 +104,11 @@ void mlk_debug_check_bounds(const char *file, int line, const int16_t *ptr,
79104
#elif defined(CBMC)
80105
#include "cbmc.h"
81106

107+
/* CBMC's memory model does not support talking about pointer alignment,
108+
* so we only check the alignment of the buffer length. */
109+
#define mlk_assert_alignment(ptr, len, alignment) \
110+
mlk_assert((len) % (alignment) == 0)
111+
82112
#define mlk_assert(val) cassert(val)
83113

84114
#define mlk_assert_bound(ptr, len, value_lb, value_ub) \
@@ -101,6 +131,11 @@ void mlk_debug_check_bounds(const char *file, int line, const int16_t *ptr,
101131

102132
#else /* !MLKEM_DEBUG && CBMC */
103133

134+
#define mlk_assert_alignment(ptr, len, alignment) \
135+
do \
136+
{ \
137+
} while (0)
138+
104139
#define mlk_assert(val) \
105140
do \
106141
{ \

mlkem/src/fips202/fips202.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
#include <stdint.h>
3838

39+
#include "../debug.h"
3940
#include "../verify.h"
4041
#include "fips202.h"
4142
#include "keccakf1600.h"
@@ -190,12 +191,14 @@ __contract__(
190191
void mlk_shake128_absorb_once(mlk_shake128ctx *state, const uint8_t *input,
191192
size_t inlen)
192193
{
194+
mlk_assert_alignment(input, inlen, 8);
193195
mlk_keccak_absorb_once(state->ctx, SHAKE128_RATE, input, inlen, 0x1F);
194196
}
195197

196198
void mlk_shake128_squeezeblocks(uint8_t *output, size_t nblocks,
197199
mlk_shake128ctx *state)
198200
{
201+
mlk_assert_alignment(output, nblocks * SHAKE128_RATE, 8);
199202
mlk_keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE128_RATE);
200203
}
201204

@@ -212,6 +215,9 @@ void mlk_shake256(uint8_t *output, size_t outlen, const uint8_t *input,
212215
size_t inlen)
213216
{
214217
mlk_shake256ctx state;
218+
mlk_assert_alignment(input, inlen, 8);
219+
mlk_assert_alignment(output, outlen, 8);
220+
215221
/* Absorb input */
216222
mlk_keccak_absorb_once(state.ctx, SHAKE256_RATE, input, inlen, 0x1F);
217223
/* Squeeze output */
@@ -224,6 +230,9 @@ void mlk_shake256(uint8_t *output, size_t outlen, const uint8_t *input,
224230
void mlk_sha3_256(uint8_t *output, const uint8_t *input, size_t inlen)
225231
{
226232
uint64_t ctx[25];
233+
mlk_assert_alignment(input, inlen, 8);
234+
mlk_assert_alignment(output, SHA3_256_RATE, 8);
235+
227236
/* Absorb input */
228237
mlk_keccak_absorb_once(ctx, SHA3_256_RATE, input, inlen, 0x06);
229238
/* Squeeze output */
@@ -236,6 +245,9 @@ void mlk_sha3_256(uint8_t *output, const uint8_t *input, size_t inlen)
236245
void mlk_sha3_512(uint8_t *output, const uint8_t *input, size_t inlen)
237246
{
238247
uint64_t ctx[25];
248+
mlk_assert_alignment(input, inlen, 8);
249+
mlk_assert_alignment(output, SHA3_512_RATE, 8);
250+
239251
/* Absorb input */
240252
mlk_keccak_absorb_once(ctx, SHA3_512_RATE, input, inlen, 0x06);
241253
/* Squeeze output */

mlkem/src/fips202/fips202.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,20 @@ typedef struct
4242
* Arguments: - mlk_shake128ctx *state: pointer to SHAKE128 context
4343
* - const uint8_t *input: pointer to input to be absorbed into
4444
* the state
45+
* Can be assumed to be 8-byte aligned.
4546
* - size_t inlen: length of input in bytes
47+
* Can be assumed to be 8-byte aligned.
4648
**************************************************/
4749
void mlk_shake128_absorb_once(mlk_shake128ctx *state, const uint8_t *input,
4850
size_t inlen)
4951
__contract__(
5052
requires(inlen <= MLK_MAX_BUFFER_SIZE)
53+
/* The alignment constraints are not needed for the implementation, but
54+
* serve as additional preconditions for users wishing to use an
55+
* alternative FIPS202 implementation. */
56+
requires(inlen % 8 == 0)
5157
requires(memory_no_alias(state, sizeof(mlk_shake128ctx)))
58+
/* We can't express alignment of input as a CBMC precondition. */
5259
requires(memory_no_alias(input, inlen))
5360
assigns(memory_slice(state, sizeof(mlk_shake128ctx)))
5461
);
@@ -62,6 +69,7 @@ __contract__(
6269
* multiple times to keep squeezing, i.e., is incremental.
6370
*
6471
* Arguments: - uint8_t *output: pointer to output blocks
72+
* Can be assumed to be 8-byte aligned.
6573
* - size_t nblocks: number of blocks to be squeezed (written
6674
* to output)
6775
* - mlk_shake128ctx *state: pointer to in/output Keccak state
@@ -71,6 +79,7 @@ void mlk_shake128_squeezeblocks(uint8_t *output, size_t nblocks,
7179
__contract__(
7280
requires(nblocks <= 8 /* somewhat arbitrary bound */)
7381
requires(memory_no_alias(state, sizeof(mlk_shake128ctx)))
82+
/* We can't express alignment of output as a CBMC precondition. */
7483
requires(memory_no_alias(output, nblocks * SHAKE128_RATE))
7584
assigns(memory_slice(output, nblocks * SHAKE128_RATE), memory_slice(state, sizeof(mlk_shake128ctx)))
7685
);
@@ -90,15 +99,25 @@ void mlk_shake128_release(mlk_shake128ctx *state);
9099
* Description: SHAKE256 XOF with non-incremental API
91100
*
92101
* Arguments: - uint8_t *output: pointer to output
102+
* Can be assumed to be 8-byte aligned.
93103
* - size_t outlen: requested output length in bytes
104+
* Can be assumed to be 8-byte aligned.
94105
* - const uint8_t *input: pointer to input
106+
* Can be assumed to be 8-byte aligned.
95107
* - size_t inlen: length of input in bytes
108+
* Can be assumed to be 8-byte aligned.
96109
**************************************************/
97110
void mlk_shake256(uint8_t *output, size_t outlen, const uint8_t *input,
98111
size_t inlen)
99112
__contract__(
100113
requires(inlen <= MLK_MAX_BUFFER_SIZE)
101114
requires(outlen <= MLK_MAX_BUFFER_SIZE)
115+
/* The alignment constraints are not needed for the implementation, but
116+
* serve as additional preconditions for users wishing to use an
117+
* alternative FIPS202 implementation. */
118+
requires(inlen % 8 == 0)
119+
requires(outlen % 8 == 0)
120+
/* We can't express alignment of input and output as a CBMC precondition. */
102121
requires(memory_no_alias(input, inlen))
103122
requires(memory_no_alias(output, outlen))
104123
assigns(memory_slice(output, outlen))
@@ -114,12 +133,20 @@ __contract__(
114133
* Description: SHA3-256 with non-incremental API
115134
*
116135
* Arguments: - uint8_t *output: pointer to output
136+
* Can be assumed to be 8-byte aligned.
117137
* - const uint8_t *input: pointer to input
138+
* Can be assumed to be 8-byte aligned.
118139
* - size_t inlen: length of input in bytes
140+
* Can be assumed to be 8-byte aligned.
119141
**************************************************/
120142
void mlk_sha3_256(uint8_t *output, const uint8_t *input, size_t inlen)
121143
__contract__(
122144
requires(inlen <= MLK_MAX_BUFFER_SIZE)
145+
/* This is not needed for the implementation, but serves
146+
* as an additional precondition for users wishing to use
147+
* an alternative FIPS202 implementation. */
148+
requires(inlen % 8 == 0)
149+
/* We can't express alignment of input and output as a CBMC precondition. */
123150
requires(memory_no_alias(input, inlen))
124151
requires(memory_no_alias(output, SHA3_256_HASHBYTES))
125152
assigns(memory_slice(output, SHA3_256_HASHBYTES))
@@ -136,11 +163,18 @@ __contract__(
136163
*
137164
* Arguments: - uint8_t *output: pointer to output
138165
* - const uint8_t *input: pointer to input
139-
* - size_t inlen: length of input in bytes
166+
* Can be assumed to be 8-byte aligned.
167+
* - size_t inlen: length of input in bytes.
168+
* Can be assumed to be 8-byte aligned.
140169
**************************************************/
141170
void mlk_sha3_512(uint8_t *output, const uint8_t *input, size_t inlen)
142171
__contract__(
143172
requires(inlen <= MLK_MAX_BUFFER_SIZE)
173+
/* This is not needed for the implementation, but serves
174+
* as an additional precondition for users wishing to use
175+
* an alternative FIPS202 implementation. */
176+
requires(inlen % 8 == 0)
177+
/* We can't express alignment of input and output as a CBMC precondition. */
144178
requires(memory_no_alias(input, inlen))
145179
requires(memory_no_alias(output, SHA3_512_HASHBYTES))
146180
assigns(memory_slice(output, SHA3_512_HASHBYTES))

mlkem/src/fips202/fips202x4.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
#include "../common.h"
1616
#if !defined(MLK_CONFIG_MULTILEVEL_NO_SHARED)
1717

18+
#include "../debug.h"
1819
#include "../verify.h"
20+
1921
#include "fips202.h"
2022
#include "fips202x4.h"
2123
#include "keccakf1600.h"
@@ -122,6 +124,11 @@ void mlk_shake128x4_absorb_once(mlk_shake128x4ctx *state, const uint8_t *in0,
122124
const uint8_t *in1, const uint8_t *in2,
123125
const uint8_t *in3, size_t inlen)
124126
{
127+
mlk_assert_alignment(in0, inlen, 8);
128+
mlk_assert_alignment(in1, inlen, 8);
129+
mlk_assert_alignment(in2, inlen, 8);
130+
mlk_assert_alignment(in3, inlen, 8);
131+
125132
mlk_memset(state, 0, sizeof(mlk_shake128x4ctx));
126133
mlk_keccak_absorb_once_x4(state->ctx, SHAKE128_RATE, in0, in1, in2, in3,
127134
inlen, 0x1F);
@@ -131,6 +138,11 @@ void mlk_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2,
131138
uint8_t *out3, size_t nblocks,
132139
mlk_shake128x4ctx *state)
133140
{
141+
mlk_assert_alignment(out0, nblocks * SHAKE128_RATE, 8);
142+
mlk_assert_alignment(out1, nblocks * SHAKE128_RATE, 8);
143+
mlk_assert_alignment(out2, nblocks * SHAKE128_RATE, 8);
144+
mlk_assert_alignment(out3, nblocks * SHAKE128_RATE, 8);
145+
134146
mlk_keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state->ctx,
135147
SHAKE128_RATE);
136148
}
@@ -168,10 +180,19 @@ void mlk_shake256x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3,
168180
{
169181
mlk_shake256x4_ctx statex;
170182
size_t nblocks = outlen / SHAKE256_RATE;
171-
uint8_t tmp0[SHAKE256_RATE];
172-
uint8_t tmp1[SHAKE256_RATE];
173-
uint8_t tmp2[SHAKE256_RATE];
174-
uint8_t tmp3[SHAKE256_RATE];
183+
uint8_t MLK_ALIGN tmp0[SHAKE256_RATE];
184+
uint8_t MLK_ALIGN tmp1[SHAKE256_RATE];
185+
uint8_t MLK_ALIGN tmp2[SHAKE256_RATE];
186+
uint8_t MLK_ALIGN tmp3[SHAKE256_RATE];
187+
188+
mlk_assert_alignment(in0, inlen, 8);
189+
mlk_assert_alignment(in1, inlen, 8);
190+
mlk_assert_alignment(in2, inlen, 8);
191+
mlk_assert_alignment(in3, inlen, 8);
192+
mlk_assert_alignment(out0, outlen, 8);
193+
mlk_assert_alignment(out1, outlen, 8);
194+
mlk_assert_alignment(out2, outlen, 8);
195+
mlk_assert_alignment(out3, outlen, 8);
175196

176197
mlk_shake256x4_absorb_once(&statex, in0, in1, in2, in3, inlen);
177198
mlk_shake256x4_squeezeblocks(out0, out1, out2, out3, nblocks, &statex);

0 commit comments

Comments
 (0)