]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bearssl/src/symcipher/aes_pwr8.c
MFV r349535: less v551.
[FreeBSD/FreeBSD.git] / contrib / bearssl / src / symcipher / aes_pwr8.c
1 /*
2  * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining 
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be 
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24
25 #define BR_POWER_ASM_MACROS   1
26 #include "inner.h"
27
28 /*
29  * This code contains the AES key schedule implementation using the
30  * POWER8 opcodes.
31  */
32
33 #if BR_POWER8
34
35 static void
36 key_schedule_128(unsigned char *sk, const unsigned char *key)
37 {
38         long cc;
39
40         static const uint32_t fmod[] = { 0x11B, 0x11B, 0x11B, 0x11B };
41 #if BR_POWER8_LE
42         static const uint32_t idx2be[] = {
43                 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
44         };
45 #endif
46
47         cc = 0;
48
49         /*
50          * We use the VSX instructions for loading and storing the
51          * key/subkeys, since they support unaligned accesses. The rest
52          * of the computation is VMX only. VMX register 0 is VSX
53          * register 32.
54          */
55         asm volatile (
56
57                 /*
58                  * v0 = all-zero word
59                  * v1 = constant -8 / +8, copied into four words
60                  * v2 = current subkey
61                  * v3 = Rcon (x4 words)
62                  * v6 = constant 8, copied into four words
63                  * v7 = constant 0x11B, copied into four words
64                  * v8 = constant for byteswapping words
65                  */
66                 vspltisw(0, 0)
67 #if BR_POWER8_LE
68                 vspltisw(1, -8)
69 #else
70                 vspltisw(1, 8)
71 #endif
72                 lxvw4x(34, 0, %[key])
73                 vspltisw(3, 1)
74                 vspltisw(6, 8)
75                 lxvw4x(39, 0, %[fmod])
76 #if BR_POWER8_LE
77                 lxvw4x(40, 0, %[idx2be])
78 #endif
79
80                 /*
81                  * First subkey is a copy of the key itself.
82                  */
83 #if BR_POWER8_LE
84                 vperm(4, 2, 2, 8)
85                 stxvw4x(36, 0, %[sk])
86 #else
87                 stxvw4x(34, 0, %[sk])
88 #endif
89
90                 /*
91                  * Loop must run 10 times.
92                  */
93                 li(%[cc], 10)
94                 mtctr(%[cc])
95         label(loop)
96                 /* Increment subkey address */
97                 addi(%[sk], %[sk], 16)
98
99                 /* Compute SubWord(RotWord(temp)) xor Rcon  (into v4, splat) */
100                 vrlw(4, 2, 1)
101                 vsbox(4, 4)
102 #if BR_POWER8_LE
103                 vxor(4, 4, 3)
104 #else
105                 vsldoi(5, 3, 0, 3)
106                 vxor(4, 4, 5)
107 #endif
108                 vspltw(4, 4, 3)
109
110                 /* XOR words for next subkey */
111                 vsldoi(5, 0, 2, 12)
112                 vxor(2, 2, 5)
113                 vsldoi(5, 0, 2, 12)
114                 vxor(2, 2, 5)
115                 vsldoi(5, 0, 2, 12)
116                 vxor(2, 2, 5)
117                 vxor(2, 2, 4)
118
119                 /* Store next subkey */
120 #if BR_POWER8_LE
121                 vperm(4, 2, 2, 8)
122                 stxvw4x(36, 0, %[sk])
123 #else
124                 stxvw4x(34, 0, %[sk])
125 #endif
126
127                 /* Update Rcon */
128                 vadduwm(3, 3, 3)
129                 vsrw(4, 3, 6)
130                 vsubuwm(4, 0, 4)
131                 vand(4, 4, 7)
132                 vxor(3, 3, 4)
133
134                 bdnz(loop)
135
136 : [sk] "+b" (sk), [cc] "+b" (cc)
137 : [key] "b" (key), [fmod] "b" (fmod)
138 #if BR_POWER8_LE
139         , [idx2be] "b" (idx2be)
140 #endif
141 : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "ctr", "memory"
142         );
143 }
144
145 static void
146 key_schedule_192(unsigned char *sk, const unsigned char *key)
147 {
148         long cc;
149
150 #if BR_POWER8_LE
151         static const uint32_t idx2be[] = {
152                 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
153         };
154 #endif
155
156         cc = 0;
157
158         /*
159          * We use the VSX instructions for loading and storing the
160          * key/subkeys, since they support unaligned accesses. The rest
161          * of the computation is VMX only. VMX register 0 is VSX
162          * register 32.
163          */
164         asm volatile (
165
166                 /*
167                  * v0 = all-zero word
168                  * v1 = constant -8 / +8, copied into four words
169                  * v2, v3 = current subkey
170                  * v5 = Rcon (x4 words) (already shifted on big-endian)
171                  * v6 = constant 8, copied into four words
172                  * v8 = constant for byteswapping words
173                  *
174                  * The left two words of v3 are ignored.
175                  */
176                 vspltisw(0, 0)
177 #if BR_POWER8_LE
178                 vspltisw(1, -8)
179 #else
180                 vspltisw(1, 8)
181 #endif
182                 li(%[cc], 8)
183                 lxvw4x(34, 0, %[key])
184                 lxvw4x(35, %[cc], %[key])
185                 vsldoi(3, 3, 0, 8)
186                 vspltisw(5, 1)
187 #if !BR_POWER8_LE
188                 vsldoi(5, 5, 0, 3)
189 #endif
190                 vspltisw(6, 8)
191 #if BR_POWER8_LE
192                 lxvw4x(40, 0, %[idx2be])
193 #endif
194
195                 /*
196                  * Loop must run 8 times. Each iteration produces 256
197                  * bits of subkeys, with a 64-bit overlap.
198                  */
199                 li(%[cc], 8)
200                 mtctr(%[cc])
201                 li(%[cc], 16)
202         label(loop)
203
204                 /*
205                  * Last 6 words in v2:v3l. Compute next 6 words into
206                  * v3r:v4.
207                  */
208                 vrlw(10, 3, 1)
209                 vsbox(10, 10)
210                 vxor(10, 10, 5)
211                 vspltw(10, 10, 1)
212                 vsldoi(11, 0, 10, 8)
213
214                 vsldoi(12, 0, 2, 12)
215                 vxor(12, 2, 12)
216                 vsldoi(13, 0, 12, 12)
217                 vxor(12, 12, 13)
218                 vsldoi(13, 0, 12, 12)
219                 vxor(12, 12, 13)
220
221                 vspltw(13, 12, 3)
222                 vxor(13, 13, 3)
223                 vsldoi(14, 0, 3, 12)
224                 vxor(13, 13, 14)
225
226                 vsldoi(4, 12, 13, 8)
227                 vsldoi(14, 0, 3, 8)
228                 vsldoi(3, 14, 12, 8)
229
230                 vxor(3, 3, 11)
231                 vxor(4, 4, 10)
232
233                 /*
234                  * Update Rcon. Since for a 192-bit key, we use only 8
235                  * such constants, we will not hit the field modulus,
236                  * so a simple shift (addition) works well.
237                  */
238                 vadduwm(5, 5, 5)
239
240                 /*
241                  * Write out the two left 128-bit words
242                  */
243 #if BR_POWER8_LE
244                 vperm(10, 2, 2, 8)
245                 vperm(11, 3, 3, 8)
246                 stxvw4x(42, 0, %[sk])
247                 stxvw4x(43, %[cc], %[sk])
248 #else
249                 stxvw4x(34, 0, %[sk])
250                 stxvw4x(35, %[cc], %[sk])
251 #endif
252                 addi(%[sk], %[sk], 24)
253
254                 /*
255                  * Shift words for next iteration.
256                  */
257                 vsldoi(2, 3, 4, 8)
258                 vsldoi(3, 4, 0, 8)
259
260                 bdnz(loop)
261
262                 /*
263                  * The loop wrote the first 50 subkey words, but we need
264                  * to produce 52, so we must do one last write.
265                  */
266 #if BR_POWER8_LE
267                 vperm(10, 2, 2, 8)
268                 stxvw4x(42, 0, %[sk])
269 #else
270                 stxvw4x(34, 0, %[sk])
271 #endif
272
273 : [sk] "+b" (sk), [cc] "+b" (cc)
274 : [key] "b" (key)
275 #if BR_POWER8_LE
276         , [idx2be] "b" (idx2be)
277 #endif
278 : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
279   "v8", "v9", "v10", "v11", "v12", "v13", "v14", "ctr", "memory"
280         );
281 }
282
283 static void
284 key_schedule_256(unsigned char *sk, const unsigned char *key)
285 {
286         long cc;
287
288 #if BR_POWER8_LE
289         static const uint32_t idx2be[] = {
290                 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
291         };
292 #endif
293
294         cc = 0;
295
296         /*
297          * We use the VSX instructions for loading and storing the
298          * key/subkeys, since they support unaligned accesses. The rest
299          * of the computation is VMX only. VMX register 0 is VSX
300          * register 32.
301          */
302         asm volatile (
303
304                 /*
305                  * v0 = all-zero word
306                  * v1 = constant -8 / +8, copied into four words
307                  * v2, v3 = current subkey
308                  * v6 = Rcon (x4 words) (already shifted on big-endian)
309                  * v7 = constant 8, copied into four words
310                  * v8 = constant for byteswapping words
311                  *
312                  * The left two words of v3 are ignored.
313                  */
314                 vspltisw(0, 0)
315 #if BR_POWER8_LE
316                 vspltisw(1, -8)
317 #else
318                 vspltisw(1, 8)
319 #endif
320                 li(%[cc], 16)
321                 lxvw4x(34, 0, %[key])
322                 lxvw4x(35, %[cc], %[key])
323                 vspltisw(6, 1)
324 #if !BR_POWER8_LE
325                 vsldoi(6, 6, 0, 3)
326 #endif
327                 vspltisw(7, 8)
328 #if BR_POWER8_LE
329                 lxvw4x(40, 0, %[idx2be])
330 #endif
331
332                 /*
333                  * Loop must run 7 times. Each iteration produces two
334                  * subkeys.
335                  */
336                 li(%[cc], 7)
337                 mtctr(%[cc])
338                 li(%[cc], 16)
339         label(loop)
340
341                 /*
342                  * Current words are in v2:v3. Compute next word in v4.
343                  */
344                 vrlw(10, 3, 1)
345                 vsbox(10, 10)
346                 vxor(10, 10, 6)
347                 vspltw(10, 10, 3)
348
349                 vsldoi(4, 0, 2, 12)
350                 vxor(4, 2, 4)
351                 vsldoi(5, 0, 4, 12)
352                 vxor(4, 4, 5)
353                 vsldoi(5, 0, 4, 12)
354                 vxor(4, 4, 5)
355                 vxor(4, 4, 10)
356
357                 /*
358                  * Then other word in v5.
359                  */
360                 vsbox(10, 4)
361                 vspltw(10, 10, 3)
362
363                 vsldoi(5, 0, 3, 12)
364                 vxor(5, 3, 5)
365                 vsldoi(11, 0, 5, 12)
366                 vxor(5, 5, 11)
367                 vsldoi(11, 0, 5, 12)
368                 vxor(5, 5, 11)
369                 vxor(5, 5, 10)
370
371                 /*
372                  * Update Rcon. Since for a 256-bit key, we use only 7
373                  * such constants, we will not hit the field modulus,
374                  * so a simple shift (addition) works well.
375                  */
376                 vadduwm(6, 6, 6)
377
378                 /*
379                  * Write out the two left 128-bit words
380                  */
381 #if BR_POWER8_LE
382                 vperm(10, 2, 2, 8)
383                 vperm(11, 3, 3, 8)
384                 stxvw4x(42, 0, %[sk])
385                 stxvw4x(43, %[cc], %[sk])
386 #else
387                 stxvw4x(34, 0, %[sk])
388                 stxvw4x(35, %[cc], %[sk])
389 #endif
390                 addi(%[sk], %[sk], 32)
391
392                 /*
393                  * Replace v2:v3 with v4:v5.
394                  */
395                 vxor(2, 0, 4)
396                 vxor(3, 0, 5)
397
398                 bdnz(loop)
399
400                 /*
401                  * The loop wrote the first 14 subkeys, but we need 15,
402                  * so we must do an extra write.
403                  */
404 #if BR_POWER8_LE
405                 vperm(10, 2, 2, 8)
406                 stxvw4x(42, 0, %[sk])
407 #else
408                 stxvw4x(34, 0, %[sk])
409 #endif
410
411 : [sk] "+b" (sk), [cc] "+b" (cc)
412 : [key] "b" (key)
413 #if BR_POWER8_LE
414         , [idx2be] "b" (idx2be)
415 #endif
416 : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
417   "v8", "v9", "v10", "v11", "v12", "v13", "v14", "ctr", "memory"
418         );
419 }
420
421 /* see inner.h */
422 int
423 br_aes_pwr8_supported(void)
424 {
425         return 1;
426 }
427
428 /* see inner.h */
429 unsigned
430 br_aes_pwr8_keysched(unsigned char *sk, const void *key, size_t len)
431 {
432         switch (len) {
433         case 16:
434                 key_schedule_128(sk, key);
435                 return 10;
436         case 24:
437                 key_schedule_192(sk, key);
438                 return 12;
439         default:
440                 key_schedule_256(sk, key);
441                 return 14;
442         }
443 }
444
445 #endif