• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@openssl.org>
48
49$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
50push(@INC,"${dir}","${dir}../../perlasm");
51require "x86asm.pl";
52
53&asm_init($ARGV[0],"vpaes-x86.pl",$x86only = $ARGV[$#ARGV] eq "386");
54
55$PREFIX="vpaes";
56
57my  ($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