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