c1417a8f74aad6758ad7bed63d0d97d919294935
[openssl.git] / crypto / aes / asm / vpaes-x86.pl
1 #! /usr/bin/env perl
2 # Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the Apache License 2.0 (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 # September 2011.
22 #
23 # Port vpaes-x86_64.pl as 32-bit "almost" drop-in replacement for
24 # aes-586.pl. "Almost" refers to the fact that AES_cbc_encrypt
25 # doesn't handle partial vectors (doesn't have to if called from
26 # EVP only). "Drop-in" implies that this module doesn't share key
27 # schedule structure with the original nor does it make assumption
28 # about its alignment...
29 #
30 # Performance summary. aes-586.pl column lists large-block CBC
31 # encrypt/decrypt/with-hyper-threading-off(*) results in cycles per
32 # byte processed with 128-bit key, and vpaes-x86.pl column - [also
33 # large-block CBC] encrypt/decrypt.
34 #
35 #               aes-586.pl              vpaes-x86.pl
36 #
37 # Core 2(**)    28.1/41.4/18.3          21.9/25.2(***)
38 # Nehalem       27.9/40.4/18.1          10.2/11.9
39 # Atom          70.7/92.1/60.1          61.1/75.4(***)
40 # Silvermont    45.4/62.9/24.1          49.2/61.1(***)
41 #
42 # (*)   "Hyper-threading" in the context refers rather to cache shared
43 #       among multiple cores, than to specifically Intel HTT. As vast
44 #       majority of contemporary cores share cache, slower code path
45 #       is common place. In other words "with-hyper-threading-off"
46 #       results are presented mostly for reference purposes.
47 #
48 # (**)  "Core 2" refers to initial 65nm design, a.k.a. Conroe.
49 #
50 # (***) Less impressive improvement on Core 2 and Atom is due to slow
51 #       pshufb, yet it's respectable +28%/64%  improvement on Core 2
52 #       and +15% on Atom (as implied, over "hyper-threading-safe"
53 #       code path).
54 #
55 #                                               <appro@openssl.org>
56
57 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
58 push(@INC,"${dir}","${dir}../../perlasm");
59 require "x86asm.pl";
60
61 $output = pop and open STDOUT,">$output";
62
63 &asm_init($ARGV[0],$x86only = $ARGV[$#ARGV] eq "386");
64
65 $PREFIX="vpaes";
66
67 my  ($round, $base, $magic, $key, $const, $inp, $out)=
68     ("eax",  "ebx", "ecx",  "edx","ebp",  "esi","edi");
69
70 &static_label("_vpaes_consts");
71 &static_label("_vpaes_schedule_low_round");
72
73 &set_label("_vpaes_consts",64);
74 $k_inv=-0x30;           # inv, inva
75         &data_word(0x0D080180,0x0E05060F,0x0A0B0C02,0x04070309);
76         &data_word(0x0F0B0780,0x01040A06,0x02050809,0x030D0E0C);
77
78 $k_s0F=-0x10;           # s0F
79         &data_word(0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F);
80
81 $k_ipt=0x00;            # input transform (lo, hi)
82         &data_word(0x5A2A7000,0xC2B2E898,0x52227808,0xCABAE090);
83         &data_word(0x317C4D00,0x4C01307D,0xB0FDCC81,0xCD80B1FC);
84
85 $k_sb1=0x20;            # sb1u, sb1t
86         &data_word(0xCB503E00,0xB19BE18F,0x142AF544,0xA5DF7A6E);
87         &data_word(0xFAE22300,0x3618D415,0x0D2ED9EF,0x3BF7CCC1);
88 $k_sb2=0x40;            # sb2u, sb2t
89         &data_word(0x0B712400,0xE27A93C6,0xBC982FCD,0x5EB7E955);
90         &data_word(0x0AE12900,0x69EB8840,0xAB82234A,0xC2A163C8);
91 $k_sbo=0x60;            # sbou, sbot
92         &data_word(0x6FBDC700,0xD0D26D17,0xC502A878,0x15AABF7A);
93         &data_word(0x5FBB6A00,0xCFE474A5,0x412B35FA,0x8E1E90D1);
94
95 $k_mc_forward=0x80;     # mc_forward
96         &data_word(0x00030201,0x04070605,0x080B0A09,0x0C0F0E0D);
97         &data_word(0x04070605,0x080B0A09,0x0C0F0E0D,0x00030201);
98         &data_word(0x080B0A09,0x0C0F0E0D,0x00030201,0x04070605);
99         &data_word(0x0C0F0E0D,0x00030201,0x04070605,0x080B0A09);
100
101 $k_mc_backward=0xc0;    # mc_backward
102         &data_word(0x02010003,0x06050407,0x0A09080B,0x0E0D0C0F);
103         &data_word(0x0E0D0C0F,0x02010003,0x06050407,0x0A09080B);
104         &data_word(0x0A09080B,0x0E0D0C0F,0x02010003,0x06050407);
105         &data_word(0x06050407,0x0A09080B,0x0E0D0C0F,0x02010003);
106
107 $k_sr=0x100;            # sr
108         &data_word(0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C);
109         &data_word(0x0F0A0500,0x030E0904,0x07020D08,0x0B06010C);
110         &data_word(0x0B020900,0x0F060D04,0x030A0108,0x070E050C);
111         &data_word(0x070A0D00,0x0B0E0104,0x0F020508,0x0306090C);
112
113 $k_rcon=0x140;          # rcon
114         &data_word(0xAF9DEEB6,0x1F8391B9,0x4D7C7D81,0x702A9808);
115
116 $k_s63=0x150;           # s63: all equal to 0x63 transformed
117         &data_word(0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B);
118
119 $k_opt=0x160;           # output transform
120         &data_word(0xD6B66000,0xFF9F4929,0xDEBE6808,0xF7974121);
121         &data_word(0x50BCEC00,0x01EDBD51,0xB05C0CE0,0xE10D5DB1);
122
123 $k_deskew=0x180;        # deskew tables: inverts the sbox's "skew"
124         &data_word(0x47A4E300,0x07E4A340,0x5DBEF91A,0x1DFEB95A);
125         &data_word(0x83EA6900,0x5F36B5DC,0xF49D1E77,0x2841C2AB);
126 ##
127 ##  Decryption stuff
128 ##  Key schedule constants
129 ##
130 $k_dksd=0x1a0;          # decryption key schedule: invskew x*D
131         &data_word(0xA3E44700,0xFEB91A5D,0x5A1DBEF9,0x0740E3A4);
132         &data_word(0xB5368300,0x41C277F4,0xAB289D1E,0x5FDC69EA);
133 $k_dksb=0x1c0;          # decryption key schedule: invskew x*B
134         &data_word(0x8550D500,0x9A4FCA1F,0x1CC94C99,0x03D65386);
135         &data_word(0xB6FC4A00,0x115BEDA7,0x7E3482C8,0xD993256F);
136 $k_dkse=0x1e0;          # decryption key schedule: invskew x*E + 0x63
137         &data_word(0x1FC9D600,0xD5031CCA,0x994F5086,0x53859A4C);
138         &data_word(0x4FDC7BE8,0xA2319605,0x20B31487,0xCD5EF96A);
139 $k_dks9=0x200;          # decryption key schedule: invskew x*9
140         &data_word(0x7ED9A700,0xB6116FC8,0x82255BFC,0x4AED9334);
141         &data_word(0x27143300,0x45765162,0xE9DAFDCE,0x8BB89FAC);
142
143 ##
144 ##  Decryption stuff
145 ##  Round function constants
146 ##
147 $k_dipt=0x220;          # decryption input transform
148         &data_word(0x0B545F00,0x0F505B04,0x114E451A,0x154A411E);
149         &data_word(0x60056500,0x86E383E6,0xF491F194,0x12771772);
150
151 $k_dsb9=0x240;          # decryption sbox output *9*u, *9*t
152         &data_word(0x9A86D600,0x851C0353,0x4F994CC9,0xCAD51F50);
153         &data_word(0xECD74900,0xC03B1789,0xB2FBA565,0x725E2C9E);
154 $k_dsbd=0x260;          # decryption sbox output *D*u, *D*t
155         &data_word(0xE6B1A200,0x7D57CCDF,0x882A4439,0xF56E9B13);
156         &data_word(0x24C6CB00,0x3CE2FAF7,0x15DEEFD3,0x2931180D);
157 $k_dsbb=0x280;          # decryption sbox output *B*u, *B*t
158         &data_word(0x96B44200,0xD0226492,0xB0F2D404,0x602646F6);
159         &data_word(0xCD596700,0xC19498A6,0x3255AA6B,0xF3FF0C3E);
160 $k_dsbe=0x2a0;          # decryption sbox output *E*u, *E*t
161         &data_word(0x26D4D000,0x46F29296,0x64B4F6B0,0x22426004);
162         &data_word(0xFFAAC100,0x0C55A6CD,0x98593E32,0x9467F36B);
163 $k_dsbo=0x2c0;          # decryption sbox final output
164         &data_word(0x7EF94000,0x1387EA53,0xD4943E2D,0xC7AA6DB9);
165         &data_word(0x93441D00,0x12D7560F,0xD8C58E9C,0xCA4B8159);
166 &asciz  ("Vector Permutation AES for x86/SSSE3, Mike Hamburg (Stanford University)");
167 &align  (64);
168
169 &function_begin_B("_vpaes_preheat");
170         &add    ($const,&DWP(0,"esp"));
171         &movdqa ("xmm7",&QWP($k_inv,$const));
172         &movdqa ("xmm6",&QWP($k_s0F,$const));
173         &ret    ();
174 &function_end_B("_vpaes_preheat");
175
176 ##
177 ##  _aes_encrypt_core
178 ##
179 ##  AES-encrypt %xmm0.
180 ##
181 ##  Inputs:
182 ##     %xmm0 = input
183 ##     %xmm6-%xmm7 as in _vpaes_preheat
184 ##    (%edx) = scheduled keys
185 ##
186 ##  Output in %xmm0
187 ##  Clobbers  %xmm1-%xmm5, %eax, %ebx, %ecx, %edx
188 ##
189 ##
190 &function_begin_B("_vpaes_encrypt_core");
191         &mov    ($magic,16);
192         &mov    ($round,&DWP(240,$key));
193         &movdqa ("xmm1","xmm6")
194         &movdqa ("xmm2",&QWP($k_ipt,$const));
195         &pandn  ("xmm1","xmm0");
196         &pand   ("xmm0","xmm6");
197         &movdqu ("xmm5",&QWP(0,$key));
198         &pshufb ("xmm2","xmm0");
199         &movdqa ("xmm0",&QWP($k_ipt+16,$const));
200         &pxor   ("xmm2","xmm5");
201         &psrld  ("xmm1",4);
202         &add    ($key,16);
203         &pshufb ("xmm0","xmm1");
204         &lea    ($base,&DWP($k_mc_backward,$const));
205         &pxor   ("xmm0","xmm2");
206         &jmp    (&label("enc_entry"));
207
208
209 &set_label("enc_loop",16);
210         # middle of middle round
211         &movdqa ("xmm4",&QWP($k_sb1,$const));   # 4 : sb1u
212         &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sb1t
213         &pshufb ("xmm4","xmm2");                # 4 = sb1u
214         &pshufb ("xmm0","xmm3");                # 0 = sb1t
215         &pxor   ("xmm4","xmm5");                # 4 = sb1u + k
216         &movdqa ("xmm5",&QWP($k_sb2,$const));   # 4 : sb2u
217         &pxor   ("xmm0","xmm4");                # 0 = A
218         &movdqa ("xmm1",&QWP(-0x40,$base,$magic));# .Lk_mc_forward[]
219         &pshufb ("xmm5","xmm2");                # 4 = sb2u
220         &movdqa ("xmm2",&QWP($k_sb2+16,$const));# 2 : sb2t
221         &movdqa ("xmm4",&QWP(0,$base,$magic));  # .Lk_mc_backward[]
222         &pshufb ("xmm2","xmm3");                # 2 = sb2t
223         &movdqa ("xmm3","xmm0");                # 3 = A
224         &pxor   ("xmm2","xmm5");                # 2 = 2A
225         &pshufb ("xmm0","xmm1");                # 0 = B
226         &add    ($key,16);                      # next key
227         &pxor   ("xmm0","xmm2");                # 0 = 2A+B
228         &pshufb ("xmm3","xmm4");                # 3 = D
229         &add    ($magic,16);                    # next mc
230         &pxor   ("xmm3","xmm0");                # 3 = 2A+B+D
231         &pshufb ("xmm0","xmm1");                # 0 = 2B+C
232         &and    ($magic,0x30);                  # ... mod 4
233         &sub    ($round,1);                     # nr--
234         &pxor   ("xmm0","xmm3");                # 0 = 2A+3B+C+D
235
236 &set_label("enc_entry");
237         # top of round
238         &movdqa ("xmm1","xmm6");                # 1 : i
239         &movdqa ("xmm5",&QWP($k_inv+16,$const));# 2 : a/k
240         &pandn  ("xmm1","xmm0");                # 1 = i<<4
241         &psrld  ("xmm1",4);                     # 1 = i
242         &pand   ("xmm0","xmm6");                # 0 = k
243         &pshufb ("xmm5","xmm0");                # 2 = a/k
244         &movdqa ("xmm3","xmm7");                # 3 : 1/i
245         &pxor   ("xmm0","xmm1");                # 0 = j
246         &pshufb ("xmm3","xmm1");                # 3 = 1/i
247         &movdqa ("xmm4","xmm7");                # 4 : 1/j
248         &pxor   ("xmm3","xmm5");                # 3 = iak = 1/i + a/k
249         &pshufb ("xmm4","xmm0");                # 4 = 1/j
250         &movdqa ("xmm2","xmm7");                # 2 : 1/iak
251         &pxor   ("xmm4","xmm5");                # 4 = jak = 1/j + a/k
252         &pshufb ("xmm2","xmm3");                # 2 = 1/iak
253         &movdqa ("xmm3","xmm7");                # 3 : 1/jak
254         &pxor   ("xmm2","xmm0");                # 2 = io
255         &pshufb ("xmm3","xmm4");                # 3 = 1/jak
256         &movdqu ("xmm5",&QWP(0,$key));
257         &pxor   ("xmm3","xmm1");                # 3 = jo
258         &jnz    (&label("enc_loop"));
259
260         # middle of last round
261         &movdqa ("xmm4",&QWP($k_sbo,$const));   # 3 : sbou      .Lk_sbo
262         &movdqa ("xmm0",&QWP($k_sbo+16,$const));# 3 : sbot      .Lk_sbo+16
263         &pshufb ("xmm4","xmm2");                # 4 = sbou
264         &pxor   ("xmm4","xmm5");                # 4 = sb1u + k
265         &pshufb ("xmm0","xmm3");                # 0 = sb1t
266         &movdqa ("xmm1",&QWP(0x40,$base,$magic));# .Lk_sr[]
267         &pxor   ("xmm0","xmm4");                # 0 = A
268         &pshufb ("xmm0","xmm1");
269         &ret    ();
270 &function_end_B("_vpaes_encrypt_core");
271
272 ##
273 ##  Decryption core
274 ##
275 ##  Same API as encryption core.
276 ##
277 &function_begin_B("_vpaes_decrypt_core");
278         &lea    ($base,&DWP($k_dsbd,$const));
279         &mov    ($round,&DWP(240,$key));
280         &movdqa ("xmm1","xmm6");
281         &movdqa ("xmm2",&QWP($k_dipt-$k_dsbd,$base));
282         &pandn  ("xmm1","xmm0");
283         &mov    ($magic,$round);
284         &psrld  ("xmm1",4)
285         &movdqu ("xmm5",&QWP(0,$key));
286         &shl    ($magic,4);
287         &pand   ("xmm0","xmm6");
288         &pshufb ("xmm2","xmm0");
289         &movdqa ("xmm0",&QWP($k_dipt-$k_dsbd+16,$base));
290         &xor    ($magic,0x30);
291         &pshufb ("xmm0","xmm1");
292         &and    ($magic,0x30);
293         &pxor   ("xmm2","xmm5");
294         &movdqa ("xmm5",&QWP($k_mc_forward+48,$const));
295         &pxor   ("xmm0","xmm2");
296         &add    ($key,16);
297         &lea    ($magic,&DWP($k_sr-$k_dsbd,$base,$magic));
298         &jmp    (&label("dec_entry"));
299
300 &set_label("dec_loop",16);
301 ##
302 ##  Inverse mix columns
303 ##
304         &movdqa ("xmm4",&QWP(-0x20,$base));     # 4 : sb9u
305         &movdqa ("xmm1",&QWP(-0x10,$base));     # 0 : sb9t
306         &pshufb ("xmm4","xmm2");                # 4 = sb9u
307         &pshufb ("xmm1","xmm3");                # 0 = sb9t
308         &pxor   ("xmm0","xmm4");
309         &movdqa ("xmm4",&QWP(0,$base));         # 4 : sbdu
310         &pxor   ("xmm0","xmm1");                # 0 = ch
311         &movdqa ("xmm1",&QWP(0x10,$base));      # 0 : sbdt
312
313         &pshufb ("xmm4","xmm2");                # 4 = sbdu
314         &pshufb ("xmm0","xmm5");                # MC ch
315         &pshufb ("xmm1","xmm3");                # 0 = sbdt
316         &pxor   ("xmm0","xmm4");                # 4 = ch
317         &movdqa ("xmm4",&QWP(0x20,$base));      # 4 : sbbu
318         &pxor   ("xmm0","xmm1");                # 0 = ch
319         &movdqa ("xmm1",&QWP(0x30,$base));      # 0 : sbbt
320
321         &pshufb ("xmm4","xmm2");                # 4 = sbbu
322         &pshufb ("xmm0","xmm5");                # MC ch
323         &pshufb ("xmm1","xmm3");                # 0 = sbbt
324         &pxor   ("xmm0","xmm4");                # 4 = ch
325         &movdqa ("xmm4",&QWP(0x40,$base));      # 4 : sbeu
326         &pxor   ("xmm0","xmm1");                # 0 = ch
327         &movdqa ("xmm1",&QWP(0x50,$base));      # 0 : sbet
328
329         &pshufb ("xmm4","xmm2");                # 4 = sbeu
330         &pshufb ("xmm0","xmm5");                # MC ch
331         &pshufb ("xmm1","xmm3");                # 0 = sbet
332         &pxor   ("xmm0","xmm4");                # 4 = ch
333         &add    ($key,16);                      # next round key
334         &palignr("xmm5","xmm5",12);
335         &pxor   ("xmm0","xmm1");                # 0 = ch
336         &sub    ($round,1);                     # nr--
337
338 &set_label("dec_entry");
339         # top of round
340         &movdqa ("xmm1","xmm6");                # 1 : i
341         &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k
342         &pandn  ("xmm1","xmm0");                # 1 = i<<4
343         &pand   ("xmm0","xmm6");                # 0 = k
344         &psrld  ("xmm1",4);                     # 1 = i
345         &pshufb ("xmm2","xmm0");                # 2 = a/k
346         &movdqa ("xmm3","xmm7");                # 3 : 1/i
347         &pxor   ("xmm0","xmm1");                # 0 = j
348         &pshufb ("xmm3","xmm1");                # 3 = 1/i
349         &movdqa ("xmm4","xmm7");                # 4 : 1/j
350         &pxor   ("xmm3","xmm2");                # 3 = iak = 1/i + a/k
351         &pshufb ("xmm4","xmm0");                # 4 = 1/j
352         &pxor   ("xmm4","xmm2");                # 4 = jak = 1/j + a/k
353         &movdqa ("xmm2","xmm7");                # 2 : 1/iak
354         &pshufb ("xmm2","xmm3");                # 2 = 1/iak
355         &movdqa ("xmm3","xmm7");                # 3 : 1/jak
356         &pxor   ("xmm2","xmm0");                # 2 = io
357         &pshufb ("xmm3","xmm4");                # 3 = 1/jak
358         &movdqu ("xmm0",&QWP(0,$key));
359         &pxor   ("xmm3","xmm1");                # 3 = jo
360         &jnz    (&label("dec_loop"));
361
362         # middle of last round
363         &movdqa ("xmm4",&QWP(0x60,$base));      # 3 : sbou
364         &pshufb ("xmm4","xmm2");                # 4 = sbou
365         &pxor   ("xmm4","xmm0");                # 4 = sb1u + k
366         &movdqa ("xmm0",&QWP(0x70,$base));      # 0 : sbot
367         &movdqa ("xmm2",&QWP(0,$magic));
368         &pshufb ("xmm0","xmm3");                # 0 = sb1t
369         &pxor   ("xmm0","xmm4");                # 0 = A
370         &pshufb ("xmm0","xmm2");
371         &ret    ();
372 &function_end_B("_vpaes_decrypt_core");
373
374 ########################################################
375 ##                                                    ##
376 ##                  AES key schedule                  ##
377 ##                                                    ##
378 ########################################################
379 &function_begin_B("_vpaes_schedule_core");
380         &add    ($const,&DWP(0,"esp"));
381         &movdqu ("xmm0",&QWP(0,$inp));          # load key (unaligned)
382         &movdqa ("xmm2",&QWP($k_rcon,$const));  # load rcon
383
384         # input transform
385         &movdqa ("xmm3","xmm0");
386         &lea    ($base,&DWP($k_ipt,$const));
387         &movdqa (&QWP(4,"esp"),"xmm2");         # xmm8
388         &call   ("_vpaes_schedule_transform");
389         &movdqa ("xmm7","xmm0");
390
391         &test   ($out,$out);
392         &jnz    (&label("schedule_am_decrypting"));
393
394         # encrypting, output zeroth round key after transform
395         &movdqu (&QWP(0,$key),"xmm0");
396         &jmp    (&label("schedule_go"));
397
398 &set_label("schedule_am_decrypting");
399         # decrypting, output zeroth round key after shiftrows
400         &movdqa ("xmm1",&QWP($k_sr,$const,$magic));
401         &pshufb ("xmm3","xmm1");
402         &movdqu (&QWP(0,$key),"xmm3");
403         &xor    ($magic,0x30);
404
405 &set_label("schedule_go");
406         &cmp    ($round,192);
407         &ja     (&label("schedule_256"));
408         &je     (&label("schedule_192"));
409         # 128: fall though
410
411 ##
412 ##  .schedule_128
413 ##
414 ##  128-bit specific part of key schedule.
415 ##
416 ##  This schedule is really simple, because all its parts
417 ##  are accomplished by the subroutines.
418 ##
419 &set_label("schedule_128");
420         &mov    ($round,10);
421
422 &set_label("loop_schedule_128");
423         &call   ("_vpaes_schedule_round");
424         &dec    ($round);
425         &jz     (&label("schedule_mangle_last"));
426         &call   ("_vpaes_schedule_mangle");     # write output
427         &jmp    (&label("loop_schedule_128"));
428
429 ##
430 ##  .aes_schedule_192
431 ##
432 ##  192-bit specific part of key schedule.
433 ##
434 ##  The main body of this schedule is the same as the 128-bit
435 ##  schedule, but with more smearing.  The long, high side is
436 ##  stored in %xmm7 as before, and the short, low side is in
437 ##  the high bits of %xmm6.
438 ##
439 ##  This schedule is somewhat nastier, however, because each
440 ##  round produces 192 bits of key material, or 1.5 round keys.
441 ##  Therefore, on each cycle we do 2 rounds and produce 3 round
442 ##  keys.
443 ##
444 &set_label("schedule_192",16);
445         &movdqu ("xmm0",&QWP(8,$inp));          # load key part 2 (very unaligned)
446         &call   ("_vpaes_schedule_transform");  # input transform
447         &movdqa ("xmm6","xmm0");                # save short part
448         &pxor   ("xmm4","xmm4");                # clear 4
449         &movhlps("xmm6","xmm4");                # clobber low side with zeros
450         &mov    ($round,4);
451
452 &set_label("loop_schedule_192");
453         &call   ("_vpaes_schedule_round");
454         &palignr("xmm0","xmm6",8);
455         &call   ("_vpaes_schedule_mangle");     # save key n
456         &call   ("_vpaes_schedule_192_smear");
457         &call   ("_vpaes_schedule_mangle");     # save key n+1
458         &call   ("_vpaes_schedule_round");
459         &dec    ($round);
460         &jz     (&label("schedule_mangle_last"));
461         &call   ("_vpaes_schedule_mangle");     # save key n+2
462         &call   ("_vpaes_schedule_192_smear");
463         &jmp    (&label("loop_schedule_192"));
464
465 ##
466 ##  .aes_schedule_256
467 ##
468 ##  256-bit specific part of key schedule.
469 ##
470 ##  The structure here is very similar to the 128-bit
471 ##  schedule, but with an additional "low side" in
472 ##  %xmm6.  The low side's rounds are the same as the
473 ##  high side's, except no rcon and no rotation.
474 ##
475 &set_label("schedule_256",16);
476         &movdqu ("xmm0",&QWP(16,$inp));         # load key part 2 (unaligned)
477         &call   ("_vpaes_schedule_transform");  # input transform
478         &mov    ($round,7);
479
480 &set_label("loop_schedule_256");
481         &call   ("_vpaes_schedule_mangle");     # output low result
482         &movdqa ("xmm6","xmm0");                # save cur_lo in xmm6
483
484         # high round
485         &call   ("_vpaes_schedule_round");
486         &dec    ($round);
487         &jz     (&label("schedule_mangle_last"));
488         &call   ("_vpaes_schedule_mangle");
489
490         # low round. swap xmm7 and xmm6
491         &pshufd ("xmm0","xmm0",0xFF);
492         &movdqa (&QWP(20,"esp"),"xmm7");
493         &movdqa ("xmm7","xmm6");
494         &call   ("_vpaes_schedule_low_round");
495         &movdqa ("xmm7",&QWP(20,"esp"));
496
497         &jmp    (&label("loop_schedule_256"));
498
499 ##
500 ##  .aes_schedule_mangle_last
501 ##
502 ##  Mangler for last round of key schedule
503 ##  Mangles %xmm0
504 ##    when encrypting, outputs out(%xmm0) ^ 63
505 ##    when decrypting, outputs unskew(%xmm0)
506 ##
507 ##  Always called right before return... jumps to cleanup and exits
508 ##
509 &set_label("schedule_mangle_last",16);
510         # schedule last round key from xmm0
511         &lea    ($base,&DWP($k_deskew,$const));
512         &test   ($out,$out);
513         &jnz    (&label("schedule_mangle_last_dec"));
514
515         # encrypting
516         &movdqa ("xmm1",&QWP($k_sr,$const,$magic));
517         &pshufb ("xmm0","xmm1");                # output permute
518         &lea    ($base,&DWP($k_opt,$const));    # prepare to output transform
519         &add    ($key,32);
520
521 &set_label("schedule_mangle_last_dec");
522         &add    ($key,-16);
523         &pxor   ("xmm0",&QWP($k_s63,$const));
524         &call   ("_vpaes_schedule_transform");  # output transform
525         &movdqu (&QWP(0,$key),"xmm0");          # save last key
526
527         # cleanup
528         &pxor   ("xmm0","xmm0");
529         &pxor   ("xmm1","xmm1");
530         &pxor   ("xmm2","xmm2");
531         &pxor   ("xmm3","xmm3");
532         &pxor   ("xmm4","xmm4");
533         &pxor   ("xmm5","xmm5");
534         &pxor   ("xmm6","xmm6");
535         &pxor   ("xmm7","xmm7");
536         &ret    ();
537 &function_end_B("_vpaes_schedule_core");
538
539 ##
540 ##  .aes_schedule_192_smear
541 ##
542 ##  Smear the short, low side in the 192-bit key schedule.
543 ##
544 ##  Inputs:
545 ##    %xmm7: high side, b  a  x  y
546 ##    %xmm6:  low side, d  c  0  0
547 ##    %xmm13: 0
548 ##
549 ##  Outputs:
550 ##    %xmm6: b+c+d  b+c  0  0
551 ##    %xmm0: b+c+d  b+c  b  a
552 ##
553 &function_begin_B("_vpaes_schedule_192_smear");
554         &pshufd ("xmm1","xmm6",0x80);           # d c 0 0 -> c 0 0 0
555         &pshufd ("xmm0","xmm7",0xFE);           # b a _ _ -> b b b a
556         &pxor   ("xmm6","xmm1");                # -> c+d c 0 0
557         &pxor   ("xmm1","xmm1");
558         &pxor   ("xmm6","xmm0");                # -> b+c+d b+c b a
559         &movdqa ("xmm0","xmm6");
560         &movhlps("xmm6","xmm1");                # clobber low side with zeros
561         &ret    ();
562 &function_end_B("_vpaes_schedule_192_smear");
563
564 ##
565 ##  .aes_schedule_round
566 ##
567 ##  Runs one main round of the key schedule on %xmm0, %xmm7
568 ##
569 ##  Specifically, runs subbytes on the high dword of %xmm0
570 ##  then rotates it by one byte and xors into the low dword of
571 ##  %xmm7.
572 ##
573 ##  Adds rcon from low byte of %xmm8, then rotates %xmm8 for
574 ##  next rcon.
575 ##
576 ##  Smears the dwords of %xmm7 by xoring the low into the
577 ##  second low, result into third, result into highest.
578 ##
579 ##  Returns results in %xmm7 = %xmm0.
580 ##  Clobbers %xmm1-%xmm5.
581 ##
582 &function_begin_B("_vpaes_schedule_round");
583         # extract rcon from xmm8
584         &movdqa ("xmm2",&QWP(8,"esp"));         # xmm8
585         &pxor   ("xmm1","xmm1");
586         &palignr("xmm1","xmm2",15);
587         &palignr("xmm2","xmm2",15);
588         &pxor   ("xmm7","xmm1");
589
590         # rotate
591         &pshufd ("xmm0","xmm0",0xFF);
592         &palignr("xmm0","xmm0",1);
593
594         # fall through...
595         &movdqa (&QWP(8,"esp"),"xmm2");         # xmm8
596
597         # low round: same as high round, but no rotation and no rcon.
598 &set_label("_vpaes_schedule_low_round");
599         # smear xmm7
600         &movdqa ("xmm1","xmm7");
601         &pslldq ("xmm7",4);
602         &pxor   ("xmm7","xmm1");
603         &movdqa ("xmm1","xmm7");
604         &pslldq ("xmm7",8);
605         &pxor   ("xmm7","xmm1");
606         &pxor   ("xmm7",&QWP($k_s63,$const));
607
608         # subbyte
609         &movdqa ("xmm4",&QWP($k_s0F,$const));
610         &movdqa ("xmm5",&QWP($k_inv,$const));   # 4 : 1/j
611         &movdqa ("xmm1","xmm4");
612         &pandn  ("xmm1","xmm0");
613         &psrld  ("xmm1",4);                     # 1 = i
614         &pand   ("xmm0","xmm4");                # 0 = k
615         &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k
616         &pshufb ("xmm2","xmm0");                # 2 = a/k
617         &pxor   ("xmm0","xmm1");                # 0 = j
618         &movdqa ("xmm3","xmm5");                # 3 : 1/i
619         &pshufb ("xmm3","xmm1");                # 3 = 1/i
620         &pxor   ("xmm3","xmm2");                # 3 = iak = 1/i + a/k
621         &movdqa ("xmm4","xmm5");                # 4 : 1/j
622         &pshufb ("xmm4","xmm0");                # 4 = 1/j
623         &pxor   ("xmm4","xmm2");                # 4 = jak = 1/j + a/k
624         &movdqa ("xmm2","xmm5");                # 2 : 1/iak
625         &pshufb ("xmm2","xmm3");                # 2 = 1/iak
626         &pxor   ("xmm2","xmm0");                # 2 = io
627         &movdqa ("xmm3","xmm5");                # 3 : 1/jak
628         &pshufb ("xmm3","xmm4");                # 3 = 1/jak
629         &pxor   ("xmm3","xmm1");                # 3 = jo
630         &movdqa ("xmm4",&QWP($k_sb1,$const));   # 4 : sbou
631         &pshufb ("xmm4","xmm2");                # 4 = sbou
632         &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sbot
633         &pshufb ("xmm0","xmm3");                # 0 = sb1t
634         &pxor   ("xmm0","xmm4");                # 0 = sbox output
635
636         # add in smeared stuff
637         &pxor   ("xmm0","xmm7");
638         &movdqa ("xmm7","xmm0");
639         &ret    ();
640 &function_end_B("_vpaes_schedule_round");
641
642 ##
643 ##  .aes_schedule_transform
644 ##
645 ##  Linear-transform %xmm0 according to tables at (%ebx)
646 ##
647 ##  Output in %xmm0
648 ##  Clobbers %xmm1, %xmm2
649 ##
650 &function_begin_B("_vpaes_schedule_transform");
651         &movdqa ("xmm2",&QWP($k_s0F,$const));
652         &movdqa ("xmm1","xmm2");
653         &pandn  ("xmm1","xmm0");
654         &psrld  ("xmm1",4);
655         &pand   ("xmm0","xmm2");
656         &movdqa ("xmm2",&QWP(0,$base));
657         &pshufb ("xmm2","xmm0");
658         &movdqa ("xmm0",&QWP(16,$base));
659         &pshufb ("xmm0","xmm1");
660         &pxor   ("xmm0","xmm2");
661         &ret    ();
662 &function_end_B("_vpaes_schedule_transform");
663
664 ##
665 ##  .aes_schedule_mangle
666 ##
667 ##  Mangle xmm0 from (basis-transformed) standard version
668 ##  to our version.
669 ##
670 ##  On encrypt,
671 ##    xor with 0x63
672 ##    multiply by circulant 0,1,1,1
673 ##    apply shiftrows transform
674 ##
675 ##  On decrypt,
676 ##    xor with 0x63
677 ##    multiply by "inverse mixcolumns" circulant E,B,D,9
678 ##    deskew
679 ##    apply shiftrows transform
680 ##
681 ##
682 ##  Writes out to (%edx), and increments or decrements it
683 ##  Keeps track of round number mod 4 in %ecx
684 ##  Preserves xmm0
685 ##  Clobbers xmm1-xmm5
686 ##
687 &function_begin_B("_vpaes_schedule_mangle");
688         &movdqa ("xmm4","xmm0");        # save xmm0 for later
689         &movdqa ("xmm5",&QWP($k_mc_forward,$const));
690         &test   ($out,$out);
691         &jnz    (&label("schedule_mangle_dec"));
692
693         # encrypting
694         &add    ($key,16);
695         &pxor   ("xmm4",&QWP($k_s63,$const));
696         &pshufb ("xmm4","xmm5");
697         &movdqa ("xmm3","xmm4");
698         &pshufb ("xmm4","xmm5");
699         &pxor   ("xmm3","xmm4");
700         &pshufb ("xmm4","xmm5");
701         &pxor   ("xmm3","xmm4");
702
703         &jmp    (&label("schedule_mangle_both"));
704
705 &set_label("schedule_mangle_dec",16);
706         # inverse mix columns
707         &movdqa ("xmm2",&QWP($k_s0F,$const));
708         &lea    ($inp,&DWP($k_dksd,$const));
709         &movdqa ("xmm1","xmm2");
710         &pandn  ("xmm1","xmm4");
711         &psrld  ("xmm1",4);                     # 1 = hi
712         &pand   ("xmm4","xmm2");                # 4 = lo
713
714         &movdqa ("xmm2",&QWP(0,$inp));
715         &pshufb ("xmm2","xmm4");
716         &movdqa ("xmm3",&QWP(0x10,$inp));
717         &pshufb ("xmm3","xmm1");
718         &pxor   ("xmm3","xmm2");
719         &pshufb ("xmm3","xmm5");
720
721         &movdqa ("xmm2",&QWP(0x20,$inp));
722         &pshufb ("xmm2","xmm4");
723         &pxor   ("xmm2","xmm3");
724         &movdqa ("xmm3",&QWP(0x30,$inp));
725         &pshufb ("xmm3","xmm1");
726         &pxor   ("xmm3","xmm2");
727         &pshufb ("xmm3","xmm5");
728
729         &movdqa ("xmm2",&QWP(0x40,$inp));
730         &pshufb ("xmm2","xmm4");
731         &pxor   ("xmm2","xmm3");
732         &movdqa ("xmm3",&QWP(0x50,$inp));
733         &pshufb ("xmm3","xmm1");
734         &pxor   ("xmm3","xmm2");
735         &pshufb ("xmm3","xmm5");
736
737         &movdqa ("xmm2",&QWP(0x60,$inp));
738         &pshufb ("xmm2","xmm4");
739         &pxor   ("xmm2","xmm3");
740         &movdqa ("xmm3",&QWP(0x70,$inp));
741         &pshufb ("xmm3","xmm1");
742         &pxor   ("xmm3","xmm2");
743
744         &add    ($key,-16);
745
746 &set_label("schedule_mangle_both");
747         &movdqa ("xmm1",&QWP($k_sr,$const,$magic));
748         &pshufb ("xmm3","xmm1");
749         &add    ($magic,-16);
750         &and    ($magic,0x30);
751         &movdqu (&QWP(0,$key),"xmm3");
752         &ret    ();
753 &function_end_B("_vpaes_schedule_mangle");
754
755 #
756 # Interface to OpenSSL
757 #
758 &function_begin("${PREFIX}_set_encrypt_key");
759         &mov    ($inp,&wparam(0));              # inp
760         &lea    ($base,&DWP(-56,"esp"));
761         &mov    ($round,&wparam(1));            # bits
762         &and    ($base,-16);
763         &mov    ($key,&wparam(2));              # key
764         &xchg   ($base,"esp");                  # alloca
765         &mov    (&DWP(48,"esp"),$base);
766
767         &mov    ($base,$round);
768         &shr    ($base,5);
769         &add    ($base,5);
770         &mov    (&DWP(240,$key),$base);         # AES_KEY->rounds = nbits/32+5;
771         &mov    ($magic,0x30);
772         &mov    ($out,0);
773
774         &lea    ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
775         &call   ("_vpaes_schedule_core");
776 &set_label("pic_point");
777
778         &mov    ("esp",&DWP(48,"esp"));
779         &xor    ("eax","eax");
780 &function_end("${PREFIX}_set_encrypt_key");
781
782 &function_begin("${PREFIX}_set_decrypt_key");
783         &mov    ($inp,&wparam(0));              # inp
784         &lea    ($base,&DWP(-56,"esp"));
785         &mov    ($round,&wparam(1));            # bits
786         &and    ($base,-16);
787         &mov    ($key,&wparam(2));              # key
788         &xchg   ($base,"esp");                  # alloca
789         &mov    (&DWP(48,"esp"),$base);
790
791         &mov    ($base,$round);
792         &shr    ($base,5);
793         &add    ($base,5);
794         &mov    (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5;
795         &shl    ($base,4);
796         &lea    ($key,&DWP(16,$key,$base));
797
798         &mov    ($out,1);
799         &mov    ($magic,$round);
800         &shr    ($magic,1);
801         &and    ($magic,32);
802         &xor    ($magic,32);                    # nbist==192?0:32;
803
804         &lea    ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
805         &call   ("_vpaes_schedule_core");
806 &set_label("pic_point");
807
808         &mov    ("esp",&DWP(48,"esp"));
809         &xor    ("eax","eax");
810 &function_end("${PREFIX}_set_decrypt_key");
811
812 &function_begin("${PREFIX}_encrypt");
813         &lea    ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
814         &call   ("_vpaes_preheat");
815 &set_label("pic_point");
816         &mov    ($inp,&wparam(0));              # inp
817         &lea    ($base,&DWP(-56,"esp"));
818         &mov    ($out,&wparam(1));              # out
819         &and    ($base,-16);
820         &mov    ($key,&wparam(2));              # key
821         &xchg   ($base,"esp");                  # alloca
822         &mov    (&DWP(48,"esp"),$base);
823
824         &movdqu ("xmm0",&QWP(0,$inp));
825         &call   ("_vpaes_encrypt_core");
826         &movdqu (&QWP(0,$out),"xmm0");
827
828         &mov    ("esp",&DWP(48,"esp"));
829 &function_end("${PREFIX}_encrypt");
830
831 &function_begin("${PREFIX}_decrypt");
832         &lea    ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
833         &call   ("_vpaes_preheat");
834 &set_label("pic_point");
835         &mov    ($inp,&wparam(0));              # inp
836         &lea    ($base,&DWP(-56,"esp"));
837         &mov    ($out,&wparam(1));              # out
838         &and    ($base,-16);
839         &mov    ($key,&wparam(2));              # key
840         &xchg   ($base,"esp");                  # alloca
841         &mov    (&DWP(48,"esp"),$base);
842
843         &movdqu ("xmm0",&QWP(0,$inp));
844         &call   ("_vpaes_decrypt_core");
845         &movdqu (&QWP(0,$out),"xmm0");
846
847         &mov    ("esp",&DWP(48,"esp"));
848 &function_end("${PREFIX}_decrypt");
849
850 &function_begin("${PREFIX}_cbc_encrypt");
851         &mov    ($inp,&wparam(0));              # inp
852         &mov    ($out,&wparam(1));              # out
853         &mov    ($round,&wparam(2));            # len
854         &mov    ($key,&wparam(3));              # key
855         &sub    ($round,16);
856         &jc     (&label("cbc_abort"));
857         &lea    ($base,&DWP(-56,"esp"));
858         &mov    ($const,&wparam(4));            # ivp
859         &and    ($base,-16);
860         &mov    ($magic,&wparam(5));            # enc
861         &xchg   ($base,"esp");                  # alloca
862         &movdqu ("xmm1",&QWP(0,$const));        # load IV
863         &sub    ($out,$inp);
864         &mov    (&DWP(48,"esp"),$base);
865
866         &mov    (&DWP(0,"esp"),$out);           # save out
867         &mov    (&DWP(4,"esp"),$key)            # save key
868         &mov    (&DWP(8,"esp"),$const);         # save ivp
869         &mov    ($out,$round);                  # $out works as $len
870
871         &lea    ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
872         &call   ("_vpaes_preheat");
873 &set_label("pic_point");
874         &cmp    ($magic,0);
875         &je     (&label("cbc_dec_loop"));
876         &jmp    (&label("cbc_enc_loop"));
877
878 &set_label("cbc_enc_loop",16);
879         &movdqu ("xmm0",&QWP(0,$inp));          # load input
880         &pxor   ("xmm0","xmm1");                # inp^=iv
881         &call   ("_vpaes_encrypt_core");
882         &mov    ($base,&DWP(0,"esp"));          # restore out
883         &mov    ($key,&DWP(4,"esp"));           # restore key
884         &movdqa ("xmm1","xmm0");
885         &movdqu (&QWP(0,$base,$inp),"xmm0");    # write output
886         &lea    ($inp,&DWP(16,$inp));
887         &sub    ($out,16);
888         &jnc    (&label("cbc_enc_loop"));
889         &jmp    (&label("cbc_done"));
890
891 &set_label("cbc_dec_loop",16);
892         &movdqu ("xmm0",&QWP(0,$inp));          # load input
893         &movdqa (&QWP(16,"esp"),"xmm1");        # save IV
894         &movdqa (&QWP(32,"esp"),"xmm0");        # save future IV
895         &call   ("_vpaes_decrypt_core");
896         &mov    ($base,&DWP(0,"esp"));          # restore out
897         &mov    ($key,&DWP(4,"esp"));           # restore key
898         &pxor   ("xmm0",&QWP(16,"esp"));        # out^=iv
899         &movdqa ("xmm1",&QWP(32,"esp"));        # load next IV
900         &movdqu (&QWP(0,$base,$inp),"xmm0");    # write output
901         &lea    ($inp,&DWP(16,$inp));
902         &sub    ($out,16);
903         &jnc    (&label("cbc_dec_loop"));
904
905 &set_label("cbc_done");
906         &mov    ($base,&DWP(8,"esp"));          # restore ivp
907         &mov    ("esp",&DWP(48,"esp"));
908         &movdqu (&QWP(0,$base),"xmm1");         # write IV
909 &set_label("cbc_abort");
910 &function_end("${PREFIX}_cbc_encrypt");
911
912 &asm_finish();
913
914 close STDOUT;