Skip to content

Commit de85d4a

Browse files
committed
C-Only fix for unaligned inputs to keccak x4 xor
Signed-off-by: Brendan Moran <brendan.moran@arm.com>
1 parent 10109b0 commit de85d4a

2 files changed

Lines changed: 350 additions & 14 deletions

File tree

  • dev/fips202/armv81m
  • mlkem/src/fips202/native/armv81m

dev/fips202/armv81m/mve.h

Lines changed: 175 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#if !defined(__ASSEMBLER__)
1919
#include "../api.h"
2020

21+
#define MLK_KECCAKF1600_X4_BITINTERLEAVED_ODD_WORDS 50u
22+
2123
/*
2224
* Native x4 permutation
2325
* State is kept in bit-interleaved format.
@@ -32,6 +34,142 @@ static MLK_INLINE int mlk_keccak_f1600_x4_native(uint64_t *state)
3234
return mlk_keccak_f1600_x4_native_impl(state);
3335
}
3436

37+
/*
38+
* Slow path for buffers that the MVE word gather/scatter main loops cannot
39+
* access directly. Returning MLK_NATIVE_FUNC_FALLBACK is not safe here because
40+
* the Armv8.1-M x4 state is bit-interleaved, while the generic C x4 fallback
41+
* uses four contiguous scalar Keccak states.
42+
*/
43+
static MLK_INLINE uint32_t mlk_keccakf1600x4_bitinterleave_even_u8(uint8_t x)
44+
{
45+
uint32_t r;
46+
47+
r = x & 0x01u;
48+
r |= (x & 0x04u) >> 1;
49+
r |= (x & 0x10u) >> 2;
50+
r |= (x & 0x40u) >> 3;
51+
return r;
52+
}
53+
54+
static MLK_INLINE uint32_t mlk_keccakf1600x4_bitinterleave_odd_u8(uint8_t x)
55+
{
56+
uint32_t r;
57+
58+
r = (x & 0x02u) >> 1;
59+
r |= (x & 0x08u) >> 2;
60+
r |= (x & 0x20u) >> 3;
61+
r |= (x & 0x80u) >> 4;
62+
return r;
63+
}
64+
65+
static MLK_INLINE uint8_t mlk_keccakf1600x4_bitdeinterleave_u8(uint32_t even,
66+
uint32_t odd)
67+
{
68+
uint8_t r;
69+
70+
r = (uint8_t)(even & 0x01u);
71+
r = (uint8_t)(r | ((odd & 0x01u) << 1));
72+
r = (uint8_t)(r | ((even & 0x02u) << 1));
73+
r = (uint8_t)(r | ((odd & 0x02u) << 2));
74+
r = (uint8_t)(r | ((even & 0x04u) << 2));
75+
r = (uint8_t)(r | ((odd & 0x04u) << 3));
76+
r = (uint8_t)(r | ((even & 0x08u) << 3));
77+
r = (uint8_t)(r | ((odd & 0x08u) << 4));
78+
return r;
79+
}
80+
81+
static MLK_INLINE void mlk_keccakf1600x4_xor_bitinterleaved_byte(
82+
uint64_t *state, uint8_t data, unsigned byte_offset, unsigned instance)
83+
{
84+
unsigned lane;
85+
unsigned byte_in_lane;
86+
unsigned state_index;
87+
unsigned shift;
88+
uint64_t even;
89+
uint64_t odd;
90+
91+
lane = byte_offset >> 3;
92+
byte_in_lane = byte_offset & 7u;
93+
state_index = (2u * lane) + (instance >> 1);
94+
shift = 32u * (instance & 1u);
95+
96+
even = (uint64_t)mlk_keccakf1600x4_bitinterleave_even_u8(data)
97+
<< (4u * byte_in_lane);
98+
odd = (uint64_t)mlk_keccakf1600x4_bitinterleave_odd_u8(data)
99+
<< (4u * byte_in_lane);
100+
101+
state[state_index] ^= even << shift;
102+
state[MLK_KECCAKF1600_X4_BITINTERLEAVED_ODD_WORDS + state_index] ^= odd
103+
<< shift;
104+
}
105+
106+
static MLK_INLINE uint8_t mlk_keccakf1600x4_extract_bitinterleaved_byte(
107+
uint64_t *state, unsigned byte_offset, unsigned instance)
108+
{
109+
unsigned lane;
110+
unsigned byte_in_lane;
111+
unsigned state_index;
112+
unsigned shift;
113+
uint32_t even;
114+
uint32_t odd;
115+
116+
lane = byte_offset >> 3;
117+
byte_in_lane = byte_offset & 7u;
118+
state_index = (2u * lane) + (instance >> 1);
119+
shift = 32u * (instance & 1u);
120+
121+
even =
122+
(uint32_t)((state[state_index] >> shift) >> (4u * byte_in_lane)) & 0x0Fu;
123+
odd = (uint32_t)((state[MLK_KECCAKF1600_X4_BITINTERLEAVED_ODD_WORDS +
124+
state_index] >>
125+
shift) >>
126+
(4u * byte_in_lane)) &
127+
0x0Fu;
128+
129+
return mlk_keccakf1600x4_bitdeinterleave_u8(even, odd);
130+
}
131+
132+
static MLK_INLINE void mlk_keccakf1600_xor_bytes_x4_bitinterleaved_c(
133+
uint64_t *state, const uint8_t *data0, const uint8_t *data1,
134+
const uint8_t *data2, const uint8_t *data3, unsigned offset,
135+
unsigned length)
136+
{
137+
unsigned i;
138+
139+
for (i = 0; i < length; i++)
140+
{
141+
unsigned byte_offset;
142+
143+
byte_offset = offset + i;
144+
mlk_keccakf1600x4_xor_bitinterleaved_byte(state, data0[i], byte_offset, 0);
145+
mlk_keccakf1600x4_xor_bitinterleaved_byte(state, data1[i], byte_offset, 1);
146+
mlk_keccakf1600x4_xor_bitinterleaved_byte(state, data2[i], byte_offset, 2);
147+
mlk_keccakf1600x4_xor_bitinterleaved_byte(state, data3[i], byte_offset, 3);
148+
}
149+
}
150+
151+
static MLK_INLINE void mlk_keccakf1600_extract_bytes_x4_bitinterleaved_c(
152+
uint64_t *state, uint8_t *data0, uint8_t *data1, uint8_t *data2,
153+
uint8_t *data3, unsigned offset, unsigned length)
154+
{
155+
unsigned i;
156+
157+
for (i = 0; i < length; i++)
158+
{
159+
unsigned byte_offset;
160+
161+
byte_offset = offset + i;
162+
data0[i] =
163+
mlk_keccakf1600x4_extract_bitinterleaved_byte(state, byte_offset, 0);
164+
data1[i] =
165+
mlk_keccakf1600x4_extract_bitinterleaved_byte(state, byte_offset, 1);
166+
data2[i] =
167+
mlk_keccakf1600x4_extract_bitinterleaved_byte(state, byte_offset, 2);
168+
data3[i] =
169+
mlk_keccakf1600x4_extract_bitinterleaved_byte(state, byte_offset, 3);
170+
}
171+
}
172+
35173
/*
36174
* Native x4 XOR bytes (with on-the-fly bit interleaving)
37175
*/
@@ -49,10 +187,12 @@ static MLK_INLINE int mlk_keccakf1600_xor_bytes_x4_native(
49187
const uint8_t *data2, const uint8_t *data3, unsigned offset,
50188
unsigned length)
51189
{
52-
unsigned offset_mod8 = offset & 7u;
53-
unsigned byte_prefix = 0;
190+
unsigned offset_mod8;
191+
unsigned byte_prefix;
54192
unsigned main_length;
55193

194+
offset_mod8 = offset & 7u;
195+
byte_prefix = 0;
56196
if (offset_mod8 != 0u)
57197
{
58198
byte_prefix = 8u - offset_mod8;
@@ -64,13 +204,13 @@ static MLK_INLINE int mlk_keccakf1600_xor_bytes_x4_native(
64204

65205
main_length = length - byte_prefix;
66206
if (main_length >= 8u &&
67-
((((uintptr_t)data0 + byte_prefix) |
68-
((uintptr_t)data1 + byte_prefix) |
69-
((uintptr_t)data2 + byte_prefix) |
70-
((uintptr_t)data3 + byte_prefix)) &
207+
((((uintptr_t)data0 + byte_prefix) | ((uintptr_t)data1 + byte_prefix) |
208+
((uintptr_t)data2 + byte_prefix) | ((uintptr_t)data3 + byte_prefix)) &
71209
3u) != 0u)
72210
{
73-
return MLK_NATIVE_FUNC_FALLBACK;
211+
mlk_keccakf1600_xor_bytes_x4_bitinterleaved_c(state, data0, data1, data2,
212+
data3, offset, length);
213+
return MLK_NATIVE_FUNC_SUCCESS;
74214
}
75215

76216
mlk_keccak_f1600_x4_state_xor_bytes(state, data0, data1, data2, data3, offset,
@@ -93,11 +233,39 @@ static MLK_INLINE int mlk_keccakf1600_extract_bytes_x4_native(
93233
uint64_t *state, uint8_t *data0, uint8_t *data1, uint8_t *data2,
94234
uint8_t *data3, unsigned offset, unsigned length)
95235
{
236+
unsigned offset_mod8;
237+
unsigned byte_prefix;
238+
unsigned main_length;
239+
240+
offset_mod8 = offset & 7u;
241+
byte_prefix = 0;
242+
if (offset_mod8 != 0u)
243+
{
244+
byte_prefix = 8u - offset_mod8;
245+
if (byte_prefix > length)
246+
{
247+
byte_prefix = length;
248+
}
249+
}
250+
251+
main_length = length - byte_prefix;
252+
if (main_length >= 8u &&
253+
((((uintptr_t)data0 + byte_prefix) | ((uintptr_t)data1 + byte_prefix) |
254+
((uintptr_t)data2 + byte_prefix) | ((uintptr_t)data3 + byte_prefix)) &
255+
3u) != 0u)
256+
{
257+
mlk_keccakf1600_extract_bytes_x4_bitinterleaved_c(
258+
state, data0, data1, data2, data3, offset, length);
259+
return MLK_NATIVE_FUNC_SUCCESS;
260+
}
261+
96262
mlk_keccak_f1600_x4_state_extract_bytes(state, data0, data1, data2, data3,
97263
offset, length);
98264
return MLK_NATIVE_FUNC_SUCCESS;
99265
}
100266

101267
#endif /* !__ASSEMBLER__ */
102268

269+
#undef MLK_KECCAKF1600_X4_BITINTERLEAVED_ODD_WORDS
270+
103271
#endif /* !MLK_DEV_FIPS202_ARMV81M_MVE_H */

0 commit comments

Comments
 (0)