aarch64: Enable building the aarch64 cipher assembly for windows
[libgcrypt.git] / cipher / chacha20-aarch64.S
1 /* chacha20-aarch64.S - ARMv8/AArch64 accelerated chacha20 blocks function
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 #include "asm-common-aarch64.h"
31
32 #if defined(__AARCH64EL__) && \
33     defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \
34     defined(HAVE_GCC_INLINE_ASM_AARCH64_NEON) && \
35     defined(USE_CHACHA20)
36
37 .cpu generic+simd
38
39 .text
40
41 #ifdef _WIN32
42 #define GET_DATA_POINTER(reg, name) \
43         adrp    reg, name ; \
44         add     reg, reg, #:lo12:name ;
45 #else
46 #define GET_DATA_POINTER(reg, name) \
47         adrp    reg, :got:name ; \
48         ldr     reg, [reg, #:got_lo12:name] ;
49 #endif
50
51 /* register macros */
52 #define INPUT     x0
53 #define DST       x1
54 #define SRC       x2
55 #define NBLKS     x3
56 #define ROUND     x4
57 #define INPUT_CTR x5
58 #define INPUT_POS x6
59 #define CTR       x7
60
61 /* vector registers */
62 #define X0 v16
63 #define X1 v17
64 #define X2 v18
65 #define X3 v19
66 #define X4 v20
67 #define X5 v21
68 #define X6 v22
69 #define X7 v23
70 #define X8 v24
71 #define X9 v25
72 #define X10 v26
73 #define X11 v27
74 #define X12 v28
75 #define X13 v29
76 #define X14 v30
77 #define X15 v31
78
79 #define VCTR    v0
80 #define VTMP0   v1
81 #define VTMP1   v2
82 #define VTMP2   v3
83 #define VTMP3   v4
84 #define X12_TMP v5
85 #define X13_TMP v6
86
87 /**********************************************************************
88   helper macros
89  **********************************************************************/
90
91 #define vpunpckldq(s1, s2, dst) \
92         zip1 dst.4s, s2.4s, s1.4s;
93
94 #define vpunpckhdq(s1, s2, dst) \
95         zip2 dst.4s, s2.4s, s1.4s;
96
97 #define vpunpcklqdq(s1, s2, dst) \
98         zip1 dst.2d, s2.2d, s1.2d;
99
100 #define vpunpckhqdq(s1, s2, dst) \
101         zip2 dst.2d, s2.2d, s1.2d;
102
103 /* 4x4 32-bit integer matrix transpose */
104 #define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \
105         vpunpckhdq(x1, x0, t2); \
106         vpunpckldq(x1, x0, x0); \
107         \
108         vpunpckldq(x3, x2, t1); \
109         vpunpckhdq(x3, x2, x2); \
110         \
111         vpunpckhqdq(t1, x0, x1); \
112         vpunpcklqdq(t1, x0, x0); \
113         \
114         vpunpckhqdq(x2, t2, x3); \
115         vpunpcklqdq(x2, t2, x2);
116
117 #define clear(x) \
118         eor x.16b, x.16b, x.16b;
119
120 /**********************************************************************
121   4-way chacha20
122  **********************************************************************/
123
124 #define ROTATE2(dst1,dst2,c,src1,src2)          \
125         shl dst1.4s, src1.4s, #(c);             \
126         shl dst2.4s, src2.4s, #(c);             \
127         sri dst1.4s, src1.4s, #(32 - (c));      \
128         sri dst2.4s, src2.4s, #(32 - (c));
129
130 #define ROTATE2_16(dst1,dst2,src1,src2)         \
131         rev32 dst1.8h, src1.8h;                 \
132         rev32 dst2.8h, src2.8h;
133
134 #define XOR(d,s1,s2) \
135         eor d.16b, s2.16b, s1.16b;
136
137 #define PLUS(ds,s) \
138         add ds.4s, ds.4s, s.4s;
139
140 #define QUARTERROUND2(a1,b1,c1,d1,a2,b2,c2,d2,ign,tmp1,tmp2)            \
141         PLUS(a1,b1); PLUS(a2,b2); XOR(tmp1,d1,a1); XOR(tmp2,d2,a2);     \
142             ROTATE2_16(d1, d2, tmp1, tmp2);                             \
143         PLUS(c1,d1); PLUS(c2,d2); XOR(tmp1,b1,c1); XOR(tmp2,b2,c2);     \
144             ROTATE2(b1, b2, 12, tmp1, tmp2);                            \
145         PLUS(a1,b1); PLUS(a2,b2); XOR(tmp1,d1,a1); XOR(tmp2,d2,a2);     \
146             ROTATE2(d1, d2,  8, tmp1, tmp2);                            \
147         PLUS(c1,d1); PLUS(c2,d2); XOR(tmp1,b1,c1); XOR(tmp2,b2,c2);     \
148             ROTATE2(b1, b2,  7, tmp1, tmp2);
149
150 chacha20_data:
151 .align 4
152 .Linc_counter:
153         .long 0,1,2,3
154
155 .align 3
156 .globl _gcry_chacha20_aarch64_blocks4
157 ELF(.type _gcry_chacha20_aarch64_blocks4,%function;)
158
159 _gcry_chacha20_aarch64_blocks4:
160         /* input:
161          *      x0: input
162          *      x1: dst
163          *      x2: src
164          *      x3: nblks (multiple of 4)
165          */
166
167         GET_DATA_POINTER(CTR, .Linc_counter);
168         add INPUT_CTR, INPUT, #(12*4);
169         mov INPUT_POS, INPUT;
170         ld1 {VCTR.16b}, [CTR];
171
172 .Loop4:
173         /* Construct counter vectors X12 and X13 */
174
175         ld1 {X15.16b}, [INPUT_CTR];
176         mov ROUND, #20;
177         ld1 {VTMP1.16b-VTMP3.16b}, [INPUT_POS];
178
179         dup X12.4s, X15.s[0];
180         dup X13.4s, X15.s[1];
181         ldr CTR, [INPUT_CTR];
182         add X12.4s, X12.4s, VCTR.4s;
183         dup X0.4s, VTMP1.s[0];
184         dup X1.4s, VTMP1.s[1];
185         dup X2.4s, VTMP1.s[2];
186         dup X3.4s, VTMP1.s[3];
187         dup X14.4s, X15.s[2];
188         cmhi VTMP0.4s, VCTR.4s, X12.4s;
189         dup X15.4s, X15.s[3];
190         add CTR, CTR, #4; /* Update counter */
191         dup X4.4s, VTMP2.s[0];
192         dup X5.4s, VTMP2.s[1];
193         dup X6.4s, VTMP2.s[2];
194         dup X7.4s, VTMP2.s[3];
195         sub X13.4s, X13.4s, VTMP0.4s;
196         dup X8.4s, VTMP3.s[0];
197         dup X9.4s, VTMP3.s[1];
198         dup X10.4s, VTMP3.s[2];
199         dup X11.4s, VTMP3.s[3];
200         mov X12_TMP.16b, X12.16b;
201         mov X13_TMP.16b, X13.16b;
202         str CTR, [INPUT_CTR];
203
204 .Lround2:
205         subs ROUND, ROUND, #2
206         QUARTERROUND2(X0, X4,  X8, X12,   X1, X5,  X9, X13, tmp:=,VTMP0,VTMP1)
207         QUARTERROUND2(X2, X6, X10, X14,   X3, X7, X11, X15, tmp:=,VTMP0,VTMP1)
208         QUARTERROUND2(X0, X5, X10, X15,   X1, X6, X11, X12, tmp:=,VTMP0,VTMP1)
209         QUARTERROUND2(X2, X7,  X8, X13,   X3, X4,  X9, X14, tmp:=,VTMP0,VTMP1)
210         b.ne .Lround2;
211
212         ld1 {VTMP0.16b, VTMP1.16b}, [INPUT_POS], #32;
213
214         PLUS(X12, X12_TMP);        /* INPUT + 12 * 4 + counter */
215         PLUS(X13, X13_TMP);        /* INPUT + 13 * 4 + counter */
216
217         dup VTMP2.4s, VTMP0.s[0]; /* INPUT + 0 * 4 */
218         dup VTMP3.4s, VTMP0.s[1]; /* INPUT + 1 * 4 */
219         dup X12_TMP.4s, VTMP0.s[2]; /* INPUT + 2 * 4 */
220         dup X13_TMP.4s, VTMP0.s[3]; /* INPUT + 3 * 4 */
221         PLUS(X0, VTMP2);
222         PLUS(X1, VTMP3);
223         PLUS(X2, X12_TMP);
224         PLUS(X3, X13_TMP);
225
226         dup VTMP2.4s, VTMP1.s[0]; /* INPUT + 4 * 4 */
227         dup VTMP3.4s, VTMP1.s[1]; /* INPUT + 5 * 4 */
228         dup X12_TMP.4s, VTMP1.s[2]; /* INPUT + 6 * 4 */
229         dup X13_TMP.4s, VTMP1.s[3]; /* INPUT + 7 * 4 */
230         ld1 {VTMP0.16b, VTMP1.16b}, [INPUT_POS];
231         mov INPUT_POS, INPUT;
232         PLUS(X4, VTMP2);
233         PLUS(X5, VTMP3);
234         PLUS(X6, X12_TMP);
235         PLUS(X7, X13_TMP);
236
237         dup VTMP2.4s, VTMP0.s[0]; /* INPUT + 8 * 4 */
238         dup VTMP3.4s, VTMP0.s[1]; /* INPUT + 9 * 4 */
239         dup X12_TMP.4s, VTMP0.s[2]; /* INPUT + 10 * 4 */
240         dup X13_TMP.4s, VTMP0.s[3]; /* INPUT + 11 * 4 */
241         dup VTMP0.4s, VTMP1.s[2]; /* INPUT + 14 * 4 */
242         dup VTMP1.4s, VTMP1.s[3]; /* INPUT + 15 * 4 */
243         PLUS(X8, VTMP2);
244         PLUS(X9, VTMP3);
245         PLUS(X10, X12_TMP);
246         PLUS(X11, X13_TMP);
247         PLUS(X14, VTMP0);
248         PLUS(X15, VTMP1);
249
250         transpose_4x4(X0, X1, X2, X3, VTMP0, VTMP1, VTMP2);
251         transpose_4x4(X4, X5, X6, X7, VTMP0, VTMP1, VTMP2);
252         transpose_4x4(X8, X9, X10, X11, VTMP0, VTMP1, VTMP2);
253         transpose_4x4(X12, X13, X14, X15, VTMP0, VTMP1, VTMP2);
254
255         subs NBLKS, NBLKS, #4;
256
257         ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64;
258         ld1 {X12_TMP.16b-X13_TMP.16b}, [SRC], #32;
259         eor VTMP0.16b, X0.16b, VTMP0.16b;
260         eor VTMP1.16b, X4.16b, VTMP1.16b;
261         eor VTMP2.16b, X8.16b, VTMP2.16b;
262         eor VTMP3.16b, X12.16b, VTMP3.16b;
263         eor X12_TMP.16b, X1.16b, X12_TMP.16b;
264         eor X13_TMP.16b, X5.16b, X13_TMP.16b;
265         st1 {VTMP0.16b-VTMP3.16b}, [DST], #64;
266         ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64;
267         st1 {X12_TMP.16b-X13_TMP.16b}, [DST], #32;
268         ld1 {X12_TMP.16b-X13_TMP.16b}, [SRC], #32;
269         eor VTMP0.16b, X9.16b, VTMP0.16b;
270         eor VTMP1.16b, X13.16b, VTMP1.16b;
271         eor VTMP2.16b, X2.16b, VTMP2.16b;
272         eor VTMP3.16b, X6.16b, VTMP3.16b;
273         eor X12_TMP.16b, X10.16b, X12_TMP.16b;
274         eor X13_TMP.16b, X14.16b, X13_TMP.16b;
275         st1 {VTMP0.16b-VTMP3.16b}, [DST], #64;
276         ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64;
277         st1 {X12_TMP.16b-X13_TMP.16b}, [DST], #32;
278         eor VTMP0.16b, X3.16b, VTMP0.16b;
279         eor VTMP1.16b, X7.16b, VTMP1.16b;
280         eor VTMP2.16b, X11.16b, VTMP2.16b;
281         eor VTMP3.16b, X15.16b, VTMP3.16b;
282         st1 {VTMP0.16b-VTMP3.16b}, [DST], #64;
283
284         b.ne .Loop4;
285
286         /* clear the used vector registers and stack */
287         clear(VTMP0);
288         clear(VTMP1);
289         clear(VTMP2);
290         clear(VTMP3);
291         clear(X12_TMP);
292         clear(X13_TMP);
293         clear(X0);
294         clear(X1);
295         clear(X2);
296         clear(X3);
297         clear(X4);
298         clear(X5);
299         clear(X6);
300         clear(X7);
301         clear(X8);
302         clear(X9);
303         clear(X10);
304         clear(X11);
305         clear(X12);
306         clear(X13);
307         clear(X14);
308         clear(X15);
309
310         eor x0, x0, x0
311         ret
312 ELF(.size _gcry_chacha20_aarch64_blocks4, .-_gcry_chacha20_aarch64_blocks4;)
313
314 #endif