bf68f2031f9cf44e87fe9b4760c219b7f941453e
[libgcrypt.git] / cipher / rijndael-armv8-aarch32-ce.S
1 /* rijndael-armv8-aarch32-ce.S - ARMv8/CE accelerated AES
2  * Copyright (C) 2016 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) && \
23     defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) && \
24     defined(HAVE_GCC_INLINE_ASM_AARCH32_CRYPTO)
25
26 .syntax unified
27 .fpu crypto-neon-fp-armv8
28 .arm
29
30 .text
31
32 #ifdef __PIC__
33 #  define GET_DATA_POINTER(reg, name, rtmp) \
34                 ldr reg, 1f; \
35                 ldr rtmp, 2f; \
36                 b 3f; \
37         1:      .word _GLOBAL_OFFSET_TABLE_-(3f+8); \
38         2:      .word name(GOT); \
39         3:      add reg, pc, reg; \
40                 ldr reg, [reg, rtmp];
41 #else
42 #  define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name
43 #endif
44
45
46 /* AES macros */
47
48 #define aes_preload_keys(keysched, rekeysched) \
49         vldmia   keysched!, {q5-q7}; \
50         mov      rekeysched, keysched; \
51         vldmialo keysched!, {q8-q15}; /* 128-bit */ \
52         addeq    keysched, #(2*16); \
53         vldmiaeq keysched!, {q10-q15}; /* 192-bit */ \
54         addhi    keysched, #(4*16); \
55         vldmiahi keysched!, {q12-q15}; /* 256-bit */ \
56
57 #define do_aes_one128(ed, mcimc, qo, qb) \
58         aes##ed.8    qb, q5; \
59         aes##mcimc.8 qb, qb; \
60         aes##ed.8    qb, q6; \
61         aes##mcimc.8 qb, qb; \
62         aes##ed.8    qb, q7; \
63         aes##mcimc.8 qb, qb; \
64         aes##ed.8    qb, q8; \
65         aes##mcimc.8 qb, qb; \
66         aes##ed.8    qb, q9; \
67         aes##mcimc.8 qb, qb; \
68         aes##ed.8    qb, q10; \
69         aes##mcimc.8 qb, qb; \
70         aes##ed.8    qb, q11; \
71         aes##mcimc.8 qb, qb; \
72         aes##ed.8    qb, q12; \
73         aes##mcimc.8 qb, qb; \
74         aes##ed.8    qb, q13; \
75         aes##mcimc.8 qb, qb; \
76         aes##ed.8    qb, q14; \
77         veor         qo, qb, q15;
78
79 #define do_aes_one128re(ed, mcimc, qo, qb, keysched, rekeysched) \
80         vldm         rekeysched, {q8-q9}; \
81         do_aes_one128(ed, mcimc, qo, qb);
82
83 #define do_aes_one192(ed, mcimc, qo, qb, keysched, rekeysched) \
84         vldm         rekeysched!, {q8}; \
85         aes##ed.8    qb, q5; \
86         aes##mcimc.8 qb, qb; \
87         vldm         rekeysched, {q9}; \
88         aes##ed.8    qb, q6; \
89         aes##mcimc.8 qb, qb; \
90         aes##ed.8    qb, q7; \
91         aes##mcimc.8 qb, qb; \
92         aes##ed.8    qb, q8; \
93         aes##mcimc.8 qb, qb; \
94         vldmia       keysched!, {q8}; \
95         aes##ed.8    qb, q9; \
96         aes##mcimc.8 qb, qb; \
97         sub          rekeysched, #(1*16); \
98         aes##ed.8    qb, q10; \
99         aes##mcimc.8 qb, qb; \
100         vldm         keysched, {q9}; \
101         aes##ed.8    qb, q11; \
102         aes##mcimc.8 qb, qb; \
103         aes##ed.8    qb, q12; \
104         aes##mcimc.8 qb, qb; \
105         sub          keysched, #16; \
106         aes##ed.8    qb, q13; \
107         aes##mcimc.8 qb, qb; \
108         aes##ed.8    qb, q14; \
109         aes##mcimc.8 qb, qb; \
110         aes##ed.8    qb, q15; \
111         aes##mcimc.8 qb, qb; \
112         aes##ed.8    qb, q8; \
113         veor         qo, qb, q9; \
114
115 #define do_aes_one256(ed, mcimc, qo, qb, keysched, rekeysched) \
116         vldmia       rekeysched!, {q8}; \
117         aes##ed.8    qb, q5; \
118         aes##mcimc.8 qb, qb; \
119         vldmia       rekeysched!, {q9}; \
120         aes##ed.8    qb, q6; \
121         aes##mcimc.8 qb, qb; \
122         vldmia       rekeysched!, {q10}; \
123         aes##ed.8    qb, q7; \
124         aes##mcimc.8 qb, qb; \
125         vldm         rekeysched, {q11}; \
126         aes##ed.8    qb, q8; \
127         aes##mcimc.8 qb, qb; \
128         vldmia       keysched!, {q8}; \
129         aes##ed.8    qb, q9; \
130         aes##mcimc.8 qb, qb; \
131         aes##ed.8    qb, q10; \
132         aes##mcimc.8 qb, qb; \
133         vldmia       keysched!, {q9}; \
134         aes##ed.8    qb, q11; \
135         aes##mcimc.8 qb, qb; \
136         sub          rekeysched, #(3*16); \
137         aes##ed.8    qb, q12; \
138         aes##mcimc.8 qb, qb; \
139         vldmia       keysched!, {q10}; \
140         aes##ed.8    qb, q13; \
141         aes##mcimc.8 qb, qb; \
142         aes##ed.8    qb, q14; \
143         aes##mcimc.8 qb, qb; \
144         vldm         keysched, {q11}; \
145         aes##ed.8    qb, q15; \
146         aes##mcimc.8 qb, qb; \
147         aes##ed.8    qb, q8; \
148         aes##mcimc.8 qb, qb; \
149         aes##ed.8    qb, q9; \
150         aes##mcimc.8 qb, qb; \
151         aes##ed.8    qb, q10; \
152         veor         qo, qb, q11; \
153         sub          keysched, #(3*16); \
154
155 #define aes_round_4(ed, mcimc, b0, b1, b2, b3, key) \
156         aes##ed.8    b0, key; \
157         aes##mcimc.8 b0, b0; \
158           aes##ed.8    b1, key; \
159           aes##mcimc.8 b1, b1; \
160             aes##ed.8    b2, key; \
161             aes##mcimc.8 b2, b2; \
162               aes##ed.8    b3, key; \
163               aes##mcimc.8 b3, b3;
164
165 #define do_aes_4_128(ed, mcimc, b0, b1, b2, b3) \
166         aes_round_4(ed, mcimc, b0, b1, b2, b3, q5); \
167         aes_round_4(ed, mcimc, b0, b1, b2, b3, q6); \
168         aes_round_4(ed, mcimc, b0, b1, b2, b3, q7); \
169         aes_round_4(ed, mcimc, b0, b1, b2, b3, q8); \
170         aes_round_4(ed, mcimc, b0, b1, b2, b3, q9); \
171         aes_round_4(ed, mcimc, b0, b1, b2, b3, q10); \
172         aes_round_4(ed, mcimc, b0, b1, b2, b3, q11); \
173         aes_round_4(ed, mcimc, b0, b1, b2, b3, q12); \
174         aes_round_4(ed, mcimc, b0, b1, b2, b3, q13); \
175         aes##ed.8    b0, q14; \
176         veor         b0, b0, q15; \
177         aes##ed.8    b1, q14; \
178         veor         b1, b1, q15; \
179         aes##ed.8    b2, q14; \
180         veor         b2, b2, q15; \
181         aes##ed.8    b3, q14; \
182         veor         b3, b3, q15;
183
184 #define do_aes_4_128re(ed, mcimc, b0, b1, b2, b3, keysched, rekeysched) \
185         vldm         rekeysched, {q8-q9}; \
186         do_aes_4_128(ed, mcimc, b0, b1, b2, b3);
187
188 #define do_aes_4_192(ed, mcimc, b0, b1, b2, b3, keysched, rekeysched) \
189         vldm         rekeysched!, {q8}; \
190         aes_round_4(ed, mcimc, b0, b1, b2, b3, q5); \
191         vldm         rekeysched, {q9}; \
192         aes_round_4(ed, mcimc, b0, b1, b2, b3, q6); \
193         aes_round_4(ed, mcimc, b0, b1, b2, b3, q7); \
194         aes_round_4(ed, mcimc, b0, b1, b2, b3, q8); \
195         vldmia       keysched!, {q8}; \
196         aes_round_4(ed, mcimc, b0, b1, b2, b3, q9); \
197         sub          rekeysched, #(1*16); \
198         aes_round_4(ed, mcimc, b0, b1, b2, b3, q10); \
199         vldm         keysched, {q9}; \
200         aes_round_4(ed, mcimc, b0, b1, b2, b3, q11); \
201         aes_round_4(ed, mcimc, b0, b1, b2, b3, q12); \
202         sub          keysched, #16; \
203         aes_round_4(ed, mcimc, b0, b1, b2, b3, q13); \
204         aes_round_4(ed, mcimc, b0, b1, b2, b3, q14); \
205         aes_round_4(ed, mcimc, b0, b1, b2, b3, q15); \
206         aes##ed.8    b0, q8; \
207         veor         b0, b0, q9; \
208         aes##ed.8    b1, q8; \
209         veor         b1, b1, q9; \
210         aes##ed.8    b2, q8; \
211         veor         b2, b2, q9; \
212         aes##ed.8    b3, q8; \
213         veor         b3, b3, q9;
214
215 #define do_aes_4_256(ed, mcimc, b0, b1, b2, b3, keysched, rekeysched) \
216         vldmia       rekeysched!, {q8}; \
217         aes_round_4(ed, mcimc, b0, b1, b2, b3, q5); \
218         vldmia       rekeysched!, {q9}; \
219         aes_round_4(ed, mcimc, b0, b1, b2, b3, q6); \
220         vldmia       rekeysched!, {q10}; \
221         aes_round_4(ed, mcimc, b0, b1, b2, b3, q7); \
222         vldm         rekeysched, {q11}; \
223         aes_round_4(ed, mcimc, b0, b1, b2, b3, q8); \
224         vldmia       keysched!, {q8}; \
225         aes_round_4(ed, mcimc, b0, b1, b2, b3, q9); \
226         aes_round_4(ed, mcimc, b0, b1, b2, b3, q10); \
227         vldmia       keysched!, {q9}; \
228         aes_round_4(ed, mcimc, b0, b1, b2, b3, q11); \
229         sub          rekeysched, #(3*16); \
230         aes_round_4(ed, mcimc, b0, b1, b2, b3, q12); \
231         vldmia       keysched!, {q10}; \
232         aes_round_4(ed, mcimc, b0, b1, b2, b3, q13); \
233         aes_round_4(ed, mcimc, b0, b1, b2, b3, q14); \
234         vldm         keysched, {q11}; \
235         aes_round_4(ed, mcimc, b0, b1, b2, b3, q15); \
236         aes_round_4(ed, mcimc, b0, b1, b2, b3, q8); \
237         aes_round_4(ed, mcimc, b0, b1, b2, b3, q9); \
238         sub          keysched, #(3*16); \
239         aes##ed.8    b0, q10; \
240         veor         b0, b0, q11; \
241         aes##ed.8    b1, q10; \
242         veor         b1, b1, q11; \
243         aes##ed.8    b2, q10; \
244         veor         b2, b2, q11; \
245         aes##ed.8    b3, q10; \
246         veor         b3, b3, q11;
247
248
249 /* Other functional macros */
250
251 #define CLEAR_REG(reg) veor reg, reg;
252
253
254 /*
255  * unsigned int _gcry_aes_enc_armv8_ce(void *keysched, byte *dst,
256  *                                     const byte *src,
257  *                                     unsigned int nrounds);
258  */
259 .align 3
260 .globl _gcry_aes_enc_armv8_ce
261 .type  _gcry_aes_enc_armv8_ce,%function;
262 _gcry_aes_enc_armv8_ce:
263   /* input:
264    *    r0: keysched
265    *    r1: dst
266    *    r2: src
267    *    r3: nrounds
268    */
269
270   vldmia r0!, {q1-q3} /* load 3 round keys */
271
272   cmp r3, #12
273
274   vld1.8 {q0}, [r2]
275
276   bhi .Lenc1_256
277   beq .Lenc1_192
278
279 .Lenc1_128:
280
281 .Lenc1_tail:
282   vldmia r0, {q8-q15} /* load 8 round keys */
283
284   aese.8  q0, q1
285   aesmc.8 q0, q0
286   CLEAR_REG(q1)
287
288   aese.8  q0, q2
289   aesmc.8 q0, q0
290   CLEAR_REG(q2)
291
292   aese.8  q0, q3
293   aesmc.8 q0, q0
294   CLEAR_REG(q3)
295
296   aese.8  q0, q8
297   aesmc.8 q0, q0
298   CLEAR_REG(q8)
299
300   aese.8  q0, q9
301   aesmc.8 q0, q0
302   CLEAR_REG(q9)
303
304   aese.8  q0, q10
305   aesmc.8 q0, q0
306   CLEAR_REG(q10)
307
308   aese.8  q0, q11
309   aesmc.8 q0, q0
310   CLEAR_REG(q11)
311
312   aese.8  q0, q12
313   aesmc.8 q0, q0
314   CLEAR_REG(q12)
315
316   aese.8  q0, q13
317   aesmc.8 q0, q0
318   CLEAR_REG(q13)
319
320   aese.8  q0, q14
321   veor    q0, q15
322   CLEAR_REG(q14)
323   CLEAR_REG(q15)
324
325   vst1.8 {q0}, [r1]
326   CLEAR_REG(q0)
327
328   mov r0, #0
329   bx lr
330
331 .Lenc1_192:
332   aese.8  q0, q1
333   aesmc.8 q0, q0
334   vmov q1, q3
335
336   aese.8  q0, q2
337   aesmc.8 q0, q0
338   vldm r0!, {q2-q3} /* load 3 round keys */
339
340   b .Lenc1_tail
341
342 .Lenc1_256:
343   vldm r0!, {q15}   /* load 1 round key */
344   aese.8  q0, q1
345   aesmc.8 q0, q0
346
347   aese.8  q0, q2
348   aesmc.8 q0, q0
349
350   aese.8  q0, q3
351   aesmc.8 q0, q0
352   vldm r0!, {q1-q3} /* load 3 round keys */
353
354   aese.8  q0, q15
355   aesmc.8 q0, q0
356
357   b .Lenc1_tail
358 .size _gcry_aes_enc_armv8_ce,.-_gcry_aes_enc_armv8_ce;
359
360
361 /*
362  * unsigned int _gcry_aes_dec_armv8_ce(void *keysched, byte *dst,
363  *                                     const byte *src,
364  *                                     unsigned int nrounds);
365  */
366 .align 3
367 .globl _gcry_aes_dec_armv8_ce
368 .type  _gcry_aes_dec_armv8_ce,%function;
369 _gcry_aes_dec_armv8_ce:
370   /* input:
371    *    r0: keysched
372    *    r1: dst
373    *    r2: src
374    *    r3: nrounds
375    */
376
377   vldmia r0!, {q1-q3} /* load 3 round keys */
378
379   cmp r3, #12
380
381   vld1.8 {q0}, [r2]
382
383   bhi .Ldec1_256
384   beq .Ldec1_192
385
386 .Ldec1_128:
387
388 .Ldec1_tail:
389   vldmia r0, {q8-q15} /* load 8 round keys */
390
391   aesd.8   q0, q1
392   aesimc.8 q0, q0
393   CLEAR_REG(q1)
394
395   aesd.8   q0, q2
396   aesimc.8 q0, q0
397   CLEAR_REG(q2)
398
399   aesd.8   q0, q3
400   aesimc.8 q0, q0
401   CLEAR_REG(q3)
402
403   aesd.8   q0, q8
404   aesimc.8 q0, q0
405   CLEAR_REG(q8)
406
407   aesd.8   q0, q9
408   aesimc.8 q0, q0
409   CLEAR_REG(q9)
410
411   aesd.8   q0, q10
412   aesimc.8 q0, q0
413   CLEAR_REG(q10)
414
415   aesd.8   q0, q11
416   aesimc.8 q0, q0
417   CLEAR_REG(q11)
418
419   aesd.8   q0, q12
420   aesimc.8 q0, q0
421   CLEAR_REG(q12)
422
423   aesd.8   q0, q13
424   aesimc.8 q0, q0
425   CLEAR_REG(q13)
426
427   aesd.8   q0, q14
428   veor     q0, q15
429   CLEAR_REG(q14)
430   CLEAR_REG(q15)
431
432   vst1.8 {q0}, [r1]
433   CLEAR_REG(q0)
434
435   mov r0, #0
436   bx lr
437
438 .Ldec1_192:
439   aesd.8   q0, q1
440   aesimc.8 q0, q0
441   vmov q1, q3
442
443   aesd.8   q0, q2
444   aesimc.8 q0, q0
445   vldm r0!, {q2-q3} /* load 3 round keys */
446
447   b .Ldec1_tail
448
449 .Ldec1_256:
450   vldm r0!, {q15}   /* load 1 round key */
451   aesd.8   q0, q1
452   aesimc.8 q0, q0
453
454   aesd.8   q0, q2
455   aesimc.8 q0, q0
456
457   aesd.8  q0, q3
458   aesimc.8 q0, q0
459   vldm r0!, {q1-q3} /* load 3 round keys */
460
461   aesd.8   q0, q15
462   aesimc.8 q0, q0
463
464   b .Ldec1_tail
465 .size _gcry_aes_dec_armv8_ce,.-_gcry_aes_dec_armv8_ce;
466
467
468 /*
469  * void _gcry_aes_cbc_enc_armv8_ce (const void *keysched,
470  *                                  unsigned char *outbuf,
471  *                                  const unsigned char *inbuf,
472  *                                  unsigned char *iv, size_t nblocks,
473  *                                  int cbc_mac, unsigned int nrounds);
474  */
475
476 .align 3
477 .globl _gcry_aes_cbc_enc_armv8_ce
478 .type  _gcry_aes_cbc_enc_armv8_ce,%function;
479 _gcry_aes_cbc_enc_armv8_ce:
480   /* input:
481    *    r0: keysched
482    *    r1: outbuf
483    *    r2: inbuf
484    *    r3: iv
485    *    %st+0: nblocks => r4
486    *    %st+4: cbc_mac => r5
487    *    %st+8: nrounds => r6
488    */
489
490   push {r4-r6,lr} /* 4*4 = 16b */
491   ldr r4, [sp, #(16+0)]
492   ldr r5, [sp, #(16+4)]
493   cmp r4, #0
494   ldr r6, [sp, #(16+8)]
495   beq .Lcbc_enc_skip
496   cmp r5, #0
497   vpush {q4-q7}
498   moveq r5, #16
499   movne r5, #0
500
501   cmp r6, #12
502   vld1.8 {q1}, [r3] /* load IV */
503
504   aes_preload_keys(r0, lr);
505
506   beq .Lcbc_enc_loop192
507   bhi .Lcbc_enc_loop256
508
509 #define CBC_ENC(bits, ...) \
510   .Lcbc_enc_loop##bits: \
511     vld1.8 {q0}, [r2]!; /* load plaintext */ \
512     veor q1, q0, q1; \
513     subs r4, r4, #1; \
514     \
515     do_aes_one##bits(e, mc, q1, q1, ##__VA_ARGS__); \
516     \
517     vst1.8 {q1}, [r1], r5; /* store ciphertext */ \
518     \
519     bne .Lcbc_enc_loop##bits; \
520     b .Lcbc_enc_done;
521
522   CBC_ENC(128)
523   CBC_ENC(192, r0, lr)
524   CBC_ENC(256, r0, lr)
525
526 #undef CBC_ENC
527
528 .Lcbc_enc_done:
529   vst1.8 {q1}, [r3] /* store IV */
530
531   CLEAR_REG(q0)
532   CLEAR_REG(q1)
533   CLEAR_REG(q2)
534   CLEAR_REG(q3)
535   CLEAR_REG(q8)
536   CLEAR_REG(q9)
537   vpop {q4-q7}
538   CLEAR_REG(q10)
539   CLEAR_REG(q11)
540   CLEAR_REG(q12)
541   CLEAR_REG(q13)
542   CLEAR_REG(q14)
543
544 .Lcbc_enc_skip:
545   pop {r4-r6,pc}
546 .size _gcry_aes_cbc_enc_armv8_ce,.-_gcry_aes_cbc_enc_armv8_ce;
547
548
549 /*
550  * void _gcry_aes_cbc_dec_armv8_ce (const void *keysched,
551  *                                  unsigned char *outbuf,
552  *                                  const unsigned char *inbuf,
553  *                                  unsigned char *iv, unsigned int nrounds);
554  */
555
556 .align 3
557 .globl _gcry_aes_cbc_dec_armv8_ce
558 .type  _gcry_aes_cbc_dec_armv8_ce,%function;
559 _gcry_aes_cbc_dec_armv8_ce:
560   /* input:
561    *    r0: keysched
562    *    r1: outbuf
563    *    r2: inbuf
564    *    r3: iv
565    *    %st+0: nblocks => r4
566    *    %st+4: nrounds => r5
567    */
568
569   push {r4-r6,lr} /* 4*4 = 16b */
570   ldr r4, [sp, #(16+0)]
571   ldr r5, [sp, #(16+4)]
572   cmp r4, #0
573   beq .Lcbc_dec_skip
574   vpush {q4-q7}
575
576   cmp r5, #12
577   vld1.8 {q0}, [r3] /* load IV */
578
579   aes_preload_keys(r0, r6);
580
581   beq .Lcbc_dec_entry_192
582   bhi .Lcbc_dec_entry_256
583
584 #define CBC_DEC(bits, ...) \
585   .Lcbc_dec_entry_##bits: \
586     cmp r4, #4; \
587     blo .Lcbc_dec_loop_##bits; \
588     \
589   .Lcbc_dec_loop4_##bits: \
590     \
591     vld1.8 {q1-q2}, [r2]!; /* load ciphertext */ \
592     sub r4, r4, #4; \
593     vld1.8 {q3-q4}, [r2]; /* load ciphertext */ \
594     cmp r4, #4; \
595     sub r2, #32; \
596     \
597     do_aes_4_##bits(d, imc, q1, q2, q3, q4, ##__VA_ARGS__); \
598     \
599     veor q1, q1, q0; \
600     vld1.8 {q0}, [r2]!; /* load next IV */ \
601     veor q2, q2, q0; \
602     vld1.8 {q0}, [r2]!; /* load next IV */ \
603     vst1.8 {q1-q2}, [r1]!; /* store plaintext */ \
604     veor q3, q3, q0; \
605     vld1.8 {q0}, [r2]!; /* load next IV */ \
606     veor q4, q4, q0; \
607     vld1.8 {q0}, [r2]!; /* load next IV */ \
608     vst1.8 {q3-q4}, [r1]!; /* store plaintext */ \
609     \
610     bhs .Lcbc_dec_loop4_##bits; \
611     cmp r4, #0; \
612     beq .Lcbc_dec_done; \
613     \
614   .Lcbc_dec_loop_##bits: \
615     vld1.8 {q1}, [r2]!; /* load ciphertext */ \
616     subs r4, r4, #1; \
617     vmov q2, q1; \
618     \
619     do_aes_one##bits(d, imc, q1, q1, ##__VA_ARGS__); \
620     \
621     veor q1, q1, q0; \
622     vmov q0, q2; \
623     vst1.8 {q1}, [r1]!; /* store plaintext */ \
624     \
625     bne .Lcbc_dec_loop_##bits; \
626     b .Lcbc_dec_done;
627
628   CBC_DEC(128)
629   CBC_DEC(192, r0, r6)
630   CBC_DEC(256, r0, r6)
631
632 #undef CBC_DEC
633
634 .Lcbc_dec_done:
635   vst1.8 {q0}, [r3] /* store IV */
636
637   CLEAR_REG(q0)
638   CLEAR_REG(q1)
639   CLEAR_REG(q2)
640   CLEAR_REG(q3)
641   CLEAR_REG(q8)
642   CLEAR_REG(q9)
643   vpop {q4-q7}
644   CLEAR_REG(q10)
645   CLEAR_REG(q11)
646   CLEAR_REG(q12)
647   CLEAR_REG(q13)
648   CLEAR_REG(q14)
649
650 .Lcbc_dec_skip:
651   pop {r4-r6,pc}
652 .size _gcry_aes_cbc_dec_armv8_ce,.-_gcry_aes_cbc_dec_armv8_ce;
653
654
655 /*
656  * void _gcry_aes_cfb_enc_armv8_ce (const void *keysched,
657  *                                  unsigned char *outbuf,
658  *                                  const unsigned char *inbuf,
659  *                                  unsigned char *iv, unsigned int nrounds);
660  */
661
662 .align 3
663 .globl _gcry_aes_cfb_enc_armv8_ce
664 .type  _gcry_aes_cfb_enc_armv8_ce,%function;
665 _gcry_aes_cfb_enc_armv8_ce:
666   /* input:
667    *    r0: keysched
668    *    r1: outbuf
669    *    r2: inbuf
670    *    r3: iv
671    *    %st+0: nblocks => r4
672    *    %st+4: nrounds => r5
673    */
674
675   push {r4-r6,lr} /* 4*4 = 16b */
676   ldr r4, [sp, #(16+0)]
677   ldr r5, [sp, #(16+4)]
678   cmp r4, #0
679   beq .Lcfb_enc_skip
680   vpush {q4-q7}
681
682   cmp r5, #12
683   vld1.8 {q0}, [r3] /* load IV */
684
685   aes_preload_keys(r0, r6);
686
687   beq .Lcfb_enc_entry_192
688   bhi .Lcfb_enc_entry_256
689
690 #define CFB_ENC(bits, ...) \
691   .Lcfb_enc_entry_##bits: \
692   .Lcfb_enc_loop_##bits: \
693     vld1.8 {q1}, [r2]!; /* load plaintext */ \
694     subs r4, r4, #1; \
695     \
696     do_aes_one##bits(e, mc, q0, q0, ##__VA_ARGS__); \
697     \
698     veor q0, q1, q0; \
699     vst1.8 {q0}, [r1]!; /* store ciphertext */ \
700     \
701     bne .Lcfb_enc_loop_##bits; \
702     b .Lcfb_enc_done;
703
704   CFB_ENC(128)
705   CFB_ENC(192, r0, r6)
706   CFB_ENC(256, r0, r6)
707
708 #undef CFB_ENC
709
710 .Lcfb_enc_done:
711   vst1.8 {q0}, [r3] /* store IV */
712
713   CLEAR_REG(q0)
714   CLEAR_REG(q1)
715   CLEAR_REG(q2)
716   CLEAR_REG(q3)
717   CLEAR_REG(q8)
718   CLEAR_REG(q9)
719   vpop {q4-q7}
720   CLEAR_REG(q10)
721   CLEAR_REG(q11)
722   CLEAR_REG(q12)
723   CLEAR_REG(q13)
724   CLEAR_REG(q14)
725
726 .Lcfb_enc_skip:
727   pop {r4-r6,pc}
728 .size _gcry_aes_cfb_enc_armv8_ce,.-_gcry_aes_cfb_enc_armv8_ce;
729
730
731 /*
732  * void _gcry_aes_cfb_dec_armv8_ce (const void *keysched,
733  *                                  unsigned char *outbuf,
734  *                                  const unsigned char *inbuf,
735  *                                  unsigned char *iv, unsigned int nrounds);
736  */
737
738 .align 3
739 .globl _gcry_aes_cfb_dec_armv8_ce
740 .type  _gcry_aes_cfb_dec_armv8_ce,%function;
741 _gcry_aes_cfb_dec_armv8_ce:
742   /* input:
743    *    r0: keysched
744    *    r1: outbuf
745    *    r2: inbuf
746    *    r3: iv
747    *    %st+0: nblocks => r4
748    *    %st+4: nrounds => r5
749    */
750
751   push {r4-r6,lr} /* 4*4 = 16b */
752   ldr r4, [sp, #(16+0)]
753   ldr r5, [sp, #(16+4)]
754   cmp r4, #0
755   beq .Lcfb_dec_skip
756   vpush {q4-q7}
757
758   cmp r5, #12
759   vld1.8 {q0}, [r3] /* load IV */
760
761   aes_preload_keys(r0, r6);
762
763   beq .Lcfb_dec_entry_192
764   bhi .Lcfb_dec_entry_256
765
766 #define CFB_DEC(bits, ...) \
767   .Lcfb_dec_entry_##bits: \
768     cmp r4, #4; \
769     blo .Lcfb_dec_loop_##bits; \
770     \
771   .Lcfb_dec_loop4_##bits: \
772     \
773     vld1.8 {q2-q3}, [r2]!; /* load ciphertext */ \
774     vmov q1, q0; \
775     sub r4, r4, #4; \
776     vld1.8 {q4}, [r2]; /* load ciphertext */ \
777     sub r2, #32; \
778     cmp r4, #4; \
779     \
780     do_aes_4_##bits(e, mc, q1, q2, q3, q4, ##__VA_ARGS__); \
781     \
782     vld1.8 {q0}, [r2]!; /* load ciphertext */ \
783     veor q1, q1, q0; \
784     vld1.8 {q0}, [r2]!; /* load ciphertext */ \
785     veor q2, q2, q0; \
786     vst1.8 {q1-q2}, [r1]!; /* store plaintext */ \
787     vld1.8 {q0}, [r2]!; \
788     veor q3, q3, q0; \
789     vld1.8 {q0}, [r2]!; /* load next IV / ciphertext */ \
790     veor q4, q4, q0; \
791     vst1.8 {q3-q4}, [r1]!; /* store plaintext */ \
792     \
793     bhs .Lcfb_dec_loop4_##bits; \
794     cmp r4, #0; \
795     beq .Lcfb_dec_done; \
796     \
797   .Lcfb_dec_loop_##bits: \
798     \
799     vld1.8 {q1}, [r2]!; /* load ciphertext */ \
800     \
801     subs r4, r4, #1; \
802     \
803     do_aes_one##bits(e, mc, q0, q0, ##__VA_ARGS__); \
804     \
805     veor q2, q1, q0; \
806     vmov q0, q1; \
807     vst1.8 {q2}, [r1]!; /* store plaintext */ \
808     \
809     bne .Lcfb_dec_loop_##bits; \
810     b .Lcfb_dec_done;
811
812   CFB_DEC(128)
813   CFB_DEC(192, r0, r6)
814   CFB_DEC(256, r0, r6)
815
816 #undef CFB_DEC
817
818 .Lcfb_dec_done:
819   vst1.8 {q0}, [r3] /* store IV */
820
821   CLEAR_REG(q0)
822   CLEAR_REG(q1)
823   CLEAR_REG(q2)
824   CLEAR_REG(q3)
825   CLEAR_REG(q8)
826   CLEAR_REG(q9)
827   vpop {q4-q7}
828   CLEAR_REG(q10)
829   CLEAR_REG(q11)
830   CLEAR_REG(q12)
831   CLEAR_REG(q13)
832   CLEAR_REG(q14)
833
834 .Lcfb_dec_skip:
835   pop {r4-r6,pc}
836 .size _gcry_aes_cfb_dec_armv8_ce,.-_gcry_aes_cfb_dec_armv8_ce;
837
838
839 /*
840  * void _gcry_aes_ctr_enc_armv8_ce (const void *keysched,
841  *                                  unsigned char *outbuf,
842  *                                  const unsigned char *inbuf,
843  *                                  unsigned char *iv, unsigned int nrounds);
844  */
845
846 .align 3
847 .globl _gcry_aes_ctr_enc_armv8_ce
848 .type  _gcry_aes_ctr_enc_armv8_ce,%function;
849 _gcry_aes_ctr_enc_armv8_ce:
850   /* input:
851    *    r0: keysched
852    *    r1: outbuf
853    *    r2: inbuf
854    *    r3: iv
855    *    %st+0: nblocks => r4
856    *    %st+4: nrounds => r5
857    */
858
859   vpush {q4-q7}
860   push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
861   ldr r4, [sp, #(104+0)]
862   ldr r5, [sp, #(104+4)]
863   cmp r4, #0
864   beq .Lctr_enc_skip
865
866   cmp r5, #12
867   ldm r3, {r7-r10}
868   vld1.8 {q0}, [r3] /* load IV */
869   rev r7, r7
870   rev r8, r8
871   rev r9, r9
872   rev r10, r10
873
874   aes_preload_keys(r0, r6);
875
876   beq .Lctr_enc_entry_192
877   bhi .Lctr_enc_entry_256
878
879 #define CTR_ENC(bits, ...) \
880   .Lctr_enc_entry_##bits: \
881     cmp r4, #4; \
882     blo .Lctr_enc_loop_##bits; \
883     \
884   .Lctr_enc_loop4_##bits: \
885     cmp r10, #0xfffffffc; \
886     sub r4, r4, #4; \
887     blo .Lctr_enc_loop4_##bits##_nocarry; \
888     cmp r9, #0xffffffff; \
889     bne .Lctr_enc_loop4_##bits##_nocarry; \
890     \
891     adds r10, #1; \
892     vmov q1, q0; \
893     blcs .Lctr_overflow_one; \
894     rev r11, r10; \
895     vmov.32 d1[1], r11; \
896     \
897     adds r10, #1; \
898     vmov q2, q0; \
899     blcs .Lctr_overflow_one; \
900     rev r11, r10; \
901     vmov.32 d1[1], r11; \
902     \
903     adds r10, #1; \
904     vmov q3, q0; \
905     blcs .Lctr_overflow_one; \
906     rev r11, r10; \
907     vmov.32 d1[1], r11; \
908     \
909     adds r10, #1; \
910     vmov q4, q0; \
911     blcs .Lctr_overflow_one; \
912     rev r11, r10; \
913     vmov.32 d1[1], r11; \
914     \
915     b .Lctr_enc_loop4_##bits##_store_ctr; \
916     \
917   .Lctr_enc_loop4_##bits##_nocarry: \
918     \
919     veor q2, q2; \
920     vrev64.8 q1, q0; \
921     vceq.u32 d5, d5; \
922     vadd.u64 q3, q2, q2; \
923     vadd.u64 q4, q3, q2; \
924     vadd.u64 q0, q3, q3; \
925     vsub.u64 q2, q1, q2; \
926     vsub.u64 q3, q1, q3; \
927     vsub.u64 q4, q1, q4; \
928     vsub.u64 q0, q1, q0; \
929     vrev64.8 q1, q1; \
930     vrev64.8 q2, q2; \
931     vrev64.8 q3, q3; \
932     vrev64.8 q0, q0; \
933     vrev64.8 q4, q4; \
934     add r10, #4; \
935     \
936   .Lctr_enc_loop4_##bits##_store_ctr: \
937     \
938     vst1.8 {q0}, [r3]; \
939     cmp r4, #4; \
940     vld1.8 {q0}, [r2]!; /* load ciphertext */ \
941     \
942     do_aes_4_##bits(e, mc, q1, q2, q3, q4, ##__VA_ARGS__); \
943     \
944     veor q1, q1, q0; \
945     vld1.8 {q0}, [r2]!; /* load ciphertext */ \
946     vst1.8 {q1}, [r1]!; /* store plaintext */ \
947     vld1.8 {q1}, [r2]!; /* load ciphertext */ \
948     veor q2, q2, q0; \
949     veor q3, q3, q1; \
950     vld1.8 {q0}, [r2]!; /* load ciphertext */ \
951     vst1.8 {q2}, [r1]!; /* store plaintext */ \
952     veor q4, q4, q0; \
953     vld1.8 {q0}, [r3]; /* reload IV */ \
954     vst1.8 {q3-q4}, [r1]!; /* store plaintext */ \
955     \
956     bhs .Lctr_enc_loop4_##bits; \
957     cmp r4, #0; \
958     beq .Lctr_enc_done; \
959     \
960   .Lctr_enc_loop_##bits: \
961     \
962     adds r10, #1; \
963     vmov q1, q0; \
964     blcs .Lctr_overflow_one; \
965     rev r11, r10; \
966     subs r4, r4, #1; \
967     vld1.8 {q2}, [r2]!; /* load ciphertext */ \
968     vmov.32 d1[1], r11; \
969     \
970     do_aes_one##bits(e, mc, q1, q1, ##__VA_ARGS__); \
971     \
972     veor q1, q2, q1; \
973     vst1.8 {q1}, [r1]!; /* store plaintext */ \
974     \
975     bne .Lctr_enc_loop_##bits; \
976     b .Lctr_enc_done;
977
978   CTR_ENC(128)
979   CTR_ENC(192, r0, r6)
980   CTR_ENC(256, r0, r6)
981
982 #undef CTR_ENC
983
984 .Lctr_enc_done:
985   vst1.8 {q0}, [r3] /* store IV */
986
987   CLEAR_REG(q0)
988   CLEAR_REG(q1)
989   CLEAR_REG(q2)
990   CLEAR_REG(q3)
991   CLEAR_REG(q8)
992   CLEAR_REG(q9)
993   CLEAR_REG(q10)
994   CLEAR_REG(q11)
995   CLEAR_REG(q12)
996   CLEAR_REG(q13)
997   CLEAR_REG(q14)
998
999 .Lctr_enc_skip:
1000   pop {r4-r12,lr}
1001   vpop {q4-q7}
1002   bx lr
1003
1004 .Lctr_overflow_one:
1005   adcs r9, #0
1006   adcs r8, #0
1007   adc r7, #0
1008   rev r11, r9
1009   rev r12, r8
1010   vmov.32 d1[0], r11
1011   rev r11, r7
1012   vmov.32 d0[1], r12
1013   vmov.32 d0[0], r11
1014   bx lr
1015 .size _gcry_aes_ctr_enc_armv8_ce,.-_gcry_aes_ctr_enc_armv8_ce;
1016
1017
1018 /*
1019  * void _gcry_aes_ocb_enc_armv8_ce (const void *keysched,
1020  *                                  unsigned char *outbuf,
1021  *                                  const unsigned char *inbuf,
1022  *                                  unsigned char *offset,
1023  *                                  unsigned char *checksum,
1024  *                                  void **Ls,
1025  *                                  size_t nblocks,
1026  *                                  unsigned int nrounds);
1027  */
1028
1029 .align 3
1030 .globl _gcry_aes_ocb_enc_armv8_ce
1031 .type  _gcry_aes_ocb_enc_armv8_ce,%function;
1032 _gcry_aes_ocb_enc_armv8_ce:
1033   /* input:
1034    *    r0: keysched
1035    *    r1: outbuf
1036    *    r2: inbuf
1037    *    r3: offset
1038    *    %st+0: checksum => r4
1039    *    %st+4: Ls => r5
1040    *    %st+8: nblocks => r6  (0 < nblocks <= 32)
1041    *    %st+12: nrounds => r7
1042    */
1043
1044   vpush {q4-q7}
1045   push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
1046   ldr r7, [sp, #(104+12)]
1047   ldr r4, [sp, #(104+0)]
1048   ldr r5, [sp, #(104+4)]
1049   ldr r6, [sp, #(104+8)]
1050
1051   cmp r7, #12
1052   vld1.8 {q0}, [r3] /* load offset */
1053
1054   aes_preload_keys(r0, r12);
1055
1056   beq .Locb_enc_entry_192
1057   bhi .Locb_enc_entry_256
1058
1059 #define OCB_ENC(bits, ...) \
1060   .Locb_enc_entry_##bits: \
1061     cmp r6, #4; \
1062     blo .Locb_enc_loop_##bits; \
1063     \
1064   .Locb_enc_loop4_##bits: \
1065     \
1066     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1067     /* Checksum_i = Checksum_{i-1} xor P_i  */ \
1068     /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */ \
1069     \
1070     ldm r5!, {r8, r9, r10, r11}; \
1071     sub r6, #4; \
1072     \
1073     vld1.8 {q9}, [r8];     /* load L_{ntz(i+0)} */ \
1074     vld1.8 {q1-q2}, [r2]!; /* load P_i+<0-1> */ \
1075     vld1.8 {q8}, [r4];     /* load Checksum_{i-1} */ \
1076     veor q0, q0, q9;       /* Offset_i+0 */ \
1077     vld1.8 {q9}, [r9];     /* load L_{ntz(i+1)} */ \
1078     veor q8, q8, q1;       /* Checksum_i+0 */ \
1079     veor q1, q1, q0;       /* P_i+0 xor Offset_i+0 */\
1080     vld1.8 {q3-q4}, [r2]!; /* load P_i+<2-3> */ \
1081     vst1.8 {q0}, [r1]!;    /* store Offset_i+0 */\
1082     veor q0, q0, q9;       /* Offset_i+1 */ \
1083     vld1.8 {q9}, [r10];    /* load L_{ntz(i+2)} */ \
1084     veor q8, q8, q2;       /* Checksum_i+1 */ \
1085     veor q2, q2, q0;       /* P_i+1 xor Offset_i+1 */\
1086     vst1.8 {q0}, [r1]!;    /* store Offset_i+1 */\
1087     veor q0, q0, q9;       /* Offset_i+2 */ \
1088     vld1.8 {q9}, [r11];    /* load L_{ntz(i+3)} */ \
1089     veor q8, q8, q3;       /* Checksum_i+2 */ \
1090     veor q3, q3, q0;       /* P_i+2 xor Offset_i+2 */\
1091     vst1.8 {q0}, [r1]!;    /* store Offset_i+2 */\
1092     veor q0, q0, q9;       /* Offset_i+3 */ \
1093     veor q8, q8, q4;       /* Checksum_i+3 */ \
1094     veor q4, q4, q0;       /* P_i+3 xor Offset_i+3 */\
1095     vst1.8 {q0}, [r1];     /* store Offset_i+3 */\
1096     sub r1, #(3*16); \
1097     vst1.8 {q8}, [r4];     /* store Checksum_i+3 */\
1098     \
1099     cmp r6, #4; \
1100     \
1101     do_aes_4_##bits(e, mc, q1, q2, q3, q4, ##__VA_ARGS__); \
1102     \
1103     mov r8, r1; \
1104     vld1.8 {q8-q9}, [r1]!; \
1105     veor q1, q1, q8; \
1106     veor q2, q2, q9; \
1107     vld1.8 {q8-q9}, [r1]!; \
1108     vst1.8 {q1-q2}, [r8]!; \
1109     veor q3, q3, q8; \
1110     veor q4, q4, q9; \
1111     vst1.8 {q3-q4}, [r8]; \
1112     \
1113     bhs .Locb_enc_loop4_##bits; \
1114     cmp r6, #0; \
1115     beq .Locb_enc_done; \
1116     \
1117   .Locb_enc_loop_##bits: \
1118     \
1119     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1120     /* Checksum_i = Checksum_{i-1} xor P_i  */ \
1121     /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */ \
1122     \
1123     ldr r8, [r5], #4; \
1124     vld1.8 {q1}, [r2]!; /* load plaintext */ \
1125     vld1.8 {q2}, [r8]; /* load L_{ntz(i)} */ \
1126     vld1.8 {q3}, [r4]; /* load checksum */ \
1127     subs r6, #1; \
1128     veor q0, q0, q2; \
1129     veor q3, q3, q1; \
1130     veor q1, q1, q0; \
1131     vst1.8 {q3}, [r4]; /* store checksum */ \
1132     \
1133     do_aes_one##bits(e, mc, q1, q1, ##__VA_ARGS__); \
1134     \
1135     veor q1, q1, q0; \
1136     vst1.8 {q1}, [r1]!; /* store ciphertext */ \
1137     \
1138     bne .Locb_enc_loop_##bits; \
1139     b .Locb_enc_done;
1140
1141   OCB_ENC(128re, r0, r12)
1142   OCB_ENC(192, r0, r12)
1143   OCB_ENC(256, r0, r12)
1144
1145 #undef OCB_ENC
1146
1147 .Locb_enc_done:
1148   vst1.8 {q0}, [r3] /* store offset */
1149
1150   CLEAR_REG(q0)
1151   CLEAR_REG(q1)
1152   CLEAR_REG(q2)
1153   CLEAR_REG(q3)
1154   CLEAR_REG(q8)
1155   CLEAR_REG(q9)
1156   CLEAR_REG(q10)
1157   CLEAR_REG(q11)
1158   CLEAR_REG(q12)
1159   CLEAR_REG(q13)
1160   CLEAR_REG(q14)
1161
1162   pop {r4-r12,lr}
1163   vpop {q4-q7}
1164   bx lr
1165 .size _gcry_aes_ocb_enc_armv8_ce,.-_gcry_aes_ocb_enc_armv8_ce;
1166
1167
1168 /*
1169  * void _gcry_aes_ocb_dec_armv8_ce (const void *keysched,
1170  *                                  unsigned char *outbuf,
1171  *                                  const unsigned char *inbuf,
1172  *                                  unsigned char *offset,
1173  *                                  unsigned char *checksum,
1174  *                                  void **Ls,
1175  *                                  size_t nblocks,
1176  *                                  unsigned int nrounds);
1177  */
1178
1179 .align 3
1180 .globl _gcry_aes_ocb_dec_armv8_ce
1181 .type  _gcry_aes_ocb_dec_armv8_ce,%function;
1182 _gcry_aes_ocb_dec_armv8_ce:
1183   /* input:
1184    *    r0: keysched
1185    *    r1: outbuf
1186    *    r2: inbuf
1187    *    r3: offset
1188    *    %st+0: checksum => r4
1189    *    %st+4: Ls => r5
1190    *    %st+8: nblocks => r6  (0 < nblocks <= 32)
1191    *    %st+12: nrounds => r7
1192    */
1193
1194   vpush {q4-q7}
1195   push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
1196   ldr r7, [sp, #(104+12)]
1197   ldr r4, [sp, #(104+0)]
1198   ldr r5, [sp, #(104+4)]
1199   ldr r6, [sp, #(104+8)]
1200
1201   cmp r7, #12
1202   vld1.8 {q0}, [r3] /* load offset */
1203
1204   aes_preload_keys(r0, r12);
1205
1206   beq .Locb_dec_entry_192
1207   bhi .Locb_dec_entry_256
1208
1209 #define OCB_DEC(bits, ...) \
1210   .Locb_dec_entry_##bits: \
1211     cmp r6, #4; \
1212     blo .Locb_dec_loop_##bits; \
1213     \
1214   .Locb_dec_loop4_##bits: \
1215     \
1216     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1217     /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)  */ \
1218     /* Checksum_i = Checksum_{i-1} xor P_i  */ \
1219     \
1220     ldm r5!, {r8, r9, r10, r11}; \
1221     sub r6, #4; \
1222     \
1223     vld1.8 {q9}, [r8];     /* load L_{ntz(i+0)} */ \
1224     vld1.8 {q1-q2}, [r2]!; /* load P_i+<0-1> */ \
1225     veor q0, q0, q9;       /* Offset_i+0 */ \
1226     vld1.8 {q9}, [r9];     /* load L_{ntz(i+1)} */ \
1227     veor q1, q1, q0;       /* P_i+0 xor Offset_i+0 */\
1228     vld1.8 {q3-q4}, [r2]!; /* load P_i+<2-3> */ \
1229     vst1.8 {q0}, [r1]!;    /* store Offset_i+0 */\
1230     veor q0, q0, q9;       /* Offset_i+1 */ \
1231     vld1.8 {q9}, [r10];    /* load L_{ntz(i+2)} */ \
1232     veor q2, q2, q0;       /* P_i+1 xor Offset_i+1 */\
1233     vst1.8 {q0}, [r1]!;    /* store Offset_i+1 */\
1234     veor q0, q0, q9;       /* Offset_i+2 */ \
1235     vld1.8 {q9}, [r11];    /* load L_{ntz(i+3)} */ \
1236     veor q3, q3, q0;       /* P_i+2 xor Offset_i+2 */\
1237     vst1.8 {q0}, [r1]!;    /* store Offset_i+2 */\
1238     veor q0, q0, q9;       /* Offset_i+3 */ \
1239     veor q4, q4, q0;       /* P_i+3 xor Offset_i+3 */\
1240     vst1.8 {q0}, [r1];     /* store Offset_i+3 */\
1241     sub r1, #(3*16); \
1242     \
1243     cmp r6, #4; \
1244     \
1245     do_aes_4_##bits(d, imc, q1, q2, q3, q4, ##__VA_ARGS__); \
1246     \
1247     mov r8, r1; \
1248     vld1.8 {q8-q9}, [r1]!; \
1249     veor q1, q1, q8; \
1250     veor q2, q2, q9; \
1251     vld1.8 {q8-q9}, [r1]!; \
1252     vst1.8 {q1-q2}, [r8]!; \
1253     veor q1, q1, q2; \
1254     vld1.8 {q2}, [r4];     /* load Checksum_{i-1} */ \
1255     veor q3, q3, q8; \
1256     veor q1, q1, q3; \
1257     veor q4, q4, q9; \
1258     veor q1, q1, q4; \
1259     vst1.8 {q3-q4}, [r8]; \
1260     veor q2, q2, q1; \
1261     vst1.8 {q2}, [r4];     /* store Checksum_i+3 */ \
1262     \
1263     bhs .Locb_dec_loop4_##bits; \
1264     cmp r6, #0; \
1265     beq .Locb_dec_done; \
1266     \
1267   .Locb_dec_loop_##bits: \
1268     \
1269     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1270     /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)  */ \
1271     /* Checksum_i = Checksum_{i-1} xor P_i  */ \
1272     \
1273     ldr r8, [r5], #4; \
1274     vld1.8 {q2}, [r8]; /* load L_{ntz(i)} */ \
1275     vld1.8 {q1}, [r2]!; /* load ciphertext */ \
1276     subs r6, #1; \
1277     veor q0, q0, q2; \
1278     veor q1, q1, q0; \
1279     \
1280     do_aes_one##bits(d, imc, q1, q1, ##__VA_ARGS__) \
1281     \
1282     vld1.8 {q2}, [r4]; /* load checksum */ \
1283     veor q1, q1, q0; \
1284     vst1.8 {q1}, [r1]!; /* store plaintext */ \
1285     veor q2, q2, q1; \
1286     vst1.8 {q2}, [r4]; /* store checksum */ \
1287     \
1288     bne .Locb_dec_loop_##bits; \
1289     b .Locb_dec_done;
1290
1291   OCB_DEC(128re, r0, r12)
1292   OCB_DEC(192, r0, r12)
1293   OCB_DEC(256, r0, r12)
1294
1295 #undef OCB_DEC
1296
1297 .Locb_dec_done:
1298   vst1.8 {q0}, [r3] /* store offset */
1299
1300   CLEAR_REG(q0)
1301   CLEAR_REG(q1)
1302   CLEAR_REG(q2)
1303   CLEAR_REG(q3)
1304   CLEAR_REG(q8)
1305   CLEAR_REG(q9)
1306   CLEAR_REG(q10)
1307   CLEAR_REG(q11)
1308   CLEAR_REG(q12)
1309   CLEAR_REG(q13)
1310   CLEAR_REG(q14)
1311
1312   pop {r4-r12,lr}
1313   vpop {q4-q7}
1314   bx lr
1315 .size _gcry_aes_ocb_dec_armv8_ce,.-_gcry_aes_ocb_dec_armv8_ce;
1316
1317
1318 /*
1319  * void _gcry_aes_ocb_auth_armv8_ce (const void *keysched,
1320  *                                   const unsigned char *abuf,
1321  *                                   unsigned char *offset,
1322  *                                   unsigned char *checksum,
1323  *                                   void **Ls,
1324  *                                   size_t nblocks,
1325  *                                   unsigned int nrounds);
1326  */
1327
1328 .align 3
1329 .globl _gcry_aes_ocb_auth_armv8_ce
1330 .type  _gcry_aes_ocb_auth_armv8_ce,%function;
1331 _gcry_aes_ocb_auth_armv8_ce:
1332   /* input:
1333    *    r0: keysched
1334    *    r1: abuf
1335    *    r2: offset
1336    *    r3: checksum
1337    *    %st+0: Ls => r5
1338    *    %st+4: nblocks => r6  (0 < nblocks <= 32)
1339    *    %st+8: nrounds => r7
1340    */
1341
1342   vpush {q4-q7}
1343   push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
1344   ldr r7, [sp, #(104+8)]
1345   ldr r5, [sp, #(104+0)]
1346   ldr r6, [sp, #(104+4)]
1347
1348   cmp r7, #12
1349   vld1.8 {q0}, [r2] /* load offset */
1350
1351   aes_preload_keys(r0, r12);
1352
1353   beq .Locb_auth_entry_192
1354   bhi .Locb_auth_entry_256
1355
1356 #define OCB_AUTH(bits, ...) \
1357   .Locb_auth_entry_##bits: \
1358     cmp r6, #4; \
1359     blo .Locb_auth_loop_##bits; \
1360     \
1361   .Locb_auth_loop4_##bits: \
1362     \
1363     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1364     /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */ \
1365     \
1366     ldm r5!, {r8, r9, r10, r11}; \
1367     sub r6, #4; \
1368     \
1369     vld1.8 {q9}, [r8];     /* load L_{ntz(i+0)} */ \
1370     vld1.8 {q1-q2}, [r1]!; /* load A_i+<0-1> */ \
1371     veor q0, q0, q9;       /* Offset_i+0 */ \
1372     vld1.8 {q9}, [r9];     /* load L_{ntz(i+1)} */ \
1373     veor q1, q1, q0;       /* A_i+0 xor Offset_i+0 */\
1374     vld1.8 {q3-q4}, [r1]!; /* load A_i+<2-3> */ \
1375     veor q0, q0, q9;       /* Offset_i+1 */ \
1376     vld1.8 {q9}, [r10];    /* load L_{ntz(i+2)} */ \
1377     veor q2, q2, q0;       /* A_i+1 xor Offset_i+1 */\
1378     veor q0, q0, q9;       /* Offset_i+2 */ \
1379     vld1.8 {q9}, [r11];    /* load L_{ntz(i+3)} */ \
1380     veor q3, q3, q0;       /* A_i+2 xor Offset_i+2 */\
1381     veor q0, q0, q9;       /* Offset_i+3 */ \
1382     veor q4, q4, q0;       /* A_i+3 xor Offset_i+3 */\
1383     \
1384     cmp r6, #4; \
1385     \
1386     do_aes_4_##bits(e, mc, q1, q2, q3, q4, ##__VA_ARGS__); \
1387     \
1388     veor q1, q1, q2; \
1389     veor q3, q3, q4; \
1390     vld1.8 {q2}, [r3]; \
1391     veor q1, q1, q3; \
1392     veor q2, q2, q1; \
1393     vst1.8 {q2}, [r3]; \
1394     \
1395     bhs .Locb_auth_loop4_##bits; \
1396     cmp r6, #0; \
1397     beq .Locb_auth_done; \
1398     \
1399   .Locb_auth_loop_##bits: \
1400     \
1401     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1402     /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */ \
1403     \
1404     ldr r8, [r5], #4; \
1405     vld1.8 {q2}, [r8]; /* load L_{ntz(i)} */ \
1406     vld1.8 {q1}, [r1]!; /* load aadtext */ \
1407     subs r6, #1; \
1408     veor q0, q0, q2; \
1409     vld1.8 {q2}, [r3]; /* load checksum */ \
1410     veor q1, q1, q0; \
1411     \
1412     do_aes_one##bits(e, mc, q1, q1, ##__VA_ARGS__) \
1413     \
1414     veor q2, q2, q1; \
1415     vst1.8 {q2}, [r3]; /* store checksum */ \
1416     \
1417     bne .Locb_auth_loop_##bits; \
1418     b .Locb_auth_done;
1419
1420   OCB_AUTH(128re, r0, r12)
1421   OCB_AUTH(192, r0, r12)
1422   OCB_AUTH(256, r0, r12)
1423
1424 #undef OCB_AUTH
1425
1426 .Locb_auth_done:
1427   vst1.8 {q0}, [r2] /* store offset */
1428
1429   CLEAR_REG(q0)
1430   CLEAR_REG(q1)
1431   CLEAR_REG(q2)
1432   CLEAR_REG(q3)
1433   CLEAR_REG(q8)
1434   CLEAR_REG(q9)
1435   CLEAR_REG(q10)
1436   CLEAR_REG(q11)
1437   CLEAR_REG(q12)
1438   CLEAR_REG(q13)
1439   CLEAR_REG(q14)
1440
1441   pop {r4-r12,lr}
1442   vpop {q4-q7}
1443   bx lr
1444 .size _gcry_aes_ocb_auth_armv8_ce,.-_gcry_aes_ocb_auth_armv8_ce;
1445
1446
1447 /*
1448  * u32 _gcry_aes_sbox4_armv8_ce(u32 in4b);
1449  */
1450 .align 3
1451 .globl _gcry_aes_sbox4_armv8_ce
1452 .type  _gcry_aes_sbox4_armv8_ce,%function;
1453 _gcry_aes_sbox4_armv8_ce:
1454   /* See "Gouvêa, C. P. L. & López, J. Implementing GCM on ARMv8. Topics in
1455    * Cryptology — CT-RSA 2015" for details.
1456    */
1457   vmov.i8 q0, #0x52
1458   vmov.i8 q1, #0
1459   vmov s0, r0
1460   aese.8 q0, q1
1461   veor d0, d1
1462   vpadd.i32 d0, d0, d1
1463   vmov r0, s0
1464   CLEAR_REG(q0)
1465   bx lr
1466 .size _gcry_aes_sbox4_armv8_ce,.-_gcry_aes_sbox4_armv8_ce;
1467
1468
1469 /*
1470  * void _gcry_aes_invmixcol_armv8_ce(void *dst, const void *src);
1471  */
1472 .align 3
1473 .globl _gcry_aes_invmixcol_armv8_ce
1474 .type  _gcry_aes_invmixcol_armv8_ce,%function;
1475 _gcry_aes_invmixcol_armv8_ce:
1476   vld1.8 {q0}, [r1]
1477   aesimc.8 q0, q0
1478   vst1.8 {q0}, [r0]
1479   CLEAR_REG(q0)
1480   bx lr
1481 .size _gcry_aes_invmixcol_armv8_ce,.-_gcry_aes_invmixcol_armv8_ce;
1482
1483 #endif