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