OCB ARM CE: Move ocb_get_l handling to assembly part
[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  *                                  unsigned char *L_table,
1025  *                                  size_t nblocks,
1026  *                                  unsigned int nrounds,
1027  *                                  unsigned int blkn);
1028  */
1029
1030 .align 3
1031 .globl _gcry_aes_ocb_enc_armv8_ce
1032 .type  _gcry_aes_ocb_enc_armv8_ce,%function;
1033 _gcry_aes_ocb_enc_armv8_ce:
1034   /* input:
1035    *    r0: keysched
1036    *    r1: outbuf
1037    *    r2: inbuf
1038    *    r3: offset
1039    *    %st+0: checksum => r4
1040    *    %st+4: Ls => r5
1041    *    %st+8: nblocks => r6  (0 < nblocks <= 32)
1042    *    %st+12: nrounds => r7
1043    *    %st+16: blkn => lr
1044    */
1045
1046   vpush {q4-q7}
1047   push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
1048   ldr r7, [sp, #(104+12)]
1049   ldr r4, [sp, #(104+0)]
1050   ldr r5, [sp, #(104+4)]
1051   ldr r6, [sp, #(104+8)]
1052   ldr lr, [sp, #(104+16)]
1053
1054   cmp r7, #12
1055   vld1.8 {q0}, [r3] /* load offset */
1056
1057   aes_preload_keys(r0, r12);
1058
1059   beq .Locb_enc_entry_192
1060   bhi .Locb_enc_entry_256
1061
1062 #define OCB_ENC(bits, ...) \
1063   .Locb_enc_entry_##bits: \
1064     cmp r6, #4; \
1065     add lr, #1; \
1066     blo .Locb_enc_loop_##bits; \
1067     \
1068   .Locb_enc_loop4_##bits: \
1069     \
1070     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1071     /* Checksum_i = Checksum_{i-1} xor P_i  */ \
1072     /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */ \
1073     \
1074     add r9, lr, #1; \
1075     add r10, lr, #2; \
1076     add r11, lr, #3; \
1077     rbit r8, lr; \
1078     add lr, lr, #4; \
1079     rbit r9, r9; \
1080     rbit r10, r10; \
1081     rbit r11, r11; \
1082     clz r8, r8; /* ntz(i+0) */ \
1083     clz r9, r9; /* ntz(i+1) */ \
1084     clz r10, r10; /* ntz(i+2) */ \
1085     clz r11, r11; /* ntz(i+3) */ \
1086     add r8, r5, r8, lsl #4; \
1087     add r9, r5, r9, lsl #4; \
1088     add r10, r5, r10, lsl #4; \
1089     add r11, r5, r11, lsl #4; \
1090     \
1091     sub r6, #4; \
1092     \
1093     vld1.8 {q9}, [r8];     /* load L_{ntz(i+0)} */ \
1094     vld1.8 {q1-q2}, [r2]!; /* load P_i+<0-1> */ \
1095     vld1.8 {q8}, [r4];     /* load Checksum_{i-1} */ \
1096     veor q0, q0, q9;       /* Offset_i+0 */ \
1097     vld1.8 {q9}, [r9];     /* load L_{ntz(i+1)} */ \
1098     veor q8, q8, q1;       /* Checksum_i+0 */ \
1099     veor q1, q1, q0;       /* P_i+0 xor Offset_i+0 */\
1100     vld1.8 {q3-q4}, [r2]!; /* load P_i+<2-3> */ \
1101     vst1.8 {q0}, [r1]!;    /* store Offset_i+0 */\
1102     veor q0, q0, q9;       /* Offset_i+1 */ \
1103     vld1.8 {q9}, [r10];    /* load L_{ntz(i+2)} */ \
1104     veor q8, q8, q2;       /* Checksum_i+1 */ \
1105     veor q2, q2, q0;       /* P_i+1 xor Offset_i+1 */\
1106     vst1.8 {q0}, [r1]!;    /* store Offset_i+1 */\
1107     veor q0, q0, q9;       /* Offset_i+2 */ \
1108     vld1.8 {q9}, [r11];    /* load L_{ntz(i+3)} */ \
1109     veor q8, q8, q3;       /* Checksum_i+2 */ \
1110     veor q3, q3, q0;       /* P_i+2 xor Offset_i+2 */\
1111     vst1.8 {q0}, [r1]!;    /* store Offset_i+2 */\
1112     veor q0, q0, q9;       /* Offset_i+3 */ \
1113     veor q8, q8, q4;       /* Checksum_i+3 */ \
1114     veor q4, q4, q0;       /* P_i+3 xor Offset_i+3 */\
1115     vst1.8 {q0}, [r1];     /* store Offset_i+3 */\
1116     sub r1, #(3*16); \
1117     vst1.8 {q8}, [r4];     /* store Checksum_i+3 */\
1118     \
1119     cmp r6, #4; \
1120     \
1121     do_aes_4_##bits(e, mc, q1, q2, q3, q4, ##__VA_ARGS__); \
1122     \
1123     mov r8, r1; \
1124     vld1.8 {q8-q9}, [r1]!; \
1125     veor q1, q1, q8; \
1126     veor q2, q2, q9; \
1127     vld1.8 {q8-q9}, [r1]!; \
1128     vst1.8 {q1-q2}, [r8]!; \
1129     veor q3, q3, q8; \
1130     veor q4, q4, q9; \
1131     vst1.8 {q3-q4}, [r8]; \
1132     \
1133     bhs .Locb_enc_loop4_##bits; \
1134     cmp r6, #0; \
1135     beq .Locb_enc_done; \
1136     \
1137   .Locb_enc_loop_##bits: \
1138     \
1139     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1140     /* Checksum_i = Checksum_{i-1} xor P_i  */ \
1141     /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */ \
1142     \
1143     rbit r8, lr; \
1144     add lr, #1; \
1145     clz r8, r8; /* ntz(i) */ \
1146     add r8, r5, r8, lsl #4; \
1147     \
1148     vld1.8 {q1}, [r2]!; /* load plaintext */ \
1149     vld1.8 {q2}, [r8]; /* load L_{ntz(i)} */ \
1150     vld1.8 {q3}, [r4]; /* load checksum */ \
1151     subs r6, #1; \
1152     veor q0, q0, q2; \
1153     veor q3, q3, q1; \
1154     veor q1, q1, q0; \
1155     vst1.8 {q3}, [r4]; /* store checksum */ \
1156     \
1157     do_aes_one##bits(e, mc, q1, q1, ##__VA_ARGS__); \
1158     \
1159     veor q1, q1, q0; \
1160     vst1.8 {q1}, [r1]!; /* store ciphertext */ \
1161     \
1162     bne .Locb_enc_loop_##bits; \
1163     b .Locb_enc_done;
1164
1165   OCB_ENC(128re, r0, r12)
1166   OCB_ENC(192, r0, r12)
1167   OCB_ENC(256, r0, r12)
1168
1169 #undef OCB_ENC
1170
1171 .Locb_enc_done:
1172   vst1.8 {q0}, [r3] /* store offset */
1173
1174   CLEAR_REG(q0)
1175   CLEAR_REG(q1)
1176   CLEAR_REG(q2)
1177   CLEAR_REG(q3)
1178   CLEAR_REG(q8)
1179   CLEAR_REG(q9)
1180   CLEAR_REG(q10)
1181   CLEAR_REG(q11)
1182   CLEAR_REG(q12)
1183   CLEAR_REG(q13)
1184   CLEAR_REG(q14)
1185
1186   pop {r4-r12,lr}
1187   vpop {q4-q7}
1188   bx lr
1189 .size _gcry_aes_ocb_enc_armv8_ce,.-_gcry_aes_ocb_enc_armv8_ce;
1190
1191
1192 /*
1193  * void _gcry_aes_ocb_dec_armv8_ce (const void *keysched,
1194  *                                  unsigned char *outbuf,
1195  *                                  const unsigned char *inbuf,
1196  *                                  unsigned char *offset,
1197  *                                  unsigned char *checksum,
1198  *                                  unsigned char *L_table,
1199  *                                  size_t nblocks,
1200  *                                  unsigned int nrounds,
1201  *                                  unsigned int blkn);
1202  */
1203
1204 .align 3
1205 .globl _gcry_aes_ocb_dec_armv8_ce
1206 .type  _gcry_aes_ocb_dec_armv8_ce,%function;
1207 _gcry_aes_ocb_dec_armv8_ce:
1208   /* input:
1209    *    r0: keysched
1210    *    r1: outbuf
1211    *    r2: inbuf
1212    *    r3: offset
1213    *    %st+0: checksum => r4
1214    *    %st+4: Ls => r5
1215    *    %st+8: nblocks => r6  (0 < nblocks <= 32)
1216    *    %st+12: nrounds => r7
1217    *    %st+16: blkn => lr
1218    */
1219
1220   vpush {q4-q7}
1221   push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
1222   ldr r7, [sp, #(104+12)]
1223   ldr r4, [sp, #(104+0)]
1224   ldr r5, [sp, #(104+4)]
1225   ldr r6, [sp, #(104+8)]
1226   ldr lr, [sp, #(104+16)]
1227
1228   cmp r7, #12
1229   vld1.8 {q0}, [r3] /* load offset */
1230
1231   aes_preload_keys(r0, r12);
1232
1233   beq .Locb_dec_entry_192
1234   bhi .Locb_dec_entry_256
1235
1236 #define OCB_DEC(bits, ...) \
1237   .Locb_dec_entry_##bits: \
1238     cmp r6, #4; \
1239     add lr, #1; \
1240     blo .Locb_dec_loop_##bits; \
1241     \
1242   .Locb_dec_loop4_##bits: \
1243     \
1244     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1245     /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)  */ \
1246     /* Checksum_i = Checksum_{i-1} xor P_i  */ \
1247     \
1248     add r9, lr, #1; \
1249     add r10, lr, #2; \
1250     add r11, lr, #3; \
1251     rbit r8, lr; \
1252     add lr, lr, #4; \
1253     rbit r9, r9; \
1254     rbit r10, r10; \
1255     rbit r11, r11; \
1256     clz r8, r8; /* ntz(i+0) */ \
1257     clz r9, r9; /* ntz(i+1) */ \
1258     clz r10, r10; /* ntz(i+2) */ \
1259     clz r11, r11; /* ntz(i+3) */ \
1260     add r8, r5, r8, lsl #4; \
1261     add r9, r5, r9, lsl #4; \
1262     add r10, r5, r10, lsl #4; \
1263     add r11, r5, r11, lsl #4; \
1264     \
1265     sub r6, #4; \
1266     \
1267     vld1.8 {q9}, [r8];     /* load L_{ntz(i+0)} */ \
1268     vld1.8 {q1-q2}, [r2]!; /* load P_i+<0-1> */ \
1269     veor q0, q0, q9;       /* Offset_i+0 */ \
1270     vld1.8 {q9}, [r9];     /* load L_{ntz(i+1)} */ \
1271     veor q1, q1, q0;       /* P_i+0 xor Offset_i+0 */\
1272     vld1.8 {q3-q4}, [r2]!; /* load P_i+<2-3> */ \
1273     vst1.8 {q0}, [r1]!;    /* store Offset_i+0 */\
1274     veor q0, q0, q9;       /* Offset_i+1 */ \
1275     vld1.8 {q9}, [r10];    /* load L_{ntz(i+2)} */ \
1276     veor q2, q2, q0;       /* P_i+1 xor Offset_i+1 */\
1277     vst1.8 {q0}, [r1]!;    /* store Offset_i+1 */\
1278     veor q0, q0, q9;       /* Offset_i+2 */ \
1279     vld1.8 {q9}, [r11];    /* load L_{ntz(i+3)} */ \
1280     veor q3, q3, q0;       /* P_i+2 xor Offset_i+2 */\
1281     vst1.8 {q0}, [r1]!;    /* store Offset_i+2 */\
1282     veor q0, q0, q9;       /* Offset_i+3 */ \
1283     veor q4, q4, q0;       /* P_i+3 xor Offset_i+3 */\
1284     vst1.8 {q0}, [r1];     /* store Offset_i+3 */\
1285     sub r1, #(3*16); \
1286     \
1287     cmp r6, #4; \
1288     \
1289     do_aes_4_##bits(d, imc, q1, q2, q3, q4, ##__VA_ARGS__); \
1290     \
1291     mov r8, r1; \
1292     vld1.8 {q8-q9}, [r1]!; \
1293     veor q1, q1, q8; \
1294     veor q2, q2, q9; \
1295     vld1.8 {q8-q9}, [r1]!; \
1296     vst1.8 {q1-q2}, [r8]!; \
1297     veor q1, q1, q2; \
1298     vld1.8 {q2}, [r4];     /* load Checksum_{i-1} */ \
1299     veor q3, q3, q8; \
1300     veor q1, q1, q3; \
1301     veor q4, q4, q9; \
1302     veor q1, q1, q4; \
1303     vst1.8 {q3-q4}, [r8]; \
1304     veor q2, q2, q1; \
1305     vst1.8 {q2}, [r4];     /* store Checksum_i+3 */ \
1306     \
1307     bhs .Locb_dec_loop4_##bits; \
1308     cmp r6, #0; \
1309     beq .Locb_dec_done; \
1310     \
1311   .Locb_dec_loop_##bits: \
1312     \
1313     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1314     /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)  */ \
1315     /* Checksum_i = Checksum_{i-1} xor P_i  */ \
1316     \
1317     rbit r8, lr; \
1318     add lr, #1; \
1319     clz r8, r8; /* ntz(i) */ \
1320     add r8, r5, r8, lsl #4; \
1321     \
1322     vld1.8 {q2}, [r8]; /* load L_{ntz(i)} */ \
1323     vld1.8 {q1}, [r2]!; /* load ciphertext */ \
1324     subs r6, #1; \
1325     veor q0, q0, q2; \
1326     veor q1, q1, q0; \
1327     \
1328     do_aes_one##bits(d, imc, q1, q1, ##__VA_ARGS__) \
1329     \
1330     vld1.8 {q2}, [r4]; /* load checksum */ \
1331     veor q1, q1, q0; \
1332     vst1.8 {q1}, [r1]!; /* store plaintext */ \
1333     veor q2, q2, q1; \
1334     vst1.8 {q2}, [r4]; /* store checksum */ \
1335     \
1336     bne .Locb_dec_loop_##bits; \
1337     b .Locb_dec_done;
1338
1339   OCB_DEC(128re, r0, r12)
1340   OCB_DEC(192, r0, r12)
1341   OCB_DEC(256, r0, r12)
1342
1343 #undef OCB_DEC
1344
1345 .Locb_dec_done:
1346   vst1.8 {q0}, [r3] /* store offset */
1347
1348   CLEAR_REG(q0)
1349   CLEAR_REG(q1)
1350   CLEAR_REG(q2)
1351   CLEAR_REG(q3)
1352   CLEAR_REG(q8)
1353   CLEAR_REG(q9)
1354   CLEAR_REG(q10)
1355   CLEAR_REG(q11)
1356   CLEAR_REG(q12)
1357   CLEAR_REG(q13)
1358   CLEAR_REG(q14)
1359
1360   pop {r4-r12,lr}
1361   vpop {q4-q7}
1362   bx lr
1363 .size _gcry_aes_ocb_dec_armv8_ce,.-_gcry_aes_ocb_dec_armv8_ce;
1364
1365
1366 /*
1367  * void _gcry_aes_ocb_auth_armv8_ce (const void *keysched,
1368  *                                   const unsigned char *abuf,
1369  *                                   unsigned char *offset,
1370  *                                   unsigned char *checksum,
1371  *                                   unsigned char *L_table,
1372  *                                   size_t nblocks,
1373  *                                   unsigned int nrounds,
1374  *                                   unsigned int blkn);
1375  */
1376
1377 .align 3
1378 .globl _gcry_aes_ocb_auth_armv8_ce
1379 .type  _gcry_aes_ocb_auth_armv8_ce,%function;
1380 _gcry_aes_ocb_auth_armv8_ce:
1381   /* input:
1382    *    r0: keysched
1383    *    r1: abuf
1384    *    r2: offset
1385    *    r3: checksum
1386    *    %st+0: Ls => r5
1387    *    %st+4: nblocks => r6  (0 < nblocks <= 32)
1388    *    %st+8: nrounds => r7
1389    *    %st+12: blkn => lr
1390    */
1391
1392   vpush {q4-q7}
1393   push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
1394   ldr r7, [sp, #(104+8)]
1395   ldr r5, [sp, #(104+0)]
1396   ldr r6, [sp, #(104+4)]
1397   ldr lr, [sp, #(104+12)]
1398
1399   cmp r7, #12
1400   vld1.8 {q0}, [r2] /* load offset */
1401
1402   aes_preload_keys(r0, r12);
1403
1404   beq .Locb_auth_entry_192
1405   bhi .Locb_auth_entry_256
1406
1407 #define OCB_AUTH(bits, ...) \
1408   .Locb_auth_entry_##bits: \
1409     cmp r6, #4; \
1410     add lr, #1; \
1411     blo .Locb_auth_loop_##bits; \
1412     \
1413   .Locb_auth_loop4_##bits: \
1414     \
1415     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1416     /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */ \
1417     \
1418     add r9, lr, #1; \
1419     add r10, lr, #2; \
1420     add r11, lr, #3; \
1421     rbit r8, lr; \
1422     add lr, lr, #4; \
1423     rbit r9, r9; \
1424     rbit r10, r10; \
1425     rbit r11, r11; \
1426     clz r8, r8; /* ntz(i+0) */ \
1427     clz r9, r9; /* ntz(i+1) */ \
1428     clz r10, r10; /* ntz(i+2) */ \
1429     clz r11, r11; /* ntz(i+3) */ \
1430     add r8, r5, r8, lsl #4; \
1431     add r9, r5, r9, lsl #4; \
1432     add r10, r5, r10, lsl #4; \
1433     add r11, r5, r11, lsl #4; \
1434     \
1435     sub r6, #4; \
1436     \
1437     vld1.8 {q9}, [r8];     /* load L_{ntz(i+0)} */ \
1438     vld1.8 {q1-q2}, [r1]!; /* load A_i+<0-1> */ \
1439     veor q0, q0, q9;       /* Offset_i+0 */ \
1440     vld1.8 {q9}, [r9];     /* load L_{ntz(i+1)} */ \
1441     veor q1, q1, q0;       /* A_i+0 xor Offset_i+0 */\
1442     vld1.8 {q3-q4}, [r1]!; /* load A_i+<2-3> */ \
1443     veor q0, q0, q9;       /* Offset_i+1 */ \
1444     vld1.8 {q9}, [r10];    /* load L_{ntz(i+2)} */ \
1445     veor q2, q2, q0;       /* A_i+1 xor Offset_i+1 */\
1446     veor q0, q0, q9;       /* Offset_i+2 */ \
1447     vld1.8 {q9}, [r11];    /* load L_{ntz(i+3)} */ \
1448     veor q3, q3, q0;       /* A_i+2 xor Offset_i+2 */\
1449     veor q0, q0, q9;       /* Offset_i+3 */ \
1450     veor q4, q4, q0;       /* A_i+3 xor Offset_i+3 */\
1451     \
1452     cmp r6, #4; \
1453     \
1454     do_aes_4_##bits(e, mc, q1, q2, q3, q4, ##__VA_ARGS__); \
1455     \
1456     veor q1, q1, q2; \
1457     veor q3, q3, q4; \
1458     vld1.8 {q2}, [r3]; \
1459     veor q1, q1, q3; \
1460     veor q2, q2, q1; \
1461     vst1.8 {q2}, [r3]; \
1462     \
1463     bhs .Locb_auth_loop4_##bits; \
1464     cmp r6, #0; \
1465     beq .Locb_auth_done; \
1466     \
1467   .Locb_auth_loop_##bits: \
1468     \
1469     /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ \
1470     /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */ \
1471     \
1472     rbit r8, lr; \
1473     add lr, #1; \
1474     clz r8, r8; /* ntz(i) */ \
1475     add r8, r5, r8, lsl #4; \
1476     \
1477     vld1.8 {q2}, [r8];  /* load L_{ntz(i)} */ \
1478     vld1.8 {q1}, [r1]!; /* load aadtext */ \
1479     subs r6, #1; \
1480     veor q0, q0, q2; \
1481     vld1.8 {q2}, [r3]; /* load checksum */ \
1482     veor q1, q1, q0; \
1483     \
1484     do_aes_one##bits(e, mc, q1, q1, ##__VA_ARGS__) \
1485     \
1486     veor q2, q2, q1; \
1487     vst1.8 {q2}, [r3]; /* store checksum */ \
1488     \
1489     bne .Locb_auth_loop_##bits; \
1490     b .Locb_auth_done;
1491
1492   OCB_AUTH(128re, r0, r12)
1493   OCB_AUTH(192, r0, r12)
1494   OCB_AUTH(256, r0, r12)
1495
1496 #undef OCB_AUTH
1497
1498 .Locb_auth_done:
1499   vst1.8 {q0}, [r2] /* store offset */
1500
1501   CLEAR_REG(q0)
1502   CLEAR_REG(q1)
1503   CLEAR_REG(q2)
1504   CLEAR_REG(q3)
1505   CLEAR_REG(q8)
1506   CLEAR_REG(q9)
1507   CLEAR_REG(q10)
1508   CLEAR_REG(q11)
1509   CLEAR_REG(q12)
1510   CLEAR_REG(q13)
1511   CLEAR_REG(q14)
1512
1513   pop {r4-r12,lr}
1514   vpop {q4-q7}
1515   bx lr
1516 .size _gcry_aes_ocb_auth_armv8_ce,.-_gcry_aes_ocb_auth_armv8_ce;
1517
1518
1519 /*
1520  * u32 _gcry_aes_sbox4_armv8_ce(u32 in4b);
1521  */
1522 .align 3
1523 .globl _gcry_aes_sbox4_armv8_ce
1524 .type  _gcry_aes_sbox4_armv8_ce,%function;
1525 _gcry_aes_sbox4_armv8_ce:
1526   /* See "Gouvêa, C. P. L. & López, J. Implementing GCM on ARMv8. Topics in
1527    * Cryptology — CT-RSA 2015" for details.
1528    */
1529   vmov.i8 q0, #0x52
1530   vmov.i8 q1, #0
1531   vmov s0, r0
1532   aese.8 q0, q1
1533   veor d0, d1
1534   vpadd.i32 d0, d0, d1
1535   vmov r0, s0
1536   CLEAR_REG(q0)
1537   bx lr
1538 .size _gcry_aes_sbox4_armv8_ce,.-_gcry_aes_sbox4_armv8_ce;
1539
1540
1541 /*
1542  * void _gcry_aes_invmixcol_armv8_ce(void *dst, const void *src);
1543  */
1544 .align 3
1545 .globl _gcry_aes_invmixcol_armv8_ce
1546 .type  _gcry_aes_invmixcol_armv8_ce,%function;
1547 _gcry_aes_invmixcol_armv8_ce:
1548   vld1.8 {q0}, [r1]
1549   aesimc.8 q0, q0
1550   vst1.8 {q0}, [r0]
1551   CLEAR_REG(q0)
1552   bx lr
1553 .size _gcry_aes_invmixcol_armv8_ce,.-_gcry_aes_invmixcol_armv8_ce;
1554
1555 #endif