c3df97db7b1421a42fc721441525af09f9848ba1
[openssl.git] / crypto / aes / asm / aesni-x86.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # This module implements support for Intel AES-NI extension. In
11 # OpenSSL context it's used with Intel engine, but can also be used as
12 # drop-in replacement for crypto/aes/asm/aes-586.pl [see below for
13 # details].
14 #
15 # Performance.
16 #
17 # To start with see corresponding paragraph in aesni-x86_64.pl...
18 # Instead of filling table similar to one found there I've chosen to
19 # summarize *comparison* results for raw ECB, CTR and CBC benchmarks.
20 # The simplified table below represents 32-bit performance relative
21 # to 64-bit one in every given point. Ratios vary for different
22 # encryption modes, therefore interval values.
23 #
24 #       16-byte     64-byte     256-byte    1-KB        8-KB
25 #       53-67%      67-84%      91-94%      95-98%      97-99.5%
26 #
27 # Lower ratios for smaller block sizes are perfectly understandable,
28 # because function call overhead is higher in 32-bit mode. Largest
29 # 8-KB block performance is virtually same: 32-bit code is less than
30 # 1% slower for ECB, CBC and CCM, and ~3% slower otherwise.
31
32 # January 2011
33 #
34 # See aesni-x86_64.pl for details. Unlike x86_64 version this module
35 # interleaves at most 6 aes[enc|dec] instructions, because there are
36 # not enough registers for 8x interleave [which should be optimal for
37 # Sandy Bridge]. Actually, performance results for 6x interleave
38 # factor presented in aesni-x86_64.pl (except for CTR) are for this
39 # module.
40
41 # April 2011
42 #
43 # Add aesni_xts_[en|de]crypt. Westmere spends 1.50 cycles processing
44 # one byte out of 8KB with 128-bit key, Sandy Bridge - 1.09.
45
46 ######################################################################
47 # Current large-block performance in cycles per byte processed with
48 # 128-bit key (less is better).
49 #
50 #               CBC en-/decrypt CTR     XTS     ECB
51 # Westmere      3.77/1.37       1.37    1.52    1.27
52 # * Bridge      5.07/0.98       0.99    1.09    0.91
53 # Haswell       4.44/0.80       0.97    1.03    0.72
54 # Atom          5.77/3.56       3.67    4.03    3.46
55 # Bulldozer     5.80/0.98       1.05    1.24    0.93
56
57 $PREFIX="aesni";        # if $PREFIX is set to "AES", the script
58                         # generates drop-in replacement for
59                         # crypto/aes/asm/aes-586.pl:-)
60 $inline=1;              # inline _aesni_[en|de]crypt
61
62 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
63 push(@INC,"${dir}","${dir}../../perlasm");
64 require "x86asm.pl";
65
66 &asm_init($ARGV[0],$0);
67
68 if ($PREFIX eq "aesni") { $movekey=\&movups; }
69 else                    { $movekey=\&movups; }
70
71 $len="eax";
72 $rounds="ecx";
73 $key="edx";
74 $inp="esi";
75 $out="edi";
76 $rounds_="ebx"; # backup copy for $rounds
77 $key_="ebp";    # backup copy for $key
78
79 $rndkey0="xmm0";
80 $rndkey1="xmm1";
81 $inout0="xmm2";
82 $inout1="xmm3";
83 $inout2="xmm4";
84 $inout3="xmm5"; $in1="xmm5";
85 $inout4="xmm6"; $in0="xmm6";
86 $inout5="xmm7"; $ivec="xmm7";
87
88 # AESNI extenstion
89 sub aeskeygenassist
90 { my($dst,$src,$imm)=@_;
91     if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
92     {   &data_byte(0x66,0x0f,0x3a,0xdf,0xc0|($1<<3)|$2,$imm);   }
93 }
94 sub aescommon
95 { my($opcodelet,$dst,$src)=@_;
96     if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
97     {   &data_byte(0x66,0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2);}
98 }
99 sub aesimc      { aescommon(0xdb,@_); }
100 sub aesenc      { aescommon(0xdc,@_); }
101 sub aesenclast  { aescommon(0xdd,@_); }
102 sub aesdec      { aescommon(0xde,@_); }
103 sub aesdeclast  { aescommon(0xdf,@_); }
104 \f
105 # Inline version of internal aesni_[en|de]crypt1
106 { my $sn;
107 sub aesni_inline_generate1
108 { my ($p,$inout,$ivec)=@_; $inout=$inout0 if (!defined($inout));
109   $sn++;
110
111     &$movekey           ($rndkey0,&QWP(0,$key));
112     &$movekey           ($rndkey1,&QWP(16,$key));
113     &xorps              ($ivec,$rndkey0)        if (defined($ivec));
114     &lea                ($key,&DWP(32,$key));
115     &xorps              ($inout,$ivec)          if (defined($ivec));
116     &xorps              ($inout,$rndkey0)       if (!defined($ivec));
117     &set_label("${p}1_loop_$sn");
118         eval"&aes${p}   ($inout,$rndkey1)";
119         &dec            ($rounds);
120         &$movekey       ($rndkey1,&QWP(0,$key));
121         &lea            ($key,&DWP(16,$key));
122     &jnz                (&label("${p}1_loop_$sn"));
123     eval"&aes${p}last   ($inout,$rndkey1)";
124 }}
125
126 sub aesni_generate1     # fully unrolled loop
127 { my ($p,$inout)=@_; $inout=$inout0 if (!defined($inout));
128
129     &function_begin_B("_aesni_${p}rypt1");
130         &movups         ($rndkey0,&QWP(0,$key));
131         &$movekey       ($rndkey1,&QWP(0x10,$key));
132         &xorps          ($inout,$rndkey0);
133         &$movekey       ($rndkey0,&QWP(0x20,$key));
134         &lea            ($key,&DWP(0x30,$key));
135         &cmp            ($rounds,11);
136         &jb             (&label("${p}128"));
137         &lea            ($key,&DWP(0x20,$key));
138         &je             (&label("${p}192"));
139         &lea            ($key,&DWP(0x20,$key));
140         eval"&aes${p}   ($inout,$rndkey1)";
141         &$movekey       ($rndkey1,&QWP(-0x40,$key));
142         eval"&aes${p}   ($inout,$rndkey0)";
143         &$movekey       ($rndkey0,&QWP(-0x30,$key));
144     &set_label("${p}192");
145         eval"&aes${p}   ($inout,$rndkey1)";
146         &$movekey       ($rndkey1,&QWP(-0x20,$key));
147         eval"&aes${p}   ($inout,$rndkey0)";
148         &$movekey       ($rndkey0,&QWP(-0x10,$key));
149     &set_label("${p}128");
150         eval"&aes${p}   ($inout,$rndkey1)";
151         &$movekey       ($rndkey1,&QWP(0,$key));
152         eval"&aes${p}   ($inout,$rndkey0)";
153         &$movekey       ($rndkey0,&QWP(0x10,$key));
154         eval"&aes${p}   ($inout,$rndkey1)";
155         &$movekey       ($rndkey1,&QWP(0x20,$key));
156         eval"&aes${p}   ($inout,$rndkey0)";
157         &$movekey       ($rndkey0,&QWP(0x30,$key));
158         eval"&aes${p}   ($inout,$rndkey1)";
159         &$movekey       ($rndkey1,&QWP(0x40,$key));
160         eval"&aes${p}   ($inout,$rndkey0)";
161         &$movekey       ($rndkey0,&QWP(0x50,$key));
162         eval"&aes${p}   ($inout,$rndkey1)";
163         &$movekey       ($rndkey1,&QWP(0x60,$key));
164         eval"&aes${p}   ($inout,$rndkey0)";
165         &$movekey       ($rndkey0,&QWP(0x70,$key));
166         eval"&aes${p}   ($inout,$rndkey1)";
167     eval"&aes${p}last   ($inout,$rndkey0)";
168     &ret();
169     &function_end_B("_aesni_${p}rypt1");
170 }
171 \f
172 # void $PREFIX_encrypt (const void *inp,void *out,const AES_KEY *key);
173 &aesni_generate1("enc") if (!$inline);
174 &function_begin_B("${PREFIX}_encrypt");
175         &mov    ("eax",&wparam(0));
176         &mov    ($key,&wparam(2));
177         &movups ($inout0,&QWP(0,"eax"));
178         &mov    ($rounds,&DWP(240,$key));
179         &mov    ("eax",&wparam(1));
180         if ($inline)
181         {   &aesni_inline_generate1("enc");     }
182         else
183         {   &call       ("_aesni_encrypt1");    }
184         &movups (&QWP(0,"eax"),$inout0);
185         &ret    ();
186 &function_end_B("${PREFIX}_encrypt");
187
188 # void $PREFIX_decrypt (const void *inp,void *out,const AES_KEY *key);
189 &aesni_generate1("dec") if(!$inline);
190 &function_begin_B("${PREFIX}_decrypt");
191         &mov    ("eax",&wparam(0));
192         &mov    ($key,&wparam(2));
193         &movups ($inout0,&QWP(0,"eax"));
194         &mov    ($rounds,&DWP(240,$key));
195         &mov    ("eax",&wparam(1));
196         if ($inline)
197         {   &aesni_inline_generate1("dec");     }
198         else
199         {   &call       ("_aesni_decrypt1");    }
200         &movups (&QWP(0,"eax"),$inout0);
201         &ret    ();
202 &function_end_B("${PREFIX}_decrypt");
203
204 # _aesni_[en|de]cryptN are private interfaces, N denotes interleave
205 # factor. Why 3x subroutine were originally used in loops? Even though
206 # aes[enc|dec] latency was originally 6, it could be scheduled only
207 # every *2nd* cycle. Thus 3x interleave was the one providing optimal
208 # utilization, i.e. when subroutine's throughput is virtually same as
209 # of non-interleaved subroutine [for number of input blocks up to 3].
210 # This is why it makes no sense to implement 2x subroutine.
211 # aes[enc|dec] latency in next processor generation is 8, but the
212 # instructions can be scheduled every cycle. Optimal interleave for
213 # new processor is therefore 8x, but it's unfeasible to accommodate it
214 # in XMM registers addreassable in 32-bit mode and therefore 6x is
215 # used instead...
216
217 sub aesni_generate3
218 { my $p=shift;
219
220     &function_begin_B("_aesni_${p}rypt3");
221         &$movekey       ($rndkey0,&QWP(0,$key));
222         &shl            ($rounds,4);
223         &$movekey       ($rndkey1,&QWP(16,$key));
224         &xorps          ($inout0,$rndkey0);
225         &pxor           ($inout1,$rndkey0);
226         &pxor           ($inout2,$rndkey0);
227         &$movekey       ($rndkey0,&QWP(32,$key));
228         &lea            ($key,&DWP(32,$key,$rounds));
229         &neg            ($rounds);
230         &add            ($rounds,16);
231
232     &set_label("${p}3_loop");
233         eval"&aes${p}   ($inout0,$rndkey1)";
234         eval"&aes${p}   ($inout1,$rndkey1)";
235         eval"&aes${p}   ($inout2,$rndkey1)";
236         &$movekey       ($rndkey1,&QWP(0,$key,$rounds));
237         &add            ($rounds,32);
238         eval"&aes${p}   ($inout0,$rndkey0)";
239         eval"&aes${p}   ($inout1,$rndkey0)";
240         eval"&aes${p}   ($inout2,$rndkey0)";
241         &$movekey       ($rndkey0,&QWP(-16,$key,$rounds));
242         &jnz            (&label("${p}3_loop"));
243     eval"&aes${p}       ($inout0,$rndkey1)";
244     eval"&aes${p}       ($inout1,$rndkey1)";
245     eval"&aes${p}       ($inout2,$rndkey1)";
246     eval"&aes${p}last   ($inout0,$rndkey0)";
247     eval"&aes${p}last   ($inout1,$rndkey0)";
248     eval"&aes${p}last   ($inout2,$rndkey0)";
249     &ret();
250     &function_end_B("_aesni_${p}rypt3");
251 }
252
253 # 4x interleave is implemented to improve small block performance,
254 # most notably [and naturally] 4 block by ~30%. One can argue that one
255 # should have implemented 5x as well, but improvement  would be <20%,
256 # so it's not worth it...
257 sub aesni_generate4
258 { my $p=shift;
259
260     &function_begin_B("_aesni_${p}rypt4");
261         &$movekey       ($rndkey0,&QWP(0,$key));
262         &$movekey       ($rndkey1,&QWP(16,$key));
263         &shl            ($rounds,4);
264         &xorps          ($inout0,$rndkey0);
265         &pxor           ($inout1,$rndkey0);
266         &pxor           ($inout2,$rndkey0);
267         &pxor           ($inout3,$rndkey0);
268         &$movekey       ($rndkey0,&QWP(32,$key));
269         &lea            ($key,&DWP(32,$key,$rounds));
270         &neg            ($rounds);
271         &data_byte      (0x0f,0x1f,0x40,0x00);
272         &add            ($rounds,16);
273
274     &set_label("${p}4_loop");
275         eval"&aes${p}   ($inout0,$rndkey1)";
276         eval"&aes${p}   ($inout1,$rndkey1)";
277         eval"&aes${p}   ($inout2,$rndkey1)";
278         eval"&aes${p}   ($inout3,$rndkey1)";
279         &$movekey       ($rndkey1,&QWP(0,$key,$rounds));
280         &add            ($rounds,32);
281         eval"&aes${p}   ($inout0,$rndkey0)";
282         eval"&aes${p}   ($inout1,$rndkey0)";
283         eval"&aes${p}   ($inout2,$rndkey0)";
284         eval"&aes${p}   ($inout3,$rndkey0)";
285         &$movekey       ($rndkey0,&QWP(-16,$key,$rounds));
286     &jnz                (&label("${p}4_loop"));
287
288     eval"&aes${p}       ($inout0,$rndkey1)";
289     eval"&aes${p}       ($inout1,$rndkey1)";
290     eval"&aes${p}       ($inout2,$rndkey1)";
291     eval"&aes${p}       ($inout3,$rndkey1)";
292     eval"&aes${p}last   ($inout0,$rndkey0)";
293     eval"&aes${p}last   ($inout1,$rndkey0)";
294     eval"&aes${p}last   ($inout2,$rndkey0)";
295     eval"&aes${p}last   ($inout3,$rndkey0)";
296     &ret();
297     &function_end_B("_aesni_${p}rypt4");
298 }
299
300 sub aesni_generate6
301 { my $p=shift;
302
303     &function_begin_B("_aesni_${p}rypt6");
304     &static_label("_aesni_${p}rypt6_enter");
305         &$movekey       ($rndkey0,&QWP(0,$key));
306         &shl            ($rounds,4);
307         &$movekey       ($rndkey1,&QWP(16,$key));
308         &xorps          ($inout0,$rndkey0);
309         &pxor           ($inout1,$rndkey0);     # pxor does better here
310         &pxor           ($inout2,$rndkey0);
311         eval"&aes${p}   ($inout0,$rndkey1)";
312         &pxor           ($inout3,$rndkey0);
313         &pxor           ($inout4,$rndkey0);
314         eval"&aes${p}   ($inout1,$rndkey1)";
315         &lea            ($key,&DWP(32,$key,$rounds));
316         &neg            ($rounds);
317         eval"&aes${p}   ($inout2,$rndkey1)";
318         &pxor           ($inout5,$rndkey0);
319         &add            ($rounds,16);
320         eval"&aes${p}   ($inout3,$rndkey1)";
321         eval"&aes${p}   ($inout4,$rndkey1)";
322         eval"&aes${p}   ($inout5,$rndkey1)";
323         &$movekey       ($rndkey0,&QWP(-16,$key,$rounds));
324         &jmp            (&label("_aesni_${p}rypt6_enter"));
325
326     &set_label("${p}6_loop",16);
327         eval"&aes${p}   ($inout0,$rndkey1)";
328         eval"&aes${p}   ($inout1,$rndkey1)";
329         eval"&aes${p}   ($inout2,$rndkey1)";
330         eval"&aes${p}   ($inout3,$rndkey1)";
331         eval"&aes${p}   ($inout4,$rndkey1)";
332         eval"&aes${p}   ($inout5,$rndkey1)";
333     &set_label("_aesni_${p}rypt6_enter");
334         &$movekey       ($rndkey1,&QWP(0,$key,$rounds));
335         &add            ($rounds,32);
336         eval"&aes${p}   ($inout0,$rndkey0)";
337         eval"&aes${p}   ($inout1,$rndkey0)";
338         eval"&aes${p}   ($inout2,$rndkey0)";
339         eval"&aes${p}   ($inout3,$rndkey0)";
340         eval"&aes${p}   ($inout4,$rndkey0)";
341         eval"&aes${p}   ($inout5,$rndkey0)";
342         &$movekey       ($rndkey0,&QWP(-16,$key,$rounds));
343     &jnz                (&label("${p}6_loop"));
344
345     eval"&aes${p}       ($inout0,$rndkey1)";
346     eval"&aes${p}       ($inout1,$rndkey1)";
347     eval"&aes${p}       ($inout2,$rndkey1)";
348     eval"&aes${p}       ($inout3,$rndkey1)";
349     eval"&aes${p}       ($inout4,$rndkey1)";
350     eval"&aes${p}       ($inout5,$rndkey1)";
351     eval"&aes${p}last   ($inout0,$rndkey0)";
352     eval"&aes${p}last   ($inout1,$rndkey0)";
353     eval"&aes${p}last   ($inout2,$rndkey0)";
354     eval"&aes${p}last   ($inout3,$rndkey0)";
355     eval"&aes${p}last   ($inout4,$rndkey0)";
356     eval"&aes${p}last   ($inout5,$rndkey0)";
357     &ret();
358     &function_end_B("_aesni_${p}rypt6");
359 }
360 &aesni_generate3("enc") if ($PREFIX eq "aesni");
361 &aesni_generate3("dec");
362 &aesni_generate4("enc") if ($PREFIX eq "aesni");
363 &aesni_generate4("dec");
364 &aesni_generate6("enc") if ($PREFIX eq "aesni");
365 &aesni_generate6("dec");
366 \f
367 if ($PREFIX eq "aesni") {
368 ######################################################################
369 # void aesni_ecb_encrypt (const void *in, void *out,
370 #                         size_t length, const AES_KEY *key,
371 #                         int enc);
372 &function_begin("aesni_ecb_encrypt");
373         &mov    ($inp,&wparam(0));
374         &mov    ($out,&wparam(1));
375         &mov    ($len,&wparam(2));
376         &mov    ($key,&wparam(3));
377         &mov    ($rounds_,&wparam(4));
378         &and    ($len,-16);
379         &jz     (&label("ecb_ret"));
380         &mov    ($rounds,&DWP(240,$key));
381         &test   ($rounds_,$rounds_);
382         &jz     (&label("ecb_decrypt"));
383
384         &mov    ($key_,$key);           # backup $key
385         &mov    ($rounds_,$rounds);     # backup $rounds
386         &cmp    ($len,0x60);
387         &jb     (&label("ecb_enc_tail"));
388
389         &movdqu ($inout0,&QWP(0,$inp));
390         &movdqu ($inout1,&QWP(0x10,$inp));
391         &movdqu ($inout2,&QWP(0x20,$inp));
392         &movdqu ($inout3,&QWP(0x30,$inp));
393         &movdqu ($inout4,&QWP(0x40,$inp));
394         &movdqu ($inout5,&QWP(0x50,$inp));
395         &lea    ($inp,&DWP(0x60,$inp));
396         &sub    ($len,0x60);
397         &jmp    (&label("ecb_enc_loop6_enter"));
398
399 &set_label("ecb_enc_loop6",16);
400         &movups (&QWP(0,$out),$inout0);
401         &movdqu ($inout0,&QWP(0,$inp));
402         &movups (&QWP(0x10,$out),$inout1);
403         &movdqu ($inout1,&QWP(0x10,$inp));
404         &movups (&QWP(0x20,$out),$inout2);
405         &movdqu ($inout2,&QWP(0x20,$inp));
406         &movups (&QWP(0x30,$out),$inout3);
407         &movdqu ($inout3,&QWP(0x30,$inp));
408         &movups (&QWP(0x40,$out),$inout4);
409         &movdqu ($inout4,&QWP(0x40,$inp));
410         &movups (&QWP(0x50,$out),$inout5);
411         &lea    ($out,&DWP(0x60,$out));
412         &movdqu ($inout5,&QWP(0x50,$inp));
413         &lea    ($inp,&DWP(0x60,$inp));
414 &set_label("ecb_enc_loop6_enter");
415
416         &call   ("_aesni_encrypt6");
417
418         &mov    ($key,$key_);           # restore $key
419         &mov    ($rounds,$rounds_);     # restore $rounds
420         &sub    ($len,0x60);
421         &jnc    (&label("ecb_enc_loop6"));
422
423         &movups (&QWP(0,$out),$inout0);
424         &movups (&QWP(0x10,$out),$inout1);
425         &movups (&QWP(0x20,$out),$inout2);
426         &movups (&QWP(0x30,$out),$inout3);
427         &movups (&QWP(0x40,$out),$inout4);
428         &movups (&QWP(0x50,$out),$inout5);
429         &lea    ($out,&DWP(0x60,$out));
430         &add    ($len,0x60);
431         &jz     (&label("ecb_ret"));
432
433 &set_label("ecb_enc_tail");
434         &movups ($inout0,&QWP(0,$inp));
435         &cmp    ($len,0x20);
436         &jb     (&label("ecb_enc_one"));
437         &movups ($inout1,&QWP(0x10,$inp));
438         &je     (&label("ecb_enc_two"));
439         &movups ($inout2,&QWP(0x20,$inp));
440         &cmp    ($len,0x40);
441         &jb     (&label("ecb_enc_three"));
442         &movups ($inout3,&QWP(0x30,$inp));
443         &je     (&label("ecb_enc_four"));
444         &movups ($inout4,&QWP(0x40,$inp));
445         &xorps  ($inout5,$inout5);
446         &call   ("_aesni_encrypt6");
447         &movups (&QWP(0,$out),$inout0);
448         &movups (&QWP(0x10,$out),$inout1);
449         &movups (&QWP(0x20,$out),$inout2);
450         &movups (&QWP(0x30,$out),$inout3);
451         &movups (&QWP(0x40,$out),$inout4);
452         jmp     (&label("ecb_ret"));
453
454 &set_label("ecb_enc_one",16);
455         if ($inline)
456         {   &aesni_inline_generate1("enc");     }
457         else
458         {   &call       ("_aesni_encrypt1");    }
459         &movups (&QWP(0,$out),$inout0);
460         &jmp    (&label("ecb_ret"));
461
462 &set_label("ecb_enc_two",16);
463         &xorps  ($inout2,$inout2);
464         &call   ("_aesni_encrypt3");
465         &movups (&QWP(0,$out),$inout0);
466         &movups (&QWP(0x10,$out),$inout1);
467         &jmp    (&label("ecb_ret"));
468
469 &set_label("ecb_enc_three",16);
470         &call   ("_aesni_encrypt3");
471         &movups (&QWP(0,$out),$inout0);
472         &movups (&QWP(0x10,$out),$inout1);
473         &movups (&QWP(0x20,$out),$inout2);
474         &jmp    (&label("ecb_ret"));
475
476 &set_label("ecb_enc_four",16);
477         &call   ("_aesni_encrypt4");
478         &movups (&QWP(0,$out),$inout0);
479         &movups (&QWP(0x10,$out),$inout1);
480         &movups (&QWP(0x20,$out),$inout2);
481         &movups (&QWP(0x30,$out),$inout3);
482         &jmp    (&label("ecb_ret"));
483 ######################################################################
484 &set_label("ecb_decrypt",16);
485         &mov    ($key_,$key);           # backup $key
486         &mov    ($rounds_,$rounds);     # backup $rounds
487         &cmp    ($len,0x60);
488         &jb     (&label("ecb_dec_tail"));
489
490         &movdqu ($inout0,&QWP(0,$inp));
491         &movdqu ($inout1,&QWP(0x10,$inp));
492         &movdqu ($inout2,&QWP(0x20,$inp));
493         &movdqu ($inout3,&QWP(0x30,$inp));
494         &movdqu ($inout4,&QWP(0x40,$inp));
495         &movdqu ($inout5,&QWP(0x50,$inp));
496         &lea    ($inp,&DWP(0x60,$inp));
497         &sub    ($len,0x60);
498         &jmp    (&label("ecb_dec_loop6_enter"));
499
500 &set_label("ecb_dec_loop6",16);
501         &movups (&QWP(0,$out),$inout0);
502         &movdqu ($inout0,&QWP(0,$inp));
503         &movups (&QWP(0x10,$out),$inout1);
504         &movdqu ($inout1,&QWP(0x10,$inp));
505         &movups (&QWP(0x20,$out),$inout2);
506         &movdqu ($inout2,&QWP(0x20,$inp));
507         &movups (&QWP(0x30,$out),$inout3);
508         &movdqu ($inout3,&QWP(0x30,$inp));
509         &movups (&QWP(0x40,$out),$inout4);
510         &movdqu ($inout4,&QWP(0x40,$inp));
511         &movups (&QWP(0x50,$out),$inout5);
512         &lea    ($out,&DWP(0x60,$out));
513         &movdqu ($inout5,&QWP(0x50,$inp));
514         &lea    ($inp,&DWP(0x60,$inp));
515 &set_label("ecb_dec_loop6_enter");
516
517         &call   ("_aesni_decrypt6");
518
519         &mov    ($key,$key_);           # restore $key
520         &mov    ($rounds,$rounds_);     # restore $rounds
521         &sub    ($len,0x60);
522         &jnc    (&label("ecb_dec_loop6"));
523
524         &movups (&QWP(0,$out),$inout0);
525         &movups (&QWP(0x10,$out),$inout1);
526         &movups (&QWP(0x20,$out),$inout2);
527         &movups (&QWP(0x30,$out),$inout3);
528         &movups (&QWP(0x40,$out),$inout4);
529         &movups (&QWP(0x50,$out),$inout5);
530         &lea    ($out,&DWP(0x60,$out));
531         &add    ($len,0x60);
532         &jz     (&label("ecb_ret"));
533
534 &set_label("ecb_dec_tail");
535         &movups ($inout0,&QWP(0,$inp));
536         &cmp    ($len,0x20);
537         &jb     (&label("ecb_dec_one"));
538         &movups ($inout1,&QWP(0x10,$inp));
539         &je     (&label("ecb_dec_two"));
540         &movups ($inout2,&QWP(0x20,$inp));
541         &cmp    ($len,0x40);
542         &jb     (&label("ecb_dec_three"));
543         &movups ($inout3,&QWP(0x30,$inp));
544         &je     (&label("ecb_dec_four"));
545         &movups ($inout4,&QWP(0x40,$inp));
546         &xorps  ($inout5,$inout5);
547         &call   ("_aesni_decrypt6");
548         &movups (&QWP(0,$out),$inout0);
549         &movups (&QWP(0x10,$out),$inout1);
550         &movups (&QWP(0x20,$out),$inout2);
551         &movups (&QWP(0x30,$out),$inout3);
552         &movups (&QWP(0x40,$out),$inout4);
553         &jmp    (&label("ecb_ret"));
554
555 &set_label("ecb_dec_one",16);
556         if ($inline)
557         {   &aesni_inline_generate1("dec");     }
558         else
559         {   &call       ("_aesni_decrypt1");    }
560         &movups (&QWP(0,$out),$inout0);
561         &jmp    (&label("ecb_ret"));
562
563 &set_label("ecb_dec_two",16);
564         &xorps  ($inout2,$inout2);
565         &call   ("_aesni_decrypt3");
566         &movups (&QWP(0,$out),$inout0);
567         &movups (&QWP(0x10,$out),$inout1);
568         &jmp    (&label("ecb_ret"));
569
570 &set_label("ecb_dec_three",16);
571         &call   ("_aesni_decrypt3");
572         &movups (&QWP(0,$out),$inout0);
573         &movups (&QWP(0x10,$out),$inout1);
574         &movups (&QWP(0x20,$out),$inout2);
575         &jmp    (&label("ecb_ret"));
576
577 &set_label("ecb_dec_four",16);
578         &call   ("_aesni_decrypt4");
579         &movups (&QWP(0,$out),$inout0);
580         &movups (&QWP(0x10,$out),$inout1);
581         &movups (&QWP(0x20,$out),$inout2);
582         &movups (&QWP(0x30,$out),$inout3);
583
584 &set_label("ecb_ret");
585 &function_end("aesni_ecb_encrypt");
586 \f
587 ######################################################################
588 # void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out,
589 #                         size_t blocks, const AES_KEY *key,
590 #                         const char *ivec,char *cmac);
591 #
592 # Handles only complete blocks, operates on 64-bit counter and
593 # does not update *ivec! Nor does it finalize CMAC value
594 # (see engine/eng_aesni.c for details)
595 #
596 { my $cmac=$inout1;
597 &function_begin("aesni_ccm64_encrypt_blocks");
598         &mov    ($inp,&wparam(0));
599         &mov    ($out,&wparam(1));
600         &mov    ($len,&wparam(2));
601         &mov    ($key,&wparam(3));
602         &mov    ($rounds_,&wparam(4));
603         &mov    ($rounds,&wparam(5));
604         &mov    ($key_,"esp");
605         &sub    ("esp",60);
606         &and    ("esp",-16);                    # align stack
607         &mov    (&DWP(48,"esp"),$key_);
608
609         &movdqu ($ivec,&QWP(0,$rounds_));       # load ivec
610         &movdqu ($cmac,&QWP(0,$rounds));        # load cmac
611         &mov    ($rounds,&DWP(240,$key));
612
613         # compose byte-swap control mask for pshufb on stack
614         &mov    (&DWP(0,"esp"),0x0c0d0e0f);
615         &mov    (&DWP(4,"esp"),0x08090a0b);
616         &mov    (&DWP(8,"esp"),0x04050607);
617         &mov    (&DWP(12,"esp"),0x00010203);
618
619         # compose counter increment vector on stack
620         &mov    ($rounds_,1);
621         &xor    ($key_,$key_);
622         &mov    (&DWP(16,"esp"),$rounds_);
623         &mov    (&DWP(20,"esp"),$key_);
624         &mov    (&DWP(24,"esp"),$key_);
625         &mov    (&DWP(28,"esp"),$key_);
626
627         &shl    ($rounds,4);
628         &mov    ($rounds_,16);
629         &lea    ($key_,&DWP(0,$key));
630         &movdqa ($inout3,&QWP(0,"esp"));
631         &movdqa ($inout0,$ivec);
632         &lea    ($key,&DWP(32,$key,$rounds));
633         &sub    ($rounds_,$rounds);
634         &pshufb ($ivec,$inout3);
635
636 &set_label("ccm64_enc_outer");
637         &$movekey       ($rndkey0,&QWP(0,$key_));
638         &mov            ($rounds,$rounds_);
639         &movups         ($in0,&QWP(0,$inp));
640
641         &xorps          ($inout0,$rndkey0);
642         &$movekey       ($rndkey1,&QWP(16,$key_));
643         &xorps          ($rndkey0,$in0);
644         &xorps          ($cmac,$rndkey0);               # cmac^=inp
645         &$movekey       ($rndkey0,&QWP(32,$key_));
646
647 &set_label("ccm64_enc2_loop");
648         &aesenc         ($inout0,$rndkey1);
649         &aesenc         ($cmac,$rndkey1);
650         &$movekey       ($rndkey1,&QWP(0,$key,$rounds));
651         &add            ($rounds,32);
652         &aesenc         ($inout0,$rndkey0);
653         &aesenc         ($cmac,$rndkey0);
654         &$movekey       ($rndkey0,&QWP(-16,$key,$rounds));
655         &jnz            (&label("ccm64_enc2_loop"));
656         &aesenc         ($inout0,$rndkey1);
657         &aesenc         ($cmac,$rndkey1);
658         &paddq          ($ivec,&QWP(16,"esp"));
659         &dec            ($len);
660         &aesenclast     ($inout0,$rndkey0);
661         &aesenclast     ($cmac,$rndkey0);
662
663         &lea    ($inp,&DWP(16,$inp));
664         &xorps  ($in0,$inout0);                 # inp^=E(ivec)
665         &movdqa ($inout0,$ivec);
666         &movups (&QWP(0,$out),$in0);            # save output
667         &pshufb ($inout0,$inout3);
668         &lea    ($out,&DWP(16,$out));
669         &jnz    (&label("ccm64_enc_outer"));
670
671         &mov    ("esp",&DWP(48,"esp"));
672         &mov    ($out,&wparam(5));
673         &movups (&QWP(0,$out),$cmac);
674 &function_end("aesni_ccm64_encrypt_blocks");
675
676 &function_begin("aesni_ccm64_decrypt_blocks");
677         &mov    ($inp,&wparam(0));
678         &mov    ($out,&wparam(1));
679         &mov    ($len,&wparam(2));
680         &mov    ($key,&wparam(3));
681         &mov    ($rounds_,&wparam(4));
682         &mov    ($rounds,&wparam(5));
683         &mov    ($key_,"esp");
684         &sub    ("esp",60);
685         &and    ("esp",-16);                    # align stack
686         &mov    (&DWP(48,"esp"),$key_);
687
688         &movdqu ($ivec,&QWP(0,$rounds_));       # load ivec
689         &movdqu ($cmac,&QWP(0,$rounds));        # load cmac
690         &mov    ($rounds,&DWP(240,$key));
691
692         # compose byte-swap control mask for pshufb on stack
693         &mov    (&DWP(0,"esp"),0x0c0d0e0f);
694         &mov    (&DWP(4,"esp"),0x08090a0b);
695         &mov    (&DWP(8,"esp"),0x04050607);
696         &mov    (&DWP(12,"esp"),0x00010203);
697
698         # compose counter increment vector on stack
699         &mov    ($rounds_,1);
700         &xor    ($key_,$key_);
701         &mov    (&DWP(16,"esp"),$rounds_);
702         &mov    (&DWP(20,"esp"),$key_);
703         &mov    (&DWP(24,"esp"),$key_);
704         &mov    (&DWP(28,"esp"),$key_);
705
706         &movdqa ($inout3,&QWP(0,"esp"));        # bswap mask
707         &movdqa ($inout0,$ivec);
708
709         &mov    ($key_,$key);
710         &mov    ($rounds_,$rounds);
711
712         &pshufb ($ivec,$inout3);
713         if ($inline)
714         {   &aesni_inline_generate1("enc");     }
715         else
716         {   &call       ("_aesni_encrypt1");    }
717         &shl    ($rounds_,4);
718         &mov    ($rounds,16);
719         &movups ($in0,&QWP(0,$inp));            # load inp
720         &paddq  ($ivec,&QWP(16,"esp"));
721         &lea    ($inp,&QWP(16,$inp));
722         &sub    ($rounds,$rounds_);
723         &lea    ($key,&DWP(32,$key_,$rounds_));
724         &mov    ($rounds_,$rounds);
725         &jmp    (&label("ccm64_dec_outer"));
726
727 &set_label("ccm64_dec_outer",16);
728         &xorps  ($in0,$inout0);                 # inp ^= E(ivec)
729         &movdqa ($inout0,$ivec);
730         &movups (&QWP(0,$out),$in0);            # save output
731         &lea    ($out,&DWP(16,$out));
732         &pshufb ($inout0,$inout3);
733
734         &sub    ($len,1);
735         &jz     (&label("ccm64_dec_break"));
736
737         &$movekey       ($rndkey0,&QWP(0,$key_));
738         &mov            ($rounds,$rounds_);
739         &$movekey       ($rndkey1,&QWP(16,$key_));
740         &xorps          ($in0,$rndkey0);
741         &xorps          ($inout0,$rndkey0);
742         &xorps          ($cmac,$in0);           # cmac^=out
743         &$movekey       ($rndkey0,&QWP(32,$key_));
744
745 &set_label("ccm64_dec2_loop");
746         &aesenc         ($inout0,$rndkey1);
747         &aesenc         ($cmac,$rndkey1);
748         &$movekey       ($rndkey1,&QWP(0,$key,$rounds));
749         &add            ($rounds,32);
750         &aesenc         ($inout0,$rndkey0);
751         &aesenc         ($cmac,$rndkey0);
752         &$movekey       ($rndkey0,&QWP(-16,$key,$rounds));
753         &jnz            (&label("ccm64_dec2_loop"));
754         &movups         ($in0,&QWP(0,$inp));    # load inp
755         &paddq          ($ivec,&QWP(16,"esp"));
756         &aesenc         ($inout0,$rndkey1);
757         &aesenc         ($cmac,$rndkey1);
758         &aesenclast     ($inout0,$rndkey0);
759         &aesenclast     ($cmac,$rndkey0);
760         &lea            ($inp,&QWP(16,$inp));
761         &jmp    (&label("ccm64_dec_outer"));
762
763 &set_label("ccm64_dec_break",16);
764         &mov    ($rounds,&DWP(240,$key_));
765         &mov    ($key,$key_);
766         if ($inline)
767         {   &aesni_inline_generate1("enc",$cmac,$in0);  }
768         else
769         {   &call       ("_aesni_encrypt1",$cmac);      }
770
771         &mov    ("esp",&DWP(48,"esp"));
772         &mov    ($out,&wparam(5));
773         &movups (&QWP(0,$out),$cmac);
774 &function_end("aesni_ccm64_decrypt_blocks");
775 }
776 \f
777 ######################################################################
778 # void aesni_ctr32_encrypt_blocks (const void *in, void *out,
779 #                         size_t blocks, const AES_KEY *key,
780 #                         const char *ivec);
781 #
782 # Handles only complete blocks, operates on 32-bit counter and
783 # does not update *ivec! (see crypto/modes/ctr128.c for details)
784 #
785 # stack layout:
786 #       0       pshufb mask
787 #       16      vector addend: 0,6,6,6
788 #       32      counter-less ivec
789 #       48      1st triplet of counter vector
790 #       64      2nd triplet of counter vector
791 #       80      saved %esp
792
793 &function_begin("aesni_ctr32_encrypt_blocks");
794         &mov    ($inp,&wparam(0));
795         &mov    ($out,&wparam(1));
796         &mov    ($len,&wparam(2));
797         &mov    ($key,&wparam(3));
798         &mov    ($rounds_,&wparam(4));
799         &mov    ($key_,"esp");
800         &sub    ("esp",88);
801         &and    ("esp",-16);                    # align stack
802         &mov    (&DWP(80,"esp"),$key_);
803
804         &cmp    ($len,1);
805         &je     (&label("ctr32_one_shortcut"));
806
807         &movdqu ($inout5,&QWP(0,$rounds_));     # load ivec
808
809         # compose byte-swap control mask for pshufb on stack
810         &mov    (&DWP(0,"esp"),0x0c0d0e0f);
811         &mov    (&DWP(4,"esp"),0x08090a0b);
812         &mov    (&DWP(8,"esp"),0x04050607);
813         &mov    (&DWP(12,"esp"),0x00010203);
814
815         # compose counter increment vector on stack
816         &mov    ($rounds,6);
817         &xor    ($key_,$key_);
818         &mov    (&DWP(16,"esp"),$rounds);
819         &mov    (&DWP(20,"esp"),$rounds);
820         &mov    (&DWP(24,"esp"),$rounds);
821         &mov    (&DWP(28,"esp"),$key_);
822
823         &pextrd ($rounds_,$inout5,3);           # pull 32-bit counter
824         &pinsrd ($inout5,$key_,3);              # wipe 32-bit counter
825
826         &mov    ($rounds,&DWP(240,$key));       # key->rounds
827
828         # compose 2 vectors of 3x32-bit counters
829         &bswap  ($rounds_);
830         &pxor   ($rndkey0,$rndkey0);
831         &pxor   ($rndkey1,$rndkey1);
832         &movdqa ($inout0,&QWP(0,"esp"));        # load byte-swap mask
833         &pinsrd ($rndkey0,$rounds_,0);
834         &lea    ($key_,&DWP(3,$rounds_));
835         &pinsrd ($rndkey1,$key_,0);
836         &inc    ($rounds_);
837         &pinsrd ($rndkey0,$rounds_,1);
838         &inc    ($key_);
839         &pinsrd ($rndkey1,$key_,1);
840         &inc    ($rounds_);
841         &pinsrd ($rndkey0,$rounds_,2);
842         &inc    ($key_);
843         &pinsrd ($rndkey1,$key_,2);
844         &movdqa (&QWP(48,"esp"),$rndkey0);      # save 1st triplet
845         &pshufb ($rndkey0,$inout0);             # byte swap
846         &movdqu ($inout4,&QWP(0,$key));         # key[0]
847         &movdqa (&QWP(64,"esp"),$rndkey1);      # save 2nd triplet
848         &pshufb ($rndkey1,$inout0);             # byte swap
849
850         &pshufd ($inout0,$rndkey0,3<<6);        # place counter to upper dword
851         &pshufd ($inout1,$rndkey0,2<<6);
852         &cmp    ($len,6);
853         &jb     (&label("ctr32_tail"));
854         &pxor   ($inout5,$inout4);              # counter-less ivec^key[0]
855         &shl    ($rounds,4);
856         &mov    ($rounds_,16);
857         &movdqa (&QWP(32,"esp"),$inout5);       # save counter-less ivec^key[0]
858         &mov    ($key_,$key);                   # backup $key
859         &sub    ($rounds_,$rounds);             # backup twisted $rounds
860         &lea    ($key,&DWP(32,$key,$rounds));
861         &sub    ($len,6);
862         &jmp    (&label("ctr32_loop6"));
863
864 &set_label("ctr32_loop6",16);
865         # inlining _aesni_encrypt6's prologue gives ~6% improvement...
866         &pshufd ($inout2,$rndkey0,1<<6);
867         &movdqa ($rndkey0,&QWP(32,"esp"));      # pull counter-less ivec
868         &pshufd ($inout3,$rndkey1,3<<6);
869         &pxor           ($inout0,$rndkey0);     # merge counter-less ivec
870         &pshufd ($inout4,$rndkey1,2<<6);
871         &pxor           ($inout1,$rndkey0);
872         &pshufd ($inout5,$rndkey1,1<<6);
873         &$movekey       ($rndkey1,&QWP(16,$key_));
874         &pxor           ($inout2,$rndkey0);
875         &pxor           ($inout3,$rndkey0);
876         &aesenc         ($inout0,$rndkey1);
877         &pxor           ($inout4,$rndkey0);
878         &pxor           ($inout5,$rndkey0);
879         &aesenc         ($inout1,$rndkey1);
880         &$movekey       ($rndkey0,&QWP(32,$key_));
881         &mov            ($rounds,$rounds_);
882         &aesenc         ($inout2,$rndkey1);
883         &aesenc         ($inout3,$rndkey1);
884         &aesenc         ($inout4,$rndkey1);
885         &aesenc         ($inout5,$rndkey1);
886
887         &call           (&label("_aesni_encrypt6_enter"));
888
889         &movups ($rndkey1,&QWP(0,$inp));
890         &movups ($rndkey0,&QWP(0x10,$inp));
891         &xorps  ($inout0,$rndkey1);
892         &movups ($rndkey1,&QWP(0x20,$inp));
893         &xorps  ($inout1,$rndkey0);
894         &movups (&QWP(0,$out),$inout0);
895         &movdqa ($rndkey0,&QWP(16,"esp"));      # load increment
896         &xorps  ($inout2,$rndkey1);
897         &movdqa ($rndkey1,&QWP(64,"esp"));      # load 2nd triplet
898         &movups (&QWP(0x10,$out),$inout1);
899         &movups (&QWP(0x20,$out),$inout2);
900
901         &paddd  ($rndkey1,$rndkey0);            # 2nd triplet increment
902         &paddd  ($rndkey0,&QWP(48,"esp"));      # 1st triplet increment
903         &movdqa ($inout0,&QWP(0,"esp"));        # load byte swap mask
904
905         &movups ($inout1,&QWP(0x30,$inp));
906         &movups ($inout2,&QWP(0x40,$inp));
907         &xorps  ($inout3,$inout1);
908         &movups ($inout1,&QWP(0x50,$inp));
909         &lea    ($inp,&DWP(0x60,$inp));
910         &movdqa (&QWP(48,"esp"),$rndkey0);      # save 1st triplet
911         &pshufb ($rndkey0,$inout0);             # byte swap
912         &xorps  ($inout4,$inout2);
913         &movups (&QWP(0x30,$out),$inout3);
914         &xorps  ($inout5,$inout1);
915         &movdqa (&QWP(64,"esp"),$rndkey1);      # save 2nd triplet
916         &pshufb ($rndkey1,$inout0);             # byte swap
917         &movups (&QWP(0x40,$out),$inout4);
918         &pshufd ($inout0,$rndkey0,3<<6);
919         &movups (&QWP(0x50,$out),$inout5);
920         &lea    ($out,&DWP(0x60,$out));
921
922         &pshufd ($inout1,$rndkey0,2<<6);
923         &sub    ($len,6);
924         &jnc    (&label("ctr32_loop6"));
925
926         &add    ($len,6);
927         &jz     (&label("ctr32_ret"));
928         &movdqu ($inout5,&QWP(0,$key_));
929         &mov    ($key,$key_);
930         &pxor   ($inout5,&QWP(32,"esp"));       # restore count-less ivec
931         &mov    ($rounds,&DWP(240,$key_));      # restore $rounds
932
933 &set_label("ctr32_tail");
934         &por    ($inout0,$inout5);
935         &cmp    ($len,2);
936         &jb     (&label("ctr32_one"));
937
938         &pshufd ($inout2,$rndkey0,1<<6);
939         &por    ($inout1,$inout5);
940         &je     (&label("ctr32_two"));
941
942         &pshufd ($inout3,$rndkey1,3<<6);
943         &por    ($inout2,$inout5);
944         &cmp    ($len,4);
945         &jb     (&label("ctr32_three"));
946
947         &pshufd ($inout4,$rndkey1,2<<6);
948         &por    ($inout3,$inout5);
949         &je     (&label("ctr32_four"));
950
951         &por    ($inout4,$inout5);
952         &call   ("_aesni_encrypt6");
953         &movups ($rndkey1,&QWP(0,$inp));
954         &movups ($rndkey0,&QWP(0x10,$inp));
955         &xorps  ($inout0,$rndkey1);
956         &movups ($rndkey1,&QWP(0x20,$inp));
957         &xorps  ($inout1,$rndkey0);
958         &movups ($rndkey0,&QWP(0x30,$inp));
959         &xorps  ($inout2,$rndkey1);
960         &movups ($rndkey1,&QWP(0x40,$inp));
961         &xorps  ($inout3,$rndkey0);
962         &movups (&QWP(0,$out),$inout0);
963         &xorps  ($inout4,$rndkey1);
964         &movups (&QWP(0x10,$out),$inout1);
965         &movups (&QWP(0x20,$out),$inout2);
966         &movups (&QWP(0x30,$out),$inout3);
967         &movups (&QWP(0x40,$out),$inout4);
968         &jmp    (&label("ctr32_ret"));
969
970 &set_label("ctr32_one_shortcut",16);
971         &movups ($inout0,&QWP(0,$rounds_));     # load ivec
972         &mov    ($rounds,&DWP(240,$key));
973         
974 &set_label("ctr32_one");
975         if ($inline)
976         {   &aesni_inline_generate1("enc");     }
977         else
978         {   &call       ("_aesni_encrypt1");    }
979         &movups ($in0,&QWP(0,$inp));
980         &xorps  ($in0,$inout0);
981         &movups (&QWP(0,$out),$in0);
982         &jmp    (&label("ctr32_ret"));
983
984 &set_label("ctr32_two",16);
985         &call   ("_aesni_encrypt3");
986         &movups ($inout3,&QWP(0,$inp));
987         &movups ($inout4,&QWP(0x10,$inp));
988         &xorps  ($inout0,$inout3);
989         &xorps  ($inout1,$inout4);
990         &movups (&QWP(0,$out),$inout0);
991         &movups (&QWP(0x10,$out),$inout1);
992         &jmp    (&label("ctr32_ret"));
993
994 &set_label("ctr32_three",16);
995         &call   ("_aesni_encrypt3");
996         &movups ($inout3,&QWP(0,$inp));
997         &movups ($inout4,&QWP(0x10,$inp));
998         &xorps  ($inout0,$inout3);
999         &movups ($inout5,&QWP(0x20,$inp));
1000         &xorps  ($inout1,$inout4);
1001         &movups (&QWP(0,$out),$inout0);
1002         &xorps  ($inout2,$inout5);
1003         &movups (&QWP(0x10,$out),$inout1);
1004         &movups (&QWP(0x20,$out),$inout2);
1005         &jmp    (&label("ctr32_ret"));
1006
1007 &set_label("ctr32_four",16);
1008         &call   ("_aesni_encrypt4");
1009         &movups ($inout4,&QWP(0,$inp));
1010         &movups ($inout5,&QWP(0x10,$inp));
1011         &movups ($rndkey1,&QWP(0x20,$inp));
1012         &xorps  ($inout0,$inout4);
1013         &movups ($rndkey0,&QWP(0x30,$inp));
1014         &xorps  ($inout1,$inout5);
1015         &movups (&QWP(0,$out),$inout0);
1016         &xorps  ($inout2,$rndkey1);
1017         &movups (&QWP(0x10,$out),$inout1);
1018         &xorps  ($inout3,$rndkey0);
1019         &movups (&QWP(0x20,$out),$inout2);
1020         &movups (&QWP(0x30,$out),$inout3);
1021
1022 &set_label("ctr32_ret");
1023         &mov    ("esp",&DWP(80,"esp"));
1024 &function_end("aesni_ctr32_encrypt_blocks");
1025 \f
1026 ######################################################################
1027 # void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len,
1028 #       const AES_KEY *key1, const AES_KEY *key2
1029 #       const unsigned char iv[16]);
1030 #
1031 { my ($tweak,$twtmp,$twres,$twmask)=($rndkey1,$rndkey0,$inout0,$inout1);
1032
1033 &function_begin("aesni_xts_encrypt");
1034         &mov    ($key,&wparam(4));              # key2
1035         &mov    ($inp,&wparam(5));              # clear-text tweak
1036
1037         &mov    ($rounds,&DWP(240,$key));       # key2->rounds
1038         &movups ($inout0,&QWP(0,$inp));
1039         if ($inline)
1040         {   &aesni_inline_generate1("enc");     }
1041         else
1042         {   &call       ("_aesni_encrypt1");    }
1043
1044         &mov    ($inp,&wparam(0));
1045         &mov    ($out,&wparam(1));
1046         &mov    ($len,&wparam(2));
1047         &mov    ($key,&wparam(3));              # key1
1048
1049         &mov    ($key_,"esp");
1050         &sub    ("esp",16*7+8);
1051         &mov    ($rounds,&DWP(240,$key));       # key1->rounds
1052         &and    ("esp",-16);                    # align stack
1053
1054         &mov    (&DWP(16*6+0,"esp"),0x87);      # compose the magic constant
1055         &mov    (&DWP(16*6+4,"esp"),0);
1056         &mov    (&DWP(16*6+8,"esp"),1);
1057         &mov    (&DWP(16*6+12,"esp"),0);
1058         &mov    (&DWP(16*7+0,"esp"),$len);      # save original $len
1059         &mov    (&DWP(16*7+4,"esp"),$key_);     # save original %esp
1060
1061         &movdqa ($tweak,$inout0);
1062         &pxor   ($twtmp,$twtmp);
1063         &movdqa ($twmask,&QWP(6*16,"esp"));     # 0x0...010...87
1064         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1065
1066         &and    ($len,-16);
1067         &mov    ($key_,$key);                   # backup $key
1068         &mov    ($rounds_,$rounds);             # backup $rounds
1069         &sub    ($len,16*6);
1070         &jc     (&label("xts_enc_short"));
1071
1072         &shl    ($rounds,4);
1073         &mov    ($rounds_,16);
1074         &sub    ($rounds_,$rounds);
1075         &lea    ($key,&DWP(32,$key,$rounds));
1076         &jmp    (&label("xts_enc_loop6"));
1077
1078 &set_label("xts_enc_loop6",16);
1079         for ($i=0;$i<4;$i++) {
1080             &pshufd     ($twres,$twtmp,0x13);
1081             &pxor       ($twtmp,$twtmp);
1082             &movdqa     (&QWP(16*$i,"esp"),$tweak);
1083             &paddq      ($tweak,$tweak);        # &psllq($tweak,1);
1084             &pand       ($twres,$twmask);       # isolate carry and residue
1085             &pcmpgtd    ($twtmp,$tweak);        # broadcast upper bits
1086             &pxor       ($tweak,$twres);
1087         }
1088         &pshufd ($inout5,$twtmp,0x13);
1089         &movdqa (&QWP(16*$i++,"esp"),$tweak);
1090         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1091          &$movekey      ($rndkey0,&QWP(0,$key_));
1092         &pand   ($inout5,$twmask);              # isolate carry and residue
1093          &movups        ($inout0,&QWP(0,$inp)); # load input
1094         &pxor   ($inout5,$tweak);
1095
1096         # inline _aesni_encrypt6 prologue and flip xor with tweak and key[0]
1097         &mov    ($rounds,$rounds_);             # restore $rounds
1098         &movdqu ($inout1,&QWP(16*1,$inp));
1099          &xorps         ($inout0,$rndkey0);     # input^=rndkey[0]
1100         &movdqu ($inout2,&QWP(16*2,$inp));
1101          &pxor          ($inout1,$rndkey0);
1102         &movdqu ($inout3,&QWP(16*3,$inp));
1103          &pxor          ($inout2,$rndkey0);
1104         &movdqu ($inout4,&QWP(16*4,$inp));
1105          &pxor          ($inout3,$rndkey0);
1106         &movdqu ($rndkey1,&QWP(16*5,$inp));
1107          &pxor          ($inout4,$rndkey0);
1108         &lea    ($inp,&DWP(16*6,$inp));
1109         &pxor   ($inout0,&QWP(16*0,"esp"));     # input^=tweak
1110         &movdqa (&QWP(16*$i,"esp"),$inout5);    # save last tweak
1111         &pxor   ($inout5,$rndkey1);
1112
1113          &$movekey      ($rndkey1,&QWP(16,$key_));
1114         &pxor   ($inout1,&QWP(16*1,"esp"));
1115         &pxor   ($inout2,&QWP(16*2,"esp"));
1116          &aesenc        ($inout0,$rndkey1);
1117         &pxor   ($inout3,&QWP(16*3,"esp"));
1118         &pxor   ($inout4,&QWP(16*4,"esp"));
1119          &aesenc        ($inout1,$rndkey1);
1120         &pxor           ($inout5,$rndkey0);
1121          &$movekey      ($rndkey0,&QWP(32,$key_));
1122          &aesenc        ($inout2,$rndkey1);
1123          &aesenc        ($inout3,$rndkey1);
1124          &aesenc        ($inout4,$rndkey1);
1125          &aesenc        ($inout5,$rndkey1);
1126         &call           (&label("_aesni_encrypt6_enter"));
1127
1128         &movdqa ($tweak,&QWP(16*5,"esp"));      # last tweak
1129        &pxor    ($twtmp,$twtmp);
1130         &xorps  ($inout0,&QWP(16*0,"esp"));     # output^=tweak
1131        &pcmpgtd ($twtmp,$tweak);                # broadcast upper bits
1132         &xorps  ($inout1,&QWP(16*1,"esp"));
1133         &movups (&QWP(16*0,$out),$inout0);      # write output
1134         &xorps  ($inout2,&QWP(16*2,"esp"));
1135         &movups (&QWP(16*1,$out),$inout1);
1136         &xorps  ($inout3,&QWP(16*3,"esp"));
1137         &movups (&QWP(16*2,$out),$inout2);
1138         &xorps  ($inout4,&QWP(16*4,"esp"));
1139         &movups (&QWP(16*3,$out),$inout3);
1140         &xorps  ($inout5,$tweak);
1141         &movups (&QWP(16*4,$out),$inout4);
1142        &pshufd  ($twres,$twtmp,0x13);
1143         &movups (&QWP(16*5,$out),$inout5);
1144         &lea    ($out,&DWP(16*6,$out));
1145        &movdqa  ($twmask,&QWP(16*6,"esp"));     # 0x0...010...87
1146
1147         &pxor   ($twtmp,$twtmp);
1148         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1149         &pand   ($twres,$twmask);               # isolate carry and residue
1150         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1151         &pxor   ($tweak,$twres);
1152
1153         &sub    ($len,16*6);
1154         &jnc    (&label("xts_enc_loop6"));
1155
1156         &mov    ($rounds,&DWP(240,$key_));      # restore $rounds
1157         &mov    ($key,$key_);                   # restore $key
1158         &mov    ($rounds_,$rounds);
1159
1160 &set_label("xts_enc_short");
1161         &add    ($len,16*6);
1162         &jz     (&label("xts_enc_done6x"));
1163
1164         &movdqa ($inout3,$tweak);               # put aside previous tweak
1165         &cmp    ($len,0x20);
1166         &jb     (&label("xts_enc_one"));
1167
1168         &pshufd ($twres,$twtmp,0x13);
1169         &pxor   ($twtmp,$twtmp);
1170         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1171         &pand   ($twres,$twmask);               # isolate carry and residue
1172         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1173         &pxor   ($tweak,$twres);
1174         &je     (&label("xts_enc_two"));
1175
1176         &pshufd ($twres,$twtmp,0x13);
1177         &pxor   ($twtmp,$twtmp);
1178         &movdqa ($inout4,$tweak);               # put aside previous tweak
1179         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1180         &pand   ($twres,$twmask);               # isolate carry and residue
1181         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1182         &pxor   ($tweak,$twres);
1183         &cmp    ($len,0x40);
1184         &jb     (&label("xts_enc_three"));
1185
1186         &pshufd ($twres,$twtmp,0x13);
1187         &pxor   ($twtmp,$twtmp);
1188         &movdqa ($inout5,$tweak);               # put aside previous tweak
1189         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1190         &pand   ($twres,$twmask);               # isolate carry and residue
1191         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1192         &pxor   ($tweak,$twres);
1193         &movdqa (&QWP(16*0,"esp"),$inout3);
1194         &movdqa (&QWP(16*1,"esp"),$inout4);
1195         &je     (&label("xts_enc_four"));
1196
1197         &movdqa (&QWP(16*2,"esp"),$inout5);
1198         &pshufd ($inout5,$twtmp,0x13);
1199         &movdqa (&QWP(16*3,"esp"),$tweak);
1200         &paddq  ($tweak,$tweak);                # &psllq($inout0,1);
1201         &pand   ($inout5,$twmask);              # isolate carry and residue
1202         &pxor   ($inout5,$tweak);
1203
1204         &movdqu ($inout0,&QWP(16*0,$inp));      # load input
1205         &movdqu ($inout1,&QWP(16*1,$inp));
1206         &movdqu ($inout2,&QWP(16*2,$inp));
1207         &pxor   ($inout0,&QWP(16*0,"esp"));     # input^=tweak
1208         &movdqu ($inout3,&QWP(16*3,$inp));
1209         &pxor   ($inout1,&QWP(16*1,"esp"));
1210         &movdqu ($inout4,&QWP(16*4,$inp));
1211         &pxor   ($inout2,&QWP(16*2,"esp"));
1212         &lea    ($inp,&DWP(16*5,$inp));
1213         &pxor   ($inout3,&QWP(16*3,"esp"));
1214         &movdqa (&QWP(16*4,"esp"),$inout5);     # save last tweak
1215         &pxor   ($inout4,$inout5);
1216
1217         &call   ("_aesni_encrypt6");
1218
1219         &movaps ($tweak,&QWP(16*4,"esp"));      # last tweak
1220         &xorps  ($inout0,&QWP(16*0,"esp"));     # output^=tweak
1221         &xorps  ($inout1,&QWP(16*1,"esp"));
1222         &xorps  ($inout2,&QWP(16*2,"esp"));
1223         &movups (&QWP(16*0,$out),$inout0);      # write output
1224         &xorps  ($inout3,&QWP(16*3,"esp"));
1225         &movups (&QWP(16*1,$out),$inout1);
1226         &xorps  ($inout4,$tweak);
1227         &movups (&QWP(16*2,$out),$inout2);
1228         &movups (&QWP(16*3,$out),$inout3);
1229         &movups (&QWP(16*4,$out),$inout4);
1230         &lea    ($out,&DWP(16*5,$out));
1231         &jmp    (&label("xts_enc_done"));
1232
1233 &set_label("xts_enc_one",16);
1234         &movups ($inout0,&QWP(16*0,$inp));      # load input
1235         &lea    ($inp,&DWP(16*1,$inp));
1236         &xorps  ($inout0,$inout3);              # input^=tweak
1237         if ($inline)
1238         {   &aesni_inline_generate1("enc");     }
1239         else
1240         {   &call       ("_aesni_encrypt1");    }
1241         &xorps  ($inout0,$inout3);              # output^=tweak
1242         &movups (&QWP(16*0,$out),$inout0);      # write output
1243         &lea    ($out,&DWP(16*1,$out));
1244
1245         &movdqa ($tweak,$inout3);               # last tweak
1246         &jmp    (&label("xts_enc_done"));
1247
1248 &set_label("xts_enc_two",16);
1249         &movaps ($inout4,$tweak);               # put aside last tweak
1250
1251         &movups ($inout0,&QWP(16*0,$inp));      # load input
1252         &movups ($inout1,&QWP(16*1,$inp));
1253         &lea    ($inp,&DWP(16*2,$inp));
1254         &xorps  ($inout0,$inout3);              # input^=tweak
1255         &xorps  ($inout1,$inout4);
1256         &xorps  ($inout2,$inout2);
1257
1258         &call   ("_aesni_encrypt3");
1259
1260         &xorps  ($inout0,$inout3);              # output^=tweak
1261         &xorps  ($inout1,$inout4);
1262         &movups (&QWP(16*0,$out),$inout0);      # write output
1263         &movups (&QWP(16*1,$out),$inout1);
1264         &lea    ($out,&DWP(16*2,$out));
1265
1266         &movdqa ($tweak,$inout4);               # last tweak
1267         &jmp    (&label("xts_enc_done"));
1268
1269 &set_label("xts_enc_three",16);
1270         &movaps ($inout5,$tweak);               # put aside last tweak
1271         &movups ($inout0,&QWP(16*0,$inp));      # load input
1272         &movups ($inout1,&QWP(16*1,$inp));
1273         &movups ($inout2,&QWP(16*2,$inp));
1274         &lea    ($inp,&DWP(16*3,$inp));
1275         &xorps  ($inout0,$inout3);              # input^=tweak
1276         &xorps  ($inout1,$inout4);
1277         &xorps  ($inout2,$inout5);
1278
1279         &call   ("_aesni_encrypt3");
1280
1281         &xorps  ($inout0,$inout3);              # output^=tweak
1282         &xorps  ($inout1,$inout4);
1283         &xorps  ($inout2,$inout5);
1284         &movups (&QWP(16*0,$out),$inout0);      # write output
1285         &movups (&QWP(16*1,$out),$inout1);
1286         &movups (&QWP(16*2,$out),$inout2);
1287         &lea    ($out,&DWP(16*3,$out));
1288
1289         &movdqa ($tweak,$inout5);               # last tweak
1290         &jmp    (&label("xts_enc_done"));
1291
1292 &set_label("xts_enc_four",16);
1293         &movaps ($inout4,$tweak);               # put aside last tweak
1294
1295         &movups ($inout0,&QWP(16*0,$inp));      # load input
1296         &movups ($inout1,&QWP(16*1,$inp));
1297         &movups ($inout2,&QWP(16*2,$inp));
1298         &xorps  ($inout0,&QWP(16*0,"esp"));     # input^=tweak
1299         &movups ($inout3,&QWP(16*3,$inp));
1300         &lea    ($inp,&DWP(16*4,$inp));
1301         &xorps  ($inout1,&QWP(16*1,"esp"));
1302         &xorps  ($inout2,$inout5);
1303         &xorps  ($inout3,$inout4);
1304
1305         &call   ("_aesni_encrypt4");
1306
1307         &xorps  ($inout0,&QWP(16*0,"esp"));     # output^=tweak
1308         &xorps  ($inout1,&QWP(16*1,"esp"));
1309         &xorps  ($inout2,$inout5);
1310         &movups (&QWP(16*0,$out),$inout0);      # write output
1311         &xorps  ($inout3,$inout4);
1312         &movups (&QWP(16*1,$out),$inout1);
1313         &movups (&QWP(16*2,$out),$inout2);
1314         &movups (&QWP(16*3,$out),$inout3);
1315         &lea    ($out,&DWP(16*4,$out));
1316
1317         &movdqa ($tweak,$inout4);               # last tweak
1318         &jmp    (&label("xts_enc_done"));
1319
1320 &set_label("xts_enc_done6x",16);                # $tweak is pre-calculated
1321         &mov    ($len,&DWP(16*7+0,"esp"));      # restore original $len
1322         &and    ($len,15);
1323         &jz     (&label("xts_enc_ret"));
1324         &movdqa ($inout3,$tweak);
1325         &mov    (&DWP(16*7+0,"esp"),$len);      # save $len%16
1326         &jmp    (&label("xts_enc_steal"));
1327
1328 &set_label("xts_enc_done",16);
1329         &mov    ($len,&DWP(16*7+0,"esp"));      # restore original $len
1330         &pxor   ($twtmp,$twtmp);
1331         &and    ($len,15);
1332         &jz     (&label("xts_enc_ret"));
1333
1334         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1335         &mov    (&DWP(16*7+0,"esp"),$len);      # save $len%16
1336         &pshufd ($inout3,$twtmp,0x13);
1337         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1338         &pand   ($inout3,&QWP(16*6,"esp"));     # isolate carry and residue
1339         &pxor   ($inout3,$tweak);
1340
1341 &set_label("xts_enc_steal");
1342         &movz   ($rounds,&BP(0,$inp));
1343         &movz   ($key,&BP(-16,$out));
1344         &lea    ($inp,&DWP(1,$inp));
1345         &mov    (&BP(-16,$out),&LB($rounds));
1346         &mov    (&BP(0,$out),&LB($key));
1347         &lea    ($out,&DWP(1,$out));
1348         &sub    ($len,1);
1349         &jnz    (&label("xts_enc_steal"));
1350
1351         &sub    ($out,&DWP(16*7+0,"esp"));      # rewind $out
1352         &mov    ($key,$key_);                   # restore $key
1353         &mov    ($rounds,$rounds_);             # restore $rounds
1354
1355         &movups ($inout0,&QWP(-16,$out));       # load input
1356         &xorps  ($inout0,$inout3);              # input^=tweak
1357         if ($inline)
1358         {   &aesni_inline_generate1("enc");     }
1359         else
1360         {   &call       ("_aesni_encrypt1");    }
1361         &xorps  ($inout0,$inout3);              # output^=tweak
1362         &movups (&QWP(-16,$out),$inout0);       # write output
1363
1364 &set_label("xts_enc_ret");
1365         &mov    ("esp",&DWP(16*7+4,"esp"));     # restore %esp
1366 &function_end("aesni_xts_encrypt");
1367
1368 &function_begin("aesni_xts_decrypt");
1369         &mov    ($key,&wparam(4));              # key2
1370         &mov    ($inp,&wparam(5));              # clear-text tweak
1371
1372         &mov    ($rounds,&DWP(240,$key));       # key2->rounds
1373         &movups ($inout0,&QWP(0,$inp));
1374         if ($inline)
1375         {   &aesni_inline_generate1("enc");     }
1376         else
1377         {   &call       ("_aesni_encrypt1");    }
1378
1379         &mov    ($inp,&wparam(0));
1380         &mov    ($out,&wparam(1));
1381         &mov    ($len,&wparam(2));
1382         &mov    ($key,&wparam(3));              # key1
1383
1384         &mov    ($key_,"esp");
1385         &sub    ("esp",16*7+8);
1386         &and    ("esp",-16);                    # align stack
1387
1388         &xor    ($rounds_,$rounds_);            # if(len%16) len-=16;
1389         &test   ($len,15);
1390         &setnz  (&LB($rounds_));
1391         &shl    ($rounds_,4);
1392         &sub    ($len,$rounds_);
1393
1394         &mov    (&DWP(16*6+0,"esp"),0x87);      # compose the magic constant
1395         &mov    (&DWP(16*6+4,"esp"),0);
1396         &mov    (&DWP(16*6+8,"esp"),1);
1397         &mov    (&DWP(16*6+12,"esp"),0);
1398         &mov    (&DWP(16*7+0,"esp"),$len);      # save original $len
1399         &mov    (&DWP(16*7+4,"esp"),$key_);     # save original %esp
1400
1401         &mov    ($rounds,&DWP(240,$key));       # key1->rounds
1402         &mov    ($key_,$key);                   # backup $key
1403         &mov    ($rounds_,$rounds);             # backup $rounds
1404
1405         &movdqa ($tweak,$inout0);
1406         &pxor   ($twtmp,$twtmp);
1407         &movdqa ($twmask,&QWP(6*16,"esp"));     # 0x0...010...87
1408         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1409
1410         &and    ($len,-16);
1411         &sub    ($len,16*6);
1412         &jc     (&label("xts_dec_short"));
1413
1414         &shl    ($rounds,4);
1415         &mov    ($rounds_,16);
1416         &sub    ($rounds_,$rounds);
1417         &lea    ($key,&DWP(32,$key,$rounds));
1418         &jmp    (&label("xts_dec_loop6"));
1419
1420 &set_label("xts_dec_loop6",16);
1421         for ($i=0;$i<4;$i++) {
1422             &pshufd     ($twres,$twtmp,0x13);
1423             &pxor       ($twtmp,$twtmp);
1424             &movdqa     (&QWP(16*$i,"esp"),$tweak);
1425             &paddq      ($tweak,$tweak);        # &psllq($tweak,1);
1426             &pand       ($twres,$twmask);       # isolate carry and residue
1427             &pcmpgtd    ($twtmp,$tweak);        # broadcast upper bits
1428             &pxor       ($tweak,$twres);
1429         }
1430         &pshufd ($inout5,$twtmp,0x13);
1431         &movdqa (&QWP(16*$i++,"esp"),$tweak);
1432         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1433          &$movekey      ($rndkey0,&QWP(0,$key_));
1434         &pand   ($inout5,$twmask);              # isolate carry and residue
1435          &movups        ($inout0,&QWP(0,$inp)); # load input
1436         &pxor   ($inout5,$tweak);
1437
1438         # inline _aesni_encrypt6 prologue and flip xor with tweak and key[0]
1439         &mov    ($rounds,$rounds_);
1440         &movdqu ($inout1,&QWP(16*1,$inp));
1441          &xorps         ($inout0,$rndkey0);     # input^=rndkey[0]
1442         &movdqu ($inout2,&QWP(16*2,$inp));
1443          &pxor          ($inout1,$rndkey0);
1444         &movdqu ($inout3,&QWP(16*3,$inp));
1445          &pxor          ($inout2,$rndkey0);
1446         &movdqu ($inout4,&QWP(16*4,$inp));
1447          &pxor          ($inout3,$rndkey0);
1448         &movdqu ($rndkey1,&QWP(16*5,$inp));
1449          &pxor          ($inout4,$rndkey0);
1450         &lea    ($inp,&DWP(16*6,$inp));
1451         &pxor   ($inout0,&QWP(16*0,"esp"));     # input^=tweak
1452         &movdqa (&QWP(16*$i,"esp"),$inout5);    # save last tweak
1453         &pxor   ($inout5,$rndkey1);
1454
1455          &$movekey      ($rndkey1,&QWP(16,$key_));
1456         &pxor   ($inout1,&QWP(16*1,"esp"));
1457         &pxor   ($inout2,&QWP(16*2,"esp"));
1458          &aesdec        ($inout0,$rndkey1);
1459         &pxor   ($inout3,&QWP(16*3,"esp"));
1460         &pxor   ($inout4,&QWP(16*4,"esp"));
1461          &aesdec        ($inout1,$rndkey1);
1462         &pxor           ($inout5,$rndkey0);
1463          &$movekey      ($rndkey0,&QWP(32,$key_));
1464          &aesdec        ($inout2,$rndkey1);
1465          &aesdec        ($inout3,$rndkey1);
1466          &aesdec        ($inout4,$rndkey1);
1467          &aesdec        ($inout5,$rndkey1);
1468         &call           (&label("_aesni_decrypt6_enter"));
1469
1470         &movdqa ($tweak,&QWP(16*5,"esp"));      # last tweak
1471        &pxor    ($twtmp,$twtmp);
1472         &xorps  ($inout0,&QWP(16*0,"esp"));     # output^=tweak
1473        &pcmpgtd ($twtmp,$tweak);                # broadcast upper bits
1474         &xorps  ($inout1,&QWP(16*1,"esp"));
1475         &movups (&QWP(16*0,$out),$inout0);      # write output
1476         &xorps  ($inout2,&QWP(16*2,"esp"));
1477         &movups (&QWP(16*1,$out),$inout1);
1478         &xorps  ($inout3,&QWP(16*3,"esp"));
1479         &movups (&QWP(16*2,$out),$inout2);
1480         &xorps  ($inout4,&QWP(16*4,"esp"));
1481         &movups (&QWP(16*3,$out),$inout3);
1482         &xorps  ($inout5,$tweak);
1483         &movups (&QWP(16*4,$out),$inout4);
1484        &pshufd  ($twres,$twtmp,0x13);
1485         &movups (&QWP(16*5,$out),$inout5);
1486         &lea    ($out,&DWP(16*6,$out));
1487        &movdqa  ($twmask,&QWP(16*6,"esp"));     # 0x0...010...87
1488
1489         &pxor   ($twtmp,$twtmp);
1490         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1491         &pand   ($twres,$twmask);               # isolate carry and residue
1492         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1493         &pxor   ($tweak,$twres);
1494
1495         &sub    ($len,16*6);
1496         &jnc    (&label("xts_dec_loop6"));
1497
1498         &mov    ($rounds,&DWP(240,$key_));      # restore $rounds
1499         &mov    ($key,$key_);                   # restore $key
1500         &mov    ($rounds_,$rounds);
1501
1502 &set_label("xts_dec_short");
1503         &add    ($len,16*6);
1504         &jz     (&label("xts_dec_done6x"));
1505
1506         &movdqa ($inout3,$tweak);               # put aside previous tweak
1507         &cmp    ($len,0x20);
1508         &jb     (&label("xts_dec_one"));
1509
1510         &pshufd ($twres,$twtmp,0x13);
1511         &pxor   ($twtmp,$twtmp);
1512         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1513         &pand   ($twres,$twmask);               # isolate carry and residue
1514         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1515         &pxor   ($tweak,$twres);
1516         &je     (&label("xts_dec_two"));
1517
1518         &pshufd ($twres,$twtmp,0x13);
1519         &pxor   ($twtmp,$twtmp);
1520         &movdqa ($inout4,$tweak);               # put aside previous tweak
1521         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1522         &pand   ($twres,$twmask);               # isolate carry and residue
1523         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1524         &pxor   ($tweak,$twres);
1525         &cmp    ($len,0x40);
1526         &jb     (&label("xts_dec_three"));
1527
1528         &pshufd ($twres,$twtmp,0x13);
1529         &pxor   ($twtmp,$twtmp);
1530         &movdqa ($inout5,$tweak);               # put aside previous tweak
1531         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1532         &pand   ($twres,$twmask);               # isolate carry and residue
1533         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1534         &pxor   ($tweak,$twres);
1535         &movdqa (&QWP(16*0,"esp"),$inout3);
1536         &movdqa (&QWP(16*1,"esp"),$inout4);
1537         &je     (&label("xts_dec_four"));
1538
1539         &movdqa (&QWP(16*2,"esp"),$inout5);
1540         &pshufd ($inout5,$twtmp,0x13);
1541         &movdqa (&QWP(16*3,"esp"),$tweak);
1542         &paddq  ($tweak,$tweak);                # &psllq($inout0,1);
1543         &pand   ($inout5,$twmask);              # isolate carry and residue
1544         &pxor   ($inout5,$tweak);
1545
1546         &movdqu ($inout0,&QWP(16*0,$inp));      # load input
1547         &movdqu ($inout1,&QWP(16*1,$inp));
1548         &movdqu ($inout2,&QWP(16*2,$inp));
1549         &pxor   ($inout0,&QWP(16*0,"esp"));     # input^=tweak
1550         &movdqu ($inout3,&QWP(16*3,$inp));
1551         &pxor   ($inout1,&QWP(16*1,"esp"));
1552         &movdqu ($inout4,&QWP(16*4,$inp));
1553         &pxor   ($inout2,&QWP(16*2,"esp"));
1554         &lea    ($inp,&DWP(16*5,$inp));
1555         &pxor   ($inout3,&QWP(16*3,"esp"));
1556         &movdqa (&QWP(16*4,"esp"),$inout5);     # save last tweak
1557         &pxor   ($inout4,$inout5);
1558
1559         &call   ("_aesni_decrypt6");
1560
1561         &movaps ($tweak,&QWP(16*4,"esp"));      # last tweak
1562         &xorps  ($inout0,&QWP(16*0,"esp"));     # output^=tweak
1563         &xorps  ($inout1,&QWP(16*1,"esp"));
1564         &xorps  ($inout2,&QWP(16*2,"esp"));
1565         &movups (&QWP(16*0,$out),$inout0);      # write output
1566         &xorps  ($inout3,&QWP(16*3,"esp"));
1567         &movups (&QWP(16*1,$out),$inout1);
1568         &xorps  ($inout4,$tweak);
1569         &movups (&QWP(16*2,$out),$inout2);
1570         &movups (&QWP(16*3,$out),$inout3);
1571         &movups (&QWP(16*4,$out),$inout4);
1572         &lea    ($out,&DWP(16*5,$out));
1573         &jmp    (&label("xts_dec_done"));
1574
1575 &set_label("xts_dec_one",16);
1576         &movups ($inout0,&QWP(16*0,$inp));      # load input
1577         &lea    ($inp,&DWP(16*1,$inp));
1578         &xorps  ($inout0,$inout3);              # input^=tweak
1579         if ($inline)
1580         {   &aesni_inline_generate1("dec");     }
1581         else
1582         {   &call       ("_aesni_decrypt1");    }
1583         &xorps  ($inout0,$inout3);              # output^=tweak
1584         &movups (&QWP(16*0,$out),$inout0);      # write output
1585         &lea    ($out,&DWP(16*1,$out));
1586
1587         &movdqa ($tweak,$inout3);               # last tweak
1588         &jmp    (&label("xts_dec_done"));
1589
1590 &set_label("xts_dec_two",16);
1591         &movaps ($inout4,$tweak);               # put aside last tweak
1592
1593         &movups ($inout0,&QWP(16*0,$inp));      # load input
1594         &movups ($inout1,&QWP(16*1,$inp));
1595         &lea    ($inp,&DWP(16*2,$inp));
1596         &xorps  ($inout0,$inout3);              # input^=tweak
1597         &xorps  ($inout1,$inout4);
1598
1599         &call   ("_aesni_decrypt3");
1600
1601         &xorps  ($inout0,$inout3);              # output^=tweak
1602         &xorps  ($inout1,$inout4);
1603         &movups (&QWP(16*0,$out),$inout0);      # write output
1604         &movups (&QWP(16*1,$out),$inout1);
1605         &lea    ($out,&DWP(16*2,$out));
1606
1607         &movdqa ($tweak,$inout4);               # last tweak
1608         &jmp    (&label("xts_dec_done"));
1609
1610 &set_label("xts_dec_three",16);
1611         &movaps ($inout5,$tweak);               # put aside last tweak
1612         &movups ($inout0,&QWP(16*0,$inp));      # load input
1613         &movups ($inout1,&QWP(16*1,$inp));
1614         &movups ($inout2,&QWP(16*2,$inp));
1615         &lea    ($inp,&DWP(16*3,$inp));
1616         &xorps  ($inout0,$inout3);              # input^=tweak
1617         &xorps  ($inout1,$inout4);
1618         &xorps  ($inout2,$inout5);
1619
1620         &call   ("_aesni_decrypt3");
1621
1622         &xorps  ($inout0,$inout3);              # output^=tweak
1623         &xorps  ($inout1,$inout4);
1624         &xorps  ($inout2,$inout5);
1625         &movups (&QWP(16*0,$out),$inout0);      # write output
1626         &movups (&QWP(16*1,$out),$inout1);
1627         &movups (&QWP(16*2,$out),$inout2);
1628         &lea    ($out,&DWP(16*3,$out));
1629
1630         &movdqa ($tweak,$inout5);               # last tweak
1631         &jmp    (&label("xts_dec_done"));
1632
1633 &set_label("xts_dec_four",16);
1634         &movaps ($inout4,$tweak);               # put aside last tweak
1635
1636         &movups ($inout0,&QWP(16*0,$inp));      # load input
1637         &movups ($inout1,&QWP(16*1,$inp));
1638         &movups ($inout2,&QWP(16*2,$inp));
1639         &xorps  ($inout0,&QWP(16*0,"esp"));     # input^=tweak
1640         &movups ($inout3,&QWP(16*3,$inp));
1641         &lea    ($inp,&DWP(16*4,$inp));
1642         &xorps  ($inout1,&QWP(16*1,"esp"));
1643         &xorps  ($inout2,$inout5);
1644         &xorps  ($inout3,$inout4);
1645
1646         &call   ("_aesni_decrypt4");
1647
1648         &xorps  ($inout0,&QWP(16*0,"esp"));     # output^=tweak
1649         &xorps  ($inout1,&QWP(16*1,"esp"));
1650         &xorps  ($inout2,$inout5);
1651         &movups (&QWP(16*0,$out),$inout0);      # write output
1652         &xorps  ($inout3,$inout4);
1653         &movups (&QWP(16*1,$out),$inout1);
1654         &movups (&QWP(16*2,$out),$inout2);
1655         &movups (&QWP(16*3,$out),$inout3);
1656         &lea    ($out,&DWP(16*4,$out));
1657
1658         &movdqa ($tweak,$inout4);               # last tweak
1659         &jmp    (&label("xts_dec_done"));
1660
1661 &set_label("xts_dec_done6x",16);                # $tweak is pre-calculated
1662         &mov    ($len,&DWP(16*7+0,"esp"));      # restore original $len
1663         &and    ($len,15);
1664         &jz     (&label("xts_dec_ret"));
1665         &mov    (&DWP(16*7+0,"esp"),$len);      # save $len%16
1666         &jmp    (&label("xts_dec_only_one_more"));
1667
1668 &set_label("xts_dec_done",16);
1669         &mov    ($len,&DWP(16*7+0,"esp"));      # restore original $len
1670         &pxor   ($twtmp,$twtmp);
1671         &and    ($len,15);
1672         &jz     (&label("xts_dec_ret"));
1673
1674         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1675         &mov    (&DWP(16*7+0,"esp"),$len);      # save $len%16
1676         &pshufd ($twres,$twtmp,0x13);
1677         &pxor   ($twtmp,$twtmp);
1678         &movdqa ($twmask,&QWP(16*6,"esp"));
1679         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1680         &pand   ($twres,$twmask);               # isolate carry and residue
1681         &pcmpgtd($twtmp,$tweak);                # broadcast upper bits
1682         &pxor   ($tweak,$twres);
1683
1684 &set_label("xts_dec_only_one_more");
1685         &pshufd ($inout3,$twtmp,0x13);
1686         &movdqa ($inout4,$tweak);               # put aside previous tweak
1687         &paddq  ($tweak,$tweak);                # &psllq($tweak,1);
1688         &pand   ($inout3,$twmask);              # isolate carry and residue
1689         &pxor   ($inout3,$tweak);
1690
1691         &mov    ($key,$key_);                   # restore $key
1692         &mov    ($rounds,$rounds_);             # restore $rounds
1693
1694         &movups ($inout0,&QWP(0,$inp));         # load input
1695         &xorps  ($inout0,$inout3);              # input^=tweak
1696         if ($inline)
1697         {   &aesni_inline_generate1("dec");     }
1698         else
1699         {   &call       ("_aesni_decrypt1");    }
1700         &xorps  ($inout0,$inout3);              # output^=tweak
1701         &movups (&QWP(0,$out),$inout0);         # write output
1702
1703 &set_label("xts_dec_steal");
1704         &movz   ($rounds,&BP(16,$inp));
1705         &movz   ($key,&BP(0,$out));
1706         &lea    ($inp,&DWP(1,$inp));
1707         &mov    (&BP(0,$out),&LB($rounds));
1708         &mov    (&BP(16,$out),&LB($key));
1709         &lea    ($out,&DWP(1,$out));
1710         &sub    ($len,1);
1711         &jnz    (&label("xts_dec_steal"));
1712
1713         &sub    ($out,&DWP(16*7+0,"esp"));      # rewind $out
1714         &mov    ($key,$key_);                   # restore $key
1715         &mov    ($rounds,$rounds_);             # restore $rounds
1716
1717         &movups ($inout0,&QWP(0,$out));         # load input
1718         &xorps  ($inout0,$inout4);              # input^=tweak
1719         if ($inline)
1720         {   &aesni_inline_generate1("dec");     }
1721         else
1722         {   &call       ("_aesni_decrypt1");    }
1723         &xorps  ($inout0,$inout4);              # output^=tweak
1724         &movups (&QWP(0,$out),$inout0);         # write output
1725
1726 &set_label("xts_dec_ret");
1727         &mov    ("esp",&DWP(16*7+4,"esp"));     # restore %esp
1728 &function_end("aesni_xts_decrypt");
1729 }
1730 }
1731 \f
1732 ######################################################################
1733 # void $PREFIX_cbc_encrypt (const void *inp, void *out,
1734 #                           size_t length, const AES_KEY *key,
1735 #                           unsigned char *ivp,const int enc);
1736 &function_begin("${PREFIX}_cbc_encrypt");
1737         &mov    ($inp,&wparam(0));
1738         &mov    ($rounds_,"esp");
1739         &mov    ($out,&wparam(1));
1740         &sub    ($rounds_,24);
1741         &mov    ($len,&wparam(2));
1742         &and    ($rounds_,-16);
1743         &mov    ($key,&wparam(3));
1744         &mov    ($key_,&wparam(4));
1745         &test   ($len,$len);
1746         &jz     (&label("cbc_abort"));
1747
1748         &cmp    (&wparam(5),0);
1749         &xchg   ($rounds_,"esp");               # alloca
1750         &movups ($ivec,&QWP(0,$key_));          # load IV
1751         &mov    ($rounds,&DWP(240,$key));
1752         &mov    ($key_,$key);                   # backup $key
1753         &mov    (&DWP(16,"esp"),$rounds_);      # save original %esp
1754         &mov    ($rounds_,$rounds);             # backup $rounds
1755         &je     (&label("cbc_decrypt"));
1756
1757         &movaps ($inout0,$ivec);
1758         &cmp    ($len,16);
1759         &jb     (&label("cbc_enc_tail"));
1760         &sub    ($len,16);
1761         &jmp    (&label("cbc_enc_loop"));
1762
1763 &set_label("cbc_enc_loop",16);
1764         &movups ($ivec,&QWP(0,$inp));           # input actually
1765         &lea    ($inp,&DWP(16,$inp));
1766         if ($inline)
1767         {   &aesni_inline_generate1("enc",$inout0,$ivec);       }
1768         else
1769         {   &xorps($inout0,$ivec); &call("_aesni_encrypt1");    }
1770         &mov    ($rounds,$rounds_);     # restore $rounds
1771         &mov    ($key,$key_);           # restore $key
1772         &movups (&QWP(0,$out),$inout0); # store output
1773         &lea    ($out,&DWP(16,$out));
1774         &sub    ($len,16);
1775         &jnc    (&label("cbc_enc_loop"));
1776         &add    ($len,16);
1777         &jnz    (&label("cbc_enc_tail"));
1778         &movaps ($ivec,$inout0);
1779         &jmp    (&label("cbc_ret"));
1780
1781 &set_label("cbc_enc_tail");
1782         &mov    ("ecx",$len);           # zaps $rounds
1783         &data_word(0xA4F3F689);         # rep movsb
1784         &mov    ("ecx",16);             # zero tail
1785         &sub    ("ecx",$len);
1786         &xor    ("eax","eax");          # zaps $len
1787         &data_word(0xAAF3F689);         # rep stosb
1788         &lea    ($out,&DWP(-16,$out));  # rewind $out by 1 block
1789         &mov    ($rounds,$rounds_);     # restore $rounds
1790         &mov    ($inp,$out);            # $inp and $out are the same
1791         &mov    ($key,$key_);           # restore $key
1792         &jmp    (&label("cbc_enc_loop"));
1793 ######################################################################
1794 &set_label("cbc_decrypt",16);
1795         &cmp    ($len,0x50);
1796         &jbe    (&label("cbc_dec_tail"));
1797         &movaps (&QWP(0,"esp"),$ivec);          # save IV
1798         &sub    ($len,0x50);
1799         &jmp    (&label("cbc_dec_loop6_enter"));
1800
1801 &set_label("cbc_dec_loop6",16);
1802         &movaps (&QWP(0,"esp"),$rndkey0);       # save IV
1803         &movups (&QWP(0,$out),$inout5);
1804         &lea    ($out,&DWP(0x10,$out));
1805 &set_label("cbc_dec_loop6_enter");
1806         &movdqu ($inout0,&QWP(0,$inp));
1807         &movdqu ($inout1,&QWP(0x10,$inp));
1808         &movdqu ($inout2,&QWP(0x20,$inp));
1809         &movdqu ($inout3,&QWP(0x30,$inp));
1810         &movdqu ($inout4,&QWP(0x40,$inp));
1811         &movdqu ($inout5,&QWP(0x50,$inp));
1812
1813         &call   ("_aesni_decrypt6");
1814
1815         &movups ($rndkey1,&QWP(0,$inp));
1816         &movups ($rndkey0,&QWP(0x10,$inp));
1817         &xorps  ($inout0,&QWP(0,"esp"));        # ^=IV
1818         &xorps  ($inout1,$rndkey1);
1819         &movups ($rndkey1,&QWP(0x20,$inp));
1820         &xorps  ($inout2,$rndkey0);
1821         &movups ($rndkey0,&QWP(0x30,$inp));
1822         &xorps  ($inout3,$rndkey1);
1823         &movups ($rndkey1,&QWP(0x40,$inp));
1824         &xorps  ($inout4,$rndkey0);
1825         &movups ($rndkey0,&QWP(0x50,$inp));     # IV
1826         &xorps  ($inout5,$rndkey1);
1827         &movups (&QWP(0,$out),$inout0);
1828         &movups (&QWP(0x10,$out),$inout1);
1829         &lea    ($inp,&DWP(0x60,$inp));
1830         &movups (&QWP(0x20,$out),$inout2);
1831         &mov    ($rounds,$rounds_);             # restore $rounds
1832         &movups (&QWP(0x30,$out),$inout3);
1833         &mov    ($key,$key_);                   # restore $key
1834         &movups (&QWP(0x40,$out),$inout4);
1835         &lea    ($out,&DWP(0x50,$out));
1836         &sub    ($len,0x60);
1837         &ja     (&label("cbc_dec_loop6"));
1838
1839         &movaps ($inout0,$inout5);
1840         &movaps ($ivec,$rndkey0);
1841         &add    ($len,0x50);
1842         &jle    (&label("cbc_dec_tail_collected"));
1843         &movups (&QWP(0,$out),$inout0);
1844         &lea    ($out,&DWP(0x10,$out));
1845 &set_label("cbc_dec_tail");
1846         &movups ($inout0,&QWP(0,$inp));
1847         &movaps ($in0,$inout0);
1848         &cmp    ($len,0x10);
1849         &jbe    (&label("cbc_dec_one"));
1850
1851         &movups ($inout1,&QWP(0x10,$inp));
1852         &movaps ($in1,$inout1);
1853         &cmp    ($len,0x20);
1854         &jbe    (&label("cbc_dec_two"));
1855
1856         &movups ($inout2,&QWP(0x20,$inp));
1857         &cmp    ($len,0x30);
1858         &jbe    (&label("cbc_dec_three"));
1859
1860         &movups ($inout3,&QWP(0x30,$inp));
1861         &cmp    ($len,0x40);
1862         &jbe    (&label("cbc_dec_four"));
1863
1864         &movups ($inout4,&QWP(0x40,$inp));
1865         &movaps (&QWP(0,"esp"),$ivec);          # save IV
1866         &movups ($inout0,&QWP(0,$inp));
1867         &xorps  ($inout5,$inout5);
1868         &call   ("_aesni_decrypt6");
1869         &movups ($rndkey1,&QWP(0,$inp));
1870         &movups ($rndkey0,&QWP(0x10,$inp));
1871         &xorps  ($inout0,&QWP(0,"esp"));        # ^= IV
1872         &xorps  ($inout1,$rndkey1);
1873         &movups ($rndkey1,&QWP(0x20,$inp));
1874         &xorps  ($inout2,$rndkey0);
1875         &movups ($rndkey0,&QWP(0x30,$inp));
1876         &xorps  ($inout3,$rndkey1);
1877         &movups ($ivec,&QWP(0x40,$inp));        # IV
1878         &xorps  ($inout4,$rndkey0);
1879         &movups (&QWP(0,$out),$inout0);
1880         &movups (&QWP(0x10,$out),$inout1);
1881         &movups (&QWP(0x20,$out),$inout2);
1882         &movups (&QWP(0x30,$out),$inout3);
1883         &lea    ($out,&DWP(0x40,$out));
1884         &movaps ($inout0,$inout4);
1885         &sub    ($len,0x50);
1886         &jmp    (&label("cbc_dec_tail_collected"));
1887
1888 &set_label("cbc_dec_one",16);
1889         if ($inline)
1890         {   &aesni_inline_generate1("dec");     }
1891         else
1892         {   &call       ("_aesni_decrypt1");    }
1893         &xorps  ($inout0,$ivec);
1894         &movaps ($ivec,$in0);
1895         &sub    ($len,0x10);
1896         &jmp    (&label("cbc_dec_tail_collected"));
1897
1898 &set_label("cbc_dec_two",16);
1899         &xorps  ($inout2,$inout2);
1900         &call   ("_aesni_decrypt3");
1901         &xorps  ($inout0,$ivec);
1902         &xorps  ($inout1,$in0);
1903         &movups (&QWP(0,$out),$inout0);
1904         &movaps ($inout0,$inout1);
1905         &lea    ($out,&DWP(0x10,$out));
1906         &movaps ($ivec,$in1);
1907         &sub    ($len,0x20);
1908         &jmp    (&label("cbc_dec_tail_collected"));
1909
1910 &set_label("cbc_dec_three",16);
1911         &call   ("_aesni_decrypt3");
1912         &xorps  ($inout0,$ivec);
1913         &xorps  ($inout1,$in0);
1914         &xorps  ($inout2,$in1);
1915         &movups (&QWP(0,$out),$inout0);
1916         &movaps ($inout0,$inout2);
1917         &movups (&QWP(0x10,$out),$inout1);
1918         &lea    ($out,&DWP(0x20,$out));
1919         &movups ($ivec,&QWP(0x20,$inp));
1920         &sub    ($len,0x30);
1921         &jmp    (&label("cbc_dec_tail_collected"));
1922
1923 &set_label("cbc_dec_four",16);
1924         &call   ("_aesni_decrypt4");
1925         &movups ($rndkey1,&QWP(0x10,$inp));
1926         &movups ($rndkey0,&QWP(0x20,$inp));
1927         &xorps  ($inout0,$ivec);
1928         &movups ($ivec,&QWP(0x30,$inp));
1929         &xorps  ($inout1,$in0);
1930         &movups (&QWP(0,$out),$inout0);
1931         &xorps  ($inout2,$rndkey1);
1932         &movups (&QWP(0x10,$out),$inout1);
1933         &xorps  ($inout3,$rndkey0);
1934         &movups (&QWP(0x20,$out),$inout2);
1935         &lea    ($out,&DWP(0x30,$out));
1936         &movaps ($inout0,$inout3);
1937         &sub    ($len,0x40);
1938
1939 &set_label("cbc_dec_tail_collected");
1940         &and    ($len,15);
1941         &jnz    (&label("cbc_dec_tail_partial"));
1942         &movups (&QWP(0,$out),$inout0);
1943         &jmp    (&label("cbc_ret"));
1944
1945 &set_label("cbc_dec_tail_partial",16);
1946         &movaps (&QWP(0,"esp"),$inout0);
1947         &mov    ("ecx",16);
1948         &mov    ($inp,"esp");
1949         &sub    ("ecx",$len);
1950         &data_word(0xA4F3F689);         # rep movsb
1951
1952 &set_label("cbc_ret");
1953         &mov    ("esp",&DWP(16,"esp")); # pull original %esp
1954         &mov    ($key_,&wparam(4));
1955         &movups (&QWP(0,$key_),$ivec);  # output IV
1956 &set_label("cbc_abort");
1957 &function_end("${PREFIX}_cbc_encrypt");
1958 \f
1959 ######################################################################
1960 # Mechanical port from aesni-x86_64.pl.
1961 #
1962 # _aesni_set_encrypt_key is private interface,
1963 # input:
1964 #       "eax"   const unsigned char *userKey
1965 #       $rounds int bits
1966 #       $key    AES_KEY *key
1967 # output:
1968 #       "eax"   return code
1969 #       $round  rounds
1970
1971 &function_begin_B("_aesni_set_encrypt_key");
1972         &test   ("eax","eax");
1973         &jz     (&label("bad_pointer"));
1974         &test   ($key,$key);
1975         &jz     (&label("bad_pointer"));
1976
1977         &movups ("xmm0",&QWP(0,"eax")); # pull first 128 bits of *userKey
1978         &xorps  ("xmm4","xmm4");        # low dword of xmm4 is assumed 0
1979         &lea    ($key,&DWP(16,$key));
1980         &cmp    ($rounds,256);
1981         &je     (&label("14rounds"));
1982         &cmp    ($rounds,192);
1983         &je     (&label("12rounds"));
1984         &cmp    ($rounds,128);
1985         &jne    (&label("bad_keybits"));
1986
1987 &set_label("10rounds",16);
1988         &mov            ($rounds,9);
1989         &$movekey       (&QWP(-16,$key),"xmm0");        # round 0
1990         &aeskeygenassist("xmm1","xmm0",0x01);           # round 1
1991         &call           (&label("key_128_cold"));
1992         &aeskeygenassist("xmm1","xmm0",0x2);            # round 2
1993         &call           (&label("key_128"));
1994         &aeskeygenassist("xmm1","xmm0",0x04);           # round 3
1995         &call           (&label("key_128"));
1996         &aeskeygenassist("xmm1","xmm0",0x08);           # round 4
1997         &call           (&label("key_128"));
1998         &aeskeygenassist("xmm1","xmm0",0x10);           # round 5
1999         &call           (&label("key_128"));
2000         &aeskeygenassist("xmm1","xmm0",0x20);           # round 6
2001         &call           (&label("key_128"));
2002         &aeskeygenassist("xmm1","xmm0",0x40);           # round 7
2003         &call           (&label("key_128"));
2004         &aeskeygenassist("xmm1","xmm0",0x80);           # round 8
2005         &call           (&label("key_128"));
2006         &aeskeygenassist("xmm1","xmm0",0x1b);           # round 9
2007         &call           (&label("key_128"));
2008         &aeskeygenassist("xmm1","xmm0",0x36);           # round 10
2009         &call           (&label("key_128"));
2010         &$movekey       (&QWP(0,$key),"xmm0");
2011         &mov            (&DWP(80,$key),$rounds);
2012         &xor            ("eax","eax");
2013         &ret();
2014
2015 &set_label("key_128",16);
2016         &$movekey       (&QWP(0,$key),"xmm0");
2017         &lea            ($key,&DWP(16,$key));
2018 &set_label("key_128_cold");
2019         &shufps         ("xmm4","xmm0",0b00010000);
2020         &xorps          ("xmm0","xmm4");
2021         &shufps         ("xmm4","xmm0",0b10001100);
2022         &xorps          ("xmm0","xmm4");
2023         &shufps         ("xmm1","xmm1",0b11111111);     # critical path
2024         &xorps          ("xmm0","xmm1");
2025         &ret();
2026
2027 &set_label("12rounds",16);
2028         &movq           ("xmm2",&QWP(16,"eax"));        # remaining 1/3 of *userKey
2029         &mov            ($rounds,11);
2030         &$movekey       (&QWP(-16,$key),"xmm0");        # round 0
2031         &aeskeygenassist("xmm1","xmm2",0x01);           # round 1,2
2032         &call           (&label("key_192a_cold"));
2033         &aeskeygenassist("xmm1","xmm2",0x02);           # round 2,3
2034         &call           (&label("key_192b"));
2035         &aeskeygenassist("xmm1","xmm2",0x04);           # round 4,5
2036         &call           (&label("key_192a"));
2037         &aeskeygenassist("xmm1","xmm2",0x08);           # round 5,6
2038         &call           (&label("key_192b"));
2039         &aeskeygenassist("xmm1","xmm2",0x10);           # round 7,8
2040         &call           (&label("key_192a"));
2041         &aeskeygenassist("xmm1","xmm2",0x20);           # round 8,9
2042         &call           (&label("key_192b"));
2043         &aeskeygenassist("xmm1","xmm2",0x40);           # round 10,11
2044         &call           (&label("key_192a"));
2045         &aeskeygenassist("xmm1","xmm2",0x80);           # round 11,12
2046         &call           (&label("key_192b"));
2047         &$movekey       (&QWP(0,$key),"xmm0");
2048         &mov            (&DWP(48,$key),$rounds);
2049         &xor            ("eax","eax");
2050         &ret();
2051
2052 &set_label("key_192a",16);
2053         &$movekey       (&QWP(0,$key),"xmm0");
2054         &lea            ($key,&DWP(16,$key));
2055 &set_label("key_192a_cold",16);
2056         &movaps         ("xmm5","xmm2");
2057 &set_label("key_192b_warm");
2058         &shufps         ("xmm4","xmm0",0b00010000);
2059         &movdqa         ("xmm3","xmm2");
2060         &xorps          ("xmm0","xmm4");
2061         &shufps         ("xmm4","xmm0",0b10001100);
2062         &pslldq         ("xmm3",4);
2063         &xorps          ("xmm0","xmm4");
2064         &pshufd         ("xmm1","xmm1",0b01010101);     # critical path
2065         &pxor           ("xmm2","xmm3");
2066         &pxor           ("xmm0","xmm1");
2067         &pshufd         ("xmm3","xmm0",0b11111111);
2068         &pxor           ("xmm2","xmm3");
2069         &ret();
2070
2071 &set_label("key_192b",16);
2072         &movaps         ("xmm3","xmm0");
2073         &shufps         ("xmm5","xmm0",0b01000100);
2074         &$movekey       (&QWP(0,$key),"xmm5");
2075         &shufps         ("xmm3","xmm2",0b01001110);
2076         &$movekey       (&QWP(16,$key),"xmm3");
2077         &lea            ($key,&DWP(32,$key));
2078         &jmp            (&label("key_192b_warm"));
2079
2080 &set_label("14rounds",16);
2081         &movups         ("xmm2",&QWP(16,"eax"));        # remaining half of *userKey
2082         &mov            ($rounds,13);
2083         &lea            ($key,&DWP(16,$key));
2084         &$movekey       (&QWP(-32,$key),"xmm0");        # round 0
2085         &$movekey       (&QWP(-16,$key),"xmm2");        # round 1
2086         &aeskeygenassist("xmm1","xmm2",0x01);           # round 2
2087         &call           (&label("key_256a_cold"));
2088         &aeskeygenassist("xmm1","xmm0",0x01);           # round 3
2089         &call           (&label("key_256b"));
2090         &aeskeygenassist("xmm1","xmm2",0x02);           # round 4
2091         &call           (&label("key_256a"));
2092         &aeskeygenassist("xmm1","xmm0",0x02);           # round 5
2093         &call           (&label("key_256b"));
2094         &aeskeygenassist("xmm1","xmm2",0x04);           # round 6
2095         &call           (&label("key_256a"));
2096         &aeskeygenassist("xmm1","xmm0",0x04);           # round 7
2097         &call           (&label("key_256b"));
2098         &aeskeygenassist("xmm1","xmm2",0x08);           # round 8
2099         &call           (&label("key_256a"));
2100         &aeskeygenassist("xmm1","xmm0",0x08);           # round 9
2101         &call           (&label("key_256b"));
2102         &aeskeygenassist("xmm1","xmm2",0x10);           # round 10
2103         &call           (&label("key_256a"));
2104         &aeskeygenassist("xmm1","xmm0",0x10);           # round 11
2105         &call           (&label("key_256b"));
2106         &aeskeygenassist("xmm1","xmm2",0x20);           # round 12
2107         &call           (&label("key_256a"));
2108         &aeskeygenassist("xmm1","xmm0",0x20);           # round 13
2109         &call           (&label("key_256b"));
2110         &aeskeygenassist("xmm1","xmm2",0x40);           # round 14
2111         &call           (&label("key_256a"));
2112         &$movekey       (&QWP(0,$key),"xmm0");
2113         &mov            (&DWP(16,$key),$rounds);
2114         &xor            ("eax","eax");
2115         &ret();
2116
2117 &set_label("key_256a",16);
2118         &$movekey       (&QWP(0,$key),"xmm2");
2119         &lea            ($key,&DWP(16,$key));
2120 &set_label("key_256a_cold");
2121         &shufps         ("xmm4","xmm0",0b00010000);
2122         &xorps          ("xmm0","xmm4");
2123         &shufps         ("xmm4","xmm0",0b10001100);
2124         &xorps          ("xmm0","xmm4");
2125         &shufps         ("xmm1","xmm1",0b11111111);     # critical path
2126         &xorps          ("xmm0","xmm1");
2127         &ret();
2128
2129 &set_label("key_256b",16);
2130         &$movekey       (&QWP(0,$key),"xmm0");
2131         &lea            ($key,&DWP(16,$key));
2132
2133         &shufps         ("xmm4","xmm2",0b00010000);
2134         &xorps          ("xmm2","xmm4");
2135         &shufps         ("xmm4","xmm2",0b10001100);
2136         &xorps          ("xmm2","xmm4");
2137         &shufps         ("xmm1","xmm1",0b10101010);     # critical path
2138         &xorps          ("xmm2","xmm1");
2139         &ret();
2140
2141 &set_label("bad_pointer",4);
2142         &mov    ("eax",-1);
2143         &ret    ();
2144 &set_label("bad_keybits",4);
2145         &mov    ("eax",-2);
2146         &ret    ();
2147 &function_end_B("_aesni_set_encrypt_key");
2148
2149 # int $PREFIX_set_encrypt_key (const unsigned char *userKey, int bits,
2150 #                              AES_KEY *key)
2151 &function_begin_B("${PREFIX}_set_encrypt_key");
2152         &mov    ("eax",&wparam(0));
2153         &mov    ($rounds,&wparam(1));
2154         &mov    ($key,&wparam(2));
2155         &call   ("_aesni_set_encrypt_key");
2156         &ret    ();
2157 &function_end_B("${PREFIX}_set_encrypt_key");
2158
2159 # int $PREFIX_set_decrypt_key (const unsigned char *userKey, int bits,
2160 #                              AES_KEY *key)
2161 &function_begin_B("${PREFIX}_set_decrypt_key");
2162         &mov    ("eax",&wparam(0));
2163         &mov    ($rounds,&wparam(1));
2164         &mov    ($key,&wparam(2));
2165         &call   ("_aesni_set_encrypt_key");
2166         &mov    ($key,&wparam(2));
2167         &shl    ($rounds,4);    # rounds-1 after _aesni_set_encrypt_key
2168         &test   ("eax","eax");
2169         &jnz    (&label("dec_key_ret"));
2170         &lea    ("eax",&DWP(16,$key,$rounds));  # end of key schedule
2171
2172         &$movekey       ("xmm0",&QWP(0,$key));  # just swap
2173         &$movekey       ("xmm1",&QWP(0,"eax"));
2174         &$movekey       (&QWP(0,"eax"),"xmm0");
2175         &$movekey       (&QWP(0,$key),"xmm1");
2176         &lea            ($key,&DWP(16,$key));
2177         &lea            ("eax",&DWP(-16,"eax"));
2178
2179 &set_label("dec_key_inverse");
2180         &$movekey       ("xmm0",&QWP(0,$key));  # swap and inverse
2181         &$movekey       ("xmm1",&QWP(0,"eax"));
2182         &aesimc         ("xmm0","xmm0");
2183         &aesimc         ("xmm1","xmm1");
2184         &lea            ($key,&DWP(16,$key));
2185         &lea            ("eax",&DWP(-16,"eax"));
2186         &$movekey       (&QWP(16,"eax"),"xmm0");
2187         &$movekey       (&QWP(-16,$key),"xmm1");
2188         &cmp            ("eax",$key);
2189         &ja             (&label("dec_key_inverse"));
2190
2191         &$movekey       ("xmm0",&QWP(0,$key));  # inverse middle
2192         &aesimc         ("xmm0","xmm0");
2193         &$movekey       (&QWP(0,$key),"xmm0");
2194
2195         &xor            ("eax","eax");          # return success
2196 &set_label("dec_key_ret");
2197         &ret    ();
2198 &function_end_B("${PREFIX}_set_decrypt_key");
2199 &asciz("AES for Intel AES-NI, CRYPTOGAMS by <appro\@openssl.org>");
2200
2201 &asm_finish();