Add ARMv8/CE acceleration for AES-XTS
[libgcrypt.git] / cipher / chacha20-amd64-ssse3.S
1 /* chacha20-amd64-ssse3.S  -  SSSE3 implementation of ChaCha20 cipher
2  *
3  * Copyright (C) 2017,2018 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 /*
22  * Based on D. J. Bernstein reference implementation at
23  * http://cr.yp.to/chacha.html:
24  *
25  * chacha-regs.c version 20080118
26  * D. J. Bernstein
27  * Public domain.
28  */
29
30 #ifdef __x86_64
31 #include <config.h>
32 #if defined(HAVE_GCC_INLINE_ASM_SSSE3) && \
33    (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
34     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
35
36 .text
37
38 #ifdef HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS
39 # define ELF(...) __VA_ARGS__
40 #else
41 # define ELF(...) /*_*/
42 #endif
43
44 #ifdef __PIC__
45 #  define RIP (%rip)
46 #else
47 #  define RIP
48 #endif
49
50 /* register macros */
51 #define INPUT %rdi
52 #define DST   %rsi
53 #define SRC   %rdx
54 #define NBLKS %rcx
55 #define ROUND %eax
56
57 /* stack structure */
58 #define STACK_VEC_X12 (16)
59 #define STACK_VEC_X13 (16 + STACK_VEC_X12)
60 #define STACK_TMP     (16 + STACK_VEC_X13)
61 #define STACK_TMP1    (16 + STACK_TMP)
62 #define STACK_TMP2    (16 + STACK_TMP1)
63
64 #define STACK_MAX     (16 + STACK_TMP2)
65
66 /* vector registers */
67 #define X0 %xmm0
68 #define X1 %xmm1
69 #define X2 %xmm2
70 #define X3 %xmm3
71 #define X4 %xmm4
72 #define X5 %xmm5
73 #define X6 %xmm6
74 #define X7 %xmm7
75 #define X8 %xmm8
76 #define X9 %xmm9
77 #define X10 %xmm10
78 #define X11 %xmm11
79 #define X12 %xmm12
80 #define X13 %xmm13
81 #define X14 %xmm14
82 #define X15 %xmm15
83
84 /**********************************************************************
85   helper macros
86  **********************************************************************/
87
88 /* 4x4 32-bit integer matrix transpose */
89 #define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \
90         movdqa    x0, t2; \
91         punpckhdq x1, t2; \
92         punpckldq x1, x0; \
93         \
94         movdqa    x2, t1; \
95         punpckldq x3, t1; \
96         punpckhdq x3, x2; \
97         \
98         movdqa     x0, x1; \
99         punpckhqdq t1, x1; \
100         punpcklqdq t1, x0; \
101         \
102         movdqa     t2, x3; \
103         punpckhqdq x2, x3; \
104         punpcklqdq x2, t2; \
105         movdqa     t2, x2;
106
107 /* fill xmm register with 32-bit value from memory */
108 #define pbroadcastd(mem32, xreg) \
109         movd mem32, xreg; \
110         pshufd $0, xreg, xreg;
111
112 /* xor with unaligned memory operand */
113 #define pxor_u(umem128, xreg, t) \
114         movdqu umem128, t; \
115         pxor t, xreg;
116
117 /* xor register with unaligned src and save to unaligned dst */
118 #define xor_src_dst(dst, src, offset, xreg, t) \
119         pxor_u(offset(src), xreg, t); \
120         movdqu xreg, offset(dst);
121
122 #define clear(x) pxor x,x;
123
124 /**********************************************************************
125   4-way chacha20
126  **********************************************************************/
127
128 #define ROTATE2(v1,v2,c,tmp1,tmp2)      \
129         movdqa v1, tmp1;                \
130         movdqa v2, tmp2;                \
131         psrld $(32 - (c)), v1;          \
132         pslld $(c), tmp1;               \
133         paddb tmp1, v1;                 \
134         psrld $(32 - (c)), v2;          \
135         pslld $(c), tmp2;               \
136         paddb tmp2, v2;
137
138 #define ROTATE_SHUF_2(v1,v2,shuf)       \
139         pshufb shuf, v1;                \
140         pshufb shuf, v2;
141
142 #define XOR(ds,s) \
143         pxor s, ds;
144
145 #define PLUS(ds,s) \
146         paddd s, ds;
147
148 #define QUARTERROUND2(a1,b1,c1,d1,a2,b2,c2,d2,ign,tmp1,tmp2)    \
149         movdqa .Lshuf_rol16 RIP, tmp1;                          \
150         PLUS(a1,b1); PLUS(a2,b2); XOR(d1,a1); XOR(d2,a2);       \
151             ROTATE_SHUF_2(d1, d2, tmp1);                        \
152         PLUS(c1,d1); PLUS(c2,d2); XOR(b1,c1); XOR(b2,c2);       \
153             ROTATE2(b1, b2, 12, tmp1, tmp2);                    \
154         movdqa .Lshuf_rol8 RIP, tmp1;                           \
155         PLUS(a1,b1); PLUS(a2,b2); XOR(d1,a1); XOR(d2,a2);       \
156             ROTATE_SHUF_2(d1, d2, tmp1);                        \
157         PLUS(c1,d1); PLUS(c2,d2); XOR(b1,c1); XOR(b2,c2);       \
158             ROTATE2(b1, b2,  7, tmp1, tmp2);
159
160 chacha20_data:
161 .align 16
162 .Lshuf_rol16:
163         .byte 2,3,0,1,6,7,4,5,10,11,8,9,14,15,12,13
164 .Lshuf_rol8:
165         .byte 3,0,1,2,7,4,5,6,11,8,9,10,15,12,13,14
166 .Linc_counter:
167         .long 0,1,2,3
168 .Lunsigned_cmp:
169         .long 0x80000000,0x80000000,0x80000000,0x80000000
170
171 .align 8
172 .globl _gcry_chacha20_amd64_ssse3_blocks4
173 ELF(.type _gcry_chacha20_amd64_ssse3_blocks4,@function;)
174
175 _gcry_chacha20_amd64_ssse3_blocks4:
176         /* input:
177          *      %rdi: input
178          *      %rsi: dst
179          *      %rdx: src
180          *      %rcx: nblks (multiple of 4)
181          */
182
183         pushq %rbp;
184         movq %rsp, %rbp;
185
186         subq $STACK_MAX, %rsp;
187         andq $~15, %rsp;
188
189 .Loop4:
190         mov $20, ROUND;
191
192         /* Construct counter vectors X12 and X13 */
193         vmovdqa .Linc_counter RIP, X0;
194         vmovdqa .Lunsigned_cmp RIP, X2;
195         pbroadcastd((12 * 4)(INPUT), X12);
196         pbroadcastd((13 * 4)(INPUT), X13);
197         paddd X0, X12;
198         movdqa X12, X1;
199         pxor X2, X0;
200         pxor X2, X1;
201         pcmpgtd X1, X0;
202         psubd X0, X13;
203         movdqa X12, (STACK_VEC_X12)(%rsp);
204         movdqa X13, (STACK_VEC_X13)(%rsp);
205
206         /* Load vectors */
207         pbroadcastd((0 * 4)(INPUT), X0);
208         pbroadcastd((1 * 4)(INPUT), X1);
209         pbroadcastd((2 * 4)(INPUT), X2);
210         pbroadcastd((3 * 4)(INPUT), X3);
211         pbroadcastd((4 * 4)(INPUT), X4);
212         pbroadcastd((5 * 4)(INPUT), X5);
213         pbroadcastd((6 * 4)(INPUT), X6);
214         pbroadcastd((7 * 4)(INPUT), X7);
215         pbroadcastd((8 * 4)(INPUT), X8);
216         pbroadcastd((9 * 4)(INPUT), X9);
217         pbroadcastd((10 * 4)(INPUT), X10);
218         pbroadcastd((11 * 4)(INPUT), X11);
219         pbroadcastd((14 * 4)(INPUT), X14);
220         pbroadcastd((15 * 4)(INPUT), X15);
221         movdqa X11, (STACK_TMP)(%rsp);
222         movdqa X15, (STACK_TMP1)(%rsp);
223
224 .Lround2:
225         QUARTERROUND2(X0, X4,  X8, X12,   X1, X5,  X9, X13, tmp:=,X11,X15)
226         movdqa (STACK_TMP)(%rsp), X11;
227         movdqa (STACK_TMP1)(%rsp), X15;
228         movdqa X8, (STACK_TMP)(%rsp);
229         movdqa X9, (STACK_TMP1)(%rsp);
230         QUARTERROUND2(X2, X6, X10, X14,   X3, X7, X11, X15, tmp:=,X8,X9)
231         QUARTERROUND2(X0, X5, X10, X15,   X1, X6, X11, X12, tmp:=,X8,X9)
232         movdqa (STACK_TMP)(%rsp), X8;
233         movdqa (STACK_TMP1)(%rsp), X9;
234         movdqa X11, (STACK_TMP)(%rsp);
235         movdqa X15, (STACK_TMP1)(%rsp);
236         QUARTERROUND2(X2, X7,  X8, X13,   X3, X4,  X9, X14, tmp:=,X11,X15)
237         sub $2, ROUND;
238         jnz .Lround2;
239
240         /* tmp := X15 */
241         movdqa (STACK_TMP)(%rsp), X11;
242         pbroadcastd((0 * 4)(INPUT), X15);
243         PLUS(X0, X15);
244         pbroadcastd((1 * 4)(INPUT), X15);
245         PLUS(X1, X15);
246         pbroadcastd((2 * 4)(INPUT), X15);
247         PLUS(X2, X15);
248         pbroadcastd((3 * 4)(INPUT), X15);
249         PLUS(X3, X15);
250         pbroadcastd((4 * 4)(INPUT), X15);
251         PLUS(X4, X15);
252         pbroadcastd((5 * 4)(INPUT), X15);
253         PLUS(X5, X15);
254         pbroadcastd((6 * 4)(INPUT), X15);
255         PLUS(X6, X15);
256         pbroadcastd((7 * 4)(INPUT), X15);
257         PLUS(X7, X15);
258         pbroadcastd((8 * 4)(INPUT), X15);
259         PLUS(X8, X15);
260         pbroadcastd((9 * 4)(INPUT), X15);
261         PLUS(X9, X15);
262         pbroadcastd((10 * 4)(INPUT), X15);
263         PLUS(X10, X15);
264         pbroadcastd((11 * 4)(INPUT), X15);
265         PLUS(X11, X15);
266         movdqa (STACK_VEC_X12)(%rsp), X15;
267         PLUS(X12, X15);
268         movdqa (STACK_VEC_X13)(%rsp), X15;
269         PLUS(X13, X15);
270         movdqa X13, (STACK_TMP)(%rsp);
271         pbroadcastd((14 * 4)(INPUT), X15);
272         PLUS(X14, X15);
273         movdqa (STACK_TMP1)(%rsp), X15;
274         movdqa X14, (STACK_TMP1)(%rsp);
275         pbroadcastd((15 * 4)(INPUT), X13);
276         PLUS(X15, X13);
277         movdqa X15, (STACK_TMP2)(%rsp);
278
279         /* Update counter */
280         addq $4, (12 * 4)(INPUT);
281
282         transpose_4x4(X0, X1, X2, X3, X13, X14, X15);
283         xor_src_dst(DST, SRC, (64 * 0 + 16 * 0), X0, X15);
284         xor_src_dst(DST, SRC, (64 * 1 + 16 * 0), X1, X15);
285         xor_src_dst(DST, SRC, (64 * 2 + 16 * 0), X2, X15);
286         xor_src_dst(DST, SRC, (64 * 3 + 16 * 0), X3, X15);
287         transpose_4x4(X4, X5, X6, X7, X0, X1, X2);
288         movdqa (STACK_TMP)(%rsp), X13;
289         movdqa (STACK_TMP1)(%rsp), X14;
290         movdqa (STACK_TMP2)(%rsp), X15;
291         xor_src_dst(DST, SRC, (64 * 0 + 16 * 1), X4, X0);
292         xor_src_dst(DST, SRC, (64 * 1 + 16 * 1), X5, X0);
293         xor_src_dst(DST, SRC, (64 * 2 + 16 * 1), X6, X0);
294         xor_src_dst(DST, SRC, (64 * 3 + 16 * 1), X7, X0);
295         transpose_4x4(X8, X9, X10, X11, X0, X1, X2);
296         xor_src_dst(DST, SRC, (64 * 0 + 16 * 2), X8, X0);
297         xor_src_dst(DST, SRC, (64 * 1 + 16 * 2), X9, X0);
298         xor_src_dst(DST, SRC, (64 * 2 + 16 * 2), X10, X0);
299         xor_src_dst(DST, SRC, (64 * 3 + 16 * 2), X11, X0);
300         transpose_4x4(X12, X13, X14, X15, X0, X1, X2);
301         xor_src_dst(DST, SRC, (64 * 0 + 16 * 3), X12, X0);
302         xor_src_dst(DST, SRC, (64 * 1 + 16 * 3), X13, X0);
303         xor_src_dst(DST, SRC, (64 * 2 + 16 * 3), X14, X0);
304         xor_src_dst(DST, SRC, (64 * 3 + 16 * 3), X15, X0);
305
306         sub $4, NBLKS;
307         lea (4 * 64)(DST), DST;
308         lea (4 * 64)(SRC), SRC;
309         jnz .Loop4;
310
311         /* clear the used vector registers and stack */
312         clear(X0);
313         movdqa X0, (STACK_VEC_X12)(%rsp);
314         movdqa X0, (STACK_VEC_X13)(%rsp);
315         movdqa X0, (STACK_TMP)(%rsp);
316         movdqa X0, (STACK_TMP1)(%rsp);
317         movdqa X0, (STACK_TMP2)(%rsp);
318         clear(X1);
319         clear(X2);
320         clear(X3);
321         clear(X4);
322         clear(X5);
323         clear(X6);
324         clear(X7);
325         clear(X8);
326         clear(X9);
327         clear(X10);
328         clear(X11);
329         clear(X12);
330         clear(X13);
331         clear(X14);
332         clear(X15);
333
334         /* eax zeroed by round loop. */
335         leave;
336         ret;
337 ELF(.size _gcry_chacha20_amd64_ssse3_blocks4,
338           .-_gcry_chacha20_amd64_ssse3_blocks4;)
339
340 #endif /*defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)*/
341 #endif /*__x86_64*/