776a9b744f3d8ce8a52bcc755b86cc643569d633
[openssl.git] / crypto / aes / asm / vpaes-armv8.pl
1 #! /usr/bin/env perl
2 # Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the OpenSSL license (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9
10 ######################################################################
11 ## Constant-time SSSE3 AES core implementation.
12 ## version 0.1
13 ##
14 ## By Mike Hamburg (Stanford University), 2009
15 ## Public domain.
16 ##
17 ## For details see http://shiftleft.org/papers/vector_aes/ and
18 ## http://crypto.stanford.edu/vpaes/.
19 ##
20 ######################################################################
21 # ARMv8 NEON adaptation by <appro@openssl.org>
22 #
23 # Reason for undertaken effort is that there is at least one popular
24 # SoC based on Cortex-A53 that doesn't have crypto extensions.
25 #
26 #                   CBC enc     ECB enc/dec(*)   [bit-sliced enc/dec]
27 # Cortex-A53        21.5        18.1/20.6        [17.5/19.8         ]
28 # Cortex-A57        36.0(**)    20.4/24.9(**)    [14.4/16.6         ]
29 # X-Gene            45.9(**)    45.8/57.7(**)    [33.1/37.6(**)     ]
30 # Denver(***)       16.6(**)    15.1/17.8(**)    [8.80/9.93         ]
31 # Apple A7(***)     22.7(**)    10.9/14.3        [8.45/10.0         ]
32 #
33 # (*)   ECB denotes approximate result for parallelizeable modes
34 #       such as CBC decrypt, CTR, etc.;
35 # (**)  these results are worse than scalar compiler-generated
36 #       code, but it's constant-time and therefore preferred;
37 # (***) presented for reference/comparison purposes;
38
39 $flavour = shift;
40 while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
41
42 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
43 ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
44 ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
45 die "can't locate arm-xlate.pl";
46
47 open OUT,"| \"$^X\" $xlate $flavour $output";
48 *STDOUT=*OUT;
49
50 $code.=<<___;
51 .text
52
53 .type   _vpaes_consts,%object
54 .align  7       // totally strategic alignment
55 _vpaes_consts:
56 .Lk_mc_forward: // mc_forward
57         .quad   0x0407060500030201, 0x0C0F0E0D080B0A09
58         .quad   0x080B0A0904070605, 0x000302010C0F0E0D
59         .quad   0x0C0F0E0D080B0A09, 0x0407060500030201
60         .quad   0x000302010C0F0E0D, 0x080B0A0904070605
61 .Lk_mc_backward:// mc_backward
62         .quad   0x0605040702010003, 0x0E0D0C0F0A09080B
63         .quad   0x020100030E0D0C0F, 0x0A09080B06050407
64         .quad   0x0E0D0C0F0A09080B, 0x0605040702010003
65         .quad   0x0A09080B06050407, 0x020100030E0D0C0F
66 .Lk_sr:         // sr
67         .quad   0x0706050403020100, 0x0F0E0D0C0B0A0908
68         .quad   0x030E09040F0A0500, 0x0B06010C07020D08
69         .quad   0x0F060D040B020900, 0x070E050C030A0108
70         .quad   0x0B0E0104070A0D00, 0x0306090C0F020508
71
72 //
73 // "Hot" constants
74 //
75 .Lk_inv:        // inv, inva
76         .quad   0x0E05060F0D080180, 0x040703090A0B0C02
77         .quad   0x01040A060F0B0780, 0x030D0E0C02050809
78 .Lk_ipt:        // input transform (lo, hi)
79         .quad   0xC2B2E8985A2A7000, 0xCABAE09052227808
80         .quad   0x4C01307D317C4D00, 0xCD80B1FCB0FDCC81
81 .Lk_sbo:        // sbou, sbot
82         .quad   0xD0D26D176FBDC700, 0x15AABF7AC502A878
83         .quad   0xCFE474A55FBB6A00, 0x8E1E90D1412B35FA
84 .Lk_sb1:        // sb1u, sb1t
85         .quad   0x3618D415FAE22300, 0x3BF7CCC10D2ED9EF
86         .quad   0xB19BE18FCB503E00, 0xA5DF7A6E142AF544
87 .Lk_sb2:        // sb2u, sb2t
88         .quad   0x69EB88400AE12900, 0xC2A163C8AB82234A
89         .quad   0xE27A93C60B712400, 0x5EB7E955BC982FCD
90
91 //
92 //  Decryption stuff
93 //
94 .Lk_dipt:       // decryption input transform
95         .quad   0x0F505B040B545F00, 0x154A411E114E451A
96         .quad   0x86E383E660056500, 0x12771772F491F194
97 .Lk_dsbo:       // decryption sbox final output
98         .quad   0x1387EA537EF94000, 0xC7AA6DB9D4943E2D
99         .quad   0x12D7560F93441D00, 0xCA4B8159D8C58E9C
100 .Lk_dsb9:       // decryption sbox output *9*u, *9*t
101         .quad   0x851C03539A86D600, 0xCAD51F504F994CC9
102         .quad   0xC03B1789ECD74900, 0x725E2C9EB2FBA565
103 .Lk_dsbd:       // decryption sbox output *D*u, *D*t
104         .quad   0x7D57CCDFE6B1A200, 0xF56E9B13882A4439
105         .quad   0x3CE2FAF724C6CB00, 0x2931180D15DEEFD3
106 .Lk_dsbb:       // decryption sbox output *B*u, *B*t
107         .quad   0xD022649296B44200, 0x602646F6B0F2D404
108         .quad   0xC19498A6CD596700, 0xF3FF0C3E3255AA6B
109 .Lk_dsbe:       // decryption sbox output *E*u, *E*t
110         .quad   0x46F2929626D4D000, 0x2242600464B4F6B0
111         .quad   0x0C55A6CDFFAAC100, 0x9467F36B98593E32
112
113 //
114 //  Key schedule constants
115 //
116 .Lk_dksd:       // decryption key schedule: invskew x*D
117         .quad   0xFEB91A5DA3E44700, 0x0740E3A45A1DBEF9
118         .quad   0x41C277F4B5368300, 0x5FDC69EAAB289D1E
119 .Lk_dksb:       // decryption key schedule: invskew x*B
120         .quad   0x9A4FCA1F8550D500, 0x03D653861CC94C99
121         .quad   0x115BEDA7B6FC4A00, 0xD993256F7E3482C8
122 .Lk_dkse:       // decryption key schedule: invskew x*E + 0x63
123         .quad   0xD5031CCA1FC9D600, 0x53859A4C994F5086
124         .quad   0xA23196054FDC7BE8, 0xCD5EF96A20B31487
125 .Lk_dks9:       // decryption key schedule: invskew x*9
126         .quad   0xB6116FC87ED9A700, 0x4AED933482255BFC
127         .quad   0x4576516227143300, 0x8BB89FACE9DAFDCE
128
129 .Lk_rcon:       // rcon
130         .quad   0x1F8391B9AF9DEEB6, 0x702A98084D7C7D81
131
132 .Lk_opt:        // output transform
133         .quad   0xFF9F4929D6B66000, 0xF7974121DEBE6808
134         .quad   0x01EDBD5150BCEC00, 0xE10D5DB1B05C0CE0
135 .Lk_deskew:     // deskew tables: inverts the sbox's "skew"
136         .quad   0x07E4A34047A4E300, 0x1DFEB95A5DBEF91A
137         .quad   0x5F36B5DC83EA6900, 0x2841C2ABF49D1E77
138
139 .asciz  "Vector Permutaion AES for ARMv8, Mike Hamburg (Stanford University)"
140 .size   _vpaes_consts,.-_vpaes_consts
141 .align  6
142 ___
143 \f
144 {
145 my ($inp,$out,$key) = map("x$_",(0..2));
146
147 my ($invlo,$invhi,$iptlo,$ipthi,$sbou,$sbot) = map("v$_.16b",(18..23));
148 my ($sb1u,$sb1t,$sb2u,$sb2t) = map("v$_.16b",(24..27));
149 my ($sb9u,$sb9t,$sbdu,$sbdt,$sbbu,$sbbt,$sbeu,$sbet)=map("v$_.16b",(24..31));
150
151 $code.=<<___;
152 ##
153 ##  _aes_preheat
154 ##
155 ##  Fills register %r10 -> .aes_consts (so you can -fPIC)
156 ##  and %xmm9-%xmm15 as specified below.
157 ##
158 .type   _vpaes_encrypt_preheat,%function
159 .align  4
160 _vpaes_encrypt_preheat:
161         adr     x10, .Lk_inv
162         movi    v17.16b, #0x0f
163         ld1     {v18.2d-v19.2d}, [x10],#32      // .Lk_inv
164         ld1     {v20.2d-v23.2d}, [x10],#64      // .Lk_ipt, .Lk_sbo
165         ld1     {v24.2d-v27.2d}, [x10]          // .Lk_sb1, .Lk_sb2
166         ret
167 .size   _vpaes_encrypt_preheat,.-_vpaes_encrypt_preheat
168
169 ##
170 ##  _aes_encrypt_core
171 ##
172 ##  AES-encrypt %xmm0.
173 ##
174 ##  Inputs:
175 ##     %xmm0 = input
176 ##     %xmm9-%xmm15 as in _vpaes_preheat
177 ##    (%rdx) = scheduled keys
178 ##
179 ##  Output in %xmm0
180 ##  Clobbers  %xmm1-%xmm5, %r9, %r10, %r11, %rax
181 ##  Preserves %xmm6 - %xmm8 so you get some local vectors
182 ##
183 ##
184 .type   _vpaes_encrypt_core,%function
185 .align 4
186 _vpaes_encrypt_core:
187         mov     x9, $key
188         ldr     w8, [$key,#240]                 // pull rounds
189         adr     x11, .Lk_mc_forward+16
190                                                 // vmovdqa      .Lk_ipt(%rip),  %xmm2   # iptlo
191         ld1     {v16.2d}, [x9], #16             // vmovdqu      (%r9),  %xmm5           # round0 key
192         and     v1.16b, v7.16b, v17.16b         // vpand        %xmm9,  %xmm0,  %xmm1
193         ushr    v0.16b, v7.16b, #4              // vpsrlb       \$4,    %xmm0,  %xmm0
194         tbl     v1.16b, {$iptlo}, v1.16b        // vpshufb      %xmm1,  %xmm2,  %xmm1
195                                                 // vmovdqa      .Lk_ipt+16(%rip), %xmm3 # ipthi
196         tbl     v2.16b, {$ipthi}, v0.16b        // vpshufb      %xmm0,  %xmm3,  %xmm2
197         eor     v0.16b, v1.16b, v16.16b         // vpxor        %xmm5,  %xmm1,  %xmm0
198         eor     v0.16b, v0.16b, v2.16b          // vpxor        %xmm2,  %xmm0,  %xmm0
199         b       .Lenc_entry
200
201 .align 4
202 .Lenc_loop:
203         // middle of middle round
204         add     x10, x11, #0x40
205         tbl     v4.16b, {$sb1t}, v2.16b         // vpshufb      %xmm2,  %xmm13, %xmm4   # 4 = sb1u
206         ld1     {v1.2d}, [x11], #16             // vmovdqa      -0x40(%r11,%r10), %xmm1 # .Lk_mc_forward[]
207         tbl     v0.16b, {$sb1u}, v3.16b         // vpshufb      %xmm3,  %xmm12, %xmm0   # 0 = sb1t
208         eor     v4.16b, v4.16b, v16.16b         // vpxor        %xmm5,  %xmm4,  %xmm4   # 4 = sb1u + k
209         tbl     v5.16b, {$sb2t}, v2.16b         // vpshufb      %xmm2,  %xmm15, %xmm5   # 4 = sb2u
210         eor     v0.16b, v0.16b, v4.16b          // vpxor        %xmm4,  %xmm0,  %xmm0   # 0 = A
211         tbl     v2.16b, {$sb2u}, v3.16b         // vpshufb      %xmm3,  %xmm14, %xmm2   # 2 = sb2t
212         ld1     {v4.2d}, [x10]                  // vmovdqa      (%r11,%r10), %xmm4      # .Lk_mc_backward[]
213         tbl     v3.16b, {v0.16b}, v1.16b        // vpshufb      %xmm1,  %xmm0,  %xmm3   # 0 = B
214         eor     v2.16b, v2.16b, v5.16b          // vpxor        %xmm5,  %xmm2,  %xmm2   # 2 = 2A
215         tbl     v0.16b, {v0.16b}, v4.16b        // vpshufb      %xmm4,  %xmm0,  %xmm0   # 3 = D
216         eor     v3.16b, v3.16b, v2.16b          // vpxor        %xmm2,  %xmm3,  %xmm3   # 0 = 2A+B
217         tbl     v4.16b, {v3.16b}, v1.16b        // vpshufb      %xmm1,  %xmm3,  %xmm4   # 0 = 2B+C
218         eor     v0.16b, v0.16b, v3.16b          // vpxor        %xmm3,  %xmm0,  %xmm0   # 3 = 2A+B+D
219         and     x11, x11, #~(1<<6)              // and          \$0x30, %r11            # ... mod 4
220         eor     v0.16b, v0.16b, v4.16b          // vpxor        %xmm4,  %xmm0, %xmm0    # 0 = 2A+3B+C+D
221         sub     w8, w8, #1                      // nr--
222
223 .Lenc_entry:
224         // top of round
225         and     v1.16b, v0.16b, v17.16b         // vpand        %xmm0,  %xmm9,  %xmm1   # 0 = k
226         ushr    v0.16b, v0.16b, #4              // vpsrlb       \$4,    %xmm0,  %xmm0   # 1 = i
227         tbl     v5.16b, {$invhi}, v1.16b        // vpshufb      %xmm1,  %xmm11, %xmm5   # 2 = a/k
228         eor     v1.16b, v1.16b, v0.16b          // vpxor        %xmm0,  %xmm1,  %xmm1   # 0 = j
229         tbl     v3.16b, {$invlo}, v0.16b        // vpshufb      %xmm0,  %xmm10, %xmm3   # 3 = 1/i
230         tbl     v4.16b, {$invlo}, v1.16b        // vpshufb      %xmm1,  %xmm10, %xmm4   # 4 = 1/j
231         eor     v3.16b, v3.16b, v5.16b          // vpxor        %xmm5,  %xmm3,  %xmm3   # 3 = iak = 1/i + a/k
232         eor     v4.16b, v4.16b, v5.16b          // vpxor        %xmm5,  %xmm4,  %xmm4   # 4 = jak = 1/j + a/k
233         tbl     v2.16b, {$invlo}, v3.16b        // vpshufb      %xmm3,  %xmm10, %xmm2   # 2 = 1/iak
234         tbl     v3.16b, {$invlo}, v4.16b        // vpshufb      %xmm4,  %xmm10, %xmm3   # 3 = 1/jak
235         eor     v2.16b, v2.16b, v1.16b          // vpxor        %xmm1,  %xmm2,  %xmm2   # 2 = io
236         eor     v3.16b, v3.16b, v0.16b          // vpxor        %xmm0,  %xmm3,  %xmm3   # 3 = jo
237         ld1     {v16.2d}, [x9],#16              // vmovdqu      (%r9),  %xmm5
238         cbnz    w8, .Lenc_loop
239
240         // middle of last round
241         add     x10, x11, #0x80
242                                                 // vmovdqa      -0x60(%r10), %xmm4      # 3 : sbou      .Lk_sbo
243                                                 // vmovdqa      -0x50(%r10), %xmm0      # 0 : sbot      .Lk_sbo+16
244         tbl     v4.16b, {$sbou}, v2.16b         // vpshufb      %xmm2,  %xmm4,  %xmm4   # 4 = sbou
245         ld1     {v1.2d}, [x10]                  // vmovdqa      0x40(%r11,%r10), %xmm1  # .Lk_sr[]
246         tbl     v0.16b, {$sbot}, v3.16b         // vpshufb      %xmm3,  %xmm0,  %xmm0   # 0 = sb1t
247         eor     v4.16b, v4.16b, v16.16b         // vpxor        %xmm5,  %xmm4,  %xmm4   # 4 = sb1u + k
248         eor     v0.16b, v0.16b, v4.16b          // vpxor        %xmm4,  %xmm0,  %xmm0   # 0 = A
249         tbl     v0.16b, {v0.16b}, v1.16b        // vpshufb      %xmm1,  %xmm0,  %xmm0
250         ret
251 .size   _vpaes_encrypt_core,.-_vpaes_encrypt_core
252
253 .globl  vpaes_encrypt
254 .type   vpaes_encrypt,%function
255 .align  4
256 vpaes_encrypt:
257         stp     x29,x30,[sp,#-16]!
258         add     x29,sp,#0
259
260         ld1     {v7.16b}, [$inp]
261         bl      _vpaes_encrypt_preheat
262         bl      _vpaes_encrypt_core
263         st1     {v0.16b}, [$out]
264
265         ldp     x29,x30,[sp],#16
266         ret
267 .size   vpaes_encrypt,.-vpaes_encrypt
268
269 .type   _vpaes_encrypt_2x,%function
270 .align 4
271 _vpaes_encrypt_2x:
272         mov     x9, $key
273         ldr     w8, [$key,#240]                 // pull rounds
274         adr     x11, .Lk_mc_forward+16
275                                                 // vmovdqa      .Lk_ipt(%rip),  %xmm2   # iptlo
276         ld1     {v16.2d}, [x9], #16             // vmovdqu      (%r9),  %xmm5           # round0 key
277         and     v1.16b,  v14.16b,  v17.16b      // vpand        %xmm9,  %xmm0,  %xmm1
278         ushr    v0.16b,  v14.16b,  #4           // vpsrlb       \$4,    %xmm0,  %xmm0
279          and    v9.16b,  v15.16b,  v17.16b
280          ushr   v8.16b,  v15.16b,  #4
281         tbl     v1.16b,  {$iptlo}, v1.16b       // vpshufb      %xmm1,  %xmm2,  %xmm1
282          tbl    v9.16b,  {$iptlo}, v9.16b
283                                                 // vmovdqa      .Lk_ipt+16(%rip), %xmm3 # ipthi
284         tbl     v2.16b,  {$ipthi}, v0.16b       // vpshufb      %xmm0,  %xmm3,  %xmm2
285          tbl    v10.16b, {$ipthi}, v8.16b
286         eor     v0.16b,  v1.16b,   v16.16b      // vpxor        %xmm5,  %xmm1,  %xmm0
287          eor    v8.16b,  v9.16b,   v16.16b
288         eor     v0.16b,  v0.16b,   v2.16b       // vpxor        %xmm2,  %xmm0,  %xmm0
289          eor    v8.16b,  v8.16b,   v10.16b
290         b       .Lenc_2x_entry
291
292 .align 4
293 .Lenc_2x_loop:
294         // middle of middle round
295         add     x10, x11, #0x40
296         tbl     v4.16b,  {$sb1t}, v2.16b        // vpshufb      %xmm2,  %xmm13, %xmm4   # 4 = sb1u
297          tbl    v12.16b, {$sb1t}, v10.16b
298         ld1     {v1.2d}, [x11], #16             // vmovdqa      -0x40(%r11,%r10), %xmm1 # .Lk_mc_forward[]
299         tbl     v0.16b,  {$sb1u}, v3.16b        // vpshufb      %xmm3,  %xmm12, %xmm0   # 0 = sb1t
300          tbl    v8.16b,  {$sb1u}, v11.16b
301         eor     v4.16b,  v4.16b,  v16.16b       // vpxor        %xmm5,  %xmm4,  %xmm4   # 4 = sb1u + k
302          eor    v12.16b, v12.16b, v16.16b
303         tbl     v5.16b,  {$sb2t}, v2.16b        // vpshufb      %xmm2,  %xmm15, %xmm5   # 4 = sb2u
304          tbl    v13.16b, {$sb2t}, v10.16b
305         eor     v0.16b,  v0.16b,  v4.16b        // vpxor        %xmm4,  %xmm0,  %xmm0   # 0 = A
306          eor    v8.16b,  v8.16b,  v12.16b
307         tbl     v2.16b,  {$sb2u}, v3.16b        // vpshufb      %xmm3,  %xmm14, %xmm2   # 2 = sb2t
308          tbl    v10.16b, {$sb2u}, v11.16b
309         ld1     {v4.2d}, [x10]                  // vmovdqa      (%r11,%r10), %xmm4      # .Lk_mc_backward[]
310         tbl     v3.16b,  {v0.16b}, v1.16b       // vpshufb      %xmm1,  %xmm0,  %xmm3   # 0 = B
311          tbl    v11.16b, {v8.16b}, v1.16b
312         eor     v2.16b,  v2.16b,  v5.16b        // vpxor        %xmm5,  %xmm2,  %xmm2   # 2 = 2A
313          eor    v10.16b, v10.16b, v13.16b
314         tbl     v0.16b,  {v0.16b}, v4.16b       // vpshufb      %xmm4,  %xmm0,  %xmm0   # 3 = D
315          tbl    v8.16b,  {v8.16b}, v4.16b
316         eor     v3.16b,  v3.16b,  v2.16b        // vpxor        %xmm2,  %xmm3,  %xmm3   # 0 = 2A+B
317          eor    v11.16b, v11.16b, v10.16b
318         tbl     v4.16b,  {v3.16b}, v1.16b       // vpshufb      %xmm1,  %xmm3,  %xmm4   # 0 = 2B+C
319          tbl    v12.16b, {v11.16b},v1.16b
320         eor     v0.16b,  v0.16b,  v3.16b        // vpxor        %xmm3,  %xmm0,  %xmm0   # 3 = 2A+B+D
321          eor    v8.16b,  v8.16b,  v11.16b
322         and     x11, x11, #~(1<<6)              // and          \$0x30, %r11            # ... mod 4
323         eor     v0.16b,  v0.16b,  v4.16b        // vpxor        %xmm4,  %xmm0, %xmm0    # 0 = 2A+3B+C+D
324          eor    v8.16b,  v8.16b,  v12.16b
325         sub     w8, w8, #1                      // nr--
326
327 .Lenc_2x_entry:
328         // top of round
329         and     v1.16b,  v0.16b, v17.16b        // vpand        %xmm0,  %xmm9,  %xmm1   # 0 = k
330         ushr    v0.16b,  v0.16b, #4             // vpsrlb       \$4,    %xmm0,  %xmm0   # 1 = i
331          and    v9.16b,  v8.16b, v17.16b
332          ushr   v8.16b,  v8.16b, #4
333         tbl     v5.16b,  {$invhi},v1.16b        // vpshufb      %xmm1,  %xmm11, %xmm5   # 2 = a/k
334          tbl    v13.16b, {$invhi},v9.16b
335         eor     v1.16b,  v1.16b,  v0.16b        // vpxor        %xmm0,  %xmm1,  %xmm1   # 0 = j
336          eor    v9.16b,  v9.16b,  v8.16b
337         tbl     v3.16b,  {$invlo},v0.16b        // vpshufb      %xmm0,  %xmm10, %xmm3   # 3 = 1/i
338          tbl    v11.16b, {$invlo},v8.16b
339         tbl     v4.16b,  {$invlo},v1.16b        // vpshufb      %xmm1,  %xmm10, %xmm4   # 4 = 1/j
340          tbl    v12.16b, {$invlo},v9.16b
341         eor     v3.16b,  v3.16b,  v5.16b        // vpxor        %xmm5,  %xmm3,  %xmm3   # 3 = iak = 1/i + a/k
342          eor    v11.16b, v11.16b, v13.16b
343         eor     v4.16b,  v4.16b,  v5.16b        // vpxor        %xmm5,  %xmm4,  %xmm4   # 4 = jak = 1/j + a/k
344          eor    v12.16b, v12.16b, v13.16b
345         tbl     v2.16b,  {$invlo},v3.16b        // vpshufb      %xmm3,  %xmm10, %xmm2   # 2 = 1/iak
346          tbl    v10.16b, {$invlo},v11.16b
347         tbl     v3.16b,  {$invlo},v4.16b        // vpshufb      %xmm4,  %xmm10, %xmm3   # 3 = 1/jak
348          tbl    v11.16b, {$invlo},v12.16b
349         eor     v2.16b,  v2.16b,  v1.16b        // vpxor        %xmm1,  %xmm2,  %xmm2   # 2 = io
350          eor    v10.16b, v10.16b, v9.16b
351         eor     v3.16b,  v3.16b,  v0.16b        // vpxor        %xmm0,  %xmm3,  %xmm3   # 3 = jo
352          eor    v11.16b, v11.16b, v8.16b
353         ld1     {v16.2d}, [x9],#16              // vmovdqu      (%r9),  %xmm5
354         cbnz    w8, .Lenc_2x_loop
355
356         // middle of last round
357         add     x10, x11, #0x80
358                                                 // vmovdqa      -0x60(%r10), %xmm4      # 3 : sbou      .Lk_sbo
359                                                 // vmovdqa      -0x50(%r10), %xmm0      # 0 : sbot      .Lk_sbo+16
360         tbl     v4.16b,  {$sbou}, v2.16b        // vpshufb      %xmm2,  %xmm4,  %xmm4   # 4 = sbou
361          tbl    v12.16b, {$sbou}, v10.16b
362         ld1     {v1.2d}, [x10]                  // vmovdqa      0x40(%r11,%r10), %xmm1  # .Lk_sr[]
363         tbl     v0.16b,  {$sbot}, v3.16b        // vpshufb      %xmm3,  %xmm0,  %xmm0   # 0 = sb1t
364          tbl    v8.16b,  {$sbot}, v11.16b
365         eor     v4.16b,  v4.16b,  v16.16b       // vpxor        %xmm5,  %xmm4,  %xmm4   # 4 = sb1u + k
366          eor    v12.16b, v12.16b, v16.16b
367         eor     v0.16b,  v0.16b,  v4.16b        // vpxor        %xmm4,  %xmm0,  %xmm0   # 0 = A
368          eor    v8.16b,  v8.16b,  v12.16b
369         tbl     v0.16b,  {v0.16b},v1.16b        // vpshufb      %xmm1,  %xmm0,  %xmm0
370          tbl    v1.16b,  {v8.16b},v1.16b
371         ret
372 .size   _vpaes_encrypt_2x,.-_vpaes_encrypt_2x
373
374 .type   _vpaes_decrypt_preheat,%function
375 .align  4
376 _vpaes_decrypt_preheat:
377         adr     x10, .Lk_inv
378         movi    v17.16b, #0x0f
379         adr     x11, .Lk_dipt
380         ld1     {v18.2d-v19.2d}, [x10],#32      // .Lk_inv
381         ld1     {v20.2d-v23.2d}, [x11],#64      // .Lk_dipt, .Lk_dsbo
382         ld1     {v24.2d-v27.2d}, [x11],#64      // .Lk_dsb9, .Lk_dsbd
383         ld1     {v28.2d-v31.2d}, [x11]          // .Lk_dsbb, .Lk_dsbe
384         ret
385 .size   _vpaes_decrypt_preheat,.-_vpaes_decrypt_preheat
386
387 ##
388 ##  Decryption core
389 ##
390 ##  Same API as encryption core.
391 ##
392 .type   _vpaes_decrypt_core,%function
393 .align  4
394 _vpaes_decrypt_core:
395         mov     x9, $key
396         ldr     w8, [$key,#240]                 // pull rounds
397
398                                                 // vmovdqa      .Lk_dipt(%rip), %xmm2   # iptlo
399         lsl     x11, x8, #4                     // mov  %rax,   %r11;   shl     \$4, %r11
400         eor     x11, x11, #0x30                 // xor          \$0x30, %r11
401         adr     x10, .Lk_sr
402         and     x11, x11, #0x30                 // and          \$0x30, %r11
403         add     x11, x11, x10
404         adr     x10, .Lk_mc_forward+48
405
406         ld1     {v16.2d}, [x9],#16              // vmovdqu      (%r9),  %xmm4           # round0 key
407         and     v1.16b, v7.16b, v17.16b         // vpand        %xmm9,  %xmm0,  %xmm1
408         ushr    v0.16b, v7.16b, #4              // vpsrlb       \$4,    %xmm0,  %xmm0
409         tbl     v2.16b, {$iptlo}, v1.16b        // vpshufb      %xmm1,  %xmm2,  %xmm2
410         ld1     {v5.2d}, [x10]                  // vmovdqa      .Lk_mc_forward+48(%rip), %xmm5
411                                                 // vmovdqa      .Lk_dipt+16(%rip), %xmm1 # ipthi
412         tbl     v0.16b, {$ipthi}, v0.16b        // vpshufb      %xmm0,  %xmm1,  %xmm0
413         eor     v2.16b, v2.16b, v16.16b         // vpxor        %xmm4,  %xmm2,  %xmm2
414         eor     v0.16b, v0.16b, v2.16b          // vpxor        %xmm2,  %xmm0,  %xmm0
415         b       .Ldec_entry
416
417 .align 4
418 .Ldec_loop:
419 //
420 //  Inverse mix columns
421 //
422                                                 // vmovdqa      -0x20(%r10),%xmm4               # 4 : sb9u
423                                                 // vmovdqa      -0x10(%r10),%xmm1               # 0 : sb9t
424         tbl     v4.16b, {$sb9u}, v2.16b         // vpshufb      %xmm2,  %xmm4,  %xmm4           # 4 = sb9u
425         tbl     v1.16b, {$sb9t}, v3.16b         // vpshufb      %xmm3,  %xmm1,  %xmm1           # 0 = sb9t
426         eor     v0.16b, v4.16b, v16.16b         // vpxor        %xmm4,  %xmm0,  %xmm0
427                                                 // vmovdqa      0x00(%r10),%xmm4                # 4 : sbdu
428         eor     v0.16b, v0.16b, v1.16b          // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
429                                                 // vmovdqa      0x10(%r10),%xmm1                # 0 : sbdt
430
431         tbl     v4.16b, {$sbdu}, v2.16b         // vpshufb      %xmm2,  %xmm4,  %xmm4           # 4 = sbdu
432         tbl     v0.16b, {v0.16b}, v5.16b        // vpshufb      %xmm5,  %xmm0,  %xmm0           # MC ch
433         tbl     v1.16b, {$sbdt}, v3.16b         // vpshufb      %xmm3,  %xmm1,  %xmm1           # 0 = sbdt
434         eor     v0.16b, v0.16b, v4.16b          // vpxor        %xmm4,  %xmm0,  %xmm0           # 4 = ch
435                                                 // vmovdqa      0x20(%r10),     %xmm4           # 4 : sbbu
436         eor     v0.16b, v0.16b, v1.16b          // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
437                                                 // vmovdqa      0x30(%r10),     %xmm1           # 0 : sbbt
438
439         tbl     v4.16b, {$sbbu}, v2.16b         // vpshufb      %xmm2,  %xmm4,  %xmm4           # 4 = sbbu
440         tbl     v0.16b, {v0.16b}, v5.16b        // vpshufb      %xmm5,  %xmm0,  %xmm0           # MC ch
441         tbl     v1.16b, {$sbbt}, v3.16b         // vpshufb      %xmm3,  %xmm1,  %xmm1           # 0 = sbbt
442         eor     v0.16b, v0.16b, v4.16b          // vpxor        %xmm4,  %xmm0,  %xmm0           # 4 = ch
443                                                 // vmovdqa      0x40(%r10),     %xmm4           # 4 : sbeu
444         eor     v0.16b, v0.16b, v1.16b          // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
445                                                 // vmovdqa      0x50(%r10),     %xmm1           # 0 : sbet
446
447         tbl     v4.16b, {$sbeu}, v2.16b         // vpshufb      %xmm2,  %xmm4,  %xmm4           # 4 = sbeu
448         tbl     v0.16b, {v0.16b}, v5.16b        // vpshufb      %xmm5,  %xmm0,  %xmm0           # MC ch
449         tbl     v1.16b, {$sbet}, v3.16b         // vpshufb      %xmm3,  %xmm1,  %xmm1           # 0 = sbet
450         eor     v0.16b, v0.16b, v4.16b          // vpxor        %xmm4,  %xmm0,  %xmm0           # 4 = ch
451         ext     v5.16b, v5.16b, v5.16b, #12     // vpalignr \$12,       %xmm5,  %xmm5,  %xmm5
452         eor     v0.16b, v0.16b, v1.16b          // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
453         sub     w8, w8, #1                      // sub          \$1,%rax                        # nr--
454
455 .Ldec_entry:
456         // top of round
457         and     v1.16b, v0.16b, v17.16b         // vpand        %xmm9,  %xmm0,  %xmm1   # 0 = k
458         ushr    v0.16b, v0.16b, #4              // vpsrlb       \$4,    %xmm0,  %xmm0   # 1 = i
459         tbl     v2.16b, {$invhi}, v1.16b        // vpshufb      %xmm1,  %xmm11, %xmm2   # 2 = a/k
460         eor     v1.16b, v1.16b, v0.16b          // vpxor        %xmm0,  %xmm1,  %xmm1   # 0 = j
461         tbl     v3.16b, {$invlo}, v0.16b        // vpshufb      %xmm0,  %xmm10, %xmm3   # 3 = 1/i
462         tbl     v4.16b, {$invlo}, v1.16b        // vpshufb      %xmm1,  %xmm10, %xmm4   # 4 = 1/j
463         eor     v3.16b, v3.16b, v2.16b          // vpxor        %xmm2,  %xmm3,  %xmm3   # 3 = iak = 1/i + a/k
464         eor     v4.16b, v4.16b, v2.16b          // vpxor        %xmm2,  %xmm4,  %xmm4   # 4 = jak = 1/j + a/k
465         tbl     v2.16b, {$invlo}, v3.16b        // vpshufb      %xmm3,  %xmm10, %xmm2   # 2 = 1/iak
466         tbl     v3.16b, {$invlo}, v4.16b        // vpshufb      %xmm4,  %xmm10, %xmm3   # 3 = 1/jak
467         eor     v2.16b, v2.16b, v1.16b          // vpxor        %xmm1,  %xmm2,  %xmm2   # 2 = io
468         eor     v3.16b, v3.16b, v0.16b          // vpxor        %xmm0,  %xmm3,  %xmm3   # 3 = jo
469         ld1     {v16.2d}, [x9],#16              // vmovdqu      (%r9),  %xmm0
470         cbnz    w8, .Ldec_loop
471
472         // middle of last round
473                                                 // vmovdqa      0x60(%r10),     %xmm4   # 3 : sbou
474         tbl     v4.16b, {$sbou}, v2.16b         // vpshufb      %xmm2,  %xmm4,  %xmm4   # 4 = sbou
475                                                 // vmovdqa      0x70(%r10),     %xmm1   # 0 : sbot
476         ld1     {v2.2d}, [x11]                  // vmovdqa      -0x160(%r11),   %xmm2   # .Lk_sr-.Lk_dsbd=-0x160
477         tbl     v1.16b, {$sbot}, v3.16b         // vpshufb      %xmm3,  %xmm1,  %xmm1   # 0 = sb1t
478         eor     v4.16b, v4.16b, v16.16b         // vpxor        %xmm0,  %xmm4,  %xmm4   # 4 = sb1u + k
479         eor     v0.16b, v1.16b, v4.16b          // vpxor        %xmm4,  %xmm1,  %xmm0   # 0 = A
480         tbl     v0.16b, {v0.16b}, v2.16b        // vpshufb      %xmm2,  %xmm0,  %xmm0
481         ret
482 .size   _vpaes_decrypt_core,.-_vpaes_decrypt_core
483
484 .globl  vpaes_decrypt
485 .type   vpaes_decrypt,%function
486 .align  4
487 vpaes_decrypt:
488         stp     x29,x30,[sp,#-16]!
489         add     x29,sp,#0
490
491         ld1     {v7.16b}, [$inp]
492         bl      _vpaes_decrypt_preheat
493         bl      _vpaes_decrypt_core
494         st1     {v0.16b}, [$out]
495
496         ldp     x29,x30,[sp],#16
497         ret
498 .size   vpaes_decrypt,.-vpaes_decrypt
499
500 // v14-v15 input, v0-v1 output
501 .type   _vpaes_decrypt_2x,%function
502 .align  4
503 _vpaes_decrypt_2x:
504         mov     x9, $key
505         ldr     w8, [$key,#240]                 // pull rounds
506
507                                                 // vmovdqa      .Lk_dipt(%rip), %xmm2   # iptlo
508         lsl     x11, x8, #4                     // mov  %rax,   %r11;   shl     \$4, %r11
509         eor     x11, x11, #0x30                 // xor          \$0x30, %r11
510         adr     x10, .Lk_sr
511         and     x11, x11, #0x30                 // and          \$0x30, %r11
512         add     x11, x11, x10
513         adr     x10, .Lk_mc_forward+48
514
515         ld1     {v16.2d}, [x9],#16              // vmovdqu      (%r9),  %xmm4           # round0 key
516         and     v1.16b,  v14.16b, v17.16b       // vpand        %xmm9,  %xmm0,  %xmm1
517         ushr    v0.16b,  v14.16b, #4            // vpsrlb       \$4,    %xmm0,  %xmm0
518          and    v9.16b,  v15.16b, v17.16b
519          ushr   v8.16b,  v15.16b, #4
520         tbl     v2.16b,  {$iptlo},v1.16b        // vpshufb      %xmm1,  %xmm2,  %xmm2
521          tbl    v10.16b, {$iptlo},v9.16b
522         ld1     {v5.2d}, [x10]                  // vmovdqa      .Lk_mc_forward+48(%rip), %xmm5
523                                                 // vmovdqa      .Lk_dipt+16(%rip), %xmm1 # ipthi
524         tbl     v0.16b,  {$ipthi},v0.16b        // vpshufb      %xmm0,  %xmm1,  %xmm0
525          tbl    v8.16b,  {$ipthi},v8.16b
526         eor     v2.16b,  v2.16b,  v16.16b       // vpxor        %xmm4,  %xmm2,  %xmm2
527          eor    v10.16b, v10.16b, v16.16b
528         eor     v0.16b,  v0.16b,  v2.16b        // vpxor        %xmm2,  %xmm0,  %xmm0
529          eor    v8.16b,  v8.16b,  v10.16b
530         b       .Ldec_2x_entry
531
532 .align 4
533 .Ldec_2x_loop:
534 //
535 //  Inverse mix columns
536 //
537                                                 // vmovdqa      -0x20(%r10),%xmm4               # 4 : sb9u
538                                                 // vmovdqa      -0x10(%r10),%xmm1               # 0 : sb9t
539         tbl     v4.16b,  {$sb9u}, v2.16b        // vpshufb      %xmm2,  %xmm4,  %xmm4           # 4 = sb9u
540          tbl    v12.16b, {$sb9u}, v10.16b
541         tbl     v1.16b,  {$sb9t}, v3.16b        // vpshufb      %xmm3,  %xmm1,  %xmm1           # 0 = sb9t
542          tbl    v9.16b,  {$sb9t}, v11.16b
543         eor     v0.16b,  v4.16b,  v16.16b       // vpxor        %xmm4,  %xmm0,  %xmm0
544          eor    v8.16b,  v12.16b, v16.16b
545                                                 // vmovdqa      0x00(%r10),%xmm4                # 4 : sbdu
546         eor     v0.16b,  v0.16b,  v1.16b        // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
547          eor    v8.16b,  v8.16b,  v9.16b        // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
548                                                 // vmovdqa      0x10(%r10),%xmm1                # 0 : sbdt
549
550         tbl     v4.16b,  {$sbdu}, v2.16b        // vpshufb      %xmm2,  %xmm4,  %xmm4           # 4 = sbdu
551          tbl    v12.16b, {$sbdu}, v10.16b
552         tbl     v0.16b,  {v0.16b},v5.16b        // vpshufb      %xmm5,  %xmm0,  %xmm0           # MC ch
553          tbl    v8.16b,  {v8.16b},v5.16b
554         tbl     v1.16b,  {$sbdt}, v3.16b        // vpshufb      %xmm3,  %xmm1,  %xmm1           # 0 = sbdt
555          tbl    v9.16b,  {$sbdt}, v11.16b
556         eor     v0.16b,  v0.16b,  v4.16b        // vpxor        %xmm4,  %xmm0,  %xmm0           # 4 = ch
557          eor    v8.16b,  v8.16b,  v12.16b
558                                                 // vmovdqa      0x20(%r10),     %xmm4           # 4 : sbbu
559         eor     v0.16b,  v0.16b,  v1.16b        // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
560          eor    v8.16b,  v8.16b,  v9.16b
561                                                 // vmovdqa      0x30(%r10),     %xmm1           # 0 : sbbt
562
563         tbl     v4.16b,  {$sbbu}, v2.16b        // vpshufb      %xmm2,  %xmm4,  %xmm4           # 4 = sbbu
564          tbl    v12.16b, {$sbbu}, v10.16b
565         tbl     v0.16b,  {v0.16b},v5.16b        // vpshufb      %xmm5,  %xmm0,  %xmm0           # MC ch
566          tbl    v8.16b,  {v8.16b},v5.16b
567         tbl     v1.16b,  {$sbbt}, v3.16b        // vpshufb      %xmm3,  %xmm1,  %xmm1           # 0 = sbbt
568          tbl    v9.16b,  {$sbbt}, v11.16b
569         eor     v0.16b,  v0.16b,  v4.16b        // vpxor        %xmm4,  %xmm0,  %xmm0           # 4 = ch
570          eor    v8.16b,  v8.16b,  v12.16b
571                                                 // vmovdqa      0x40(%r10),     %xmm4           # 4 : sbeu
572         eor     v0.16b,  v0.16b,  v1.16b        // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
573          eor    v8.16b,  v8.16b,  v9.16b
574                                                 // vmovdqa      0x50(%r10),     %xmm1           # 0 : sbet
575
576         tbl     v4.16b,  {$sbeu}, v2.16b        // vpshufb      %xmm2,  %xmm4,  %xmm4           # 4 = sbeu
577          tbl    v12.16b, {$sbeu}, v10.16b
578         tbl     v0.16b,  {v0.16b},v5.16b        // vpshufb      %xmm5,  %xmm0,  %xmm0           # MC ch
579          tbl    v8.16b,  {v8.16b},v5.16b
580         tbl     v1.16b,  {$sbet}, v3.16b        // vpshufb      %xmm3,  %xmm1,  %xmm1           # 0 = sbet
581          tbl    v9.16b,  {$sbet}, v11.16b
582         eor     v0.16b,  v0.16b,  v4.16b        // vpxor        %xmm4,  %xmm0,  %xmm0           # 4 = ch
583          eor    v8.16b,  v8.16b,  v12.16b
584         ext     v5.16b,  v5.16b,  v5.16b, #12   // vpalignr \$12,       %xmm5,  %xmm5,  %xmm5
585         eor     v0.16b,  v0.16b,  v1.16b        // vpxor        %xmm1,  %xmm0,  %xmm0           # 0 = ch
586          eor    v8.16b,  v8.16b,  v9.16b
587         sub     w8, w8, #1                      // sub          \$1,%rax                        # nr--
588
589 .Ldec_2x_entry:
590         // top of round
591         and     v1.16b,  v0.16b,  v17.16b       // vpand        %xmm9,  %xmm0,  %xmm1   # 0 = k
592         ushr    v0.16b,  v0.16b,  #4            // vpsrlb       \$4,    %xmm0,  %xmm0   # 1 = i
593          and    v9.16b,  v8.16b,  v17.16b
594          ushr   v8.16b,  v8.16b,  #4
595         tbl     v2.16b,  {$invhi},v1.16b        // vpshufb      %xmm1,  %xmm11, %xmm2   # 2 = a/k
596          tbl    v10.16b, {$invhi},v9.16b
597         eor     v1.16b,  v1.16b,  v0.16b        // vpxor        %xmm0,  %xmm1,  %xmm1   # 0 = j
598          eor    v9.16b,  v9.16b,  v8.16b
599         tbl     v3.16b,  {$invlo},v0.16b        // vpshufb      %xmm0,  %xmm10, %xmm3   # 3 = 1/i
600          tbl    v11.16b, {$invlo},v8.16b
601         tbl     v4.16b,  {$invlo},v1.16b        // vpshufb      %xmm1,  %xmm10, %xmm4   # 4 = 1/j
602          tbl    v12.16b, {$invlo},v9.16b
603         eor     v3.16b,  v3.16b,  v2.16b        // vpxor        %xmm2,  %xmm3,  %xmm3   # 3 = iak = 1/i + a/k
604          eor    v11.16b, v11.16b, v10.16b
605         eor     v4.16b,  v4.16b,  v2.16b        // vpxor        %xmm2,  %xmm4,  %xmm4   # 4 = jak = 1/j + a/k
606          eor    v12.16b, v12.16b, v10.16b
607         tbl     v2.16b,  {$invlo},v3.16b        // vpshufb      %xmm3,  %xmm10, %xmm2   # 2 = 1/iak
608          tbl    v10.16b, {$invlo},v11.16b
609         tbl     v3.16b,  {$invlo},v4.16b        // vpshufb      %xmm4,  %xmm10, %xmm3   # 3 = 1/jak
610          tbl    v11.16b, {$invlo},v12.16b
611         eor     v2.16b,  v2.16b,  v1.16b        // vpxor        %xmm1,  %xmm2,  %xmm2   # 2 = io
612          eor    v10.16b, v10.16b, v9.16b
613         eor     v3.16b,  v3.16b,  v0.16b        // vpxor        %xmm0,  %xmm3,  %xmm3   # 3 = jo
614          eor    v11.16b, v11.16b, v8.16b
615         ld1     {v16.2d}, [x9],#16              // vmovdqu      (%r9),  %xmm0
616         cbnz    w8, .Ldec_2x_loop
617
618         // middle of last round
619                                                 // vmovdqa      0x60(%r10),     %xmm4   # 3 : sbou
620         tbl     v4.16b,  {$sbou}, v2.16b        // vpshufb      %xmm2,  %xmm4,  %xmm4   # 4 = sbou
621          tbl    v12.16b, {$sbou}, v10.16b
622                                                 // vmovdqa      0x70(%r10),     %xmm1   # 0 : sbot
623         tbl     v1.16b,  {$sbot}, v3.16b        // vpshufb      %xmm3,  %xmm1,  %xmm1   # 0 = sb1t
624          tbl    v9.16b,  {$sbot}, v11.16b
625         ld1     {v2.2d}, [x11]                  // vmovdqa      -0x160(%r11),   %xmm2   # .Lk_sr-.Lk_dsbd=-0x160
626         eor     v4.16b,  v4.16b,  v16.16b       // vpxor        %xmm0,  %xmm4,  %xmm4   # 4 = sb1u + k
627          eor    v12.16b, v12.16b, v16.16b
628         eor     v0.16b,  v1.16b,  v4.16b        // vpxor        %xmm4,  %xmm1,  %xmm0   # 0 = A
629          eor    v8.16b,  v9.16b,  v12.16b
630         tbl     v0.16b,  {v0.16b},v2.16b        // vpshufb      %xmm2,  %xmm0,  %xmm0
631          tbl    v1.16b,  {v8.16b},v2.16b
632         ret
633 .size   _vpaes_decrypt_2x,.-_vpaes_decrypt_2x
634 ___
635 }\f
636 {
637 my ($inp,$bits,$out,$dir)=("x0","w1","x2","w3");
638 my ($invlo,$invhi,$iptlo,$ipthi,$rcon) = map("v$_.16b",(18..21,8));
639
640 $code.=<<___;
641 ########################################################
642 ##                                                    ##
643 ##                  AES key schedule                  ##
644 ##                                                    ##
645 ########################################################
646 .type   _vpaes_key_preheat,%function
647 .align  4
648 _vpaes_key_preheat:
649         adr     x10, .Lk_inv
650         movi    v16.16b, #0x5b                  // .Lk_s63
651         adr     x11, .Lk_sb1
652         movi    v17.16b, #0x0f                  // .Lk_s0F
653         ld1     {v18.2d-v21.2d}, [x10]          // .Lk_inv, .Lk_ipt
654         adr     x10, .Lk_dksd
655         ld1     {v22.2d-v23.2d}, [x11]          // .Lk_sb1
656         adr     x11, .Lk_mc_forward
657         ld1     {v24.2d-v27.2d}, [x10],#64      // .Lk_dksd, .Lk_dksb
658         ld1     {v28.2d-v31.2d}, [x10],#64      // .Lk_dkse, .Lk_dks9
659         ld1     {v8.2d}, [x10]                  // .Lk_rcon
660         ld1     {v9.2d}, [x11]                  // .Lk_mc_forward[0]
661         ret
662 .size   _vpaes_key_preheat,.-_vpaes_key_preheat
663
664 .type   _vpaes_schedule_core,%function
665 .align  4
666 _vpaes_schedule_core:
667         stp     x29, x30, [sp,#-16]!
668         add     x29,sp,#0
669
670         bl      _vpaes_key_preheat              // load the tables
671
672         ld1     {v0.16b}, [$inp],#16            // vmovdqu      (%rdi), %xmm0           # load key (unaligned)
673
674         // input transform
675         mov     v3.16b, v0.16b                  // vmovdqa      %xmm0,  %xmm3
676         bl      _vpaes_schedule_transform
677         mov     v7.16b, v0.16b                  // vmovdqa      %xmm0,  %xmm7
678
679         adr     x10, .Lk_sr                     // lea  .Lk_sr(%rip),%r10
680         add     x8, x8, x10
681         cbnz    $dir, .Lschedule_am_decrypting
682
683         // encrypting, output zeroth round key after transform
684         st1     {v0.2d}, [$out]                 // vmovdqu      %xmm0,  (%rdx)
685         b       .Lschedule_go
686
687 .Lschedule_am_decrypting:
688         // decrypting, output zeroth round key after shiftrows
689         ld1     {v1.2d}, [x8]                   // vmovdqa      (%r8,%r10),     %xmm1
690         tbl     v3.16b, {v3.16b}, v1.16b        // vpshufb  %xmm1,      %xmm3,  %xmm3
691         st1     {v3.2d}, [$out]                 // vmovdqu      %xmm3,  (%rdx)
692         eor     x8, x8, #0x30                   // xor  \$0x30, %r8
693
694 .Lschedule_go:
695         cmp     $bits, #192                     // cmp  \$192,  %esi
696         b.hi    .Lschedule_256
697         b.eq    .Lschedule_192
698         // 128: fall though
699
700 ##
701 ##  .schedule_128
702 ##
703 ##  128-bit specific part of key schedule.
704 ##
705 ##  This schedule is really simple, because all its parts
706 ##  are accomplished by the subroutines.
707 ##
708 .Lschedule_128:
709         mov     $inp, #10                       // mov  \$10, %esi
710
711 .Loop_schedule_128:
712         sub     $inp, $inp, #1                  // dec  %esi
713         bl      _vpaes_schedule_round
714         cbz     $inp, .Lschedule_mangle_last
715         bl      _vpaes_schedule_mangle          // write output
716         b       .Loop_schedule_128
717
718 ##
719 ##  .aes_schedule_192
720 ##
721 ##  192-bit specific part of key schedule.
722 ##
723 ##  The main body of this schedule is the same as the 128-bit
724 ##  schedule, but with more smearing.  The long, high side is
725 ##  stored in %xmm7 as before, and the short, low side is in
726 ##  the high bits of %xmm6.
727 ##
728 ##  This schedule is somewhat nastier, however, because each
729 ##  round produces 192 bits of key material, or 1.5 round keys.
730 ##  Therefore, on each cycle we do 2 rounds and produce 3 round
731 ##  keys.
732 ##
733 .align  4
734 .Lschedule_192:
735         sub     $inp, $inp, #8
736         ld1     {v0.16b}, [$inp]                // vmovdqu      8(%rdi),%xmm0           # load key part 2 (very unaligned)
737         bl      _vpaes_schedule_transform       // input transform
738         mov     v6.16b, v0.16b                  // vmovdqa      %xmm0,  %xmm6           # save short part
739         eor     v4.16b, v4.16b, v4.16b          // vpxor        %xmm4,  %xmm4, %xmm4    # clear 4
740         ins     v6.d[0], v4.d[0]                // vmovhlps     %xmm4,  %xmm6,  %xmm6           # clobber low side with zeros
741         mov     $inp, #4                        // mov  \$4,    %esi
742
743 .Loop_schedule_192:
744         sub     $inp, $inp, #1                  // dec  %esi
745         bl      _vpaes_schedule_round
746         ext     v0.16b, v6.16b, v0.16b, #8      // vpalignr     \$8,%xmm6,%xmm0,%xmm0
747         bl      _vpaes_schedule_mangle          // save key n
748         bl      _vpaes_schedule_192_smear
749         bl      _vpaes_schedule_mangle          // save key n+1
750         bl      _vpaes_schedule_round
751         cbz     $inp, .Lschedule_mangle_last
752         bl      _vpaes_schedule_mangle          // save key n+2
753         bl      _vpaes_schedule_192_smear
754         b       .Loop_schedule_192
755
756 ##
757 ##  .aes_schedule_256
758 ##
759 ##  256-bit specific part of key schedule.
760 ##
761 ##  The structure here is very similar to the 128-bit
762 ##  schedule, but with an additional "low side" in
763 ##  %xmm6.  The low side's rounds are the same as the
764 ##  high side's, except no rcon and no rotation.
765 ##
766 .align  4
767 .Lschedule_256:
768         ld1     {v0.16b}, [$inp]                // vmovdqu      16(%rdi),%xmm0          # load key part 2 (unaligned)
769         bl      _vpaes_schedule_transform       // input transform
770         mov     $inp, #7                        // mov  \$7, %esi
771         
772 .Loop_schedule_256:
773         sub     $inp, $inp, #1                  // dec  %esi
774         bl      _vpaes_schedule_mangle          // output low result
775         mov     v6.16b, v0.16b                  // vmovdqa      %xmm0,  %xmm6           # save cur_lo in xmm6
776
777         // high round
778         bl      _vpaes_schedule_round
779         cbz     $inp, .Lschedule_mangle_last
780         bl      _vpaes_schedule_mangle  
781
782         // low round. swap xmm7 and xmm6
783         dup     v0.4s, v0.s[3]                  // vpshufd      \$0xFF, %xmm0,  %xmm0
784         movi    v4.16b, #0
785         mov     v5.16b, v7.16b                  // vmovdqa      %xmm7,  %xmm5
786         mov     v7.16b, v6.16b                  // vmovdqa      %xmm6,  %xmm7
787         bl      _vpaes_schedule_low_round
788         mov     v7.16b, v5.16b                  // vmovdqa      %xmm5,  %xmm7
789         
790         b       .Loop_schedule_256
791
792 ##
793 ##  .aes_schedule_mangle_last
794 ##
795 ##  Mangler for last round of key schedule
796 ##  Mangles %xmm0
797 ##    when encrypting, outputs out(%xmm0) ^ 63
798 ##    when decrypting, outputs unskew(%xmm0)
799 ##
800 ##  Always called right before return... jumps to cleanup and exits
801 ##
802 .align  4
803 .Lschedule_mangle_last:
804         // schedule last round key from xmm0
805         adr     x11, .Lk_deskew                 // lea  .Lk_deskew(%rip),%r11   # prepare to deskew
806         cbnz    $dir, .Lschedule_mangle_last_dec
807
808         // encrypting
809         ld1     {v1.2d}, [x8]                   // vmovdqa      (%r8,%r10),%xmm1
810         adr     x11, .Lk_opt                    // lea  .Lk_opt(%rip),  %r11            # prepare to output transform
811         add     $out, $out, #32                 // add  \$32,   %rdx
812         tbl     v0.16b, {v0.16b}, v1.16b        // vpshufb      %xmm1,  %xmm0,  %xmm0           # output permute
813
814 .Lschedule_mangle_last_dec:
815         ld1     {v20.2d-v21.2d}, [x11]          // reload constants
816         sub     $out, $out, #16                 // add  \$-16,  %rdx 
817         eor     v0.16b, v0.16b, v16.16b         // vpxor        .Lk_s63(%rip),  %xmm0,  %xmm0
818         bl      _vpaes_schedule_transform       // output transform
819         st1     {v0.2d}, [$out]                 // vmovdqu      %xmm0,  (%rdx)          # save last key
820
821         // cleanup
822         eor     v0.16b, v0.16b, v0.16b          // vpxor        %xmm0,  %xmm0,  %xmm0
823         eor     v1.16b, v1.16b, v1.16b          // vpxor        %xmm1,  %xmm1,  %xmm1
824         eor     v2.16b, v2.16b, v2.16b          // vpxor        %xmm2,  %xmm2,  %xmm2
825         eor     v3.16b, v3.16b, v3.16b          // vpxor        %xmm3,  %xmm3,  %xmm3
826         eor     v4.16b, v4.16b, v4.16b          // vpxor        %xmm4,  %xmm4,  %xmm4
827         eor     v5.16b, v5.16b, v5.16b          // vpxor        %xmm5,  %xmm5,  %xmm5
828         eor     v6.16b, v6.16b, v6.16b          // vpxor        %xmm6,  %xmm6,  %xmm6
829         eor     v7.16b, v7.16b, v7.16b          // vpxor        %xmm7,  %xmm7,  %xmm7
830         ldp     x29, x30, [sp],#16
831         ret
832 .size   _vpaes_schedule_core,.-_vpaes_schedule_core
833
834 ##
835 ##  .aes_schedule_192_smear
836 ##
837 ##  Smear the short, low side in the 192-bit key schedule.
838 ##
839 ##  Inputs:
840 ##    %xmm7: high side, b  a  x  y
841 ##    %xmm6:  low side, d  c  0  0
842 ##    %xmm13: 0
843 ##
844 ##  Outputs:
845 ##    %xmm6: b+c+d  b+c  0  0
846 ##    %xmm0: b+c+d  b+c  b  a
847 ##
848 .type   _vpaes_schedule_192_smear,%function
849 .align  4
850 _vpaes_schedule_192_smear:
851         movi    v1.16b, #0
852         dup     v0.4s, v7.s[3]
853         ins     v1.s[3], v6.s[2]        // vpshufd      \$0x80, %xmm6,  %xmm1   # d c 0 0 -> c 0 0 0
854         ins     v0.s[0], v7.s[2]        // vpshufd      \$0xFE, %xmm7,  %xmm0   # b a _ _ -> b b b a
855         eor     v6.16b, v6.16b, v1.16b  // vpxor        %xmm1,  %xmm6,  %xmm6   # -> c+d c 0 0
856         eor     v1.16b, v1.16b, v1.16b  // vpxor        %xmm1,  %xmm1,  %xmm1
857         eor     v6.16b, v6.16b, v0.16b  // vpxor        %xmm0,  %xmm6,  %xmm6   # -> b+c+d b+c b a
858         mov     v0.16b, v6.16b          // vmovdqa      %xmm6,  %xmm0
859         ins     v6.d[0], v1.d[0]        // vmovhlps     %xmm1,  %xmm6,  %xmm6   # clobber low side with zeros
860         ret
861 .size   _vpaes_schedule_192_smear,.-_vpaes_schedule_192_smear
862
863 ##
864 ##  .aes_schedule_round
865 ##
866 ##  Runs one main round of the key schedule on %xmm0, %xmm7
867 ##
868 ##  Specifically, runs subbytes on the high dword of %xmm0
869 ##  then rotates it by one byte and xors into the low dword of
870 ##  %xmm7.
871 ##
872 ##  Adds rcon from low byte of %xmm8, then rotates %xmm8 for
873 ##  next rcon.
874 ##
875 ##  Smears the dwords of %xmm7 by xoring the low into the
876 ##  second low, result into third, result into highest.
877 ##
878 ##  Returns results in %xmm7 = %xmm0.
879 ##  Clobbers %xmm1-%xmm4, %r11.
880 ##
881 .type   _vpaes_schedule_round,%function
882 .align  4
883 _vpaes_schedule_round:
884         // extract rcon from xmm8
885         movi    v4.16b, #0                      // vpxor        %xmm4,  %xmm4,  %xmm4
886         ext     v1.16b, $rcon, v4.16b, #15      // vpalignr     \$15,   %xmm8,  %xmm4,  %xmm1
887         ext     $rcon, $rcon, $rcon, #15        // vpalignr     \$15,   %xmm8,  %xmm8,  %xmm8
888         eor     v7.16b, v7.16b, v1.16b          // vpxor        %xmm1,  %xmm7,  %xmm7
889
890         // rotate
891         dup     v0.4s, v0.s[3]                  // vpshufd      \$0xFF, %xmm0,  %xmm0
892         ext     v0.16b, v0.16b, v0.16b, #1      // vpalignr     \$1,    %xmm0,  %xmm0,  %xmm0
893
894         // fall through...
895
896         // low round: same as high round, but no rotation and no rcon.
897 _vpaes_schedule_low_round:
898         // smear xmm7
899         ext     v1.16b, v4.16b, v7.16b, #12     // vpslldq      \$4,    %xmm7,  %xmm1
900         eor     v7.16b, v7.16b, v1.16b          // vpxor        %xmm1,  %xmm7,  %xmm7
901         ext     v4.16b, v4.16b, v7.16b, #8      // vpslldq      \$8,    %xmm7,  %xmm4
902
903         // subbytes
904         and     v1.16b, v0.16b, v17.16b         // vpand        %xmm9,  %xmm0,  %xmm1           # 0 = k
905         ushr    v0.16b, v0.16b, #4              // vpsrlb       \$4,    %xmm0,  %xmm0           # 1 = i
906          eor    v7.16b, v7.16b, v4.16b          // vpxor        %xmm4,  %xmm7,  %xmm7
907         tbl     v2.16b, {$invhi}, v1.16b        // vpshufb      %xmm1,  %xmm11, %xmm2           # 2 = a/k
908         eor     v1.16b, v1.16b, v0.16b          // vpxor        %xmm0,  %xmm1,  %xmm1           # 0 = j
909         tbl     v3.16b, {$invlo}, v0.16b        // vpshufb      %xmm0,  %xmm10, %xmm3           # 3 = 1/i
910         eor     v3.16b, v3.16b, v2.16b          // vpxor        %xmm2,  %xmm3,  %xmm3           # 3 = iak = 1/i + a/k
911         tbl     v4.16b, {$invlo}, v1.16b        // vpshufb      %xmm1,  %xmm10, %xmm4           # 4 = 1/j
912          eor    v7.16b, v7.16b, v16.16b         // vpxor        .Lk_s63(%rip),  %xmm7,  %xmm7
913         tbl     v3.16b, {$invlo}, v3.16b        // vpshufb      %xmm3,  %xmm10, %xmm3           # 2 = 1/iak
914         eor     v4.16b, v4.16b, v2.16b          // vpxor        %xmm2,  %xmm4,  %xmm4           # 4 = jak = 1/j + a/k
915         tbl     v2.16b, {$invlo}, v4.16b        // vpshufb      %xmm4,  %xmm10, %xmm2           # 3 = 1/jak
916         eor     v3.16b, v3.16b, v1.16b          // vpxor        %xmm1,  %xmm3,  %xmm3           # 2 = io
917         eor     v2.16b, v2.16b, v0.16b          // vpxor        %xmm0,  %xmm2,  %xmm2           # 3 = jo
918         tbl     v4.16b, {v23.16b}, v3.16b       // vpshufb      %xmm3,  %xmm13, %xmm4           # 4 = sbou
919         tbl     v1.16b, {v22.16b}, v2.16b       // vpshufb      %xmm2,  %xmm12, %xmm1           # 0 = sb1t
920         eor     v1.16b, v1.16b, v4.16b          // vpxor        %xmm4,  %xmm1,  %xmm1           # 0 = sbox output
921
922         // add in smeared stuff
923         eor     v0.16b, v1.16b, v7.16b          // vpxor        %xmm7,  %xmm1,  %xmm0
924         eor     v7.16b, v1.16b, v7.16b          // vmovdqa      %xmm0,  %xmm7
925         ret
926 .size   _vpaes_schedule_round,.-_vpaes_schedule_round
927
928 ##
929 ##  .aes_schedule_transform
930 ##
931 ##  Linear-transform %xmm0 according to tables at (%r11)
932 ##
933 ##  Requires that %xmm9 = 0x0F0F... as in preheat
934 ##  Output in %xmm0
935 ##  Clobbers %xmm1, %xmm2
936 ##
937 .type   _vpaes_schedule_transform,%function
938 .align  4
939 _vpaes_schedule_transform:
940         and     v1.16b, v0.16b, v17.16b         // vpand        %xmm9,  %xmm0,  %xmm1
941         ushr    v0.16b, v0.16b, #4              // vpsrlb       \$4,    %xmm0,  %xmm0
942                                                 // vmovdqa      (%r11), %xmm2   # lo
943         tbl     v2.16b, {$iptlo}, v1.16b        // vpshufb      %xmm1,  %xmm2,  %xmm2
944                                                 // vmovdqa      16(%r11),       %xmm1 # hi
945         tbl     v0.16b, {$ipthi}, v0.16b        // vpshufb      %xmm0,  %xmm1,  %xmm0
946         eor     v0.16b, v0.16b, v2.16b          // vpxor        %xmm2,  %xmm0,  %xmm0
947         ret
948 .size   _vpaes_schedule_transform,.-_vpaes_schedule_transform
949
950 ##
951 ##  .aes_schedule_mangle
952 ##
953 ##  Mangle xmm0 from (basis-transformed) standard version
954 ##  to our version.
955 ##
956 ##  On encrypt,
957 ##    xor with 0x63
958 ##    multiply by circulant 0,1,1,1
959 ##    apply shiftrows transform
960 ##
961 ##  On decrypt,
962 ##    xor with 0x63
963 ##    multiply by "inverse mixcolumns" circulant E,B,D,9
964 ##    deskew
965 ##    apply shiftrows transform
966 ##
967 ##
968 ##  Writes out to (%rdx), and increments or decrements it
969 ##  Keeps track of round number mod 4 in %r8
970 ##  Preserves xmm0
971 ##  Clobbers xmm1-xmm5
972 ##
973 .type   _vpaes_schedule_mangle,%function
974 .align  4
975 _vpaes_schedule_mangle:
976         mov     v4.16b, v0.16b                  // vmovdqa      %xmm0,  %xmm4   # save xmm0 for later
977                                                 // vmovdqa      .Lk_mc_forward(%rip),%xmm5
978         cbnz    $dir, .Lschedule_mangle_dec
979
980         // encrypting
981         eor     v4.16b, v0.16b, v16.16b         // vpxor        .Lk_s63(%rip),  %xmm0,  %xmm4
982         add     $out, $out, #16                 // add  \$16,   %rdx
983         tbl     v4.16b, {v4.16b}, v9.16b        // vpshufb      %xmm5,  %xmm4,  %xmm4
984         tbl     v1.16b, {v4.16b}, v9.16b        // vpshufb      %xmm5,  %xmm4,  %xmm1
985         tbl     v3.16b, {v1.16b}, v9.16b        // vpshufb      %xmm5,  %xmm1,  %xmm3
986         eor     v4.16b, v4.16b, v1.16b          // vpxor        %xmm1,  %xmm4,  %xmm4
987         ld1     {v1.2d}, [x8]                   // vmovdqa      (%r8,%r10),     %xmm1
988         eor     v3.16b, v3.16b, v4.16b          // vpxor        %xmm4,  %xmm3,  %xmm3
989
990         b       .Lschedule_mangle_both
991 .align  4
992 .Lschedule_mangle_dec:
993         // inverse mix columns
994                                                 // lea  .Lk_dksd(%rip),%r11
995         ushr    v1.16b, v4.16b, #4              // vpsrlb       \$4,    %xmm4,  %xmm1   # 1 = hi
996         and     v4.16b, v4.16b, v17.16b         // vpand        %xmm9,  %xmm4,  %xmm4   # 4 = lo
997
998                                                 // vmovdqa      0x00(%r11),     %xmm2
999         tbl     v2.16b, {v24.16b}, v4.16b       // vpshufb      %xmm4,  %xmm2,  %xmm2
1000                                                 // vmovdqa      0x10(%r11),     %xmm3
1001         tbl     v3.16b, {v25.16b}, v1.16b       // vpshufb      %xmm1,  %xmm3,  %xmm3
1002         eor     v3.16b, v3.16b, v2.16b          // vpxor        %xmm2,  %xmm3,  %xmm3
1003         tbl     v3.16b, {v3.16b}, v9.16b        // vpshufb      %xmm5,  %xmm3,  %xmm3
1004
1005                                                 // vmovdqa      0x20(%r11),     %xmm2
1006         tbl     v2.16b, {v26.16b}, v4.16b       // vpshufb      %xmm4,  %xmm2,  %xmm2
1007         eor     v2.16b, v2.16b, v3.16b          // vpxor        %xmm3,  %xmm2,  %xmm2
1008                                                 // vmovdqa      0x30(%r11),     %xmm3
1009         tbl     v3.16b, {v27.16b}, v1.16b       // vpshufb      %xmm1,  %xmm3,  %xmm3
1010         eor     v3.16b, v3.16b, v2.16b          // vpxor        %xmm2,  %xmm3,  %xmm3
1011         tbl     v3.16b, {v3.16b}, v9.16b        // vpshufb      %xmm5,  %xmm3,  %xmm3
1012
1013                                                 // vmovdqa      0x40(%r11),     %xmm2
1014         tbl     v2.16b, {v28.16b}, v4.16b       // vpshufb      %xmm4,  %xmm2,  %xmm2
1015         eor     v2.16b, v2.16b, v3.16b          // vpxor        %xmm3,  %xmm2,  %xmm2
1016                                                 // vmovdqa      0x50(%r11),     %xmm3
1017         tbl     v3.16b, {v29.16b}, v1.16b       // vpshufb      %xmm1,  %xmm3,  %xmm3
1018         eor     v3.16b, v3.16b, v2.16b          // vpxor        %xmm2,  %xmm3,  %xmm3
1019
1020                                                 // vmovdqa      0x60(%r11),     %xmm2
1021         tbl     v2.16b, {v30.16b}, v4.16b       // vpshufb      %xmm4,  %xmm2,  %xmm2
1022         tbl     v3.16b, {v3.16b}, v9.16b        // vpshufb      %xmm5,  %xmm3,  %xmm3
1023                                                 // vmovdqa      0x70(%r11),     %xmm4
1024         tbl     v4.16b, {v31.16b}, v1.16b       // vpshufb      %xmm1,  %xmm4,  %xmm4
1025         ld1     {v1.2d}, [x8]                   // vmovdqa      (%r8,%r10),     %xmm1
1026         eor     v2.16b, v2.16b, v3.16b          // vpxor        %xmm3,  %xmm2,  %xmm2
1027         eor     v3.16b, v4.16b, v2.16b          // vpxor        %xmm2,  %xmm4,  %xmm3
1028
1029         sub     $out, $out, #16                 // add  \$-16,  %rdx
1030
1031 .Lschedule_mangle_both:
1032         tbl     v3.16b, {v3.16b}, v1.16b        // vpshufb      %xmm1,  %xmm3,  %xmm3
1033         add     x8, x8, #64-16                  // add  \$-16,  %r8
1034         and     x8, x8, #~(1<<6)                // and  \$0x30, %r8
1035         st1     {v3.2d}, [$out]                 // vmovdqu      %xmm3,  (%rdx)
1036         ret
1037 .size   _vpaes_schedule_mangle,.-_vpaes_schedule_mangle
1038
1039 .globl  vpaes_set_encrypt_key
1040 .type   vpaes_set_encrypt_key,%function
1041 .align  4
1042 vpaes_set_encrypt_key:
1043         stp     x29,x30,[sp,#-16]!
1044         add     x29,sp,#0
1045         stp     d8,d9,[sp,#-16]!        // ABI spec says so
1046
1047         lsr     w9, $bits, #5           // shr  \$5,%eax
1048         add     w9, w9, #5              // \$5,%eax
1049         str     w9, [$out,#240]         // mov  %eax,240(%rdx)  # AES_KEY->rounds = nbits/32+5;
1050
1051         mov     $dir, #0                // mov  \$0,%ecx
1052         mov     x8, #0x30               // mov  \$0x30,%r8d
1053         bl      _vpaes_schedule_core
1054         eor     x0, x0, x0
1055
1056         ldp     d8,d9,[sp],#16
1057         ldp     x29,x30,[sp],#16
1058         ret
1059 .size   vpaes_set_encrypt_key,.-vpaes_set_encrypt_key
1060
1061 .globl  vpaes_set_decrypt_key
1062 .type   vpaes_set_decrypt_key,%function
1063 .align  4
1064 vpaes_set_decrypt_key:
1065         stp     x29,x30,[sp,#-16]!
1066         add     x29,sp,#0
1067         stp     d8,d9,[sp,#-16]!        // ABI spec says so
1068
1069         lsr     w9, $bits, #5           // shr  \$5,%eax
1070         add     w9, w9, #5              // \$5,%eax
1071         str     w9, [$out,#240]         // mov  %eax,240(%rdx)  # AES_KEY->rounds = nbits/32+5;
1072         lsl     w9, w9, #4              // shl  \$4,%eax
1073         add     $out, $out, #16         // lea  16(%rdx,%rax),%rdx
1074         add     $out, $out, x9
1075
1076         mov     $dir, #1                // mov  \$1,%ecx
1077         lsr     w8, $bits, #1           // shr  \$1,%r8d
1078         and     x8, x8, #32             // and  \$32,%r8d
1079         eor     x8, x8, #32             // xor  \$32,%r8d       # nbits==192?0:32
1080         bl      _vpaes_schedule_core
1081
1082         ldp     d8,d9,[sp],#16
1083         ldp     x29,x30,[sp],#16
1084         ret
1085 .size   vpaes_set_decrypt_key,.-vpaes_set_decrypt_key
1086 ___
1087 }
1088 {
1089 my ($inp,$out,$len,$key,$ivec,$dir) = map("x$_",(0..5));
1090
1091 $code.=<<___;
1092 .globl  vpaes_cbc_encrypt
1093 .type   vpaes_cbc_encrypt,%function
1094 .align  4
1095 vpaes_cbc_encrypt:
1096         cbz     $len, .Lcbc_abort
1097         cmp     w5, #0                  // check direction
1098         b.eq    vpaes_cbc_decrypt
1099
1100         stp     x29,x30,[sp,#-16]!
1101         add     x29,sp,#0
1102
1103         mov     x17, $len               // reassign
1104         mov     x2,  $key               // reassign
1105
1106         ld1     {v0.16b}, [$ivec]       // load ivec
1107         bl      _vpaes_encrypt_preheat
1108         b       .Lcbc_enc_loop
1109
1110 .align  4
1111 .Lcbc_enc_loop:
1112         ld1     {v7.16b}, [$inp],#16    // load input
1113         eor     v7.16b, v7.16b, v0.16b  // xor with ivec
1114         bl      _vpaes_encrypt_core
1115         st1     {v0.16b}, [$out],#16    // save output
1116         subs    x17, x17, #16
1117         b.hi    .Lcbc_enc_loop
1118
1119         st1     {v0.16b}, [$ivec]       // write ivec
1120
1121         ldp     x29,x30,[sp],#16
1122 .Lcbc_abort:
1123         ret
1124 .size   vpaes_cbc_encrypt,.-vpaes_cbc_encrypt
1125
1126 .type   vpaes_cbc_decrypt,%function
1127 .align  4
1128 vpaes_cbc_decrypt:
1129         stp     x29,x30,[sp,#-16]!
1130         add     x29,sp,#0
1131         stp     d8,d9,[sp,#-16]!        // ABI spec says so
1132         stp     d10,d11,[sp,#-16]!
1133         stp     d12,d13,[sp,#-16]!
1134         stp     d14,d15,[sp,#-16]!
1135
1136         mov     x17, $len               // reassign
1137         mov     x2,  $key               // reassign
1138         ld1     {v6.16b}, [$ivec]       // load ivec
1139         bl      _vpaes_decrypt_preheat
1140         tst     x17, #16
1141         b.eq    .Lcbc_dec_loop2x
1142
1143         ld1     {v7.16b}, [$inp], #16   // load input
1144         bl      _vpaes_decrypt_core
1145         eor     v0.16b, v0.16b, v6.16b  // xor with ivec
1146         orr     v6.16b, v7.16b, v7.16b  // next ivec value
1147         st1     {v0.16b}, [$out], #16
1148         subs    x17, x17, #16
1149         b.ls    .Lcbc_dec_done
1150
1151 .align  4
1152 .Lcbc_dec_loop2x:
1153         ld1     {v14.16b,v15.16b}, [$inp], #32
1154         bl      _vpaes_decrypt_2x
1155         eor     v0.16b, v0.16b, v6.16b  // xor with ivec
1156         eor     v1.16b, v1.16b, v14.16b
1157         orr     v6.16b, v15.16b, v15.16b
1158         st1     {v0.16b,v1.16b}, [$out], #32
1159         subs    x17, x17, #32
1160         b.hi    .Lcbc_dec_loop2x
1161
1162 .Lcbc_dec_done:
1163         st1     {v6.16b}, [$ivec]
1164
1165         ldp     d14,d15,[sp],#16
1166         ldp     d12,d13,[sp],#16
1167         ldp     d10,d11,[sp],#16
1168         ldp     d8,d9,[sp],#16
1169         ldp     x29,x30,[sp],#16
1170         ret
1171 .size   vpaes_cbc_decrypt,.-vpaes_cbc_decrypt
1172 ___
1173 if (1) {
1174 $code.=<<___;
1175 .globl  vpaes_ecb_encrypt
1176 .type   vpaes_ecb_encrypt,%function
1177 .align  4
1178 vpaes_ecb_encrypt:
1179         stp     x29,x30,[sp,#-16]!
1180         add     x29,sp,#0
1181         stp     d8,d9,[sp,#-16]!        // ABI spec says so
1182         stp     d10,d11,[sp,#-16]!
1183         stp     d12,d13,[sp,#-16]!
1184         stp     d14,d15,[sp,#-16]!
1185
1186         mov     x17, $len
1187         mov     x2,  $key
1188         bl      _vpaes_encrypt_preheat
1189         tst     x17, #16
1190         b.eq    .Lecb_enc_loop
1191
1192         ld1     {v7.16b}, [$inp],#16
1193         bl      _vpaes_encrypt_core
1194         st1     {v0.16b}, [$out],#16
1195         subs    x17, x17, #16
1196         b.ls    .Lecb_enc_done
1197
1198 .align  4
1199 .Lecb_enc_loop:
1200         ld1     {v14.16b,v15.16b}, [$inp], #32
1201         bl      _vpaes_encrypt_2x
1202         st1     {v0.16b,v1.16b}, [$out], #32
1203         subs    x17, x17, #32
1204         b.hi    .Lecb_enc_loop
1205
1206 .Lecb_enc_done:
1207         ldp     d14,d15,[sp],#16
1208         ldp     d12,d13,[sp],#16
1209         ldp     d10,d11,[sp],#16
1210         ldp     d8,d9,[sp],#16
1211         ldp     x29,x30,[sp],#16
1212         ret
1213 .size   vpaes_ecb_encrypt,.-vpaes_ecb_encrypt
1214
1215 .globl  vpaes_ecb_decrypt
1216 .type   vpaes_ecb_decrypt,%function
1217 .align  4
1218 vpaes_ecb_decrypt:
1219         stp     x29,x30,[sp,#-16]!
1220         add     x29,sp,#0
1221         stp     d8,d9,[sp,#-16]!        // ABI spec says so
1222         stp     d10,d11,[sp,#-16]!
1223         stp     d12,d13,[sp,#-16]!
1224         stp     d14,d15,[sp,#-16]!
1225
1226         mov     x17, $len
1227         mov     x2,  $key
1228         bl      _vpaes_decrypt_preheat
1229         tst     x17, #16
1230         b.eq    .Lecb_dec_loop
1231
1232         ld1     {v7.16b}, [$inp],#16
1233         bl      _vpaes_encrypt_core
1234         st1     {v0.16b}, [$out],#16
1235         subs    x17, x17, #16
1236         b.ls    .Lecb_dec_done
1237
1238 .align  4
1239 .Lecb_dec_loop:
1240         ld1     {v14.16b,v15.16b}, [$inp], #32
1241         bl      _vpaes_decrypt_2x
1242         st1     {v0.16b,v1.16b}, [$out], #32
1243         subs    x17, x17, #32
1244         b.hi    .Lecb_dec_loop
1245
1246 .Lecb_dec_done:
1247         ldp     d14,d15,[sp],#16
1248         ldp     d12,d13,[sp],#16
1249         ldp     d10,d11,[sp],#16
1250         ldp     d8,d9,[sp],#16
1251         ldp     x29,x30,[sp],#16
1252         ret
1253 .size   vpaes_ecb_decrypt,.-vpaes_ecb_decrypt
1254 ___
1255 }       }
1256 print $code;
1257
1258 close STDOUT;