ea66589a0671b9ca7951538d0b8a5c2fde291900
[openssl.git] / crypto / aes / asm / aes-586.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. Rights for redistribution and usage in source and binary
6 # forms are granted according to the OpenSSL license.
7 # ====================================================================
8 #
9 # Version 4.2.
10 #
11 # You might fail to appreciate this module performance from the first
12 # try. If compared to "vanilla" linux-ia32-icc target, i.e. considered
13 # to be *the* best Intel C compiler without -KPIC, performance appears
14 # to be virtually identical... But try to re-configure with shared
15 # library support... Aha! Intel compiler "suddenly" lags behind by 30%
16 # [on P4, more on others]:-) And if compared to position-independent
17 # code generated by GNU C, this code performs *more* than *twice* as
18 # fast! Yes, all this buzz about PIC means that unlike other hand-
19 # coded implementations, this one was explicitly designed to be safe
20 # to use even in shared library context... This also means that this
21 # code isn't necessarily absolutely fastest "ever," because in order
22 # to achieve position independence an extra register has to be
23 # off-loaded to stack, which affects the benchmark result.
24 #
25 # Special note about instruction choice. Do you recall RC4_INT code
26 # performing poorly on P4? It might be the time to figure out why.
27 # RC4_INT code implies effective address calculations in base+offset*4
28 # form. Trouble is that it seems that offset scaling turned to be
29 # critical path... At least eliminating scaling resulted in 2.8x RC4
30 # performance improvement [as you might recall]. As AES code is hungry
31 # for scaling too, I [try to] avoid the latter by favoring off-by-2
32 # shifts and masking the result with 0xFF<<2 instead of "boring" 0xFF.
33 #
34 # As was shown by Dean Gaudet <dean@arctic.org>, the above note turned
35 # void. Performance improvement with off-by-2 shifts was observed on
36 # intermediate implementation, which was spilling yet another register
37 # to stack... Final offset*4 code below runs just a tad faster on P4,
38 # but exhibits up to 10% improvement on other cores.
39 #
40 # Second version is "monolithic" replacement for aes_core.c, which in
41 # addition to AES_[de|en]crypt implements AES_set_[de|en]cryption_key.
42 # This made it possible to implement little-endian variant of the
43 # algorithm without modifying the base C code. Motivating factor for
44 # the undertaken effort was that it appeared that in tight IA-32
45 # register window little-endian flavor could achieve slightly higher
46 # Instruction Level Parallelism, and it indeed resulted in up to 15%
47 # better performance on most recent µ-archs...
48 #
49 # Third version adds AES_cbc_encrypt implementation, which resulted in
50 # up to 40% performance imrovement of CBC benchmark results. 40% was
51 # observed on P4 core, where "overall" imrovement coefficient, i.e. if
52 # compared to PIC generated by GCC and in CBC mode, was observed to be
53 # as large as 4x:-) CBC performance is virtually identical to ECB now
54 # and on some platforms even better, e.g. 17.6 "small" cycles/byte on
55 # Opteron, because certain function prologues and epilogues are
56 # effectively taken out of the loop...
57 #
58 # Version 3.2 implements compressed tables and prefetch of these tables
59 # in CBC[!] mode. Former means that 3/4 of table references are now
60 # misaligned, which unfortunately has negative impact on elder IA-32
61 # implementations, Pentium suffered 30% penalty, PIII - 10%.
62 #
63 # Version 3.3 avoids L1 cache aliasing between stack frame and
64 # S-boxes, and 3.4 - L1 cache aliasing even between key schedule. The
65 # latter is achieved by copying the key schedule to controlled place in
66 # stack. This unfortunately has rather strong impact on small block CBC
67 # performance, ~2x deterioration on 16-byte block if compared to 3.3.
68 #
69 # Version 3.5 checks if there is L1 cache aliasing between user-supplied
70 # key schedule and S-boxes and abstains from copying the former if
71 # there is no. This allows end-user to consciously retain small block
72 # performance by aligning key schedule in specific manner.
73 #
74 # Version 3.6 compresses Td4 to 256 bytes and prefetches it in ECB.
75 #
76 # Current ECB performance numbers for 128-bit key in CPU cycles per
77 # processed byte [measure commonly used by AES benchmarkers] are:
78 #
79 #               small footprint         fully unrolled
80 # P4            24                      22
81 # AMD K8        20                      19
82 # PIII          25                      23
83 # Pentium       81                      78
84 #
85 # Version 3.7 reimplements outer rounds as "compact." Meaning that
86 # first and last rounds reference compact 256 bytes S-box. This means
87 # that first round consumes a lot more CPU cycles and that encrypt
88 # and decrypt performance becomes asymmetric. Encrypt performance
89 # drops by 10-12%, while decrypt - by 20-25%:-( 256 bytes S-box is
90 # aggressively pre-fetched.
91 #
92 # Version 4.0 effectively rolls back to 3.6 and instead implements
93 # additional set of functions, _[x86|sse]_AES_[en|de]crypt_compact,
94 # which use exclusively 256 byte S-box. These functions are to be
95 # called in modes not concealing plain text, such as ECB, or when
96 # we're asked to process smaller amount of data [or unconditionally
97 # on hyper-threading CPU]. Currently it's called unconditionally from
98 # AES_[en|de]crypt, which affects all modes, but CBC. CBC routine
99 # still needs to be modified to switch between slower and faster
100 # mode when appropriate... But in either case benchmark landscape
101 # changes dramatically and below numbers are CPU cycles per processed
102 # byte for 128-bit key.
103 #
104 #               ECB encrypt     ECB decrypt     CBC large chunk
105 # P4            56[60]          84[100]         23
106 # AMD K8        48[44]          70[79]          18
107 # PIII          41[50]          61[91]          24
108 # Pentium       120             160             77
109 #
110 # Version 4.1 switches to compact S-box even in key schedule setup.
111 #
112 # Version 4.2 prefetches compact S-box in every SSE round or in other
113 # words every cache-line is *guaranteed* to be accessed within ~50
114 # cycles window. Why just SSE? Because it's needed on hyper-threading
115 # CPU! Which is also why it's prefetched with 64 byte stride. Best
116 # part is that it has no negative effect on performance:-)  
117
118 push(@INC,"perlasm","../../perlasm");
119 require "x86asm.pl";
120
121 &asm_init($ARGV[0],"aes-586.pl",$ARGV[$#ARGV] eq "386");
122
123 $s0="eax";
124 $s1="ebx";
125 $s2="ecx";
126 $s3="edx";
127 $key="edi";
128 $acc="esi";
129 $tbl="ebp";
130
131 sub _data_word() { my $i; while(defined($i=shift)) { &data_word($i,$i); } }
132
133 $compromise=0;          # $compromise=128 abstains from copying key
134                         # schedule to stack when encrypting inputs
135                         # shorter than 128 bytes at the cost of
136                         # risksing aliasing with S-boxes. In return
137                         # you get way better, up to +70%, small block
138                         # performance.
139 $small_footprint=1;     # $small_footprint=1 code is ~5% slower [on
140                         # recent µ-archs], but ~5 times smaller!
141                         # I favor compact code to minimize cache
142                         # contention and in hope to "collect" 5% back
143                         # in real-life applications...
144
145 $vertical_spin=0;       # shift "verticaly" defaults to 0, because of
146                         # its proof-of-concept status...
147 # Note that there is no decvert(), as well as last encryption round is
148 # performed with "horizontal" shifts. This is because this "vertical"
149 # implementation [one which groups shifts on a given $s[i] to form a
150 # "column," unlike "horizontal" one, which groups shifts on different
151 # $s[i] to form a "row"] is work in progress. It was observed to run
152 # few percents faster on Intel cores, but not AMD. On AMD K8 core it's
153 # whole 12% slower:-( So we face a trade-off... Shall it be resolved
154 # some day? Till then the code is considered experimental and by
155 # default remains dormant...
156
157 sub encvert()
158 { my ($te,@s) = @_;
159   my $v0 = $acc, $v1 = $key;
160
161         &mov    ($v0,$s[3]);                            # copy s3
162         &mov    (&DWP(4,"esp"),$s[2]);                  # save s2
163         &mov    ($v1,$s[0]);                            # copy s0
164         &mov    (&DWP(8,"esp"),$s[1]);                  # save s1
165
166         &movz   ($s[2],&HB($s[0]));
167         &and    ($s[0],0xFF);
168         &mov    ($s[0],&DWP(0,$te,$s[0],8));            # s0>>0
169         &shr    ($v1,16);
170         &mov    ($s[3],&DWP(3,$te,$s[2],8));            # s0>>8
171         &movz   ($s[1],&HB($v1));
172         &and    ($v1,0xFF);
173         &mov    ($s[2],&DWP(2,$te,$v1,8));              # s0>>16
174          &mov   ($v1,$v0);
175         &mov    ($s[1],&DWP(1,$te,$s[1],8));            # s0>>24
176
177         &and    ($v0,0xFF);
178         &xor    ($s[3],&DWP(0,$te,$v0,8));              # s3>>0
179         &movz   ($v0,&HB($v1));
180         &shr    ($v1,16);
181         &xor    ($s[2],&DWP(3,$te,$v0,8));              # s3>>8
182         &movz   ($v0,&HB($v1));
183         &and    ($v1,0xFF);
184         &xor    ($s[1],&DWP(2,$te,$v1,8));              # s3>>16
185          &mov   ($v1,&DWP(4,"esp"));                    # restore s2
186         &xor    ($s[0],&DWP(1,$te,$v0,8));              # s3>>24
187
188         &mov    ($v0,$v1);
189         &and    ($v1,0xFF);
190         &xor    ($s[2],&DWP(0,$te,$v1,8));              # s2>>0
191         &movz   ($v1,&HB($v0));
192         &shr    ($v0,16);
193         &xor    ($s[1],&DWP(3,$te,$v1,8));              # s2>>8
194         &movz   ($v1,&HB($v0));
195         &and    ($v0,0xFF);
196         &xor    ($s[0],&DWP(2,$te,$v0,8));              # s2>>16
197          &mov   ($v0,&DWP(8,"esp"));                    # restore s1
198         &xor    ($s[3],&DWP(1,$te,$v1,8));              # s2>>24
199
200         &mov    ($v1,$v0);
201         &and    ($v0,0xFF);
202         &xor    ($s[1],&DWP(0,$te,$v0,8));              # s1>>0
203         &movz   ($v0,&HB($v1));
204         &shr    ($v1,16);
205         &xor    ($s[0],&DWP(3,$te,$v0,8));              # s1>>8
206         &movz   ($v0,&HB($v1));
207         &and    ($v1,0xFF);
208         &xor    ($s[3],&DWP(2,$te,$v1,8));              # s1>>16
209          &mov   ($key,&DWP(20,"esp"));                  # reincarnate v1 as key
210         &xor    ($s[2],&DWP(1,$te,$v0,8));              # s1>>24
211 }
212
213 # Another experimental routine, which features "horizontal spin," but
214 # eliminates one reference to stack. Strangely enough runs slower...
215 sub enchoriz()
216 { my $v0 = $key, $v1 = $acc;
217
218         &movz   ($v0,&LB($s0));                 #  3, 2, 1, 0*
219         &rotr   ($s2,8);                        #  8,11,10, 9
220         &mov    ($v1,&DWP(0,$te,$v0,8));        #  0
221         &movz   ($v0,&HB($s1));                 #  7, 6, 5*, 4
222         &rotr   ($s3,16);                       # 13,12,15,14
223         &xor    ($v1,&DWP(3,$te,$v0,8));        #  5
224         &movz   ($v0,&HB($s2));                 #  8,11,10*, 9
225         &rotr   ($s0,16);                       #  1, 0, 3, 2
226         &xor    ($v1,&DWP(2,$te,$v0,8));        # 10
227         &movz   ($v0,&HB($s3));                 # 13,12,15*,14
228         &xor    ($v1,&DWP(1,$te,$v0,8));        # 15, t[0] collected
229         &mov    (&DWP(4,"esp"),$v1);            # t[0] saved
230
231         &movz   ($v0,&LB($s1));                 #  7, 6, 5, 4*
232         &shr    ($s1,16);                       #  -, -, 7, 6
233         &mov    ($v1,&DWP(0,$te,$v0,8));        #  4
234         &movz   ($v0,&LB($s3));                 # 13,12,15,14*
235         &xor    ($v1,&DWP(2,$te,$v0,8));        # 14
236         &movz   ($v0,&HB($s0));                 #  1, 0, 3*, 2
237         &and    ($s3,0xffff0000);               # 13,12, -, -
238         &xor    ($v1,&DWP(1,$te,$v0,8));        #  3
239         &movz   ($v0,&LB($s2));                 #  8,11,10, 9*
240         &or     ($s3,$s1);                      # 13,12, 7, 6
241         &xor    ($v1,&DWP(3,$te,$v0,8));        #  9, t[1] collected
242         &mov    ($s1,$v1);                      #  s[1]=t[1]
243
244         &movz   ($v0,&LB($s0));                 #  1, 0, 3, 2*
245         &shr    ($s2,16);                       #  -, -, 8,11
246         &mov    ($v1,&DWP(2,$te,$v0,8));        #  2
247         &movz   ($v0,&HB($s3));                 # 13,12, 7*, 6
248         &xor    ($v1,&DWP(1,$te,$v0,8));        #  7
249         &movz   ($v0,&HB($s2));                 #  -, -, 8*,11
250         &xor    ($v1,&DWP(0,$te,$v0,8));        #  8
251         &mov    ($v0,$s3);
252         &shr    ($v0,24);                       # 13
253         &xor    ($v1,&DWP(3,$te,$v0,8));        # 13, t[2] collected
254
255         &movz   ($v0,&LB($s2));                 #  -, -, 8,11*
256         &shr    ($s0,24);                       #  1*
257         &mov    ($s2,&DWP(1,$te,$v0,8));        # 11
258         &xor    ($s2,&DWP(3,$te,$s0,8));        #  1
259         &mov    ($s0,&DWP(4,"esp"));            # s[0]=t[0]
260         &movz   ($v0,&LB($s3));                 # 13,12, 7, 6*
261         &shr    ($s3,16);                       #   ,  ,13,12
262         &xor    ($s2,&DWP(2,$te,$v0,8));        #  6
263         &mov    ($key,&DWP(20,"esp"));          # reincarnate v0 as key
264         &and    ($s3,0xff);                     #   ,  ,13,12*
265         &mov    ($s3,&DWP(0,$te,$s3,8));        # 12
266         &xor    ($s3,$s2);                      # s[2]=t[3] collected
267         &mov    ($s2,$v1);                      # s[2]=t[2]
268 }
269
270 # More experimental code... SSE one... Even though this one eliminates
271 # *all* references to stack, it's not faster...
272 sub sse_encbody()
273 {
274         &movz   ($acc,&LB("eax"));              #  0
275         &mov    ("ecx",&DWP(0,$tbl,$acc,8));    #  0
276         &pshufw ("mm2","mm0",0x0d);             #  7, 6, 3, 2
277         &movz   ("edx",&HB("eax"));             #  1
278         &mov    ("edx",&DWP(3,$tbl,"edx",8));   #  1
279         &shr    ("eax",16);                     #  5, 4
280
281         &movz   ($acc,&LB("ebx"));              # 10
282         &xor    ("ecx",&DWP(2,$tbl,$acc,8));    # 10
283         &pshufw ("mm6","mm4",0x08);             # 13,12, 9, 8
284         &movz   ($acc,&HB("ebx"));              # 11
285         &xor    ("edx",&DWP(1,$tbl,$acc,8));    # 11
286         &shr    ("ebx",16);                     # 15,14
287
288         &movz   ($acc,&HB("eax"));              #  5
289         &xor    ("ecx",&DWP(3,$tbl,$acc,8));    #  5
290         &movq   ("mm3",QWP(16,$key));
291         &movz   ($acc,&HB("ebx"));              # 15
292         &xor    ("ecx",&DWP(1,$tbl,$acc,8));    # 15
293         &movd   ("mm0","ecx");                  # t[0] collected
294
295         &movz   ($acc,&LB("eax"));              #  4
296         &mov    ("ecx",&DWP(0,$tbl,$acc,8));    #  4
297         &movd   ("eax","mm2");                  #  7, 6, 3, 2
298         &movz   ($acc,&LB("ebx"));              # 14
299         &xor    ("ecx",&DWP(2,$tbl,$acc,8));    # 14
300         &movd   ("ebx","mm6");                  # 13,12, 9, 8
301
302         &movz   ($acc,&HB("eax"));              #  3
303         &xor    ("ecx",&DWP(1,$tbl,$acc,8));    #  3
304         &movz   ($acc,&HB("ebx"));              #  9
305         &xor    ("ecx",&DWP(3,$tbl,$acc,8));    #  9
306         &movd   ("mm1","ecx");                  # t[1] collected
307
308         &movz   ($acc,&LB("eax"));              #  2
309         &mov    ("ecx",&DWP(2,$tbl,$acc,8));    #  2
310         &shr    ("eax",16);                     #  7, 6
311         &punpckldq      ("mm0","mm1");          # t[0,1] collected
312         &movz   ($acc,&LB("ebx"));              #  8
313         &xor    ("ecx",&DWP(0,$tbl,$acc,8));    #  8
314         &shr    ("ebx",16);                     # 13,12
315
316         &movz   ($acc,&HB("eax"));              #  7
317         &xor    ("ecx",&DWP(1,$tbl,$acc,8));    #  7
318         &pxor   ("mm0","mm3");
319         &movz   ("eax",&LB("eax"));             #  6
320         &xor    ("edx",&DWP(2,$tbl,"eax",8));   #  6
321         &pshufw ("mm1","mm0",0x08);             #  5, 4, 1, 0
322         &movz   ($acc,&HB("ebx"));              # 13
323         &xor    ("ecx",&DWP(3,$tbl,$acc,8));    # 13
324         &xor    ("ecx",&DWP(24,$key));          # t[2]
325         &movd   ("mm4","ecx");                  # t[2] collected
326         &movz   ("ebx",&LB("ebx"));             # 12
327         &xor    ("edx",&DWP(0,$tbl,"ebx",8));   # 12
328         &shr    ("ecx",16);
329         &movd   ("eax","mm1");                  #  5, 4, 1, 0
330         &mov    ("ebx",&DWP(28,$key));          # t[3]
331         &xor    ("ebx","edx");
332         &movd   ("mm5","ebx");                  # t[3] collected
333         &and    ("ebx",0xffff0000);
334         &or     ("ebx","ecx");
335
336         &punpckldq      ("mm4","mm5");          # t[2,3] collected
337 }
338
339 ######################################################################
340 # "Compact" block function
341 ######################################################################
342
343 sub enccompact()
344 { my $Fn = mov;
345   while ($#_>5) { pop(@_); $Fn=sub{}; }
346   my ($i,$te,@s)=@_;
347   my $tmp = $key;
348   my $out = $i==3?$s[0]:$acc;
349
350         # $Fn is used in first compact round and its purpose is to
351         # void restoration of some values from stack, so that after
352         # 4xenccompact with extra argument $key value is left there...
353         if ($i==3)  {   &$Fn    ($key,&DWP(20,"esp"));          }##%edx
354         else        {   &mov    ($out,$s[0]);                   }
355                         &and    ($out,0xFF);
356         if ($i==1)  {   &shr    ($s[0],16);                     }#%ebx[1]
357         if ($i==2)  {   &shr    ($s[0],24);                     }#%ecx[2]
358                         &movz   ($out,&BP(-128,$te,$out,1));
359
360         if ($i==3)  {   $tmp=$s[1];                             }##%eax
361                         &movz   ($tmp,&HB($s[1]));
362                         &movz   ($tmp,&BP(-128,$te,$tmp,1));
363                         &shl    ($tmp,8);
364                         &xor    ($out,$tmp);
365
366         if ($i==3)  {   $tmp=$s[2]; &mov ($s[1],&DWP(4,"esp")); }##%ebx
367         else        {   &mov    ($tmp,$s[2]);
368                         &shr    ($tmp,16);                      }
369         if ($i==2)  {   &and    ($s[1],0xFF);                   }#%edx[2]
370                         &and    ($tmp,0xFF);
371                         &movz   ($tmp,&BP(-128,$te,$tmp,1));
372                         &shl    ($tmp,16);
373                         &xor    ($out,$tmp);
374
375         if ($i==3)  {   $tmp=$s[3]; &mov ($s[2],&DWP(8,"esp")); }##%ecx
376         elsif($i==2){   &movz   ($tmp,&HB($s[3]));              }#%ebx[2]
377         else        {   &mov    ($tmp,$s[3]);
378                         &shr    ($tmp,24);                      }
379                         &movz   ($tmp,&BP(-128,$te,$tmp,1));
380                         &shl    ($tmp,24);
381                         &xor    ($out,$tmp);
382         if ($i<2)   {   &mov    (&DWP(4+4*$i,"esp"),$out);      }
383         if ($i==3)  {   &mov    ($s[3],$acc);                   }
384         &comment();
385 }
386
387 sub enctransform()
388 { my @s = ($s0,$s1,$s2,$s3);
389   my $i = shift;
390   my $tmp = $tbl;
391   my $r2  = $key ;
392
393         &mov    ($acc,$s[$i]);
394         &and    ($acc,0x80808080);
395         &mov    ($tmp,$acc);
396         &mov    ($r2,$s[$i]);
397         &shr    ($tmp,7);
398         &and    ($r2,0x7f7f7f7f);
399         &sub    ($acc,$tmp);
400         &lea    ($r2,&DWP(0,$r2,$r2));
401         &and    ($acc,0x1b1b1b1b);
402         &mov    ($tmp,$s[$i]);
403         &xor    ($acc,$r2);     # r2
404
405         &xor    ($s[$i],$acc);  # r0 ^ r2
406         &rotl   ($s[$i],24);
407         &xor    ($s[$i],$acc)   # ROTATE(r2^r0,24) ^ r2
408         &rotr   ($tmp,16);
409         &xor    ($s[$i],$tmp);
410         &rotr   ($tmp,8);
411         &xor    ($s[$i],$tmp);
412 }
413
414 &public_label("AES_Te");
415 &function_begin_B("_x86_AES_encrypt_compact");
416         # note that caller is expected to allocate stack frame for me!
417         &mov    (&DWP(20,"esp"),$key);          # save key
418
419         &xor    ($s0,&DWP(0,$key));             # xor with key
420         &xor    ($s1,&DWP(4,$key));
421         &xor    ($s2,&DWP(8,$key));
422         &xor    ($s3,&DWP(12,$key));
423
424         &mov    ($acc,&DWP(240,$key));          # load key->rounds
425         &lea    ($acc,&DWP(-2,$acc,$acc));
426         &lea    ($acc,&DWP(0,$key,$acc,8));
427         &mov    (&DWP(24,"esp"),$acc);          # end of key schedule
428
429         # prefetch Te4
430         &mov    ($key,&DWP(0-128,$tbl));
431         &mov    ($acc,&DWP(32-128,$tbl));
432         &mov    ($key,&DWP(64-128,$tbl));
433         &mov    ($acc,&DWP(96-128,$tbl));
434         &mov    ($key,&DWP(128-128,$tbl));
435         &mov    ($acc,&DWP(160-128,$tbl));
436         &mov    ($key,&DWP(192-128,$tbl));
437         &mov    ($acc,&DWP(224-128,$tbl));
438
439         &set_label("loop",16);
440
441                 &enccompact(0,$tbl,$s0,$s1,$s2,$s3,1);
442                 &enccompact(1,$tbl,$s1,$s2,$s3,$s0,1);
443                 &enccompact(2,$tbl,$s2,$s3,$s0,$s1,1);
444                 &enccompact(3,$tbl,$s3,$s0,$s1,$s2,1);
445                 &enctransform(2);
446                 &enctransform(3);
447                 &enctransform(0);
448                 &enctransform(1);
449                 &mov    ($key,&DWP(20,"esp"));
450                 &mov    ($tbl,&DWP(28,"esp"));
451                 &add    ($key,16);              # advance rd_key
452                 &xor    ($s0,&DWP(0,$key));
453                 &xor    ($s1,&DWP(4,$key));
454                 &xor    ($s2,&DWP(8,$key));
455                 &xor    ($s3,&DWP(12,$key));
456
457         &cmp    ($key,&DWP(24,"esp"));
458         &mov    (&DWP(20,"esp"),$key);
459         &jb     (&label("loop"));
460
461         &enccompact(0,$tbl,$s0,$s1,$s2,$s3);
462         &enccompact(1,$tbl,$s1,$s2,$s3,$s0);
463         &enccompact(2,$tbl,$s2,$s3,$s0,$s1);
464         &enccompact(3,$tbl,$s3,$s0,$s1,$s2);
465
466         &xor    ($s0,&DWP(16,$key));
467         &xor    ($s1,&DWP(20,$key));
468         &xor    ($s2,&DWP(24,$key));
469         &xor    ($s3,&DWP(28,$key));
470
471         &ret    ();
472 &function_end_B("_x86_AES_encrypt_compact");
473
474 ######################################################################
475 # "Compact" SSE block function.
476 ######################################################################
477 #
478 # Performance is not actually extraordinary in comparison to pure
479 # x86 code. In particular encrypt performance is virtually the same.
480 # Decrypt performance on the other hand is 15-20% better on newer
481 # µ-archs [but we're thankful for *any* improvement here], and ~50%
482 # better on PIII:-) And additionally on the pros side this code
483 # eliminates redundant references to stack and thus relieves/
484 # minimizes the pressure on the memory bus.
485 #
486 # MMX register layout                           lsb
487 # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
488 # |          mm4          |          mm0          |
489 # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
490 # |     s3    |     s2    |     s1    |     s0    |    
491 # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
492 # |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
493 # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
494 #
495 # Indexes translate as s[N/4]>>(8*(N%4)), e.g. 5 means s1>>8.
496 # In this terms encryption and decryption "compact" permutation
497 # matrices can be depicted as following:
498 #
499 # encryption              lsb   # decryption              lsb
500 # +----++----+----+----+----+   # +----++----+----+----+----+
501 # | t0 || 15 | 10 |  5 |  0 |   # | t0 ||  7 | 10 | 13 |  0 |
502 # +----++----+----+----+----+   # +----++----+----+----+----+
503 # | t1 ||  3 | 14 |  9 |  4 |   # | t1 || 11 | 14 |  1 |  4 |
504 # +----++----+----+----+----+   # +----++----+----+----+----+
505 # | t2 ||  7 |  2 | 13 |  8 |   # | t2 || 15 |  2 |  5 |  8 |
506 # +----++----+----+----+----+   # +----++----+----+----+----+
507 # | t3 || 11 |  6 |  1 | 12 |   # | t3 ||  3 |  6 |  9 | 12 |
508 # +----++----+----+----+----+   # +----++----+----+----+----+
509 #
510 ######################################################################
511 # Why not xmm registers? Short answer. It was actually tested and
512 # was not any faster, but *contrary*, most notably on Intel CPUs.
513 # Longer answer. Main advantage of using mm registers is that movd
514 # latency is lower, especially on Intel P4. While arithmetic
515 # instructions are twice as many, they can be scheduled every cycle
516 # and not every second one when they are operating on xmm register,
517 # so that "arithmetic throughput" remains virtually the same. And
518 # finally the code can be executed even on elder SSE-only CPUs:-)
519
520 sub sse_enccompact()
521 {
522         &pshufw ("mm1","mm0",0x08);             #  5, 4, 1, 0
523         &pshufw ("mm5","mm4",0x0d);             # 15,14,11,10
524         &movd   ("eax","mm1");                  #  5, 4, 1, 0
525         &movd   ("ebx","mm5");                  # 15,14,11,10
526
527         &movz   ($acc,&LB("eax"));              #  0
528         &movz   ("ecx",&BP(-128,$tbl,$acc,1));  #  0
529         &pshufw ("mm2","mm0",0x0d);             #  7, 6, 3, 2
530         &movz   ("edx",&HB("eax"));             #  1
531         &movz   ("edx",&BP(-128,$tbl,"edx",1)); #  1
532         &shl    ("edx",8);                      #  1
533         &shr    ("eax",16);                     #  5, 4
534
535         &movz   ($acc,&LB("ebx"));              # 10
536         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 10
537         &shl    ($acc,16);                      # 10
538         &or     ("ecx",$acc);                   # 10
539         &pshufw ("mm6","mm4",0x08);             # 13,12, 9, 8
540         &movz   ($acc,&HB("ebx"));              # 11
541         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 11
542         &shl    ($acc,24);                      # 11
543         &or     ("edx",$acc);                   # 11
544         &shr    ("ebx",16);                     # 15,14
545
546         &movz   ($acc,&HB("eax"));              #  5
547         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  5
548         &shl    ($acc,8);                       #  5
549         &or     ("ecx",$acc);                   #  5
550         &movz   ($acc,&HB("ebx"));              # 15
551         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 15
552         &shl    ($acc,24);                      # 15
553         &or     ("ecx",$acc);                   # 15
554         &movd   ("mm0","ecx");                  # t[0] collected
555
556         &movz   ($acc,&LB("eax"));              #  4
557         &movz   ("ecx",&BP(-128,$tbl,$acc,1));  #  4
558         &movd   ("eax","mm2");                  #  7, 6, 3, 2
559         &movz   ($acc,&LB("ebx"));              # 14
560         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 14
561         &shl    ($acc,16);                      # 14
562         &or     ("ecx",$acc);                   # 14
563
564         &movd   ("ebx","mm6");                  # 13,12, 9, 8
565         &movz   ($acc,&HB("eax"));              #  3
566         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  3
567         &shl    ($acc,24);                      #  3
568         &or     ("ecx",$acc);                   #  3
569         &movz   ($acc,&HB("ebx"));              #  9
570         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  9
571         &shl    ($acc,8);                       #  9
572         &or     ("ecx",$acc);                   #  9
573         &movd   ("mm1","ecx");                  # t[1] collected
574
575         &movz   ($acc,&LB("ebx"));              #  8
576         &movz   ("ecx",&BP(-128,$tbl,$acc,1));  #  8
577         &shr    ("ebx",16);                     # 13,12
578         &movz   ($acc,&LB("eax"));              #  2
579         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  2
580         &shl    ($acc,16);                      #  2
581         &or     ("ecx",$acc);                   #  2
582         &shr    ("eax",16);                     #  7, 6
583
584         &punpckldq      ("mm0","mm1");          # t[0,1] collected
585
586         &movz   ($acc,&HB("eax"));              #  7
587         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  7
588         &shl    ($acc,24);                      #  7
589         &or     ("ecx",$acc);                   #  7
590         &and    ("eax",0xff);                   #  6
591         &movz   ("eax",&BP(-128,$tbl,"eax",1)); #  6
592         &shl    ("eax",16);                     #  6
593         &or     ("edx","eax");                  #  6
594         &movz   ($acc,&HB("ebx"));              # 13
595         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 13
596         &shl    ($acc,8);                       # 13
597         &or     ("ecx",$acc);                   # 13
598         &movd   ("mm4","ecx");                  # t[2] collected
599         &and    ("ebx",0xff);                   # 12
600         &movz   ("ebx",&BP(-128,$tbl,"ebx",1)); # 12
601         &or     ("edx","ebx");                  # 12
602         &movd   ("mm5","edx");                  # t[3] collected
603
604         &punpckldq      ("mm4","mm5");          # t[2,3] collected
605 }
606
607 &public_label("AES_Te");
608 &function_begin_B("_sse_AES_encrypt_compact");
609         &pxor   ("mm0",&QWP(0,$key));   #  7, 6, 5, 4, 3, 2, 1, 0
610         &pxor   ("mm4",&QWP(8,$key));   # 15,14,13,12,11,10, 9, 8
611
612         # note that caller is expected to allocate stack frame for me!
613         &mov    ($acc,&DWP(240,$key));          # load key->rounds
614         &lea    ($acc,&DWP(-2,$acc,$acc));
615         &lea    ($acc,&DWP(0,$key,$acc,8));
616         &mov    (&DWP(24,"esp"),$acc);          # end of key schedule
617
618         &mov    ($s0,0x1b1b1b1b);               # magic constant
619         &mov    (&DWP(8,"esp"),$s0);
620         &mov    (&DWP(12,"esp"),$s0);
621
622         # prefetch Te4
623         &mov    ($s0,&DWP(0-128,$tbl));
624         &mov    ($s1,&DWP(32-128,$tbl));
625         &mov    ($s2,&DWP(64-128,$tbl));
626         &mov    ($s3,&DWP(96-128,$tbl));
627         &mov    ($s0,&DWP(128-128,$tbl));
628         &mov    ($s1,&DWP(160-128,$tbl));
629         &mov    ($s2,&DWP(192-128,$tbl));
630         &mov    ($s3,&DWP(224-128,$tbl));
631
632         &set_label("loop",16);
633                 &sse_enccompact();
634                 &add    ($key,16);
635                 &cmp    ($key,&DWP(24,"esp"));
636                 &ja     (&label("out"));
637
638                 &movq   ("mm2",&QWP(8,"esp"));
639                 &pxor   ("mm3","mm3");          &pxor   ("mm7","mm7");
640                 &movq   ("mm1","mm0");          &movq   ("mm5","mm4");  # r0
641                 &pcmpgtb("mm3","mm0");          &pcmpgtb("mm7","mm4");
642                 &pand   ("mm3","mm2");          &pand   ("mm7","mm2");
643                 &pshufw ("mm2","mm0",0xb1);     &pshufw ("mm6","mm4",0xb1);# ROTATE(r0,16)
644                 &paddb  ("mm0","mm0");          &paddb  ("mm4","mm4");
645                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # = r2
646                 &pshufw ("mm3","mm2",0xb1);     &pshufw ("mm7","mm6",0xb1);# r0
647                 &pxor   ("mm1","mm0");          &pxor   ("mm5","mm4");  # r0^r2
648                 &pxor   ("mm0","mm2");          &pxor   ("mm4","mm6");  # ^= ROTATE(r0,16)
649
650                 &movq   ("mm2","mm3");          &movq   ("mm6","mm7");
651                 &pslld  ("mm3",8);              &pslld  ("mm7",8);
652                 &psrld  ("mm2",24);             &psrld  ("mm6",24);
653                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # ^= r0<<8
654                 &pxor   ("mm0","mm2");          &pxor   ("mm4","mm6");  # ^= r0>>24
655
656                 &movq   ("mm3","mm1");          &movq   ("mm7","mm5");
657                 &movq   ("mm2",&QWP(0,$key));   &movq   ("mm6",&QWP(8,$key));
658                 &psrld  ("mm1",8);              &psrld  ("mm5",8);
659                 &mov    ($s0,&DWP(0-128,$tbl));
660                 &pslld  ("mm3",24);             &pslld  ("mm7",24);
661                 &mov    ($s1,&DWP(64-128,$tbl));
662                 &pxor   ("mm0","mm1");          &pxor   ("mm4","mm5");  # ^= (r2^r0)<<8
663                 &mov    ($s2,&DWP(128-128,$tbl));
664                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # ^= (r2^r0)>>24
665                 &mov    ($s3,&DWP(192-128,$tbl));
666
667                 &pxor   ("mm0","mm2");          &pxor   ("mm4","mm6");
668         &jmp    (&label("loop"));
669
670         &set_label("out",16);
671         &pxor   ("mm0",&QWP(0,$key));
672         &pxor   ("mm4",&QWP(8,$key));
673
674         &ret    ();
675 &function_end_B("_sse_AES_encrypt_compact");
676
677 ######################################################################
678 # Vanilla block function.
679 ######################################################################
680
681 sub encstep()
682 { my ($i,$te,@s) = @_;
683   my $tmp = $key;
684   my $out = $i==3?$s[0]:$acc;
685
686         # lines marked with #%e?x[i] denote "reordered" instructions...
687         if ($i==3)  {   &mov    ($key,&DWP(20,"esp"));          }##%edx
688         else        {   &mov    ($out,$s[0]);
689                         &and    ($out,0xFF);                    }
690         if ($i==1)  {   &shr    ($s[0],16);                     }#%ebx[1]
691         if ($i==2)  {   &shr    ($s[0],24);                     }#%ecx[2]
692                         &mov    ($out,&DWP(0,$te,$out,8));
693
694         if ($i==3)  {   $tmp=$s[1];                             }##%eax
695                         &movz   ($tmp,&HB($s[1]));
696                         &xor    ($out,&DWP(3,$te,$tmp,8));
697
698         if ($i==3)  {   $tmp=$s[2]; &mov ($s[1],&DWP(4,"esp")); }##%ebx
699         else        {   &mov    ($tmp,$s[2]);
700                         &shr    ($tmp,16);                      }
701         if ($i==2)  {   &and    ($s[1],0xFF);                   }#%edx[2]
702                         &and    ($tmp,0xFF);
703                         &xor    ($out,&DWP(2,$te,$tmp,8));
704
705         if ($i==3)  {   $tmp=$s[3]; &mov ($s[2],&DWP(8,"esp")); }##%ecx
706         elsif($i==2){   &movz   ($tmp,&HB($s[3]));              }#%ebx[2]
707         else        {   &mov    ($tmp,$s[3]); 
708                         &shr    ($tmp,24)                       }
709                         &xor    ($out,&DWP(1,$te,$tmp,8));
710         if ($i<2)   {   &mov    (&DWP(4+4*$i,"esp"),$out);      }
711         if ($i==3)  {   &mov    ($s[3],$acc);                   }
712                         &comment();
713 }
714
715 sub enclast()
716 { my ($i,$te,@s)=@_;
717   my $tmp = $key;
718   my $out = $i==3?$s[0]:$acc;
719
720         if ($i==3)  {   &mov    ($key,&DWP(20,"esp"));          }##%edx
721         else        {   &mov    ($out,$s[0]);                   }
722                         &and    ($out,0xFF);
723         if ($i==1)  {   &shr    ($s[0],16);                     }#%ebx[1]
724         if ($i==2)  {   &shr    ($s[0],24);                     }#%ecx[2]
725                         &mov    ($out,&DWP(2,$te,$out,8));
726                         &and    ($out,0x000000ff);
727
728         if ($i==3)  {   $tmp=$s[1];                             }##%eax
729                         &movz   ($tmp,&HB($s[1]));
730                         &mov    ($tmp,&DWP(0,$te,$tmp,8));
731                         &and    ($tmp,0x0000ff00);
732                         &xor    ($out,$tmp);
733
734         if ($i==3)  {   $tmp=$s[2]; &mov ($s[1],&DWP(4,"esp")); }##%ebx
735         else        {   &mov    ($tmp,$s[2]);
736                         &shr    ($tmp,16);                      }
737         if ($i==2)  {   &and    ($s[1],0xFF);                   }#%edx[2]
738                         &and    ($tmp,0xFF);
739                         &mov    ($tmp,&DWP(0,$te,$tmp,8));
740                         &and    ($tmp,0x00ff0000);
741                         &xor    ($out,$tmp);
742
743         if ($i==3)  {   $tmp=$s[3]; &mov ($s[2],&DWP(8,"esp")); }##%ecx
744         elsif($i==2){   &movz   ($tmp,&HB($s[3]));              }#%ebx[2]
745         else        {   &mov    ($tmp,$s[3]);
746                         &shr    ($tmp,24);                      }
747                         &mov    ($tmp,&DWP(2,$te,$tmp,8));
748                         &and    ($tmp,0xff000000);
749                         &xor    ($out,$tmp);
750         if ($i<2)   {   &mov    (&DWP(4+4*$i,"esp"),$out);      }
751         if ($i==3)  {   &mov    ($s[3],$acc);                   }
752 }
753
754 &public_label("AES_Te");
755 &function_begin_B("_x86_AES_encrypt");
756         if ($vertical_spin) {
757                 # I need high parts of volatile registers to be accessible...
758                 &exch   ($s1="edi",$key="ebx");
759                 &mov    ($s2="esi",$acc="ecx");
760         }
761
762         # note that caller is expected to allocate stack frame for me!
763         &mov    (&DWP(20,"esp"),$key);          # save key
764
765         &xor    ($s0,&DWP(0,$key));             # xor with key
766         &xor    ($s1,&DWP(4,$key));
767         &xor    ($s2,&DWP(8,$key));
768         &xor    ($s3,&DWP(12,$key));
769
770         &mov    ($acc,&DWP(240,$key));          # load key->rounds
771
772         if ($small_footprint) {
773             &lea        ($acc,&DWP(-2,$acc,$acc));
774             &lea        ($acc,&DWP(0,$key,$acc,8));
775             &mov        (&DWP(24,"esp"),$acc);  # end of key schedule
776
777             &set_label("loop",16);
778                 if ($vertical_spin) {
779                     &encvert($tbl,$s0,$s1,$s2,$s3);
780                 } else {
781                     &encstep(0,$tbl,$s0,$s1,$s2,$s3);
782                     &encstep(1,$tbl,$s1,$s2,$s3,$s0);
783                     &encstep(2,$tbl,$s2,$s3,$s0,$s1);
784                     &encstep(3,$tbl,$s3,$s0,$s1,$s2);
785                 }
786                 &add    ($key,16);              # advance rd_key
787                 &xor    ($s0,&DWP(0,$key));
788                 &xor    ($s1,&DWP(4,$key));
789                 &xor    ($s2,&DWP(8,$key));
790                 &xor    ($s3,&DWP(12,$key));
791             &cmp        ($key,&DWP(24,"esp"));
792             &mov        (&DWP(20,"esp"),$key);
793             &jb         (&label("loop"));
794         }
795         else {
796             &cmp        ($acc,10);
797             &jle        (&label("10rounds"));
798             &cmp        ($acc,12);
799             &jle        (&label("12rounds"));
800
801         &set_label("14rounds",4);
802             for ($i=1;$i<3;$i++) {
803                 if ($vertical_spin) {
804                     &encvert($tbl,$s0,$s1,$s2,$s3);
805                 } else {
806                     &encstep(0,$tbl,$s0,$s1,$s2,$s3);
807                     &encstep(1,$tbl,$s1,$s2,$s3,$s0);
808                     &encstep(2,$tbl,$s2,$s3,$s0,$s1);
809                     &encstep(3,$tbl,$s3,$s0,$s1,$s2);
810                 }
811                 &xor    ($s0,&DWP(16*$i+0,$key));
812                 &xor    ($s1,&DWP(16*$i+4,$key));
813                 &xor    ($s2,&DWP(16*$i+8,$key));
814                 &xor    ($s3,&DWP(16*$i+12,$key));
815             }
816             &add        ($key,32);
817             &mov        (&DWP(20,"esp"),$key);  # advance rd_key
818         &set_label("12rounds",4);
819             for ($i=1;$i<3;$i++) {
820                 if ($vertical_spin) {
821                     &encvert($tbl,$s0,$s1,$s2,$s3);
822                 } else {
823                     &encstep(0,$tbl,$s0,$s1,$s2,$s3);
824                     &encstep(1,$tbl,$s1,$s2,$s3,$s0);
825                     &encstep(2,$tbl,$s2,$s3,$s0,$s1);
826                     &encstep(3,$tbl,$s3,$s0,$s1,$s2);
827                 }
828                 &xor    ($s0,&DWP(16*$i+0,$key));
829                 &xor    ($s1,&DWP(16*$i+4,$key));
830                 &xor    ($s2,&DWP(16*$i+8,$key));
831                 &xor    ($s3,&DWP(16*$i+12,$key));
832             }
833             &add        ($key,32);
834             &mov        (&DWP(20,"esp"),$key);  # advance rd_key
835         &set_label("10rounds",4);
836             for ($i=1;$i<10;$i++) {
837                 if ($vertical_spin) {
838                     &encvert($tbl,$s0,$s1,$s2,$s3);
839                 } else {
840                     &encstep(0,$tbl,$s0,$s1,$s2,$s3);
841                     &encstep(1,$tbl,$s1,$s2,$s3,$s0);
842                     &encstep(2,$tbl,$s2,$s3,$s0,$s1);
843                     &encstep(3,$tbl,$s3,$s0,$s1,$s2);
844                 }
845                 &xor    ($s0,&DWP(16*$i+0,$key));
846                 &xor    ($s1,&DWP(16*$i+4,$key));
847                 &xor    ($s2,&DWP(16*$i+8,$key));
848                 &xor    ($s3,&DWP(16*$i+12,$key));
849             }
850         }
851
852         if ($vertical_spin) {
853             # "reincarnate" some registers for "horizontal" spin...
854             &mov        ($s1="ebx",$key="edi");
855             &mov        ($s2="ecx",$acc="esi");
856         }
857         &enclast(0,$tbl,$s0,$s1,$s2,$s3);
858         &enclast(1,$tbl,$s1,$s2,$s3,$s0);
859         &enclast(2,$tbl,$s2,$s3,$s0,$s1);
860         &enclast(3,$tbl,$s3,$s0,$s1,$s2);
861
862         &add    ($key,$small_footprint?16:160);
863         &xor    ($s0,&DWP(0,$key));
864         &xor    ($s1,&DWP(4,$key));
865         &xor    ($s2,&DWP(8,$key));
866         &xor    ($s3,&DWP(12,$key));
867
868         &ret    ();
869
870 &set_label("AES_Te",64);        # Yes! I keep it in the code segment!
871         &_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6);
872         &_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591);
873         &_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56);
874         &_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec);
875         &_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa);
876         &_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb);
877         &_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45);
878         &_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b);
879         &_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c);
880         &_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83);
881         &_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9);
882         &_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a);
883         &_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d);
884         &_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f);
885         &_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df);
886         &_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea);
887         &_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34);
888         &_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b);
889         &_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d);
890         &_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413);
891         &_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1);
892         &_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6);
893         &_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972);
894         &_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85);
895         &_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed);
896         &_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511);
897         &_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe);
898         &_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b);
899         &_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05);
900         &_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1);
901         &_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142);
902         &_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf);
903         &_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3);
904         &_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e);
905         &_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a);
906         &_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6);
907         &_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3);
908         &_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b);
909         &_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428);
910         &_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad);
911         &_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14);
912         &_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8);
913         &_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4);
914         &_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2);
915         &_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda);
916         &_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949);
917         &_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf);
918         &_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810);
919         &_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c);
920         &_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697);
921         &_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e);
922         &_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f);
923         &_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc);
924         &_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c);
925         &_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969);
926         &_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27);
927         &_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122);
928         &_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433);
929         &_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9);
930         &_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5);
931         &_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a);
932         &_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0);
933         &_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e);
934         &_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c);
935
936 #Te4    # four copies of Te4 to choose from to avoid L1 aliasing
937         &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
938         &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
939         &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
940         &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
941         &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
942         &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
943         &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
944         &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
945         &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
946         &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
947         &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
948         &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
949         &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
950         &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
951         &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
952         &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
953         &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
954         &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
955         &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
956         &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
957         &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
958         &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
959         &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
960         &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
961         &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
962         &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
963         &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
964         &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
965         &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
966         &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
967         &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
968         &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
969
970         &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
971         &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
972         &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
973         &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
974         &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
975         &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
976         &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
977         &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
978         &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
979         &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
980         &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
981         &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
982         &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
983         &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
984         &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
985         &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
986         &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
987         &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
988         &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
989         &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
990         &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
991         &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
992         &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
993         &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
994         &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
995         &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
996         &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
997         &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
998         &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
999         &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
1000         &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
1001         &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
1002
1003         &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
1004         &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
1005         &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
1006         &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
1007         &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
1008         &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
1009         &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
1010         &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
1011         &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
1012         &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
1013         &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
1014         &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
1015         &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
1016         &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
1017         &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
1018         &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
1019         &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
1020         &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
1021         &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
1022         &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
1023         &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
1024         &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
1025         &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
1026         &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
1027         &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
1028         &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
1029         &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
1030         &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
1031         &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
1032         &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
1033         &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
1034         &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
1035
1036         &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
1037         &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
1038         &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
1039         &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
1040         &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
1041         &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
1042         &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
1043         &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
1044         &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
1045         &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
1046         &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
1047         &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
1048         &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
1049         &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
1050         &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
1051         &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
1052         &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
1053         &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
1054         &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
1055         &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
1056         &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
1057         &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
1058         &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
1059         &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
1060         &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
1061         &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
1062         &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
1063         &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
1064         &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
1065         &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
1066         &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
1067         &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
1068 #rcon:
1069         &data_word(0x00000001, 0x00000002, 0x00000004, 0x00000008);
1070         &data_word(0x00000010, 0x00000020, 0x00000040, 0x00000080);
1071         &data_word(0x0000001b, 0x00000036, 0x00000000, 0x00000000);
1072         &data_word(0x00000000, 0x00000000, 0x00000000, 0x00000000);
1073 &function_end_B("_x86_AES_encrypt");
1074
1075 # void AES_encrypt (const void *inp,void *out,const AES_KEY *key);
1076 &public_label("AES_Te");
1077 &function_begin("AES_encrypt");
1078         &mov    ($acc,&wparam(0));              # load inp
1079         &mov    ($key,&wparam(2));              # load key
1080
1081         &mov    ($s0,"esp");
1082         &sub    ("esp",36);
1083         &and    ("esp",-64);                    # align to cache-line
1084
1085         # place stack frame just "above" the key schedule
1086         &lea    ($s1,&DWP(-64-63,$key));
1087         &sub    ($s1,"esp");
1088         &neg    ($s1);
1089         &and    ($s1,0x3C0);    # modulo 1024, but aligned to cache-line
1090         &sub    ("esp",$s1);
1091         &add    ("esp",4);      # 4 is reserved for caller's return address
1092         &mov    (&DWP(28,"esp"),$s0);           # save stack pointer
1093
1094         &call   (&label("pic_point"));          # make it PIC!
1095         &set_label("pic_point");
1096         &blindpop($tbl);
1097         &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point"));
1098         &lea    ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
1099         # pick Te4 copy which can't "overlap" with stack frame or key schedule
1100         &lea    ($s1,&DWP(768-4,"esp"));
1101         &sub    ($s1,$tbl);
1102         &and    ($s1,0x300);
1103         &lea    ($tbl,&DWP(2048+128,$tbl,$s1));
1104
1105         &bt     (&DWP(0,$s0),25);               # check for SSE bit
1106         &jnc    (&label("x86"));
1107
1108         &movq   ("mm0",&QWP(0,$acc));
1109         &movq   ("mm4",&QWP(8,$acc));
1110         &call   ("_sse_AES_encrypt_compact");
1111         &mov    ("esp",&DWP(28,"esp"));         # restore stack pointer
1112         &mov    ($acc,&wparam(1));              # load out
1113         &movq   (&QWP(0,$acc),"mm0");           # write output data
1114         &movq   (&QWP(8,$acc),"mm4");
1115         &emms   ();
1116         &function_end_A();
1117
1118         &set_label("x86",16);
1119         &mov    (&DWP(24,"esp"),$tbl);
1120         &mov    ($s0,&DWP(0,$acc));             # load input data
1121         &mov    ($s1,&DWP(4,$acc));
1122         &mov    ($s2,&DWP(8,$acc));
1123         &mov    ($s3,&DWP(12,$acc));
1124         &call   ("_x86_AES_encrypt_compact");
1125         &mov    ("esp",&DWP(28,"esp"));         # restore stack pointer
1126         &mov    ($acc,&wparam(1));              # load out
1127         &mov    (&DWP(0,$acc),$s0);             # write output data
1128         &mov    (&DWP(4,$acc),$s1);
1129         &mov    (&DWP(8,$acc),$s2);
1130         &mov    (&DWP(12,$acc),$s3);
1131 &function_end("AES_encrypt");
1132
1133 #--------------------------------------------------------------------#
1134
1135 ######################################################################
1136 # "Compact" block function
1137 ######################################################################
1138
1139 sub deccompact()
1140 { my $Fn = mov;
1141   while ($#_>5) { pop(@_); $Fn=sub{}; }
1142   my ($i,$td,@s)=@_;
1143   my $tmp = $key;
1144   my $out = $i==3?$s[0]:$acc;
1145
1146         # $Fn is used in first compact round and its purpose is to
1147         # void restoration of some values from stack, so that after
1148         # 4xdeccompact with extra argument $key, $s0 and $s1 values
1149         # are left there...
1150         if($i==3)   {   &$Fn    ($key,&DWP(20,"esp"));          }
1151         else        {   &mov    ($out,$s[0]);                   }
1152                         &and    ($out,0xFF);
1153                         &movz   ($out,&BP(-128,$td,$out,1));
1154
1155         if ($i==3)  {   $tmp=$s[1];                             }
1156                         &movz   ($tmp,&HB($s[1]));
1157                         &movz   ($tmp,&BP(-128,$td,$tmp,1));
1158                         &shl    ($tmp,8);
1159                         &xor    ($out,$tmp);
1160
1161         if ($i==3)  {   $tmp=$s[2]; &mov ($s[1],$acc);          }
1162         else        {   mov     ($tmp,$s[2]);                   }
1163                         &shr    ($tmp,16);
1164                         &and    ($tmp,0xFF);
1165                         &movz   ($tmp,&BP(-128,$td,$tmp,1));
1166                         &shl    ($tmp,16);
1167                         &xor    ($out,$tmp);
1168
1169         if ($i==3)  {   $tmp=$s[3]; &$Fn ($s[2],&DWP(8,"esp")); }
1170         else        {   &mov    ($tmp,$s[3]);                   }
1171                         &shr    ($tmp,24);
1172                         &movz   ($tmp,&BP(-128,$td,$tmp,1));
1173                         &shl    ($tmp,24);
1174                         &xor    ($out,$tmp);
1175         if ($i<2)   {   &mov    (&DWP(4+4*$i,"esp"),$out);      }
1176         if ($i==3)  {   &$Fn    ($s[3],&DWP(4,"esp"));          }
1177 }
1178
1179 # must be called with 2,3,0,1 as argument sequence!!!
1180 sub dectransform()
1181 { my @s = ($s0,$s1,$s2,$s3);
1182   my $i = shift;
1183   my $tmp = $key;
1184   my $tp2 = @s[($i+2)%4]; $tp2 = @s[2] if ($i==1);
1185   my $tp4 = @s[($i+3)%4]; $tp4 = @s[3] if ($i==1);
1186   my $tp8 = $tbl;
1187
1188         &mov    ($acc,$s[$i]);
1189         &and    ($acc,0x80808080);
1190         &mov    ($tmp,$acc);
1191         &mov    ($tp2,$s[$i]);
1192         &shr    ($tmp,7);
1193         &and    ($tp2,0x7f7f7f7f);
1194         &sub    ($acc,$tmp);
1195         &add    ($tp2,$tp2);
1196         &and    ($acc,0x1b1b1b1b);
1197         &xor    ($acc,$tp2);
1198         &mov    ($tp2,$acc);
1199
1200         &and    ($acc,0x80808080);
1201         &mov    ($tmp,$acc);
1202         &mov    ($tp4,$tp2);
1203          &xor   ($tp2,$s[$i]);  # tp2^tp1
1204         &shr    ($tmp,7);
1205         &and    ($tp4,0x7f7f7f7f);
1206         &sub    ($acc,$tmp);
1207         &add    ($tp4,$tp4);
1208         &and    ($acc,0x1b1b1b1b);
1209         &xor    ($acc,$tp4);
1210         &mov    ($tp4,$acc);
1211
1212         &and    ($acc,0x80808080);
1213         &mov    ($tmp,$acc);
1214         &mov    ($tp8,$tp4);
1215          &xor   ($tp4,$s[$i]);  # tp4^tp1
1216         &shr    ($tmp,7);
1217         &and    ($tp8,0x7f7f7f7f);
1218         &sub    ($acc,$tmp);
1219         &add    ($tp8,$tp8);
1220         &and    ($acc,0x1b1b1b1b);
1221          &rotl  ($s[$i],8);     # = ROTATE(tp1,8)
1222         &xor    ($tp8,$acc);
1223
1224         &xor    ($s[$i],$tp2);
1225         &xor    ($tp2,$tp8);
1226         &xor    ($s[$i],$tp4);
1227         &rotl   ($tp2,24);
1228         &xor    ($tp4,$tp8);
1229         &xor    ($s[$i],$tp8);  # ^= tp8^(tp4^tp1)^(tp2^tp1)
1230         &rotl   ($tp4,16);
1231         &xor    ($s[$i],$tp2);  # ^= ROTATE(tp8^tp2^tp1,24)
1232         &rotl   ($tp8,8);
1233         &xor    ($s[$i],$tp4);  # ^= ROTATE(tp8^tp4^tp1,16)
1234         &xor    ($s[$i],$tp8);  # ^= ROTATE(tp8,8)
1235
1236         &mov    ($s[0],&DWP(4,"esp"))           if($i==2); #prefetch $s0
1237         &mov    ($s[1],&DWP(8,"esp"))           if($i==3); #prefetch $s1
1238         &mov    ($s[2],&DWP(12,"esp"))          if($i==1);
1239         &mov    ($s[3],&DWP(16,"esp"))          if($i==1);
1240         &mov    (&DWP(4+4*$i,"esp"),$s[$i])     if($i>=2);
1241 }
1242
1243 &public_label("AES_Td");
1244 &function_begin_B("_x86_AES_decrypt_compact");
1245         # note that caller is expected to allocate stack frame for me!
1246         &mov    (&DWP(20,"esp"),$key);          # save key
1247
1248         &xor    ($s0,&DWP(0,$key));             # xor with key
1249         &xor    ($s1,&DWP(4,$key));
1250         &xor    ($s2,&DWP(8,$key));
1251         &xor    ($s3,&DWP(12,$key));
1252
1253         &mov    ($acc,&DWP(240,$key));          # load key->rounds
1254
1255         &lea    ($acc,&DWP(-2,$acc,$acc));
1256         &lea    ($acc,&DWP(0,$key,$acc,8));
1257         &mov    (&DWP(24,"esp"),$acc);          # end of key schedule
1258
1259         # prefetch Td4
1260         &mov    ($key,&DWP(0-128,$tbl));
1261         &mov    ($acc,&DWP(32-128,$tbl));
1262         &mov    ($key,&DWP(64-128,$tbl));
1263         &mov    ($acc,&DWP(96-128,$tbl));
1264         &mov    ($key,&DWP(128-128,$tbl));
1265         &mov    ($acc,&DWP(160-128,$tbl));
1266         &mov    ($key,&DWP(192-128,$tbl));
1267         &mov    ($acc,&DWP(224-128,$tbl));
1268
1269         &set_label("loop",16);
1270
1271                 &deccompact(0,$tbl,$s0,$s3,$s2,$s1,1);
1272                 &deccompact(1,$tbl,$s1,$s0,$s3,$s2,1);
1273                 &deccompact(2,$tbl,$s2,$s1,$s0,$s3,1);
1274                 &deccompact(3,$tbl,$s3,$s2,$s1,$s0,1);
1275                 &dectransform(2);
1276                 &dectransform(3);
1277                 &dectransform(0);
1278                 &dectransform(1);
1279                 &mov    ($key,&DWP(20,"esp"));
1280                 &mov    ($tbl,&DWP(28,"esp"));
1281                 &add    ($key,16);              # advance rd_key
1282                 &xor    ($s0,&DWP(0,$key));
1283                 &xor    ($s1,&DWP(4,$key));
1284                 &xor    ($s2,&DWP(8,$key));
1285                 &xor    ($s3,&DWP(12,$key));
1286
1287         &cmp    ($key,&DWP(24,"esp"));
1288         &mov    (&DWP(20,"esp"),$key);
1289         &jb     (&label("loop"));
1290
1291         &deccompact(0,$tbl,$s0,$s3,$s2,$s1);
1292         &deccompact(1,$tbl,$s1,$s0,$s3,$s2);
1293         &deccompact(2,$tbl,$s2,$s1,$s0,$s3);
1294         &deccompact(3,$tbl,$s3,$s2,$s1,$s0);
1295
1296         &xor    ($s0,&DWP(16,$key));
1297         &xor    ($s1,&DWP(20,$key));
1298         &xor    ($s2,&DWP(24,$key));
1299         &xor    ($s3,&DWP(28,$key));
1300
1301         &ret    ();
1302 &function_end_B("_x86_AES_decrypt_compact");
1303
1304 ######################################################################
1305 # "Compact" SSE block function.
1306 ######################################################################
1307
1308 sub sse_deccompact()
1309 {
1310         &pshufw ("mm1","mm0",0x0c);             #  7, 6, 1, 0
1311         &movd   ("eax","mm1");                  #  7, 6, 1, 0
1312
1313         &pshufw ("mm5","mm4",0x09);             # 13,12,11,10
1314         &movz   ($acc,&LB("eax"));              #  0
1315         &movz   ("ecx",&BP(-128,$tbl,$acc,1));  #  0
1316         &movd   ("ebx","mm5");                  # 13,12,11,10
1317         &movz   ("edx",&HB("eax"));             #  1
1318         &movz   ("edx",&BP(-128,$tbl,"edx",1)); #  1
1319         &shl    ("edx",8);                      #  1
1320
1321         &pshufw ("mm2","mm0",0x06);             #  3, 2, 5, 4
1322         &movz   ($acc,&LB("ebx"));              # 10
1323         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 10
1324         &shl    ($acc,16);                      # 10
1325         &or     ("ecx",$acc);                   # 10
1326         &shr    ("eax",16);                     #  7, 6
1327         &movz   ($acc,&HB("ebx"));              # 11
1328         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 11
1329         &shl    ($acc,24);                      # 11
1330         &or     ("edx",$acc);                   # 11
1331         &shr    ("ebx",16);                     # 13,12
1332
1333         &pshufw ("mm6","mm4",0x03);             # 9, 8,15,14
1334         &movz   ($acc,&HB("eax"));              #  7
1335         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  7
1336         &shl    ($acc,24);                      #  7
1337         &or     ("ecx",$acc);                   #  7
1338         &movz   ($acc,&HB("ebx"));              # 13
1339         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 13
1340         &shl    ($acc,8);                       # 13
1341         &or     ("ecx",$acc);                   # 13
1342         &movd   ("mm0","ecx");                  # t[0] collected
1343
1344         &movz   ($acc,&LB("eax"));              #  6
1345         &movd   ("eax","mm2");                  #  3, 2, 5, 4
1346         &movz   ("ecx",&BP(-128,$tbl,$acc,1));  #  6
1347         &shl    ("ecx",16);                     #  6
1348         &movz   ($acc,&LB("ebx"));              # 12
1349         &movd   ("ebx","mm6");                  #  9, 8,15,14
1350         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 12
1351         &or     ("ecx",$acc);                   # 12
1352
1353         &movz   ($acc,&LB("eax"));              #  4
1354         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  4
1355         &or     ("edx",$acc);                   #  4
1356         &movz   ($acc,&LB("ebx"));              # 14
1357         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 14
1358         &shl    ($acc,16);                      # 14
1359         &or     ("edx",$acc);                   # 14
1360         &movd   ("mm1","edx");                  # t[1] collected
1361
1362         &movz   ($acc,&HB("eax"));              #  5
1363         &movz   ("edx",&BP(-128,$tbl,$acc,1));  #  5
1364         &shl    ("edx",8);                      #  5
1365         &movz   ($acc,&HB("ebx"));              # 15
1366         &shr    ("eax",16);                     #  3, 2
1367         &movz   ($acc,&BP(-128,$tbl,$acc,1));   # 15
1368         &shl    ($acc,24);                      # 15
1369         &or     ("edx",$acc);                   # 15
1370         &shr    ("ebx",16);                     #  9, 8
1371
1372         &punpckldq      ("mm0","mm1");          # t[0,1] collected
1373
1374         &movz   ($acc,&HB("ebx"));              #  9
1375         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  9
1376         &shl    ($acc,8);                       #  9
1377         &or     ("ecx",$acc);                   #  9
1378         &and    ("ebx",0xff);                   #  8
1379         &movz   ("ebx",&BP(-128,$tbl,"ebx",1)); #  8
1380         &or     ("edx","ebx");                  #  8
1381         &movz   ($acc,&LB("eax"));              #  2
1382         &movz   ($acc,&BP(-128,$tbl,$acc,1));   #  2
1383         &shl    ($acc,16);                      #  2
1384         &or     ("edx",$acc);                   #  2
1385         &movd   ("mm4","edx");                  # t[2] collected
1386         &movz   ("eax",&HB("eax"));             #  3
1387         &movz   ("eax",&BP(-128,$tbl,"eax",1)); #  3
1388         &shl    ("eax",24);                     #  3
1389         &or     ("ecx","eax");                  #  3
1390         &movd   ("mm5","ecx");                  # t[3] collected
1391
1392         &punpckldq      ("mm4","mm5");          # t[2,3] collected
1393 }
1394
1395 &public_label("AES_Td");
1396 &function_begin_B("_sse_AES_decrypt_compact");
1397         &pxor   ("mm0",&QWP(0,$key));   #  7, 6, 5, 4, 3, 2, 1, 0
1398         &pxor   ("mm4",&QWP(8,$key));   # 15,14,13,12,11,10, 9, 8
1399
1400         # note that caller is expected to allocate stack frame for me!
1401         &mov    ($acc,&DWP(240,$key));          # load key->rounds
1402         &lea    ($acc,&DWP(-2,$acc,$acc));
1403         &lea    ($acc,&DWP(0,$key,$acc,8));
1404         &mov    (&DWP(24,"esp"),$acc);          # end of key schedule
1405
1406         &mov    ($s0,0x1b1b1b1b);               # magic constant
1407         &mov    (&DWP(8,"esp"),$s0);
1408         &mov    (&DWP(12,"esp"),$s0);
1409
1410         # prefetch Td4
1411         &mov    ($s0,&DWP(0-128,$tbl));
1412         &mov    ($s1,&DWP(32-128,$tbl));
1413         &mov    ($s2,&DWP(64-128,$tbl));
1414         &mov    ($s3,&DWP(96-128,$tbl));
1415         &mov    ($s0,&DWP(128-128,$tbl));
1416         &mov    ($s1,&DWP(160-128,$tbl));
1417         &mov    ($s2,&DWP(192-128,$tbl));
1418         &mov    ($s3,&DWP(224-128,$tbl));
1419
1420         &set_label("loop",16);
1421                 &sse_deccompact();
1422                 &add    ($key,16);
1423                 &cmp    ($key,&DWP(24,"esp"));
1424                 &ja     (&label("out"));
1425
1426                 # ROTATE(x^y,N) == ROTATE(x,N)^ROTATE(y,N)
1427                 &movq   ("mm3","mm0");          &movq   ("mm7","mm4");
1428                 &movq   ("mm2","mm0",1);        &movq   ("mm6","mm4",1);
1429                 &movq   ("mm1","mm0");          &movq   ("mm5","mm4");
1430                 &pshufw ("mm0","mm0",0xb1);     &pshufw ("mm4","mm4",0xb1);# = ROTATE(tp0,16)
1431                 &pslld  ("mm2",8);              &pslld  ("mm6",8);
1432                 &psrld  ("mm3",8);              &psrld  ("mm7",8);
1433                 &pxor   ("mm0","mm2");          &pxor   ("mm4","mm6");  # ^= tp0<<8
1434                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # ^= tp0>>8
1435                 &pslld  ("mm2",16);             &pslld  ("mm6",16);
1436                 &psrld  ("mm3",16);             &psrld  ("mm7",16);
1437                 &pxor   ("mm0","mm2");          &pxor   ("mm4","mm6");  # ^= tp0<<24
1438                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # ^= tp0>>24
1439
1440                 &movq   ("mm3",&QWP(8,"esp"));
1441                 &pxor   ("mm2","mm2");          &pxor   ("mm6","mm6");
1442                 &pcmpgtb("mm2","mm1");          &pcmpgtb("mm6","mm5");
1443                 &pand   ("mm2","mm3");          &pand   ("mm6","mm3");
1444                 &paddb  ("mm1","mm1");          &paddb  ("mm5","mm5");
1445                 &pxor   ("mm1","mm2");          &pxor   ("mm5","mm6");  # tp2
1446                 &movq   ("mm3","mm1");          &movq   ("mm7","mm5");
1447                 &movq   ("mm2","mm1");          &movq   ("mm6","mm5");
1448                 &pxor   ("mm0","mm1");          &pxor   ("mm4","mm5");  # ^= tp2
1449                 &pslld  ("mm3",24);             &pslld  ("mm7",24);
1450                 &psrld  ("mm2",8);              &psrld  ("mm6",8);
1451                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # ^= tp2<<24
1452                 &pxor   ("mm0","mm2");          &pxor   ("mm4","mm6");  # ^= tp2>>8
1453
1454                 &movq   ("mm2",&QWP(8,"esp"));
1455                 &pxor   ("mm3","mm3");          &pxor   ("mm7","mm7");
1456                 &pcmpgtb("mm3","mm1");          &pcmpgtb("mm7","mm5");
1457                 &pand   ("mm3","mm2");          &pand   ("mm7","mm2");
1458                 &paddb  ("mm1","mm1");          &paddb  ("mm5","mm5");
1459                 &pxor   ("mm1","mm3");          &pxor   ("mm5","mm7");  # tp4
1460                 &pshufw ("mm3","mm1",0xb1);     &pshufw ("mm7","mm5",0xb1);
1461                 &pxor   ("mm0","mm1");          &pxor   ("mm4","mm5");  # ^= tp4
1462                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # ^= ROTATE(tp4,16)     
1463
1464                 &pxor   ("mm3","mm3");          &pxor   ("mm7","mm7");
1465                 &pcmpgtb("mm3","mm1");          &pcmpgtb("mm7","mm5");
1466                 &pand   ("mm3","mm2");          &pand   ("mm7","mm2");
1467                 &paddb  ("mm1","mm1");          &paddb  ("mm5","mm5");
1468                 &pxor   ("mm1","mm3");          &pxor   ("mm5","mm7");  # tp8
1469                 &pxor   ("mm0","mm1");          &pxor   ("mm4","mm5");  # ^= tp8
1470                 &movq   ("mm3","mm1");          &movq   ("mm7","mm5");
1471                 &pshufw ("mm2","mm1",0xb1);     &pshufw ("mm6","mm5",0xb1);
1472                 &pxor   ("mm0","mm2");          &pxor   ("mm4","mm6");  # ^= ROTATE(tp8,16)
1473                 &pslld  ("mm1",8);              &pslld  ("mm5",8);
1474                 &psrld  ("mm3",8);              &psrld  ("mm7",8);
1475                 &movq   ("mm2",&QWP(0,$key));   &movq   ("mm6",&QWP(8,$key));
1476                 &pxor   ("mm0","mm1");          &pxor   ("mm4","mm5");  # ^= tp8<<8
1477                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # ^= tp8>>8
1478                 &mov    ($s0,&DWP(0-128,$tbl));
1479                 &pslld  ("mm1",16);             &pslld  ("mm5",16);
1480                 &mov    ($s1,&DWP(64-128,$tbl));
1481                 &psrld  ("mm3",16);             &psrld  ("mm7",16);
1482                 &mov    ($s2,&DWP(128-128,$tbl));
1483                 &pxor   ("mm0","mm1");          &pxor   ("mm4","mm5");  # ^= tp8<<24
1484                 &mov    ($s3,&DWP(192-128,$tbl));
1485                 &pxor   ("mm0","mm3");          &pxor   ("mm4","mm7");  # ^= tp8>>24
1486
1487                 &pxor   ("mm0","mm2");          &pxor   ("mm4","mm6");
1488         &jmp    (&label("loop"));
1489
1490         &set_label("out",16);
1491         &pxor   ("mm0",&QWP(0,$key));
1492         &pxor   ("mm4",&QWP(8,$key));
1493
1494         &ret    ();
1495 &function_end_B("_sse_AES_decrypt_compact");
1496
1497 ######################################################################
1498 # Vanilla block function.
1499 ######################################################################
1500
1501 sub decstep()
1502 { my ($i,$td,@s) = @_;
1503   my $tmp = $key;
1504   my $out = $i==3?$s[0]:$acc;
1505
1506         # no instructions are reordered, as performance appears
1507         # optimal... or rather that all attempts to reorder didn't
1508         # result in better performance [which by the way is not a
1509         # bit lower than ecryption].
1510         if($i==3)   {   &mov    ($key,&DWP(20,"esp"));          }
1511         else        {   &mov    ($out,$s[0]);                   }
1512                         &and    ($out,0xFF);
1513                         &mov    ($out,&DWP(0,$td,$out,8));
1514
1515         if ($i==3)  {   $tmp=$s[1];                             }
1516                         &movz   ($tmp,&HB($s[1]));
1517                         &xor    ($out,&DWP(3,$td,$tmp,8));
1518
1519         if ($i==3)  {   $tmp=$s[2]; &mov ($s[1],$acc);          }
1520         else        {   &mov    ($tmp,$s[2]);                   }
1521                         &shr    ($tmp,16);
1522                         &and    ($tmp,0xFF);
1523                         &xor    ($out,&DWP(2,$td,$tmp,8));
1524
1525         if ($i==3)  {   $tmp=$s[3]; &mov ($s[2],&DWP(8,"esp")); }
1526         else        {   &mov    ($tmp,$s[3]);                   }
1527                         &shr    ($tmp,24);
1528                         &xor    ($out,&DWP(1,$td,$tmp,8));
1529         if ($i<2)   {   &mov    (&DWP(4+4*$i,"esp"),$out);      }
1530         if ($i==3)  {   &mov    ($s[3],&DWP(4,"esp"));          }
1531                         &comment();
1532 }
1533
1534 sub declast()
1535 { my ($i,$td,@s)=@_;
1536   my $tmp = $key;
1537   my $out = $i==3?$s[0]:$acc;
1538
1539         if($i==0)   {   &lea    ($td,&DWP(2048+128,$td));
1540                         &mov    ($tmp,&DWP(0-128,$td));
1541                         &mov    ($acc,&DWP(32-128,$td));
1542                         &mov    ($tmp,&DWP(64-128,$td));
1543                         &mov    ($acc,&DWP(96-128,$td));
1544                         &mov    ($tmp,&DWP(128-128,$td));
1545                         &mov    ($acc,&DWP(160-128,$td));
1546                         &mov    ($tmp,&DWP(192-128,$td));
1547                         &mov    ($acc,&DWP(224-128,$td));
1548                         &lea    ($td,&DWP(-128,$td));           }
1549         if($i==3)   {   &mov    ($key,&DWP(20,"esp"));          }
1550         else        {   &mov    ($out,$s[0]);                   }
1551                         &and    ($out,0xFF);
1552                         &movz   ($out,&BP(0,$td,$out,1));
1553
1554         if ($i==3)  {   $tmp=$s[1];                             }
1555                         &movz   ($tmp,&HB($s[1]));
1556                         &movz   ($tmp,&BP(0,$td,$tmp,1));
1557                         &shl    ($tmp,8);
1558                         &xor    ($out,$tmp);
1559
1560         if ($i==3)  {   $tmp=$s[2]; &mov ($s[1],$acc);          }
1561         else        {   mov     ($tmp,$s[2]);                   }
1562                         &shr    ($tmp,16);
1563                         &and    ($tmp,0xFF);
1564                         &movz   ($tmp,&BP(0,$td,$tmp,1));
1565                         &shl    ($tmp,16);
1566                         &xor    ($out,$tmp);
1567
1568         if ($i==3)  {   $tmp=$s[3]; &mov ($s[2],&DWP(8,"esp")); }
1569         else        {   &mov    ($tmp,$s[3]);                   }
1570                         &shr    ($tmp,24);
1571                         &movz   ($tmp,&BP(0,$td,$tmp,1));
1572                         &shl    ($tmp,24);
1573                         &xor    ($out,$tmp);
1574         if ($i<2)   {   &mov    (&DWP(4+4*$i,"esp"),$out);      }
1575         if ($i==3)  {   &mov    ($s[3],&DWP(4,"esp"));
1576                         &lea    ($td,&DWP(-2048,$td));          }
1577 }
1578
1579 &public_label("AES_Td");
1580 &function_begin_B("_x86_AES_decrypt");
1581         # note that caller is expected to allocate stack frame for me!
1582         &mov    (&DWP(20,"esp"),$key);          # save key
1583
1584         &xor    ($s0,&DWP(0,$key));             # xor with key
1585         &xor    ($s1,&DWP(4,$key));
1586         &xor    ($s2,&DWP(8,$key));
1587         &xor    ($s3,&DWP(12,$key));
1588
1589         &mov    ($acc,&DWP(240,$key));          # load key->rounds
1590
1591         if ($small_footprint) {
1592             &lea        ($acc,&DWP(-2,$acc,$acc));
1593             &lea        ($acc,&DWP(0,$key,$acc,8));
1594             &mov        (&DWP(24,"esp"),$acc);  # end of key schedule
1595             &set_label("loop",16);
1596                 &decstep(0,$tbl,$s0,$s3,$s2,$s1);
1597                 &decstep(1,$tbl,$s1,$s0,$s3,$s2);
1598                 &decstep(2,$tbl,$s2,$s1,$s0,$s3);
1599                 &decstep(3,$tbl,$s3,$s2,$s1,$s0);
1600                 &add    ($key,16);              # advance rd_key
1601                 &xor    ($s0,&DWP(0,$key));
1602                 &xor    ($s1,&DWP(4,$key));
1603                 &xor    ($s2,&DWP(8,$key));
1604                 &xor    ($s3,&DWP(12,$key));
1605             &cmp        ($key,&DWP(24,"esp"));
1606             &mov        (&DWP(20,"esp"),$key);
1607             &jb         (&label("loop"));
1608         }
1609         else {
1610             &cmp        ($acc,10);
1611             &jle        (&label("10rounds"));
1612             &cmp        ($acc,12);
1613             &jle        (&label("12rounds"));
1614
1615         &set_label("14rounds",4);
1616             for ($i=1;$i<3;$i++) {
1617                 &decstep(0,$tbl,$s0,$s3,$s2,$s1);
1618                 &decstep(1,$tbl,$s1,$s0,$s3,$s2);
1619                 &decstep(2,$tbl,$s2,$s1,$s0,$s3);
1620                 &decstep(3,$tbl,$s3,$s2,$s1,$s0);
1621                 &xor    ($s0,&DWP(16*$i+0,$key));
1622                 &xor    ($s1,&DWP(16*$i+4,$key));
1623                 &xor    ($s2,&DWP(16*$i+8,$key));
1624                 &xor    ($s3,&DWP(16*$i+12,$key));
1625             }
1626             &add        ($key,32);
1627             &mov        (&DWP(20,"esp"),$key);  # advance rd_key
1628         &set_label("12rounds",4);
1629             for ($i=1;$i<3;$i++) {
1630                 &decstep(0,$tbl,$s0,$s3,$s2,$s1);
1631                 &decstep(1,$tbl,$s1,$s0,$s3,$s2);
1632                 &decstep(2,$tbl,$s2,$s1,$s0,$s3);
1633                 &decstep(3,$tbl,$s3,$s2,$s1,$s0);
1634                 &xor    ($s0,&DWP(16*$i+0,$key));
1635                 &xor    ($s1,&DWP(16*$i+4,$key));
1636                 &xor    ($s2,&DWP(16*$i+8,$key));
1637                 &xor    ($s3,&DWP(16*$i+12,$key));
1638             }
1639             &add        ($key,32);
1640             &mov        (&DWP(20,"esp"),$key);  # advance rd_key
1641         &set_label("10rounds",4);
1642             for ($i=1;$i<10;$i++) {
1643                 &decstep(0,$tbl,$s0,$s3,$s2,$s1);
1644                 &decstep(1,$tbl,$s1,$s0,$s3,$s2);
1645                 &decstep(2,$tbl,$s2,$s1,$s0,$s3);
1646                 &decstep(3,$tbl,$s3,$s2,$s1,$s0);
1647                 &xor    ($s0,&DWP(16*$i+0,$key));
1648                 &xor    ($s1,&DWP(16*$i+4,$key));
1649                 &xor    ($s2,&DWP(16*$i+8,$key));
1650                 &xor    ($s3,&DWP(16*$i+12,$key));
1651             }
1652         }
1653
1654         &declast(0,$tbl,$s0,$s3,$s2,$s1);
1655         &declast(1,$tbl,$s1,$s0,$s3,$s2);
1656         &declast(2,$tbl,$s2,$s1,$s0,$s3);
1657         &declast(3,$tbl,$s3,$s2,$s1,$s0);
1658
1659         &add    ($key,$small_footprint?16:160);
1660         &xor    ($s0,&DWP(0,$key));
1661         &xor    ($s1,&DWP(4,$key));
1662         &xor    ($s2,&DWP(8,$key));
1663         &xor    ($s3,&DWP(12,$key));
1664
1665         &ret    ();
1666
1667 &set_label("AES_Td",64);        # Yes! I keep it in the code segment!
1668         &_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a);
1669         &_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b);
1670         &_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5);
1671         &_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5);
1672         &_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d);
1673         &_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b);
1674         &_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295);
1675         &_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e);
1676         &_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927);
1677         &_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d);
1678         &_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362);
1679         &_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9);
1680         &_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52);
1681         &_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566);
1682         &_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3);
1683         &_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed);
1684         &_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e);
1685         &_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4);
1686         &_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4);
1687         &_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd);
1688         &_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d);
1689         &_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060);
1690         &_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967);
1691         &_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879);
1692         &_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000);
1693         &_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c);
1694         &_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36);
1695         &_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624);
1696         &_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b);
1697         &_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c);
1698         &_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12);
1699         &_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14);
1700         &_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3);
1701         &_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b);
1702         &_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8);
1703         &_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684);
1704         &_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7);
1705         &_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177);
1706         &_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947);
1707         &_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322);
1708         &_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498);
1709         &_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f);
1710         &_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54);
1711         &_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382);
1712         &_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf);
1713         &_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb);
1714         &_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83);
1715         &_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef);
1716         &_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029);
1717         &_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235);
1718         &_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733);
1719         &_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117);
1720         &_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4);
1721         &_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546);
1722         &_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb);
1723         &_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d);
1724         &_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb);
1725         &_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a);
1726         &_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773);
1727         &_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478);
1728         &_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2);
1729         &_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff);
1730         &_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664);
1731         &_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0);
1732
1733 #Td4:   # four copies of Td4 to choose from to avoid L1 aliasing
1734         &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
1735         &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
1736         &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
1737         &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
1738         &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
1739         &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
1740         &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
1741         &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
1742         &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
1743         &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
1744         &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
1745         &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
1746         &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
1747         &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
1748         &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
1749         &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
1750         &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
1751         &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
1752         &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
1753         &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
1754         &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
1755         &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
1756         &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
1757         &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
1758         &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
1759         &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
1760         &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
1761         &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
1762         &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
1763         &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
1764         &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
1765         &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
1766
1767         &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
1768         &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
1769         &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
1770         &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
1771         &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
1772         &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
1773         &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
1774         &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
1775         &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
1776         &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
1777         &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
1778         &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
1779         &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
1780         &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
1781         &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
1782         &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
1783         &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
1784         &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
1785         &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
1786         &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
1787         &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
1788         &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
1789         &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
1790         &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
1791         &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
1792         &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
1793         &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
1794         &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
1795         &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
1796         &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
1797         &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
1798         &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
1799
1800         &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
1801         &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
1802         &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
1803         &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
1804         &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
1805         &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
1806         &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
1807         &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
1808         &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
1809         &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
1810         &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
1811         &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
1812         &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
1813         &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
1814         &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
1815         &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
1816         &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
1817         &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
1818         &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
1819         &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
1820         &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
1821         &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
1822         &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
1823         &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
1824         &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
1825         &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
1826         &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
1827         &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
1828         &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
1829         &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
1830         &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
1831         &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
1832
1833         &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
1834         &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
1835         &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
1836         &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
1837         &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
1838         &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
1839         &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
1840         &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
1841         &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
1842         &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
1843         &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
1844         &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
1845         &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
1846         &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
1847         &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
1848         &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
1849         &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
1850         &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
1851         &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
1852         &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
1853         &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
1854         &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
1855         &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
1856         &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
1857         &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
1858         &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
1859         &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
1860         &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
1861         &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
1862         &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
1863         &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
1864         &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
1865 &function_end_B("_x86_AES_decrypt");
1866
1867 # void AES_decrypt (const void *inp,void *out,const AES_KEY *key);
1868 &public_label("AES_Td");
1869 &function_begin("AES_decrypt");
1870         &mov    ($acc,&wparam(0));              # load inp
1871         &mov    ($key,&wparam(2));              # load key
1872
1873         &mov    ($s0,"esp");
1874         &sub    ("esp",36);
1875         &and    ("esp",-64);                    # align to cache-line
1876
1877         # place stack frame just "above" the key schedule
1878         &lea    ($s1,&DWP(-64-63,$key));
1879         &sub    ($s1,"esp");
1880         &neg    ($s1);
1881         &and    ($s1,0x3C0);    # modulo 1024, but aligned to cache-line
1882         &sub    ("esp",$s1);
1883         &add    ("esp",4);      # 4 is reserved for caller's return address
1884         &mov    (&DWP(28,"esp"),$s0);           # save stack pointer
1885
1886         &call   (&label("pic_point"));          # make it PIC!
1887         &set_label("pic_point");
1888         &blindpop($tbl);
1889         &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point"));
1890         &lea    ($tbl,&DWP(&label("AES_Td")."-".&label("pic_point"),$tbl));
1891         # pick Td4 copy which can't "overlap" with stack frame or key schedule
1892         &lea    ($s1,&DWP(768-4,"esp"));
1893         &sub    ($s1,$tbl);
1894         &and    ($s1,0x300);
1895         &lea    ($tbl,&DWP(2048+128,$tbl,$s1));
1896
1897         &bt     (&DWP(0,$s0),25);               # check for SSE bit
1898         &jnc    (&label("x86"));
1899
1900         &movq   ("mm0",&QWP(0,$acc));
1901         &movq   ("mm4",&QWP(8,$acc));
1902         &call   ("_sse_AES_decrypt_compact");
1903         &mov    ("esp",&DWP(28,"esp"));         # restore stack pointer
1904         &mov    ($acc,&wparam(1));              # load out
1905         &movq   (&QWP(0,$acc),"mm0");           # write output data
1906         &movq   (&QWP(8,$acc),"mm4");
1907         &emms   ();
1908         &function_end_A();
1909
1910         &set_label("x86",16);
1911         &mov    (&DWP(24,"esp"),$tbl);
1912         &mov    ($s0,&DWP(0,$acc));             # load input data
1913         &mov    ($s1,&DWP(4,$acc));
1914         &mov    ($s2,&DWP(8,$acc));
1915         &mov    ($s3,&DWP(12,$acc));
1916         &call   ("_x86_AES_decrypt_compact");
1917         &mov    ("esp",&DWP(28,"esp"));         # restore stack pointer
1918         &mov    ($acc,&wparam(1));              # load out
1919         &mov    (&DWP(0,$acc),$s0);             # write output data
1920         &mov    (&DWP(4,$acc),$s1);
1921         &mov    (&DWP(8,$acc),$s2);
1922         &mov    (&DWP(12,$acc),$s3);
1923 &function_end("AES_decrypt");
1924
1925 # void AES_cbc_encrypt (const void char *inp, unsigned char *out,
1926 #                       size_t length, const AES_KEY *key,
1927 #                       unsigned char *ivp,const int enc);
1928 {
1929 # stack frame layout
1930 # -4(%esp)      0(%esp)         return address
1931 # 0(%esp)       4(%esp)         s0 backup
1932 # 4(%esp)       8(%esp)         s1 backup
1933 # 8(%esp)       12(%esp)        s2 backup
1934 # 12(%esp)      16(%esp)        s3 backup
1935 # 16(%esp)      20(%esp)        key backup      
1936 # 20(%esp)      24(%esp)        end of key schedule
1937 # 24(%esp)      28(%esp)        ebp backup
1938 my $_esp=&DWP(28,"esp");        #saved %esp
1939 my $_inp=&DWP(32,"esp");        #copy of wparam(0)
1940 my $_out=&DWP(36,"esp");        #copy of wparam(1)
1941 my $_len=&DWP(40,"esp");        #copy of wparam(2)
1942 my $_key=&DWP(44,"esp");        #copy of wparam(3)
1943 my $_ivp=&DWP(48,"esp");        #copy of wparam(4)
1944 my $_tmp=&DWP(52,"esp");        #volatile variable
1945 my $ivec=&DWP(56,"esp");        #ivec[16]
1946 my $aes_key=&DWP(72,"esp");     #copy of aes_key
1947 my $mark=&DWP(72+240,"esp");    #copy of aes_key->rounds
1948
1949 &public_label("AES_Te");
1950 &public_label("AES_Td");
1951 &function_begin("AES_cbc_encrypt");
1952         &mov    ($s2 eq "ecx"? $s2 : "",&wparam(2));    # load len
1953         &cmp    ($s2,0);
1954         &je     (&label("enc_out"));
1955
1956         &call   (&label("pic_point"));          # make it PIC!
1957         &set_label("pic_point");
1958         &blindpop($tbl);
1959
1960         &pushf  ();
1961         &cld    ();
1962
1963         &cmp    (&wparam(5),0);
1964         &je     (&label("DECRYPT"));
1965
1966         &lea    ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
1967
1968         # allocate aligned stack frame...
1969         &lea    ($key,&DWP(-76-244,"esp"));
1970         &and    ($key,-64);
1971
1972         # ... and make sure it doesn't alias with AES_Te modulo 4096
1973         &mov    ($s0,$tbl);
1974         &lea    ($s1,&DWP(2048,$tbl));
1975         &mov    ($s3,$key);
1976         &and    ($s0,0xfff);            # s = %ebp&0xfff
1977         &and    ($s1,0xfff);            # e = (%ebp+2048)&0xfff
1978         &and    ($s3,0xfff);            # p = %esp&0xfff
1979
1980         &cmp    ($s3,$s1);              # if (p>=e) %esp =- (p-e);
1981         &jb     (&label("te_break_out"));
1982         &sub    ($s3,$s1);
1983         &sub    ($key,$s3);
1984         &jmp    (&label("te_ok"));
1985         &set_label("te_break_out");     # else %esp -= (p-s)&0xfff + framesz;
1986         &sub    ($s3,$s0);
1987         &and    ($s3,0xfff);
1988         &add    ($s3,72+256);
1989         &sub    ($key,$s3);
1990         &align  (4);
1991         &set_label("te_ok");
1992
1993         &mov    ($s0,&wparam(0));       # load inp
1994         &mov    ($s1,&wparam(1));       # load out
1995         &mov    ($s3,&wparam(3));       # load key
1996         &mov    ($acc,&wparam(4));      # load ivp
1997
1998         &exch   ("esp",$key);
1999         &add    ("esp",4);              # reserve for return address!
2000         &mov    ($_esp,$key);           # save %esp
2001
2002         &mov    ($_inp,$s0);            # save copy of inp
2003         &mov    ($_out,$s1);            # save copy of out
2004         &mov    ($_len,$s2);            # save copy of len
2005         &mov    ($_key,$s3);            # save copy of key
2006         &mov    ($_ivp,$acc);           # save copy of ivp
2007
2008         &mov    ($mark,0);              # copy of aes_key->rounds = 0;
2009         if ($compromise) {
2010                 &cmp    ($s2,$compromise);
2011                 &jb     (&label("skip_ecopy"));
2012         }
2013         # do we copy key schedule to stack?
2014         &mov    ($s1 eq "ebx" ? $s1 : "",$s3);
2015         &mov    ($s2 eq "ecx" ? $s2 : "",244/4);
2016         &sub    ($s1,$tbl);
2017         &mov    ("esi",$s3);
2018         &and    ($s1,0xfff);
2019         &lea    ("edi",$aes_key);
2020         &cmp    ($s1,2048);
2021         &jb     (&label("do_ecopy"));
2022         &cmp    ($s1,4096-244);
2023         &jb     (&label("skip_ecopy"));
2024         &align  (4);
2025         &set_label("do_ecopy");
2026                 &mov    ($_key,"edi");
2027                 &data_word(0xA5F3F689); # rep movsd
2028         &set_label("skip_ecopy");
2029
2030         &mov    ($acc,$s0);
2031         &mov    ($key,16);
2032         &align  (4);
2033         &set_label("prefetch_te");
2034                 &mov    ($s0,&DWP(0,$tbl));
2035                 &mov    ($s1,&DWP(32,$tbl));
2036                 &mov    ($s2,&DWP(64,$tbl));
2037                 &mov    ($s3,&DWP(96,$tbl));
2038                 &lea    ($tbl,&DWP(128,$tbl));
2039                 &dec    ($key);
2040         &jnz    (&label("prefetch_te"));
2041         &sub    ($tbl,2048);
2042         &mov    (&DWP(24,"esp"),$tbl);
2043
2044         &mov    ($s2,$_len);
2045         &mov    ($key,$_ivp);
2046         &test   ($s2,0xFFFFFFF0);
2047         &jz     (&label("enc_tail"));           # short input...
2048
2049         &mov    ($s0,&DWP(0,$key));             # load iv
2050         &mov    ($s1,&DWP(4,$key));
2051
2052         &align  (4);
2053         &set_label("enc_loop");
2054                 &mov    ($s2,&DWP(8,$key));
2055                 &mov    ($s3,&DWP(12,$key));
2056
2057                 &xor    ($s0,&DWP(0,$acc));     # xor input data
2058                 &xor    ($s1,&DWP(4,$acc));
2059                 &xor    ($s2,&DWP(8,$acc));
2060                 &xor    ($s3,&DWP(12,$acc));
2061
2062                 &mov    ($key,$_key);           # load key
2063                 &call   ("_x86_AES_encrypt");
2064
2065                 &mov    ($acc,$_inp);           # load inp
2066                 &mov    ($key,$_out);           # load out
2067
2068                 &mov    (&DWP(0,$key),$s0);     # save output data
2069                 &mov    (&DWP(4,$key),$s1);
2070                 &mov    (&DWP(8,$key),$s2);
2071                 &mov    (&DWP(12,$key),$s3);
2072
2073                 &mov    ($s2,$_len);            # load len
2074
2075                 &lea    ($acc,&DWP(16,$acc));
2076                 &mov    ($_inp,$acc);           # save inp
2077
2078                 &lea    ($s3,&DWP(16,$key));
2079                 &mov    ($_out,$s3);            # save out
2080
2081                 &sub    ($s2,16);
2082                 &test   ($s2,0xFFFFFFF0);
2083                 &mov    ($_len,$s2);            # save len
2084         &jnz    (&label("enc_loop"));
2085         &test   ($s2,15);
2086         &jnz    (&label("enc_tail"));
2087         &mov    ($acc,$_ivp);           # load ivp
2088         &mov    ($s2,&DWP(8,$key));     # restore last dwords
2089         &mov    ($s3,&DWP(12,$key));
2090         &mov    (&DWP(0,$acc),$s0);     # save ivec
2091         &mov    (&DWP(4,$acc),$s1);
2092         &mov    (&DWP(8,$acc),$s2);
2093         &mov    (&DWP(12,$acc),$s3);
2094
2095         &cmp    ($mark,0);              # was the key schedule copied?
2096         &mov    ("edi",$_key);
2097         &mov    ("esp",$_esp);
2098         &je     (&label("skip_ezero"));
2099         # zero copy of key schedule
2100         &mov    ("ecx",240/4);
2101         &xor    ("eax","eax");
2102         &align  (4);
2103         &data_word(0xABF3F689); # rep stosd
2104         &set_label("skip_ezero")
2105         &popf   ();
2106     &set_label("enc_out");
2107         &function_end_A();
2108         &pushf  ();                     # kludge, never executed
2109
2110     &align      (4);
2111     &set_label("enc_tail");
2112         &push   ($key eq "edi" ? $key : "");    # push ivp
2113         &mov    ($key,$_out);                   # load out
2114         &mov    ($s1,16);
2115         &sub    ($s1,$s2);
2116         &cmp    ($key,$acc);                    # compare with inp
2117         &je     (&label("enc_in_place"));
2118         &align  (4);
2119         &data_word(0xA4F3F689); # rep movsb     # copy input
2120         &jmp    (&label("enc_skip_in_place"));
2121     &set_label("enc_in_place");
2122         &lea    ($key,&DWP(0,$key,$s2));
2123     &set_label("enc_skip_in_place");
2124         &mov    ($s2,$s1);
2125         &xor    ($s0,$s0);
2126         &align  (4);
2127         &data_word(0xAAF3F689); # rep stosb     # zero tail
2128         &pop    ($key);                         # pop ivp
2129
2130         &mov    ($acc,$_out);                   # output as input
2131         &mov    ($s0,&DWP(0,$key));
2132         &mov    ($s1,&DWP(4,$key));
2133         &mov    ($_len,16);                     # len=16
2134         &jmp    (&label("enc_loop"));           # one more spin...
2135
2136 #----------------------------- DECRYPT -----------------------------#
2137 &align  (4);
2138 &set_label("DECRYPT");
2139         &lea    ($tbl,&DWP(&label("AES_Td")."-".&label("pic_point"),$tbl));
2140
2141         # allocate aligned stack frame...
2142         &lea    ($key,&DWP(-64-244,"esp"));
2143         &and    ($key,-64);
2144
2145         # ... and make sure it doesn't alias with AES_Td modulo 4096
2146         &mov    ($s0,$tbl);
2147         &lea    ($s1,&DWP(2048+256,$tbl));
2148         &mov    ($s3,$key);
2149         &and    ($s0,0xfff);            # s = %ebp&0xfff
2150         &and    ($s1,0xfff);            # e = (%ebp+2048+256)&0xfff
2151         &and    ($s3,0xfff);            # p = %esp&0xfff
2152
2153         &cmp    ($s3,$s1);              # if (p>=e) %esp =- (p-e);
2154         &jb     (&label("td_break_out"));
2155         &sub    ($s3,$s1);
2156         &sub    ($key,$s3);
2157         &jmp    (&label("td_ok"));
2158         &set_label("td_break_out");     # else %esp -= (p-s)&0xfff + framesz;
2159         &sub    ($s3,$s0);
2160         &and    ($s3,0xfff);
2161         &add    ($s3,72+256);
2162         &sub    ($key,$s3);
2163         &align  (4);
2164         &set_label("td_ok");
2165
2166         &mov    ($s0,&wparam(0));       # load inp
2167         &mov    ($s1,&wparam(1));       # load out
2168         &mov    ($s3,&wparam(3));       # load key
2169         &mov    ($acc,&wparam(4));      # load ivp
2170
2171         &exch   ("esp",$key);
2172         &add    ("esp",4);              # reserve for return address!
2173         &mov    ($_esp,$key);           # save %esp
2174
2175         &mov    ($_inp,$s0);            # save copy of inp
2176         &mov    ($_out,$s1);            # save copy of out
2177         &mov    ($_len,$s2);            # save copy of len
2178         &mov    ($_key,$s3);            # save copy of key
2179         &mov    ($_ivp,$acc);           # save copy of ivp
2180
2181         &mov    ($mark,0);              # copy of aes_key->rounds = 0;
2182         if ($compromise) {
2183                 &cmp    ($s2,$compromise);
2184                 &jb     (&label("skip_dcopy"));
2185         }
2186         # do we copy key schedule to stack?
2187         &mov    ($s1 eq "ebx" ? $s1 : "",$s3);
2188         &mov    ($s2 eq "ecx" ? $s2 : "",244/4);
2189         &sub    ($s1,$tbl);
2190         &mov    ("esi",$s3);
2191         &and    ($s1,0xfff);
2192         &lea    ("edi",$aes_key);
2193         &cmp    ($s1,2048+256);
2194         &jb     (&label("do_dcopy"));
2195         &cmp    ($s1,4096-244);
2196         &jb     (&label("skip_dcopy"));
2197         &align  (4);
2198         &set_label("do_dcopy");
2199                 &mov    ($_key,"edi");
2200                 &data_word(0xA5F3F689); # rep movsd
2201         &set_label("skip_dcopy");
2202
2203         &mov    ($acc,$s0);
2204         &mov    ($key,18);
2205         &align  (4);
2206         &set_label("prefetch_td");
2207                 &mov    ($s0,&DWP(0,$tbl));
2208                 &mov    ($s1,&DWP(32,$tbl));
2209                 &mov    ($s2,&DWP(64,$tbl));
2210                 &mov    ($s3,&DWP(96,$tbl));
2211                 &lea    ($tbl,&DWP(128,$tbl));
2212                 &dec    ($key);
2213         &jnz    (&label("prefetch_td"));
2214         &sub    ($tbl,2048+256);
2215         &mov    (&DWP(24,"esp"),$tbl);
2216
2217         &cmp    ($acc,$_out);
2218         &je     (&label("dec_in_place"));       # in-place processing...
2219
2220         &mov    ($key,$_ivp);           # load ivp
2221         &mov    ($_tmp,$key);
2222
2223         &align  (4);
2224         &set_label("dec_loop");
2225                 &mov    ($s0,&DWP(0,$acc));     # read input
2226                 &mov    ($s1,&DWP(4,$acc));
2227                 &mov    ($s2,&DWP(8,$acc));
2228                 &mov    ($s3,&DWP(12,$acc));
2229
2230                 &mov    ($key,$_key);           # load key
2231                 &call   ("_x86_AES_decrypt");
2232
2233                 &mov    ($key,$_tmp);           # load ivp
2234                 &mov    ($acc,$_len);           # load len
2235                 &xor    ($s0,&DWP(0,$key));     # xor iv
2236                 &xor    ($s1,&DWP(4,$key));
2237                 &xor    ($s2,&DWP(8,$key));
2238                 &xor    ($s3,&DWP(12,$key));
2239
2240                 &sub    ($acc,16);
2241                 &jc     (&label("dec_partial"));
2242                 &mov    ($_len,$acc);           # save len
2243                 &mov    ($acc,$_inp);           # load inp
2244                 &mov    ($key,$_out);           # load out
2245
2246                 &mov    (&DWP(0,$key),$s0);     # write output
2247                 &mov    (&DWP(4,$key),$s1);
2248                 &mov    (&DWP(8,$key),$s2);
2249                 &mov    (&DWP(12,$key),$s3);
2250
2251                 &mov    ($_tmp,$acc);           # save ivp
2252                 &lea    ($acc,&DWP(16,$acc));
2253                 &mov    ($_inp,$acc);           # save inp
2254
2255                 &lea    ($key,&DWP(16,$key));
2256                 &mov    ($_out,$key);           # save out
2257
2258         &jnz    (&label("dec_loop"));
2259         &mov    ($key,$_tmp);           # load temp ivp
2260     &set_label("dec_end");
2261         &mov    ($acc,$_ivp);           # load user ivp
2262         &mov    ($s0,&DWP(0,$key));     # load iv
2263         &mov    ($s1,&DWP(4,$key));
2264         &mov    ($s2,&DWP(8,$key));
2265         &mov    ($s3,&DWP(12,$key));
2266         &mov    (&DWP(0,$acc),$s0);     # copy back to user
2267         &mov    (&DWP(4,$acc),$s1);
2268         &mov    (&DWP(8,$acc),$s2);
2269         &mov    (&DWP(12,$acc),$s3);
2270         &jmp    (&label("dec_out"));
2271
2272     &align      (4);
2273     &set_label("dec_partial");
2274         &lea    ($key,$ivec);
2275         &mov    (&DWP(0,$key),$s0);     # dump output to stack
2276         &mov    (&DWP(4,$key),$s1);
2277         &mov    (&DWP(8,$key),$s2);
2278         &mov    (&DWP(12,$key),$s3);
2279         &lea    ($s2 eq "ecx" ? $s2 : "",&DWP(16,$acc));
2280         &mov    ($acc eq "esi" ? $acc : "",$key);
2281         &mov    ($key eq "edi" ? $key : "",$_out);      # load out
2282         &data_word(0xA4F3F689); # rep movsb             # copy output
2283         &mov    ($key,$_inp);                           # use inp as temp ivp
2284         &jmp    (&label("dec_end"));
2285
2286     &align      (4);
2287     &set_label("dec_in_place");
2288         &set_label("dec_in_place_loop");
2289                 &lea    ($key,$ivec);
2290                 &mov    ($s0,&DWP(0,$acc));     # read input
2291                 &mov    ($s1,&DWP(4,$acc));
2292                 &mov    ($s2,&DWP(8,$acc));
2293                 &mov    ($s3,&DWP(12,$acc));
2294
2295                 &mov    (&DWP(0,$key),$s0);     # copy to temp
2296                 &mov    (&DWP(4,$key),$s1);
2297                 &mov    (&DWP(8,$key),$s2);
2298                 &mov    (&DWP(12,$key),$s3);
2299
2300                 &mov    ($key,$_key);           # load key
2301                 &call   ("_x86_AES_decrypt");
2302
2303                 &mov    ($key,$_ivp);           # load ivp
2304                 &mov    ($acc,$_out);           # load out
2305                 &xor    ($s0,&DWP(0,$key));     # xor iv
2306                 &xor    ($s1,&DWP(4,$key));
2307                 &xor    ($s2,&DWP(8,$key));
2308                 &xor    ($s3,&DWP(12,$key));
2309
2310                 &mov    (&DWP(0,$acc),$s0);     # write output
2311                 &mov    (&DWP(4,$acc),$s1);
2312                 &mov    (&DWP(8,$acc),$s2);
2313                 &mov    (&DWP(12,$acc),$s3);
2314
2315                 &lea    ($acc,&DWP(16,$acc));
2316                 &mov    ($_out,$acc);           # save out
2317
2318                 &lea    ($acc,$ivec);
2319                 &mov    ($s0,&DWP(0,$acc));     # read temp
2320                 &mov    ($s1,&DWP(4,$acc));
2321                 &mov    ($s2,&DWP(8,$acc));
2322                 &mov    ($s3,&DWP(12,$acc));
2323
2324                 &mov    (&DWP(0,$key),$s0);     # copy iv
2325                 &mov    (&DWP(4,$key),$s1);
2326                 &mov    (&DWP(8,$key),$s2);
2327                 &mov    (&DWP(12,$key),$s3);
2328
2329                 &mov    ($acc,$_inp);           # load inp
2330
2331                 &lea    ($acc,&DWP(16,$acc));
2332                 &mov    ($_inp,$acc);           # save inp
2333
2334                 &mov    ($s2,$_len);            # load len
2335                 &sub    ($s2,16);
2336                 &jc     (&label("dec_in_place_partial"));
2337                 &mov    ($_len,$s2);            # save len
2338         &jnz    (&label("dec_in_place_loop"));
2339         &jmp    (&label("dec_out"));
2340
2341     &align      (4);
2342     &set_label("dec_in_place_partial");
2343         # one can argue if this is actually required...
2344         &mov    ($key eq "edi" ? $key : "",$_out);
2345         &lea    ($acc eq "esi" ? $acc : "",$ivec);
2346         &lea    ($key,&DWP(0,$key,$s2));
2347         &lea    ($acc,&DWP(16,$acc,$s2));
2348         &neg    ($s2 eq "ecx" ? $s2 : "");
2349         &data_word(0xA4F3F689); # rep movsb     # restore tail
2350
2351     &align      (4);
2352     &set_label("dec_out");
2353     &cmp        ($mark,0);              # was the key schedule copied?
2354     &mov        ("edi",$_key);
2355     &mov        ("esp",$_esp);
2356     &je         (&label("skip_dzero"));
2357     # zero copy of key schedule
2358     &mov        ("ecx",240/4);
2359     &xor        ("eax","eax");
2360     &align      (4);
2361     &data_word(0xABF3F689);     # rep stosd
2362     &set_label("skip_dzero")
2363     &popf       ();
2364 &function_end("AES_cbc_encrypt");
2365 }
2366
2367 #------------------------------------------------------------------#
2368
2369 sub enckey()
2370 {
2371         &movz   ("esi",&LB("edx"));             # rk[i]>>0
2372         &movz   ("ebx",&BP(-128,$tbl,"esi",1));
2373         &movz   ("esi",&HB("edx"));             # rk[i]>>8
2374         &shl    ("ebx",24);
2375         &xor    ("eax","ebx");
2376
2377         &movz   ("ebx",&BP(-128,$tbl,"esi",1));
2378         &shr    ("edx",16);
2379         &movz   ("esi",&LB("edx"));             # rk[i]>>16
2380         &xor    ("eax","ebx");
2381
2382         &movz   ("ebx",&BP(-128,$tbl,"esi",1));
2383         &movz   ("esi",&HB("edx"));             # rk[i]>>24
2384         &shl    ("ebx",8);
2385         &xor    ("eax","ebx");
2386
2387         &movz   ("ebx",&BP(-128,$tbl,"esi",1));
2388         &shl    ("ebx",16);
2389         &xor    ("eax","ebx");
2390
2391         &xor    ("eax",&DWP(1024-128,$tbl,"ecx",4));    # rcon
2392 }
2393
2394 # int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
2395 #                        AES_KEY *key)
2396 &public_label("AES_Te");
2397 &function_begin("AES_set_encrypt_key");
2398         &mov    ("esi",&wparam(0));             # user supplied key
2399         &mov    ("edi",&wparam(2));             # private key schedule
2400
2401         &test   ("esi",-1);
2402         &jz     (&label("badpointer"));
2403         &test   ("edi",-1);
2404         &jz     (&label("badpointer"));
2405
2406         &call   (&label("pic_point"));
2407         &set_label("pic_point");
2408         &blindpop($tbl);
2409         &lea    ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
2410         &lea    ($tbl,&DWP(2048+128,$tbl));
2411
2412         # prefetch Te4
2413         &mov    ("eax",&DWP(0-128,$tbl));
2414         &mov    ("ebx",&DWP(32-128,$tbl));
2415         &mov    ("ecx",&DWP(64-128,$tbl));
2416         &mov    ("edx",&DWP(96-128,$tbl));
2417         &mov    ("eax",&DWP(128-128,$tbl));
2418         &mov    ("ebx",&DWP(160-128,$tbl));
2419         &mov    ("ecx",&DWP(192-128,$tbl));
2420         &mov    ("edx",&DWP(224-128,$tbl));
2421
2422         &mov    ("ecx",&wparam(1));             # number of bits in key
2423         &cmp    ("ecx",128);
2424         &je     (&label("10rounds"));
2425         &cmp    ("ecx",192);
2426         &je     (&label("12rounds"));
2427         &cmp    ("ecx",256);
2428         &je     (&label("14rounds"));
2429         &mov    ("eax",-2);                     # invalid number of bits
2430         &jmp    (&label("exit"));
2431
2432     &set_label("10rounds");
2433         &mov    ("eax",&DWP(0,"esi"));          # copy first 4 dwords
2434         &mov    ("ebx",&DWP(4,"esi"));
2435         &mov    ("ecx",&DWP(8,"esi"));
2436         &mov    ("edx",&DWP(12,"esi"));
2437         &mov    (&DWP(0,"edi"),"eax");
2438         &mov    (&DWP(4,"edi"),"ebx");
2439         &mov    (&DWP(8,"edi"),"ecx");
2440         &mov    (&DWP(12,"edi"),"edx");
2441
2442         &xor    ("ecx","ecx");
2443         &jmp    (&label("10shortcut"));
2444
2445         &align  (4);
2446         &set_label("10loop");
2447                 &mov    ("eax",&DWP(0,"edi"));          # rk[0]
2448                 &mov    ("edx",&DWP(12,"edi"));         # rk[3]
2449         &set_label("10shortcut");
2450                 &enckey ();
2451
2452                 &mov    (&DWP(16,"edi"),"eax");         # rk[4]
2453                 &xor    ("eax",&DWP(4,"edi"));
2454                 &mov    (&DWP(20,"edi"),"eax");         # rk[5]
2455                 &xor    ("eax",&DWP(8,"edi"));
2456                 &mov    (&DWP(24,"edi"),"eax");         # rk[6]
2457                 &xor    ("eax",&DWP(12,"edi"));
2458                 &mov    (&DWP(28,"edi"),"eax");         # rk[7]
2459                 &inc    ("ecx");
2460                 &add    ("edi",16);
2461                 &cmp    ("ecx",10);
2462         &jl     (&label("10loop"));
2463
2464         &mov    (&DWP(80,"edi"),10);            # setup number of rounds
2465         &xor    ("eax","eax");
2466         &jmp    (&label("exit"));
2467                 
2468     &set_label("12rounds");
2469         &mov    ("eax",&DWP(0,"esi"));          # copy first 6 dwords
2470         &mov    ("ebx",&DWP(4,"esi"));
2471         &mov    ("ecx",&DWP(8,"esi"));
2472         &mov    ("edx",&DWP(12,"esi"));
2473         &mov    (&DWP(0,"edi"),"eax");
2474         &mov    (&DWP(4,"edi"),"ebx");
2475         &mov    (&DWP(8,"edi"),"ecx");
2476         &mov    (&DWP(12,"edi"),"edx");
2477         &mov    ("ecx",&DWP(16,"esi"));
2478         &mov    ("edx",&DWP(20,"esi"));
2479         &mov    (&DWP(16,"edi"),"ecx");
2480         &mov    (&DWP(20,"edi"),"edx");
2481
2482         &xor    ("ecx","ecx");
2483         &jmp    (&label("12shortcut"));
2484
2485         &align  (4);
2486         &set_label("12loop");
2487                 &mov    ("eax",&DWP(0,"edi"));          # rk[0]
2488                 &mov    ("edx",&DWP(20,"edi"));         # rk[5]
2489         &set_label("12shortcut");
2490                 &enckey ();
2491
2492                 &mov    (&DWP(24,"edi"),"eax");         # rk[6]
2493                 &xor    ("eax",&DWP(4,"edi"));
2494                 &mov    (&DWP(28,"edi"),"eax");         # rk[7]
2495                 &xor    ("eax",&DWP(8,"edi"));
2496                 &mov    (&DWP(32,"edi"),"eax");         # rk[8]
2497                 &xor    ("eax",&DWP(12,"edi"));
2498                 &mov    (&DWP(36,"edi"),"eax");         # rk[9]
2499
2500                 &cmp    ("ecx",7);
2501                 &je     (&label("12break"));
2502                 &inc    ("ecx");
2503
2504                 &xor    ("eax",&DWP(16,"edi"));
2505                 &mov    (&DWP(40,"edi"),"eax");         # rk[10]
2506                 &xor    ("eax",&DWP(20,"edi"));
2507                 &mov    (&DWP(44,"edi"),"eax");         # rk[11]
2508
2509                 &add    ("edi",24);
2510         &jmp    (&label("12loop"));
2511
2512         &set_label("12break");
2513         &mov    (&DWP(72,"edi"),12);            # setup number of rounds
2514         &xor    ("eax","eax");
2515         &jmp    (&label("exit"));
2516
2517     &set_label("14rounds");
2518         &mov    ("eax",&DWP(0,"esi"));          # copy first 8 dwords
2519         &mov    ("ebx",&DWP(4,"esi"));
2520         &mov    ("ecx",&DWP(8,"esi"));
2521         &mov    ("edx",&DWP(12,"esi"));
2522         &mov    (&DWP(0,"edi"),"eax");
2523         &mov    (&DWP(4,"edi"),"ebx");
2524         &mov    (&DWP(8,"edi"),"ecx");
2525         &mov    (&DWP(12,"edi"),"edx");
2526         &mov    ("eax",&DWP(16,"esi"));
2527         &mov    ("ebx",&DWP(20,"esi"));
2528         &mov    ("ecx",&DWP(24,"esi"));
2529         &mov    ("edx",&DWP(28,"esi"));
2530         &mov    (&DWP(16,"edi"),"eax");
2531         &mov    (&DWP(20,"edi"),"ebx");
2532         &mov    (&DWP(24,"edi"),"ecx");
2533         &mov    (&DWP(28,"edi"),"edx");
2534
2535         &xor    ("ecx","ecx");
2536         &jmp    (&label("14shortcut"));
2537
2538         &align  (4);
2539         &set_label("14loop");
2540                 &mov    ("edx",&DWP(28,"edi"));         # rk[7]
2541         &set_label("14shortcut");
2542                 &mov    ("eax",&DWP(0,"edi"));          # rk[0]
2543
2544                 &enckey ();
2545
2546                 &mov    (&DWP(32,"edi"),"eax");         # rk[8]
2547                 &xor    ("eax",&DWP(4,"edi"));
2548                 &mov    (&DWP(36,"edi"),"eax");         # rk[9]
2549                 &xor    ("eax",&DWP(8,"edi"));
2550                 &mov    (&DWP(40,"edi"),"eax");         # rk[10]
2551                 &xor    ("eax",&DWP(12,"edi"));
2552                 &mov    (&DWP(44,"edi"),"eax");         # rk[11]
2553
2554                 &cmp    ("ecx",6);
2555                 &je     (&label("14break"));
2556                 &inc    ("ecx");
2557
2558                 &mov    ("edx","eax");
2559                 &mov    ("eax",&DWP(16,"edi"));         # rk[4]
2560                 &movz   ("esi",&LB("edx"));             # rk[11]>>0
2561                 &movz   ("ebx",&BP(-128,$tbl,"esi",1));
2562                 &movz   ("esi",&HB("edx"));             # rk[11]>>8
2563                 &xor    ("eax","ebx");
2564
2565                 &movz   ("ebx",&BP(-128,$tbl,"esi",1));
2566                 &shr    ("edx",16);
2567                 &shl    ("ebx",8);
2568                 &movz   ("esi",&LB("edx"));             # rk[11]>>16
2569                 &xor    ("eax","ebx");
2570
2571                 &movz   ("ebx",&BP(-128,$tbl,"esi",1));
2572                 &movz   ("esi",&HB("edx"));             # rk[11]>>24
2573                 &shl    ("ebx",16);
2574                 &xor    ("eax","ebx");
2575
2576                 &movz   ("ebx",&BP(-128,$tbl,"esi",1));
2577                 &shl    ("ebx",24);
2578                 &xor    ("eax","ebx");
2579
2580                 &mov    (&DWP(48,"edi"),"eax");         # rk[12]
2581                 &xor    ("eax",&DWP(20,"edi"));
2582                 &mov    (&DWP(52,"edi"),"eax");         # rk[13]
2583                 &xor    ("eax",&DWP(24,"edi"));
2584                 &mov    (&DWP(56,"edi"),"eax");         # rk[14]
2585                 &xor    ("eax",&DWP(28,"edi"));
2586                 &mov    (&DWP(60,"edi"),"eax");         # rk[15]
2587
2588                 &add    ("edi",32);
2589         &jmp    (&label("14loop"));
2590
2591         &set_label("14break");
2592         &mov    (&DWP(48,"edi"),14);            # setup number of rounds
2593         &xor    ("eax","eax");
2594         &jmp    (&label("exit"));
2595
2596     &set_label("badpointer");
2597         &mov    ("eax",-1);
2598     &set_label("exit");
2599 &function_end("AES_set_encrypt_key");
2600
2601 sub deckey()
2602 { my ($i,$key,$tp1,$tp2,$tp4,$tp8) = @_;
2603   my $tmp = $tbl;
2604
2605         &mov    ($acc,$tp1);
2606         &and    ($acc,0x80808080);
2607         &mov    ($tmp,$acc);
2608         &mov    ($tp2,$tp1);
2609         &shr    ($tmp,7);
2610         &and    ($tp2,0x7f7f7f7f);
2611         &sub    ($acc,$tmp);
2612         &add    ($tp2,$tp2);
2613         &and    ($acc,0x1b1b1b1b);
2614         &xor    ($acc,$tp2);
2615         &mov    ($tp2,$acc);
2616
2617         &and    ($acc,0x80808080);
2618         &mov    ($tmp,$acc);
2619         &mov    ($tp4,$tp2);
2620          &xor   ($tp2,$tp1);    # tp2^tp1
2621         &shr    ($tmp,7);
2622         &and    ($tp4,0x7f7f7f7f);
2623         &sub    ($acc,$tmp);
2624         &add    ($tp4,$tp4);
2625         &and    ($acc,0x1b1b1b1b);
2626         &xor    ($acc,$tp4);
2627         &mov    ($tp4,$acc);
2628
2629         &and    ($acc,0x80808080);
2630         &mov    ($tmp,$acc);
2631         &mov    ($tp8,$tp4);
2632          &xor   ($tp4,$tp1);    # tp4^tp1
2633         &shr    ($tmp,7);
2634         &and    ($tp8,0x7f7f7f7f);
2635         &sub    ($acc,$tmp);
2636         &add    ($tp8,$tp8);
2637         &and    ($acc,0x1b1b1b1b);
2638          &rotl  ($tp1,8);       # = ROTATE(tp1,8)
2639         &xor    ($tp8,$acc);
2640
2641         &mov    ($tmp,&DWP(4*($i+1),$key));     # modulo-scheduled load
2642
2643         &xor    ($tp1,$tp2);
2644         &xor    ($tp2,$tp8);
2645         &xor    ($tp1,$tp4);
2646         &rotl   ($tp2,24);
2647         &xor    ($tp4,$tp8);
2648         &xor    ($tp1,$tp8);    # ^= tp8^(tp4^tp1)^(tp2^tp1)
2649         &rotl   ($tp4,16);
2650         &xor    ($tp1,$tp2);    # ^= ROTATE(tp8^tp2^tp1,24)
2651         &rotl   ($tp8,8);
2652         &xor    ($tp1,$tp4);    # ^= ROTATE(tp8^tp4^tp1,16)
2653         &mov    ($tp2,$tmp);
2654         &xor    ($tp1,$tp8);    # ^= ROTATE(tp8,8)
2655
2656         &mov    (&DWP(4*$i,$key),$tp1);
2657 }
2658
2659 # int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
2660 #                        AES_KEY *key)
2661 &public_label("AES_Td");
2662 &public_label("AES_Te");
2663 &function_begin_B("AES_set_decrypt_key");
2664         &mov    ("eax",&wparam(0));
2665         &mov    ("ecx",&wparam(1));
2666         &mov    ("edx",&wparam(2));
2667         &sub    ("esp",12);
2668         &mov    (&DWP(0,"esp"),"eax");
2669         &mov    (&DWP(4,"esp"),"ecx");
2670         &mov    (&DWP(8,"esp"),"edx");
2671         &call   ("AES_set_encrypt_key");
2672         &add    ("esp",12);
2673         &cmp    ("eax",0);
2674         &je     (&label("proceed"));
2675         &ret    ();
2676
2677     &set_label("proceed");
2678         &push   ("ebp");
2679         &push   ("ebx");
2680         &push   ("esi");
2681         &push   ("edi");
2682
2683         &mov    ("esi",&wparam(2));
2684         &mov    ("ecx",&DWP(240,"esi"));        # pull number of rounds
2685         &lea    ("ecx",&DWP(0,"","ecx",4));
2686         &lea    ("edi",&DWP(0,"esi","ecx",4));  # pointer to last chunk
2687
2688         &set_label("invert",4);                 # invert order of chunks
2689                 &mov    ("eax",&DWP(0,"esi"));
2690                 &mov    ("ebx",&DWP(4,"esi"));
2691                 &mov    ("ecx",&DWP(0,"edi"));
2692                 &mov    ("edx",&DWP(4,"edi"));
2693                 &mov    (&DWP(0,"edi"),"eax");
2694                 &mov    (&DWP(4,"edi"),"ebx");
2695                 &mov    (&DWP(0,"esi"),"ecx");
2696                 &mov    (&DWP(4,"esi"),"edx");
2697                 &mov    ("eax",&DWP(8,"esi"));
2698                 &mov    ("ebx",&DWP(12,"esi"));
2699                 &mov    ("ecx",&DWP(8,"edi"));
2700                 &mov    ("edx",&DWP(12,"edi"));
2701                 &mov    (&DWP(8,"edi"),"eax");
2702                 &mov    (&DWP(12,"edi"),"ebx");
2703                 &mov    (&DWP(8,"esi"),"ecx");
2704                 &mov    (&DWP(12,"esi"),"edx");
2705                 &add    ("esi",16);
2706                 &sub    ("edi",16);
2707                 &cmp    ("esi","edi");
2708         &jne    (&label("invert"));
2709
2710         &mov    ($key,&wparam(2));
2711         &mov    ($acc,&DWP(240,$key));          # pull number of rounds
2712         &lea    ($acc,&DWP(-2,$acc,$acc));
2713         &lea    ($acc,&DWP(0,$key,$acc,8));
2714         &mov    (&wparam(2),$acc);
2715
2716         &mov    ($s0,&DWP(16,$key));            # modulo-scheduled load
2717         &set_label("permute",4);                # permute the key schedule
2718                 &add    ($key,16);
2719                 &deckey (0,$key,$s0,$s1,$s2,$s3);
2720                 &deckey (1,$key,$s1,$s2,$s3,$s0);
2721                 &deckey (2,$key,$s2,$s3,$s0,$s1);
2722                 &deckey (3,$key,$s3,$s0,$s1,$s2);
2723                 &cmp    ($key,&wparam(2));
2724         &jb     (&label("permute"));
2725
2726         &xor    ("eax","eax");                  # return success
2727 &function_end("AES_set_decrypt_key");
2728
2729 &asm_finish();