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