a5cf3539dadf992d55e9f4495afbcf4dd278e3ca
[libgcrypt.git] / cipher / serpent-sse2-amd64.S
1 /* serpent-sse2-amd64.S  -  SSE2 implementation of Serpent cipher
2  *
3  * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #ifdef __x86_64
22 #include <config.h>
23 #if defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && defined(USE_SERPENT)
24
25 #ifdef __PIC__
26 #  define RIP (%rip)
27 #else
28 #  define RIP
29 #endif
30
31 /* struct serpent_context: */
32 #define ctx_keys 0
33
34 /* register macros */
35 #define CTX %rdi
36
37 /* vector registers */
38 .set RA0, %xmm0
39 .set RA1, %xmm1
40 .set RA2, %xmm2
41 .set RA3, %xmm3
42 .set RA4, %xmm4
43
44 .set RB0, %xmm5
45 .set RB1, %xmm6
46 .set RB2, %xmm7
47 .set RB3, %xmm8
48 .set RB4, %xmm9
49
50 .set RNOT, %xmm10
51 .set RTMP0, %xmm11
52 .set RTMP1, %xmm12
53 .set RTMP2, %xmm13
54
55 /**********************************************************************
56   helper macros
57  **********************************************************************/
58
59 /* preprocessor macro for renaming vector registers using GAS macros */
60 #define sbox_reg_rename(r0, r1, r2, r3, r4, \
61                         new_r0, new_r1, new_r2, new_r3, new_r4) \
62         .set rename_reg0, new_r0; \
63         .set rename_reg1, new_r1; \
64         .set rename_reg2, new_r2; \
65         .set rename_reg3, new_r3; \
66         .set rename_reg4, new_r4; \
67         \
68         .set r0, rename_reg0; \
69         .set r1, rename_reg1; \
70         .set r2, rename_reg2; \
71         .set r3, rename_reg3; \
72         .set r4, rename_reg4;
73
74 /* vector 32-bit rotation to left */
75 #define vec_rol(reg, nleft, tmp) \
76         movdqa reg, tmp;                \
77         pslld $(nleft), tmp;            \
78         psrld $(32 - (nleft)), reg;     \
79         por tmp, reg;
80
81 /* vector 32-bit rotation to right */
82 #define vec_ror(reg, nright, tmp) \
83         vec_rol(reg, 32 - nright, tmp)
84
85 /* 4x4 32-bit integer matrix transpose */
86 #define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \
87         movdqa    x0, t2; \
88         punpckhdq x1, t2; \
89         punpckldq x1, x0; \
90         \
91         movdqa    x2, t1; \
92         punpckldq x3, t1; \
93         punpckhdq x3, x2; \
94         \
95         movdqa     x0, x1; \
96         punpckhqdq t1, x1; \
97         punpcklqdq t1, x0; \
98         \
99         movdqa     t2, x3; \
100         punpckhqdq x2, x3; \
101         punpcklqdq x2, t2; \
102         movdqa     t2, x2;
103
104 /* fill xmm register with 32-bit value from memory */
105 #define pbroadcastd(mem32, xreg) \
106         movd mem32, xreg; \
107         pshufd $0, xreg, xreg;
108
109 /* xor with unaligned memory operand */
110 #define pxor_u(umem128, xreg, t) \
111         movdqu umem128, t; \
112         pxor t, xreg;
113
114 /* 128-bit wide byte swap */
115 #define pbswap(xreg, t0) \
116         /* reorder 32-bit words, [a,b,c,d] => [d,c,b,a] */ \
117         pshufd $0x1b, xreg, xreg; \
118         /* reorder high&low 16-bit words, [d0,d1,c0,c1] => [d1,d0,c1,c0] */ \
119         pshuflw $0xb1, xreg, xreg; \
120         pshufhw $0xb1, xreg, xreg; \
121         /* reorder bytes in 16-bit words */ \
122         movdqa xreg, t0; \
123         psrlw $8, t0; \
124         psllw $8, xreg; \
125         por t0, xreg;
126
127 /**********************************************************************
128   8-way serpent
129  **********************************************************************/
130
131 /*
132  * These are the S-Boxes of Serpent from following research paper.
133  *
134  *  D. A. Osvik, “Speeding up Serpent,” in Third AES Candidate Conference,
135  *   (New York, New York, USA), p. 317–329, National Institute of Standards and
136  *   Technology, 2000.
137  *
138  * Paper is also available at: http://www.ii.uib.no/~osvik/pub/aes3.pdf
139  *
140  */
141 #define SBOX0(r0, r1, r2, r3, r4) \
142         pxor    r0, r3;         movdqa  r1, r4;         \
143         pand    r3, r1;         pxor    r2, r4;         \
144         pxor    r0, r1;         por     r3, r0;         \
145         pxor    r4, r0;         pxor    r3, r4;         \
146         pxor    r2, r3;         por     r1, r2;         \
147         pxor    r4, r2;         pxor    RNOT, r4;       \
148         por     r1, r4;         pxor    r3, r1;         \
149         pxor    r4, r1;         por     r0, r3;         \
150         pxor    r3, r1;         pxor    r3, r4;         \
151         \
152         sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r0,r3);
153
154 #define SBOX0_INVERSE(r0, r1, r2, r3, r4) \
155         pxor    RNOT, r2;       movdqa  r1, r4;         \
156         por     r0, r1;         pxor    RNOT, r4;       \
157         pxor    r2, r1;         por     r4, r2;         \
158         pxor    r3, r1;         pxor    r4, r0;         \
159         pxor    r0, r2;         pand    r3, r0;         \
160         pxor    r0, r4;         por     r1, r0;         \
161         pxor    r2, r0;         pxor    r4, r3;         \
162         pxor    r1, r2;         pxor    r0, r3;         \
163         pxor    r1, r3; \
164         pand    r3, r2; \
165         pxor    r2, r4; \
166         \
167         sbox_reg_rename(r0,r1,r2,r3,r4, r0,r4,r1,r3,r2);
168
169 #define SBOX1(r0, r1, r2, r3, r4) \
170         pxor    RNOT, r0;       pxor    RNOT, r2;       \
171         movdqa  r0, r4;         pand    r1, r0;         \
172         pxor    r0, r2;         por     r3, r0;         \
173         pxor    r2, r3;         pxor    r0, r1;         \
174         pxor    r4, r0;         por     r1, r4;         \
175         pxor    r3, r1;         por     r0, r2;         \
176         pand    r4, r2;         pxor    r1, r0;         \
177         pand    r2, r1; \
178         pxor    r0, r1;         pand    r2, r0;         \
179         pxor    r4, r0; \
180         \
181         sbox_reg_rename(r0,r1,r2,r3,r4, r2,r0,r3,r1,r4);
182
183 #define SBOX1_INVERSE(r0, r1, r2, r3, r4) \
184         movdqa  r1, r4;         pxor    r3, r1;         \
185         pand    r1, r3;         pxor    r2, r4;         \
186         pxor    r0, r3;         por     r1, r0;         \
187         pxor    r3, r2;         pxor    r4, r0;         \
188         por     r2, r0;         pxor    r3, r1;         \
189         pxor    r1, r0;         por     r3, r1;         \
190         pxor    r0, r1;         pxor    RNOT, r4;       \
191         pxor    r1, r4;         por     r0, r1;         \
192         pxor    r0, r1; \
193         por     r4, r1; \
194         pxor    r1, r3; \
195         \
196         sbox_reg_rename(r0,r1,r2,r3,r4, r4,r0,r3,r2,r1);
197
198 #define SBOX2(r0, r1, r2, r3, r4) \
199         movdqa  r0, r4;         pand    r2, r0;         \
200         pxor    r3, r0;         pxor    r1, r2;         \
201         pxor    r0, r2;         por     r4, r3;         \
202         pxor    r1, r3;         pxor    r2, r4;         \
203         movdqa  r3, r1;         por     r4, r3;         \
204         pxor    r0, r3;         pand    r1, r0;         \
205         pxor    r0, r4;         pxor    r3, r1;         \
206         pxor    r4, r1;         pxor    RNOT, r4;       \
207         \
208         sbox_reg_rename(r0,r1,r2,r3,r4, r2,r3,r1,r4,r0);
209
210 #define SBOX2_INVERSE(r0, r1, r2, r3, r4) \
211         pxor    r3, r2;         pxor    r0, r3;         \
212         movdqa  r3, r4;         pand    r2, r3;         \
213         pxor    r1, r3;         por     r2, r1;         \
214         pxor    r4, r1;         pand    r3, r4;         \
215         pxor    r3, r2;         pand    r0, r4;         \
216         pxor    r2, r4;         pand    r1, r2;         \
217         por     r0, r2;         pxor    RNOT, r3;       \
218         pxor    r3, r2;         pxor    r3, r0;         \
219         pand    r1, r0;         pxor    r4, r3;         \
220         pxor    r0, r3; \
221         \
222         sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r3,r0);
223
224 #define SBOX3(r0, r1, r2, r3, r4) \
225         movdqa  r0, r4;         por     r3, r0;         \
226         pxor    r1, r3;         pand    r4, r1;         \
227         pxor    r2, r4;         pxor    r3, r2;         \
228         pand    r0, r3;         por     r1, r4;         \
229         pxor    r4, r3;         pxor    r1, r0;         \
230         pand    r0, r4;         pxor    r3, r1;         \
231         pxor    r2, r4;         por     r0, r1;         \
232         pxor    r2, r1;         pxor    r3, r0;         \
233         movdqa  r1, r2;         por     r3, r1;         \
234         pxor    r0, r1; \
235         \
236         sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r3,r4,r0);
237
238 #define SBOX3_INVERSE(r0, r1, r2, r3, r4) \
239         movdqa  r2, r4;         pxor    r1, r2;         \
240         pxor    r2, r0;         pand    r2, r4;         \
241         pxor    r0, r4;         pand    r1, r0;         \
242         pxor    r3, r1;         por     r4, r3;         \
243         pxor    r3, r2;         pxor    r3, r0;         \
244         pxor    r4, r1;         pand    r2, r3;         \
245         pxor    r1, r3;         pxor    r0, r1;         \
246         por     r2, r1;         pxor    r3, r0;         \
247         pxor    r4, r1; \
248         pxor    r1, r0; \
249         \
250         sbox_reg_rename(r0,r1,r2,r3,r4, r2,r1,r3,r0,r4);
251
252 #define SBOX4(r0, r1, r2, r3, r4) \
253         pxor    r3, r1;         pxor    RNOT, r3;       \
254         pxor    r3, r2;         pxor    r0, r3;         \
255         movdqa  r1, r4;         pand    r3, r1;         \
256         pxor    r2, r1;         pxor    r3, r4;         \
257         pxor    r4, r0;         pand    r4, r2;         \
258         pxor    r0, r2;         pand    r1, r0;         \
259         pxor    r0, r3;         por     r1, r4;         \
260         pxor    r0, r4;         por     r3, r0;         \
261         pxor    r2, r0;         pand    r3, r2;         \
262         pxor    RNOT, r0;       pxor    r2, r4;         \
263         \
264         sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r0,r3,r2);
265
266 #define SBOX4_INVERSE(r0, r1, r2, r3, r4) \
267         movdqa  r2, r4;         pand    r3, r2;         \
268         pxor    r1, r2;         por     r3, r1;         \
269         pand    r0, r1;         pxor    r2, r4;         \
270         pxor    r1, r4;         pand    r2, r1;         \
271         pxor    RNOT, r0;       pxor    r4, r3;         \
272         pxor    r3, r1;         pand    r0, r3;         \
273         pxor    r2, r3;         pxor    r1, r0;         \
274         pand    r0, r2;         pxor    r0, r3;         \
275         pxor    r4, r2; \
276         por     r3, r2;         pxor    r0, r3;         \
277         pxor    r1, r2; \
278         \
279         sbox_reg_rename(r0,r1,r2,r3,r4, r0,r3,r2,r4,r1);
280
281 #define SBOX5(r0, r1, r2, r3, r4) \
282         pxor    r1, r0;         pxor    r3, r1;         \
283         pxor    RNOT, r3;       movdqa  r1, r4;         \
284         pand    r0, r1;         pxor    r3, r2;         \
285         pxor    r2, r1;         por     r4, r2;         \
286         pxor    r3, r4;         pand    r1, r3;         \
287         pxor    r0, r3;         pxor    r1, r4;         \
288         pxor    r2, r4;         pxor    r0, r2;         \
289         pand    r3, r0;         pxor    RNOT, r2;       \
290         pxor    r4, r0;         por     r3, r4;         \
291         pxor    r4, r2; \
292         \
293         sbox_reg_rename(r0,r1,r2,r3,r4, r1,r3,r0,r2,r4);
294
295 #define SBOX5_INVERSE(r0, r1, r2, r3, r4) \
296         pxor    RNOT, r1;       movdqa  r3, r4;         \
297         pxor    r1, r2;         por     r0, r3;         \
298         pxor    r2, r3;         por     r1, r2;         \
299         pand    r0, r2;         pxor    r3, r4;         \
300         pxor    r4, r2;         por     r0, r4;         \
301         pxor    r1, r4;         pand    r2, r1;         \
302         pxor    r3, r1;         pxor    r2, r4;         \
303         pand    r4, r3;         pxor    r1, r4;         \
304         pxor    r4, r3;         pxor    RNOT, r4;       \
305         pxor    r0, r3; \
306         \
307         sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r3,r2,r0);
308
309 #define SBOX6(r0, r1, r2, r3, r4) \
310         pxor    RNOT, r2;       movdqa  r3, r4;         \
311         pand    r0, r3;         pxor    r4, r0;         \
312         pxor    r2, r3;         por     r4, r2;         \
313         pxor    r3, r1;         pxor    r0, r2;         \
314         por     r1, r0;         pxor    r1, r2;         \
315         pxor    r0, r4;         por     r3, r0;         \
316         pxor    r2, r0;         pxor    r3, r4;         \
317         pxor    r0, r4;         pxor    RNOT, r3;       \
318         pand    r4, r2; \
319         pxor    r3, r2; \
320         \
321         sbox_reg_rename(r0,r1,r2,r3,r4, r0,r1,r4,r2,r3);
322
323 #define SBOX6_INVERSE(r0, r1, r2, r3, r4) \
324         pxor    r2, r0;         movdqa  r2, r4;         \
325         pand    r0, r2;         pxor    r3, r4;         \
326         pxor    RNOT, r2;       pxor    r1, r3;         \
327         pxor    r3, r2;         por     r0, r4;         \
328         pxor    r2, r0;         pxor    r4, r3;         \
329         pxor    r1, r4;         pand    r3, r1;         \
330         pxor    r0, r1;         pxor    r3, r0;         \
331         por     r2, r0;         pxor    r1, r3;         \
332         pxor    r0, r4; \
333         \
334         sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r4,r3,r0);
335
336 #define SBOX7(r0, r1, r2, r3, r4) \
337         movdqa  r1, r4;         por     r2, r1;         \
338         pxor    r3, r1;         pxor    r2, r4;         \
339         pxor    r1, r2;         por     r4, r3;         \
340         pand    r0, r3;         pxor    r2, r4;         \
341         pxor    r1, r3;         por     r4, r1;         \
342         pxor    r0, r1;         por     r4, r0;         \
343         pxor    r2, r0;         pxor    r4, r1;         \
344         pxor    r1, r2;         pand    r0, r1;         \
345         pxor    r4, r1;         pxor    RNOT, r2;       \
346         por     r0, r2; \
347         pxor    r2, r4; \
348         \
349         sbox_reg_rename(r0,r1,r2,r3,r4, r4,r3,r1,r0,r2);
350
351 #define SBOX7_INVERSE(r0, r1, r2, r3, r4) \
352         movdqa  r2, r4;         pxor    r0, r2;         \
353         pand    r3, r0;         por     r3, r4;         \
354         pxor    RNOT, r2;       pxor    r1, r3;         \
355         por     r0, r1;         pxor    r2, r0;         \
356         pand    r4, r2;         pand    r4, r3;         \
357         pxor    r2, r1;         pxor    r0, r2;         \
358         por     r2, r0;         pxor    r1, r4;         \
359         pxor    r3, r0;         pxor    r4, r3;         \
360         por     r0, r4;         pxor    r2, r3;         \
361         pxor    r2, r4; \
362         \
363         sbox_reg_rename(r0,r1,r2,r3,r4, r3,r0,r1,r4,r2);
364
365 /* Apply SBOX number WHICH to to the block.  */
366 #define SBOX(which, r0, r1, r2, r3, r4) \
367         SBOX##which (r0, r1, r2, r3, r4)
368
369 /* Apply inverse SBOX number WHICH to to the block.  */
370 #define SBOX_INVERSE(which, r0, r1, r2, r3, r4) \
371         SBOX##which##_INVERSE (r0, r1, r2, r3, r4)
372
373 /* XOR round key into block state in r0,r1,r2,r3. r4 used as temporary.  */
374 #define BLOCK_XOR_KEY(r0, r1, r2, r3, r4, round) \
375         pbroadcastd ((ctx_keys + (round) * 16 + 0 * 4)(CTX), r4); \
376         pxor r4, r0; \
377         pbroadcastd ((ctx_keys + (round) * 16 + 1 * 4)(CTX), r4); \
378         pxor r4, r1; \
379         pbroadcastd ((ctx_keys + (round) * 16 + 2 * 4)(CTX), r4); \
380         pxor r4, r2; \
381         pbroadcastd ((ctx_keys + (round) * 16 + 3 * 4)(CTX), r4); \
382         pxor r4, r3;
383
384 /* Apply the linear transformation to BLOCK.  */
385 #define LINEAR_TRANSFORMATION(r0, r1, r2, r3, r4) \
386         vec_rol(r0, 13, r4);    \
387         vec_rol(r2, 3, r4);     \
388         pxor r0, r1;            \
389         pxor r2, r1;            \
390         movdqa r0, r4;          \
391         pslld $3, r4;           \
392         pxor r2, r3;            \
393         pxor r4, r3;            \
394         vec_rol(r1, 1, r4);     \
395         vec_rol(r3, 7, r4);     \
396         pxor r1, r0;            \
397         pxor r3, r0;            \
398         movdqa r1, r4;          \
399         pslld $7, r4;           \
400         pxor r3, r2;            \
401         pxor r4, r2;            \
402         vec_rol(r0, 5, r4);     \
403         vec_rol(r2, 22, r4);
404
405 /* Apply the inverse linear transformation to BLOCK.  */
406 #define LINEAR_TRANSFORMATION_INVERSE(r0, r1, r2, r3, r4) \
407         vec_ror(r2, 22, r4);    \
408         vec_ror(r0, 5, r4);     \
409         movdqa r1, r4;          \
410         pslld $7, r4;           \
411         pxor r3, r2;            \
412         pxor r4, r2;            \
413         pxor r1, r0;            \
414         pxor r3, r0;            \
415         vec_ror(r3, 7, r4);     \
416         vec_ror(r1, 1, r4);     \
417         movdqa r0, r4;          \
418         pslld $3, r4;           \
419         pxor r2, r3;            \
420         pxor r4, r3;            \
421         pxor r0, r1;            \
422         pxor r2, r1;            \
423         vec_ror(r2, 3, r4);     \
424         vec_ror(r0, 13, r4);
425
426 /* Apply a Serpent round to eight parallel blocks.  This macro increments
427    `round'.  */
428 #define ROUND(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \
429         BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round);      \
430         SBOX (which, a0, a1, a2, a3, a4);               \
431                 BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round);      \
432                 SBOX (which, b0, b1, b2, b3, b4);               \
433         LINEAR_TRANSFORMATION (a0, a1, a2, a3, a4);     \
434                 LINEAR_TRANSFORMATION (b0, b1, b2, b3, b4);     \
435         .set round, (round + 1);
436
437 /* Apply the last Serpent round to eight parallel blocks.  This macro increments
438    `round'.  */
439 #define ROUND_LAST(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \
440         BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round);      \
441         SBOX (which, a0, a1, a2, a3, a4);               \
442                 BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round);      \
443                 SBOX (which, b0, b1, b2, b3, b4);               \
444         .set round, (round + 1);                        \
445         BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round);      \
446                 BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round);      \
447         .set round, (round + 1);
448
449 /* Apply an inverse Serpent round to eight parallel blocks.  This macro
450    increments `round'.  */
451 #define ROUND_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \
452         LINEAR_TRANSFORMATION_INVERSE (a0, a1, a2, a3, a4);     \
453                 LINEAR_TRANSFORMATION_INVERSE (b0, b1, b2, b3, b4);     \
454         SBOX_INVERSE (which, a0, a1, a2, a3, a4);               \
455         BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round);              \
456                 SBOX_INVERSE (which, b0, b1, b2, b3, b4);               \
457                 BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round);              \
458         .set round, (round - 1);
459
460 /* Apply the first inverse Serpent round to eight parallel blocks.  This macro
461    increments `round'.  */
462 #define ROUND_FIRST_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \
463         BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round);      \
464                 BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round);      \
465         .set round, (round - 1);                        \
466         SBOX_INVERSE (which, a0, a1, a2, a3, a4);       \
467         BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round);      \
468                 SBOX_INVERSE (which, b0, b1, b2, b3, b4);       \
469                 BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round);      \
470         .set round, (round - 1);
471
472 .text
473
474 .align 8
475 .type   __serpent_enc_blk8,@function;
476 __serpent_enc_blk8:
477         /* input:
478          *      %rdi: ctx, CTX
479          *      RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: eight parallel plaintext
480          *                                              blocks
481          * output:
482          *      RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: eight parallel
483          *                                              ciphertext blocks
484          */
485
486         /* record input vector names for __serpent_enc_blk8 */
487         .set enc_in_a0, RA0
488         .set enc_in_a1, RA1
489         .set enc_in_a2, RA2
490         .set enc_in_a3, RA3
491         .set enc_in_b0, RB0
492         .set enc_in_b1, RB1
493         .set enc_in_b2, RB2
494         .set enc_in_b3, RB3
495
496         pcmpeqd RNOT, RNOT;
497
498         transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1);
499         transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1);
500
501         .set round, 0
502         ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
503         ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
504         ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
505         ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
506         ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
507         ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
508         ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
509         ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
510         ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
511         ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
512         ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
513         ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
514         ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
515         ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
516         ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
517         ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
518         ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
519         ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
520         ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
521         ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
522         ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
523         ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
524         ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
525         ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
526         ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
527         ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
528         ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
529         ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
530         ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
531         ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
532         ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
533
534         ROUND_LAST (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
535
536         transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1);
537         transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1);
538
539         /* record output vector names for __serpent_enc_blk8 */
540         .set enc_out_a0, RA0
541         .set enc_out_a1, RA1
542         .set enc_out_a2, RA2
543         .set enc_out_a3, RA3
544         .set enc_out_b0, RB0
545         .set enc_out_b1, RB1
546         .set enc_out_b2, RB2
547         .set enc_out_b3, RB3
548
549         ret;
550 .size __serpent_enc_blk8,.-__serpent_enc_blk8;
551
552 .align 8
553 .type   __serpent_dec_blk8,@function;
554 __serpent_dec_blk8:
555         /* input:
556          *      %rdi: ctx, CTX
557          *      RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: eight parallel
558          *                                              ciphertext blocks
559          * output:
560          *      RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: eight parallel plaintext
561          *                                              blocks
562          */
563
564         /* record input vector names for __serpent_dec_blk8 */
565         .set dec_in_a0, RA0
566         .set dec_in_a1, RA1
567         .set dec_in_a2, RA2
568         .set dec_in_a3, RA3
569         .set dec_in_b0, RB0
570         .set dec_in_b1, RB1
571         .set dec_in_b2, RB2
572         .set dec_in_b3, RB3
573
574         pcmpeqd RNOT, RNOT;
575
576         transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1);
577         transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1);
578
579         .set round, 32
580         ROUND_FIRST_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
581
582         ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
583         ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
584         ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
585         ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
586         ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
587         ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
588         ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
589         ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
590         ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
591         ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
592         ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
593         ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
594         ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
595         ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
596         ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
597         ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
598         ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
599         ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
600         ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
601         ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
602         ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
603         ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
604         ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
605         ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
606         ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
607         ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
608         ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
609         ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
610         ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
611         ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
612         ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4);
613
614         transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1);
615         transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1);
616
617         /* record output vector names for __serpent_dec_blk8 */
618         .set dec_out_a0, RA0
619         .set dec_out_a1, RA1
620         .set dec_out_a2, RA2
621         .set dec_out_a3, RA3
622         .set dec_out_b0, RB0
623         .set dec_out_b1, RB1
624         .set dec_out_b2, RB2
625         .set dec_out_b3, RB3
626
627         ret;
628 .size __serpent_dec_blk8,.-__serpent_dec_blk8;
629
630 .align 8
631 .global _gcry_serpent_sse2_ctr_enc
632 .type   _gcry_serpent_sse2_ctr_enc,@function;
633 _gcry_serpent_sse2_ctr_enc:
634         /* input:
635          *      %rdi: ctx, CTX
636          *      %rsi: dst (8 blocks)
637          *      %rdx: src (8 blocks)
638          *      %rcx: iv (big endian, 128bit)
639          */
640
641         .set RA0, enc_in_a0
642         .set RA1, enc_in_a1
643         .set RA2, enc_in_a2
644         .set RA3, enc_in_a3
645         .set RB0, enc_in_b0
646         .set RB1, enc_in_b1
647         .set RB2, enc_in_b2
648         .set RB3, enc_in_b3
649
650         /* load IV and byteswap */
651         movdqu (%rcx), RA0;
652         movdqa RA0, RTMP0;
653         pbswap(RTMP0, RTMP1); /* be => le */
654
655         pcmpeqd RNOT, RNOT;
656         psrldq $8, RNOT; /* low: -1, high: 0 */
657         movdqa RNOT, RTMP2;
658         paddq RTMP2, RTMP2; /* low: -2, high: 0 */
659
660         /* construct IVs */
661         movdqa RTMP0, RTMP1;
662         psubq RNOT, RTMP0; /* +1 */
663         movdqa RTMP0, RA1;
664         psubq RTMP2, RTMP1; /* +2 */
665         movdqa RTMP1, RA2;
666         psubq RTMP2, RTMP0; /* +3 */
667         movdqa RTMP0, RA3;
668         psubq RTMP2, RTMP1; /* +4 */
669         movdqa RTMP1, RB0;
670         psubq RTMP2, RTMP0; /* +5 */
671         movdqa RTMP0, RB1;
672         psubq RTMP2, RTMP1; /* +6 */
673         movdqa RTMP1, RB2;
674         psubq RTMP2, RTMP0; /* +7 */
675         movdqa RTMP0, RB3;
676         psubq RTMP2, RTMP1; /* +8 */
677
678         /* check need for handling 64-bit overflow and carry */
679         cmpl $0xffffffff, 8(%rcx);
680         jne .Lno_ctr_carry;
681
682         movl 12(%rcx), %eax;
683         bswapl %eax;
684         cmpl $-8, %eax;
685         jb .Lno_ctr_carry;
686         pslldq $8, RNOT; /* low: 0, high: -1 */
687         je .Lcarry_RTMP0;
688
689         cmpl $-6, %eax;
690         jb .Lcarry_RB3;
691         je .Lcarry_RB2;
692
693         cmpl $-4, %eax;
694         jb .Lcarry_RB1;
695         je .Lcarry_RB0;
696
697         cmpl $-2, %eax;
698         jb .Lcarry_RA3;
699         je .Lcarry_RA2;
700
701         psubq RNOT, RA1;
702 .Lcarry_RA2:
703         psubq RNOT, RA2;
704 .Lcarry_RA3:
705         psubq RNOT, RA3;
706 .Lcarry_RB0:
707         psubq RNOT, RB0;
708 .Lcarry_RB1:
709         psubq RNOT, RB1;
710 .Lcarry_RB2:
711         psubq RNOT, RB2;
712 .Lcarry_RB3:
713         psubq RNOT, RB3;
714 .Lcarry_RTMP0:
715         psubq RNOT, RTMP1;
716
717 .Lno_ctr_carry:
718         /* le => be */
719         pbswap(RA1, RTMP0);
720         pbswap(RA2, RTMP0);
721         pbswap(RA3, RTMP0);
722         pbswap(RB0, RTMP0);
723         pbswap(RB1, RTMP0);
724         pbswap(RB2, RTMP0);
725         pbswap(RB3, RTMP0);
726         pbswap(RTMP1, RTMP0);
727         /* store new IV */
728         movdqu RTMP1, (%rcx);
729
730         call __serpent_enc_blk8;
731
732         .set RA0, enc_out_a0
733         .set RA1, enc_out_a1
734         .set RA2, enc_out_a2
735         .set RA3, enc_out_a3
736         .set RB0, enc_out_b0
737         .set RB1, enc_out_b1
738         .set RB2, enc_out_b2
739         .set RB3, enc_out_b3
740
741         pxor_u((0 * 16)(%rdx), RA0, RTMP0);
742         pxor_u((1 * 16)(%rdx), RA1, RTMP0);
743         pxor_u((2 * 16)(%rdx), RA2, RTMP0);
744         pxor_u((3 * 16)(%rdx), RA3, RTMP0);
745         pxor_u((4 * 16)(%rdx), RB0, RTMP0);
746         pxor_u((5 * 16)(%rdx), RB1, RTMP0);
747         pxor_u((6 * 16)(%rdx), RB2, RTMP0);
748         pxor_u((7 * 16)(%rdx), RB3, RTMP0);
749
750         movdqu RA0, (0 * 16)(%rsi);
751         movdqu RA1, (1 * 16)(%rsi);
752         movdqu RA2, (2 * 16)(%rsi);
753         movdqu RA3, (3 * 16)(%rsi);
754         movdqu RB0, (4 * 16)(%rsi);
755         movdqu RB1, (5 * 16)(%rsi);
756         movdqu RB2, (6 * 16)(%rsi);
757         movdqu RB3, (7 * 16)(%rsi);
758
759         /* clear the used registers */
760         pxor RA0, RA0;
761         pxor RA1, RA1;
762         pxor RA2, RA2;
763         pxor RA3, RA3;
764         pxor RB0, RB0;
765         pxor RB1, RB1;
766         pxor RB2, RB2;
767         pxor RB3, RB3;
768         pxor RTMP0, RTMP0;
769         pxor RTMP1, RTMP1;
770         pxor RTMP2, RTMP2;
771         pxor RNOT, RNOT;
772
773         ret
774 .size _gcry_serpent_sse2_ctr_enc,.-_gcry_serpent_sse2_ctr_enc;
775
776 .align 8
777 .global _gcry_serpent_sse2_cbc_dec
778 .type   _gcry_serpent_sse2_cbc_dec,@function;
779 _gcry_serpent_sse2_cbc_dec:
780         /* input:
781          *      %rdi: ctx, CTX
782          *      %rsi: dst (8 blocks)
783          *      %rdx: src (8 blocks)
784          *      %rcx: iv
785          */
786
787         .set RA0, dec_in_a0
788         .set RA1, dec_in_a1
789         .set RA2, dec_in_a2
790         .set RA3, dec_in_a3
791         .set RB0, dec_in_b0
792         .set RB1, dec_in_b1
793         .set RB2, dec_in_b2
794         .set RB3, dec_in_b3
795
796         movdqu (0 * 16)(%rdx), RA0;
797         movdqu (1 * 16)(%rdx), RA1;
798         movdqu (2 * 16)(%rdx), RA2;
799         movdqu (3 * 16)(%rdx), RA3;
800         movdqu (4 * 16)(%rdx), RB0;
801         movdqu (5 * 16)(%rdx), RB1;
802         movdqu (6 * 16)(%rdx), RB2;
803         movdqu (7 * 16)(%rdx), RB3;
804
805         call __serpent_dec_blk8;
806
807         .set RA0, dec_out_a0
808         .set RA1, dec_out_a1
809         .set RA2, dec_out_a2
810         .set RA3, dec_out_a3
811         .set RB0, dec_out_b0
812         .set RB1, dec_out_b1
813         .set RB2, dec_out_b2
814         .set RB3, dec_out_b3
815
816         movdqu (7 * 16)(%rdx), RNOT;
817         pxor_u((%rcx), RA0, RTMP0);
818         pxor_u((0 * 16)(%rdx), RA1, RTMP0);
819         pxor_u((1 * 16)(%rdx), RA2, RTMP0);
820         pxor_u((2 * 16)(%rdx), RA3, RTMP0);
821         pxor_u((3 * 16)(%rdx), RB0, RTMP0);
822         pxor_u((4 * 16)(%rdx), RB1, RTMP0);
823         pxor_u((5 * 16)(%rdx), RB2, RTMP0);
824         pxor_u((6 * 16)(%rdx), RB3, RTMP0);
825         movdqu RNOT, (%rcx); /* store new IV */
826
827         movdqu RA0, (0 * 16)(%rsi);
828         movdqu RA1, (1 * 16)(%rsi);
829         movdqu RA2, (2 * 16)(%rsi);
830         movdqu RA3, (3 * 16)(%rsi);
831         movdqu RB0, (4 * 16)(%rsi);
832         movdqu RB1, (5 * 16)(%rsi);
833         movdqu RB2, (6 * 16)(%rsi);
834         movdqu RB3, (7 * 16)(%rsi);
835
836         /* clear the used registers */
837         pxor RA0, RA0;
838         pxor RA1, RA1;
839         pxor RA2, RA2;
840         pxor RA3, RA3;
841         pxor RB0, RB0;
842         pxor RB1, RB1;
843         pxor RB2, RB2;
844         pxor RB3, RB3;
845         pxor RTMP0, RTMP0;
846         pxor RTMP1, RTMP1;
847         pxor RTMP2, RTMP2;
848         pxor RNOT, RNOT;
849
850         ret
851 .size _gcry_serpent_sse2_cbc_dec,.-_gcry_serpent_sse2_cbc_dec;
852
853 .align 8
854 .global _gcry_serpent_sse2_cfb_dec
855 .type   _gcry_serpent_sse2_cfb_dec,@function;
856 _gcry_serpent_sse2_cfb_dec:
857         /* input:
858          *      %rdi: ctx, CTX
859          *      %rsi: dst (8 blocks)
860          *      %rdx: src (8 blocks)
861          *      %rcx: iv
862          */
863
864         .set RA0, enc_in_a0
865         .set RA1, enc_in_a1
866         .set RA2, enc_in_a2
867         .set RA3, enc_in_a3
868         .set RB0, enc_in_b0
869         .set RB1, enc_in_b1
870         .set RB2, enc_in_b2
871         .set RB3, enc_in_b3
872
873         /* Load input */
874         movdqu (%rcx), RA0;
875         movdqu 0 * 16(%rdx), RA1;
876         movdqu 1 * 16(%rdx), RA2;
877         movdqu 2 * 16(%rdx), RA3;
878         movdqu 3 * 16(%rdx), RB0;
879         movdqu 4 * 16(%rdx), RB1;
880         movdqu 5 * 16(%rdx), RB2;
881         movdqu 6 * 16(%rdx), RB3;
882
883         /* Update IV */
884         movdqu 7 * 16(%rdx), RNOT;
885         movdqu RNOT, (%rcx);
886
887         call __serpent_enc_blk8;
888
889         .set RA0, enc_out_a0
890         .set RA1, enc_out_a1
891         .set RA2, enc_out_a2
892         .set RA3, enc_out_a3
893         .set RB0, enc_out_b0
894         .set RB1, enc_out_b1
895         .set RB2, enc_out_b2
896         .set RB3, enc_out_b3
897
898         pxor_u((0 * 16)(%rdx), RA0, RTMP0);
899         pxor_u((1 * 16)(%rdx), RA1, RTMP0);
900         pxor_u((2 * 16)(%rdx), RA2, RTMP0);
901         pxor_u((3 * 16)(%rdx), RA3, RTMP0);
902         pxor_u((4 * 16)(%rdx), RB0, RTMP0);
903         pxor_u((5 * 16)(%rdx), RB1, RTMP0);
904         pxor_u((6 * 16)(%rdx), RB2, RTMP0);
905         pxor_u((7 * 16)(%rdx), RB3, RTMP0);
906
907         movdqu RA0, (0 * 16)(%rsi);
908         movdqu RA1, (1 * 16)(%rsi);
909         movdqu RA2, (2 * 16)(%rsi);
910         movdqu RA3, (3 * 16)(%rsi);
911         movdqu RB0, (4 * 16)(%rsi);
912         movdqu RB1, (5 * 16)(%rsi);
913         movdqu RB2, (6 * 16)(%rsi);
914         movdqu RB3, (7 * 16)(%rsi);
915
916         /* clear the used registers */
917         pxor RA0, RA0;
918         pxor RA1, RA1;
919         pxor RA2, RA2;
920         pxor RA3, RA3;
921         pxor RB0, RB0;
922         pxor RB1, RB1;
923         pxor RB2, RB2;
924         pxor RB3, RB3;
925         pxor RTMP0, RTMP0;
926         pxor RTMP1, RTMP1;
927         pxor RTMP2, RTMP2;
928         pxor RNOT, RNOT;
929
930         ret
931 .size _gcry_serpent_sse2_cfb_dec,.-_gcry_serpent_sse2_cfb_dec;
932
933 #endif /*defined(USE_SERPENT)*/
934 #endif /*__x86_64*/