46af77eac340b1f564bbfc2336ee4058258c306f
[libgcrypt.git] / cipher / cipher-gcm-intel-pclmul.c
1 /* cipher-gcm-intel-pclmul.c  -  Intel PCLMUL accelerated Galois Counter Mode
2  *                               implementation
3  * Copyright (C) 2013-2014,2019 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 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include "g10lib.h"
28 #include "cipher.h"
29 #include "bufhelp.h"
30 #include "./cipher-internal.h"
31
32
33 #ifdef GCM_USE_INTEL_PCLMUL
34
35
36 #if _GCRY_GCC_VERSION >= 40400 /* 4.4 */
37 /* Prevent compiler from issuing SSE instructions between asm blocks. */
38 #  pragma GCC target("no-sse")
39 #endif
40 #if __clang__
41 #  pragma clang attribute push (__attribute__((target("no-sse"))), apply_to = function)
42 #endif
43
44
45 /*
46  Intel PCLMUL ghash based on white paper:
47   "Intel® Carry-Less Multiplication Instruction and its Usage for Computing the
48    GCM Mode - Rev 2.01"; Shay Gueron, Michael E. Kounavis.
49  */
50 static inline void reduction(void)
51 {
52   /* input: <xmm1:xmm3> */
53
54   asm volatile (/* first phase of the reduction */
55                 "movdqa %%xmm3, %%xmm6\n\t"
56                 "movdqa %%xmm3, %%xmm7\n\t"
57                 "psllq $1, %%xmm6\n\t"  /* packed right shifting << 63 */
58                 "pxor %%xmm3, %%xmm6\n\t"
59                 "psllq $57, %%xmm7\n\t"  /* packed right shifting << 57 */
60                 "psllq $62, %%xmm6\n\t"  /* packed right shifting << 62 */
61                 "pxor %%xmm7, %%xmm6\n\t" /* xor the shifted versions */
62                 "pshufd $0x6a, %%xmm6, %%xmm7\n\t"
63                 "pshufd $0xae, %%xmm6, %%xmm6\n\t"
64                 "pxor %%xmm7, %%xmm3\n\t" /* first phase of the reduction
65                                              complete */
66
67                 /* second phase of the reduction */
68                 "pxor %%xmm3, %%xmm1\n\t" /* xor the shifted versions */
69                 "psrlq $1, %%xmm3\n\t"    /* packed left shifting >> 1 */
70                 "pxor %%xmm3, %%xmm6\n\t"
71                 "psrlq $1, %%xmm3\n\t"    /* packed left shifting >> 2 */
72                 "pxor %%xmm3, %%xmm1\n\t"
73                 "psrlq $5, %%xmm3\n\t"    /* packed left shifting >> 7 */
74                 "pxor %%xmm3, %%xmm6\n\t"
75                 "pxor %%xmm6, %%xmm1\n\t" /* the result is in xmm1 */
76                 ::: "memory" );
77 }
78
79 static inline void gfmul_pclmul(void)
80 {
81   /* Input: XMM0 and XMM1, Output: XMM1. Input XMM0 stays unmodified.
82      Input must be converted to little-endian.
83    */
84   asm volatile (/* gfmul, xmm0 has operator a and xmm1 has operator b. */
85                 "pshufd $78, %%xmm0, %%xmm2\n\t"
86                 "pshufd $78, %%xmm1, %%xmm4\n\t"
87                 "pxor %%xmm0, %%xmm2\n\t" /* xmm2 holds a0+a1 */
88                 "pxor %%xmm1, %%xmm4\n\t" /* xmm4 holds b0+b1 */
89
90                 "movdqa %%xmm0, %%xmm3\n\t"
91                 "pclmulqdq $0, %%xmm1, %%xmm3\n\t"  /* xmm3 holds a0*b0 */
92                 "pclmulqdq $17, %%xmm0, %%xmm1\n\t" /* xmm6 holds a1*b1 */
93                 "movdqa %%xmm3, %%xmm5\n\t"
94                 "pclmulqdq $0, %%xmm2, %%xmm4\n\t"  /* xmm4 holds (a0+a1)*(b0+b1) */
95
96                 "pxor %%xmm1, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */
97                 "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */
98                 "movdqa %%xmm4, %%xmm5\n\t"
99                 "psrldq $8, %%xmm4\n\t"
100                 "pslldq $8, %%xmm5\n\t"
101                 "pxor %%xmm5, %%xmm3\n\t"
102                 "pxor %%xmm4, %%xmm1\n\t" /* <xmm1:xmm3> holds the result of the
103                                              carry-less multiplication of xmm0
104                                              by xmm1 */
105                 ::: "memory" );
106
107   reduction();
108 }
109
110 #ifdef __x86_64__
111 static inline void gfmul_pclmul_aggr4(const void *buf, const void *h_table)
112 {
113   /* Input:
114       H¹: XMM0
115       bemask: XMM15
116       Hash: XMM1
117      Output:
118       Hash: XMM1
119      Inputs XMM0 and XMM14 stays unmodified.
120    */
121   asm volatile (/* Load H2, H3, H4. */
122                 "movdqu 2*16(%[h_table]), %%xmm10\n\t"
123                 "movdqu 1*16(%[h_table]), %%xmm9\n\t"
124                 "movdqu 0*16(%[h_table]), %%xmm8\n\t"
125
126                 /* perform clmul and merge results... */
127                 "movdqu 0*16(%[buf]), %%xmm5\n\t"
128                 "movdqu 1*16(%[buf]), %%xmm2\n\t"
129                 "pshufb %%xmm15, %%xmm5\n\t" /* be => le */
130                 "pshufb %%xmm15, %%xmm2\n\t" /* be => le */
131                 "pxor %%xmm5, %%xmm1\n\t"
132
133                 "pshufd $78, %%xmm10, %%xmm5\n\t"
134                 "pshufd $78, %%xmm1, %%xmm4\n\t"
135                 "pxor %%xmm10, %%xmm5\n\t" /* xmm5 holds 4:a0+a1 */
136                 "pxor %%xmm1, %%xmm4\n\t"  /* xmm4 holds 4:b0+b1 */
137                 "movdqa %%xmm10, %%xmm3\n\t"
138                 "pclmulqdq $0, %%xmm1, %%xmm3\n\t"   /* xmm3 holds 4:a0*b0 */
139                 "pclmulqdq $17, %%xmm10, %%xmm1\n\t" /* xmm1 holds 4:a1*b1 */
140                 "pclmulqdq $0, %%xmm5, %%xmm4\n\t"   /* xmm4 holds 4:(a0+a1)*(b0+b1) */
141
142                 "pshufd $78, %%xmm9, %%xmm11\n\t"
143                 "pshufd $78, %%xmm2, %%xmm7\n\t"
144                 "pxor %%xmm9, %%xmm11\n\t" /* xmm11 holds 3:a0+a1 */
145                 "pxor %%xmm2, %%xmm7\n\t"  /* xmm7 holds 3:b0+b1 */
146                 "movdqa %%xmm9, %%xmm6\n\t"
147                 "pclmulqdq $0, %%xmm2, %%xmm6\n\t"  /* xmm6 holds 3:a0*b0 */
148                 "pclmulqdq $17, %%xmm9, %%xmm2\n\t" /* xmm2 holds 3:a1*b1 */
149                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 3:(a0+a1)*(b0+b1) */
150
151                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 3+4:a0*b0 */
152                 "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 3+4:a1*b1 */
153                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 3+4:(a0+a1)*(b0+b1) */
154
155                 "movdqu 2*16(%[buf]), %%xmm5\n\t"
156                 "movdqu 3*16(%[buf]), %%xmm2\n\t"
157                 "pshufb %%xmm15, %%xmm5\n\t" /* be => le */
158                 "pshufb %%xmm15, %%xmm2\n\t" /* be => le */
159
160                 "pshufd $78, %%xmm8, %%xmm11\n\t"
161                 "pshufd $78, %%xmm5, %%xmm7\n\t"
162                 "pxor %%xmm8, %%xmm11\n\t" /* xmm11 holds 2:a0+a1 */
163                 "pxor %%xmm5, %%xmm7\n\t"  /* xmm7 holds 2:b0+b1 */
164                 "movdqa %%xmm8, %%xmm6\n\t"
165                 "pclmulqdq $0, %%xmm5, %%xmm6\n\t"  /* xmm6 holds 2:a0*b0 */
166                 "pclmulqdq $17, %%xmm8, %%xmm5\n\t" /* xmm5 holds 2:a1*b1 */
167                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 2:(a0+a1)*(b0+b1) */
168
169                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 2+3+4:a0*b0 */
170                 "pxor %%xmm5, %%xmm1\n\t" /* xmm1 holds 2+3+4:a1*b1 */
171                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 2+3+4:(a0+a1)*(b0+b1) */
172
173                 "pshufd $78, %%xmm0, %%xmm11\n\t"
174                 "pshufd $78, %%xmm2, %%xmm7\n\t"
175                 "pxor %%xmm0, %%xmm11\n\t" /* xmm11 holds 1:a0+a1 */
176                 "pxor %%xmm2, %%xmm7\n\t"  /* xmm7 holds 1:b0+b1 */
177                 "movdqa %%xmm0, %%xmm6\n\t"
178                 "pclmulqdq $0, %%xmm2, %%xmm6\n\t"  /* xmm6 holds 1:a0*b0 */
179                 "pclmulqdq $17, %%xmm0, %%xmm2\n\t" /* xmm2 holds 1:a1*b1 */
180                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 1:(a0+a1)*(b0+b1) */
181
182                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 1+2+3+4:a0*b0 */
183                 "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 1+2+3+4:a1*b1 */
184                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 1+2+3+4:(a0+a1)*(b0+b1) */
185
186                 /* aggregated reduction... */
187                 "movdqa %%xmm3, %%xmm5\n\t"
188                 "pxor %%xmm1, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */
189                 "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */
190                 "movdqa %%xmm4, %%xmm5\n\t"
191                 "psrldq $8, %%xmm4\n\t"
192                 "pslldq $8, %%xmm5\n\t"
193                 "pxor %%xmm5, %%xmm3\n\t"
194                 "pxor %%xmm4, %%xmm1\n\t" /* <xmm1:xmm3> holds the result of the
195                                              carry-less multiplication of xmm0
196                                              by xmm1 */
197                 :
198                 : [buf] "r" (buf),
199                   [h_table] "r" (h_table)
200                 : "memory" );
201
202   reduction();
203 }
204
205 static inline void gfmul_pclmul_aggr8(const void *buf, const void *h_table)
206 {
207   /* Input:
208       H¹: XMM0
209       bemask: XMM15
210       Hash: XMM1
211      Output:
212       Hash: XMM1
213      Inputs XMM0 and XMM14 stays unmodified.
214    */
215   asm volatile (/* Load H6, H7, H8. */
216                 "movdqu 6*16(%[h_table]), %%xmm10\n\t"
217                 "movdqu 5*16(%[h_table]), %%xmm9\n\t"
218                 "movdqu 4*16(%[h_table]), %%xmm8\n\t"
219
220                 /* perform clmul and merge results... */
221                 "movdqu 0*16(%[buf]), %%xmm5\n\t"
222                 "movdqu 1*16(%[buf]), %%xmm2\n\t"
223                 "pshufb %%xmm15, %%xmm5\n\t" /* be => le */
224                 "pshufb %%xmm15, %%xmm2\n\t" /* be => le */
225                 "pxor %%xmm5, %%xmm1\n\t"
226
227                 "pshufd $78, %%xmm10, %%xmm5\n\t"
228                 "pshufd $78, %%xmm1, %%xmm4\n\t"
229                 "pxor %%xmm10, %%xmm5\n\t" /* xmm5 holds 8:a0+a1 */
230                 "pxor %%xmm1, %%xmm4\n\t"  /* xmm4 holds 8:b0+b1 */
231                 "movdqa %%xmm10, %%xmm3\n\t"
232                 "pclmulqdq $0, %%xmm1, %%xmm3\n\t"   /* xmm3 holds 8:a0*b0 */
233                 "pclmulqdq $17, %%xmm10, %%xmm1\n\t" /* xmm1 holds 8:a1*b1 */
234                 "pclmulqdq $0, %%xmm5, %%xmm4\n\t"   /* xmm4 holds 8:(a0+a1)*(b0+b1) */
235
236                 "pshufd $78, %%xmm9, %%xmm11\n\t"
237                 "pshufd $78, %%xmm2, %%xmm7\n\t"
238                 "pxor %%xmm9, %%xmm11\n\t" /* xmm11 holds 7:a0+a1 */
239                 "pxor %%xmm2, %%xmm7\n\t"  /* xmm7 holds 7:b0+b1 */
240                 "movdqa %%xmm9, %%xmm6\n\t"
241                 "pclmulqdq $0, %%xmm2, %%xmm6\n\t"  /* xmm6 holds 7:a0*b0 */
242                 "pclmulqdq $17, %%xmm9, %%xmm2\n\t" /* xmm2 holds 7:a1*b1 */
243                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 7:(a0+a1)*(b0+b1) */
244
245                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 7+8:a0*b0 */
246                 "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 7+8:a1*b1 */
247                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 7+8:(a0+a1)*(b0+b1) */
248
249                 "movdqu 2*16(%[buf]), %%xmm5\n\t"
250                 "movdqu 3*16(%[buf]), %%xmm2\n\t"
251                 "pshufb %%xmm15, %%xmm5\n\t" /* be => le */
252                 "pshufb %%xmm15, %%xmm2\n\t" /* be => le */
253
254                 "pshufd $78, %%xmm8, %%xmm11\n\t"
255                 "pshufd $78, %%xmm5, %%xmm7\n\t"
256                 "pxor %%xmm8, %%xmm11\n\t" /* xmm11 holds 6:a0+a1 */
257                 "pxor %%xmm5, %%xmm7\n\t"  /* xmm7 holds 6:b0+b1 */
258                 "movdqa %%xmm8, %%xmm6\n\t"
259                 "pclmulqdq $0, %%xmm5, %%xmm6\n\t"  /* xmm6 holds 6:a0*b0 */
260                 "pclmulqdq $17, %%xmm8, %%xmm5\n\t" /* xmm5 holds 6:a1*b1 */
261                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 6:(a0+a1)*(b0+b1) */
262
263                 /* Load H3, H4, H5. */
264                 "movdqu 3*16(%[h_table]), %%xmm10\n\t"
265                 "movdqu 2*16(%[h_table]), %%xmm9\n\t"
266                 "movdqu 1*16(%[h_table]), %%xmm8\n\t"
267
268                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 6+7+8:a0*b0 */
269                 "pxor %%xmm5, %%xmm1\n\t" /* xmm1 holds 6+7+8:a1*b1 */
270                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 6+7+8:(a0+a1)*(b0+b1) */
271
272                 "pshufd $78, %%xmm10, %%xmm11\n\t"
273                 "pshufd $78, %%xmm2, %%xmm7\n\t"
274                 "pxor %%xmm10, %%xmm11\n\t" /* xmm11 holds 5:a0+a1 */
275                 "pxor %%xmm2, %%xmm7\n\t"   /* xmm7 holds 5:b0+b1 */
276                 "movdqa %%xmm10, %%xmm6\n\t"
277                 "pclmulqdq $0, %%xmm2, %%xmm6\n\t"   /* xmm6 holds 5:a0*b0 */
278                 "pclmulqdq $17, %%xmm10, %%xmm2\n\t" /* xmm2 holds 5:a1*b1 */
279                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t"  /* xmm7 holds 5:(a0+a1)*(b0+b1) */
280
281                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 5+6+7+8:a0*b0 */
282                 "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 5+6+7+8:a1*b1 */
283                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 5+6+7+8:(a0+a1)*(b0+b1) */
284
285                 "movdqu 4*16(%[buf]), %%xmm5\n\t"
286                 "movdqu 5*16(%[buf]), %%xmm2\n\t"
287                 "pshufb %%xmm15, %%xmm5\n\t" /* be => le */
288                 "pshufb %%xmm15, %%xmm2\n\t" /* be => le */
289
290                 "pshufd $78, %%xmm9, %%xmm11\n\t"
291                 "pshufd $78, %%xmm5, %%xmm7\n\t"
292                 "pxor %%xmm9, %%xmm11\n\t" /* xmm11 holds 4:a0+a1 */
293                 "pxor %%xmm5, %%xmm7\n\t"  /* xmm7 holds 4:b0+b1 */
294                 "movdqa %%xmm9, %%xmm6\n\t"
295                 "pclmulqdq $0, %%xmm5, %%xmm6\n\t"  /* xmm6 holds 4:a0*b0 */
296                 "pclmulqdq $17, %%xmm9, %%xmm5\n\t" /* xmm5 holds 4:a1*b1 */
297                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 4:(a0+a1)*(b0+b1) */
298
299                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 4+5+6+7+8:a0*b0 */
300                 "pxor %%xmm5, %%xmm1\n\t" /* xmm1 holds 4+5+6+7+8:a1*b1 */
301                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 4+5+6+7+8:(a0+a1)*(b0+b1) */
302
303                 "pshufd $78, %%xmm8, %%xmm11\n\t"
304                 "pshufd $78, %%xmm2, %%xmm7\n\t"
305                 "pxor %%xmm8, %%xmm11\n\t" /* xmm11 holds 3:a0+a1 */
306                 "pxor %%xmm2, %%xmm7\n\t"  /* xmm7 holds 3:b0+b1 */
307                 "movdqa %%xmm8, %%xmm6\n\t"
308                 "pclmulqdq $0, %%xmm2, %%xmm6\n\t"  /* xmm6 holds 3:a0*b0 */
309                 "pclmulqdq $17, %%xmm8, %%xmm2\n\t" /* xmm2 holds 3:a1*b1 */
310                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 3:(a0+a1)*(b0+b1) */
311
312                 "movdqu 0*16(%[h_table]), %%xmm8\n\t" /* Load H2 */
313
314                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 3+4+5+6+7+8:a0*b0 */
315                 "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 3+4+5+6+7+8:a1*b1 */
316                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 3+4+5+6+7+8:(a0+a1)*(b0+b1) */
317
318                 "movdqu 6*16(%[buf]), %%xmm5\n\t"
319                 "movdqu 7*16(%[buf]), %%xmm2\n\t"
320                 "pshufb %%xmm15, %%xmm5\n\t" /* be => le */
321                 "pshufb %%xmm15, %%xmm2\n\t" /* be => le */
322
323                 "pshufd $78, %%xmm8, %%xmm11\n\t"
324                 "pshufd $78, %%xmm5, %%xmm7\n\t"
325                 "pxor %%xmm8, %%xmm11\n\t"  /* xmm11 holds 4:a0+a1 */
326                 "pxor %%xmm5, %%xmm7\n\t"   /* xmm7 holds 4:b0+b1 */
327                 "movdqa %%xmm8, %%xmm6\n\t"
328                 "pclmulqdq $0, %%xmm5, %%xmm6\n\t"   /* xmm6 holds 4:a0*b0 */
329                 "pclmulqdq $17, %%xmm8, %%xmm5\n\t"  /* xmm5 holds 4:a1*b1 */
330                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t"  /* xmm7 holds 4:(a0+a1)*(b0+b1) */
331
332                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 2+3+4+5+6+7+8:a0*b0 */
333                 "pxor %%xmm5, %%xmm1\n\t" /* xmm1 holds 2+3+4+5+6+7+8:a1*b1 */
334                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 2+3+4+5+6+7+8:(a0+a1)*(b0+b1) */
335
336                 "pshufd $78, %%xmm0, %%xmm11\n\t"
337                 "pshufd $78, %%xmm2, %%xmm7\n\t"
338                 "pxor %%xmm0, %%xmm11\n\t" /* xmm11 holds 3:a0+a1 */
339                 "pxor %%xmm2, %%xmm7\n\t"  /* xmm7 holds 3:b0+b1 */
340                 "movdqa %%xmm0, %%xmm6\n\t"
341                 "pclmulqdq $0, %%xmm2, %%xmm6\n\t"  /* xmm6 holds 3:a0*b0 */
342                 "pclmulqdq $17, %%xmm0, %%xmm2\n\t" /* xmm2 holds 3:a1*b1 */
343                 "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 3:(a0+a1)*(b0+b1) */
344
345                 "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 1+2+3+3+4+5+6+7+8:a0*b0 */
346                 "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 1+2+3+3+4+5+6+7+8:a1*b1 */
347                 "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 1+2+3+3+4+5+6+7+8:(a0+a1)*(b0+b1) */
348
349                 /* aggregated reduction... */
350                 "movdqa %%xmm3, %%xmm5\n\t"
351                 "pxor %%xmm1, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */
352                 "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */
353                 "movdqa %%xmm4, %%xmm5\n\t"
354                 "psrldq $8, %%xmm4\n\t"
355                 "pslldq $8, %%xmm5\n\t"
356                 "pxor %%xmm5, %%xmm3\n\t"
357                 "pxor %%xmm4, %%xmm1\n\t" /* <xmm1:xmm3> holds the result of the
358                                              carry-less multiplication of xmm0
359                                              by xmm1 */
360                 :
361                 : [buf] "r" (buf),
362                   [h_table] "r" (h_table)
363                 : "memory" );
364
365   reduction();
366 }
367 #endif
368
369 static inline void gcm_lsh(void *h, unsigned int hoffs)
370 {
371   static const u64 pconst[2] __attribute__ ((aligned (16))) =
372     { U64_C(0x0000000000000001), U64_C(0xc200000000000000) };
373
374   asm volatile ("movdqu (%[h]), %%xmm2\n\t"
375                 "pshufd $0xff, %%xmm2, %%xmm3\n\t"
376                 "movdqa %%xmm2, %%xmm4\n\t"
377                 "psrad $31, %%xmm3\n\t"
378                 "pslldq $8, %%xmm4\n\t"
379                 "pand %[pconst], %%xmm3\n\t"
380                 "paddq %%xmm2, %%xmm2\n\t"
381                 "psrlq $63, %%xmm4\n\t"
382                 "pxor %%xmm3, %%xmm2\n\t"
383                 "pxor %%xmm4, %%xmm2\n\t"
384                 "movdqu %%xmm2, (%[h])\n\t"
385                 :
386                 : [pconst] "m" (pconst),
387                   [h] "r" ((byte *)h + hoffs)
388                 : "memory" );
389 }
390
391 void
392 _gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c)
393 {
394   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
395     { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
396 #if defined(__x86_64__) && defined(__WIN64__)
397   char win64tmp[10 * 16];
398
399   /* XMM6-XMM15 need to be restored after use. */
400   asm volatile ("movdqu %%xmm6,  0*16(%0)\n\t"
401                 "movdqu %%xmm7,  1*16(%0)\n\t"
402                 "movdqu %%xmm8,  2*16(%0)\n\t"
403                 "movdqu %%xmm9,  3*16(%0)\n\t"
404                 "movdqu %%xmm10, 4*16(%0)\n\t"
405                 "movdqu %%xmm11, 5*16(%0)\n\t"
406                 "movdqu %%xmm12, 6*16(%0)\n\t"
407                 "movdqu %%xmm13, 7*16(%0)\n\t"
408                 "movdqu %%xmm14, 8*16(%0)\n\t"
409                 "movdqu %%xmm15, 9*16(%0)\n\t"
410                 :
411                 : "r" (win64tmp)
412                 : "memory" );
413 #endif
414
415   /* Swap endianness of hsub. */
416   asm volatile ("movdqu (%[key]), %%xmm0\n\t"
417                 "pshufb %[be_mask], %%xmm0\n\t"
418                 "movdqu %%xmm0, (%[key])\n\t"
419                 :
420                 : [key] "r" (c->u_mode.gcm.u_ghash_key.key),
421                   [be_mask] "m" (*be_mask)
422                 : "memory");
423
424   gcm_lsh(c->u_mode.gcm.u_ghash_key.key, 0); /* H <<< 1 */
425
426 #ifdef __x86_64__
427   asm volatile ("movdqa %%xmm0, %%xmm1\n\t"
428                 "movdqu (%[key]), %%xmm0\n\t" /* load H <<< 1 */
429                 :
430                 : [key] "r" (c->u_mode.gcm.u_ghash_key.key)
431                 : "memory");
432
433   gfmul_pclmul (); /* H<<<1•H => H² */
434
435   asm volatile ("movdqu %%xmm1, 0*16(%[h_table])\n\t"
436                 "movdqa %%xmm1, %%xmm8\n\t"
437                 :
438                 : [h_table] "r" (c->u_mode.gcm.gcm_table)
439                 : "memory");
440
441   gcm_lsh(c->u_mode.gcm.gcm_table, 0 * 16); /* H² <<< 1 */
442   gfmul_pclmul (); /* H<<<1•H² => H³ */
443
444   asm volatile ("movdqa %%xmm8, %%xmm0\n\t"
445                 "movdqu %%xmm1, 1*16(%[h_table])\n\t"
446                 "movdqu 0*16(%[h_table]), %%xmm1\n\t" /* load H² <<< 1 */
447                 :
448                 : [h_table] "r" (c->u_mode.gcm.gcm_table)
449                 : "memory");
450
451   gfmul_pclmul (); /* H²<<<1•H² => H⁴ */
452
453   asm volatile ("movdqu %%xmm1, 2*16(%[h_table])\n\t"
454                 "movdqa %%xmm1, %%xmm0\n\t"
455                 "movdqu (%[key]), %%xmm1\n\t" /* load H <<< 1 */
456                 :
457                 : [h_table] "r" (c->u_mode.gcm.gcm_table),
458                   [key] "r" (c->u_mode.gcm.u_ghash_key.key)
459                 : "memory");
460
461   gcm_lsh(c->u_mode.gcm.gcm_table, 1 * 16); /* H³ <<< 1 */
462   gcm_lsh(c->u_mode.gcm.gcm_table, 2 * 16); /* H⁴ <<< 1 */
463
464   gfmul_pclmul (); /* H<<<1•H⁴ => H⁵ */
465
466   asm volatile ("movdqu %%xmm1, 3*16(%[h_table])\n\t"
467                 "movdqu 0*16(%[h_table]), %%xmm1\n\t" /* load H² <<< 1 */
468                 :
469                 : [h_table] "r" (c->u_mode.gcm.gcm_table)
470                 : "memory");
471
472   gfmul_pclmul (); /* H²<<<1•H⁴ => H⁶ */
473
474   asm volatile ("movdqu %%xmm1, 4*16(%[h_table])\n\t"
475                 "movdqu 1*16(%[h_table]), %%xmm1\n\t" /* load H³ <<< 1 */
476                 :
477                 : [h_table] "r" (c->u_mode.gcm.gcm_table)
478                 : "memory");
479
480   gfmul_pclmul (); /* H³<<<1•H⁴ => H⁷ */
481
482   asm volatile ("movdqu %%xmm1, 5*16(%[h_table])\n\t"
483                 "movdqu 2*16(%[h_table]), %%xmm1\n\t" /* load H⁴ <<< 1 */
484                 :
485                 : [h_table] "r" (c->u_mode.gcm.gcm_table)
486                 : "memory");
487
488   gfmul_pclmul (); /* H³<<<1•H⁴ => H⁸ */
489
490   asm volatile ("movdqu %%xmm1, 6*16(%[h_table])\n\t"
491                 :
492                 : [h_table] "r" (c->u_mode.gcm.gcm_table)
493                 : "memory");
494
495   gcm_lsh(c->u_mode.gcm.gcm_table, 3 * 16); /* H⁵ <<< 1 */
496   gcm_lsh(c->u_mode.gcm.gcm_table, 4 * 16); /* H⁶ <<< 1 */
497   gcm_lsh(c->u_mode.gcm.gcm_table, 5 * 16); /* H⁷ <<< 1 */
498   gcm_lsh(c->u_mode.gcm.gcm_table, 6 * 16); /* H⁸ <<< 1 */
499
500 #ifdef __WIN64__
501   /* Clear/restore used registers. */
502   asm volatile( "pxor %%xmm0, %%xmm0\n\t"
503                 "pxor %%xmm1, %%xmm1\n\t"
504                 "pxor %%xmm2, %%xmm2\n\t"
505                 "pxor %%xmm3, %%xmm3\n\t"
506                 "pxor %%xmm4, %%xmm4\n\t"
507                 "pxor %%xmm5, %%xmm5\n\t"
508                 "movdqu 0*16(%0), %%xmm6\n\t"
509                 "movdqu 1*16(%0), %%xmm7\n\t"
510                 "movdqu 2*16(%0), %%xmm8\n\t"
511                 "movdqu 3*16(%0), %%xmm9\n\t"
512                 "movdqu 4*16(%0), %%xmm10\n\t"
513                 "movdqu 5*16(%0), %%xmm11\n\t"
514                 "movdqu 6*16(%0), %%xmm12\n\t"
515                 "movdqu 7*16(%0), %%xmm13\n\t"
516                 "movdqu 8*16(%0), %%xmm14\n\t"
517                 "movdqu 9*16(%0), %%xmm15\n\t"
518                 :
519                 : "r" (win64tmp)
520                 : "memory" );
521 #else
522   /* Clear used registers. */
523   asm volatile( "pxor %%xmm0, %%xmm0\n\t"
524                 "pxor %%xmm1, %%xmm1\n\t"
525                 "pxor %%xmm2, %%xmm2\n\t"
526                 "pxor %%xmm3, %%xmm3\n\t"
527                 "pxor %%xmm4, %%xmm4\n\t"
528                 "pxor %%xmm5, %%xmm5\n\t"
529                 "pxor %%xmm6, %%xmm6\n\t"
530                 "pxor %%xmm7, %%xmm7\n\t"
531                 "pxor %%xmm8, %%xmm8\n\t"
532                 "pxor %%xmm9, %%xmm9\n\t"
533                 "pxor %%xmm10, %%xmm10\n\t"
534                 "pxor %%xmm11, %%xmm11\n\t"
535                 "pxor %%xmm12, %%xmm12\n\t"
536                 "pxor %%xmm13, %%xmm13\n\t"
537                 "pxor %%xmm14, %%xmm14\n\t"
538                 "pxor %%xmm15, %%xmm15\n\t"
539                 ::: "memory" );
540 #endif
541 #endif
542 }
543
544
545 unsigned int
546 _gcry_ghash_intel_pclmul (gcry_cipher_hd_t c, byte *result, const byte *buf,
547                           size_t nblocks)
548 {
549   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
550     { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
551   const unsigned int blocksize = GCRY_GCM_BLOCK_LEN;
552 #if defined(__x86_64__) && defined(__WIN64__)
553   char win64tmp[10 * 16];
554 #endif
555
556   if (nblocks == 0)
557     return 0;
558
559 #if defined(__x86_64__) && defined(__WIN64__)
560   /* XMM6-XMM15 need to be restored after use. */
561   asm volatile ("movdqu %%xmm6,  0*16(%0)\n\t"
562                 "movdqu %%xmm7,  1*16(%0)\n\t"
563                 "movdqu %%xmm8,  2*16(%0)\n\t"
564                 "movdqu %%xmm9,  3*16(%0)\n\t"
565                 "movdqu %%xmm10, 4*16(%0)\n\t"
566                 "movdqu %%xmm11, 5*16(%0)\n\t"
567                 "movdqu %%xmm12, 6*16(%0)\n\t"
568                 "movdqu %%xmm13, 7*16(%0)\n\t"
569                 "movdqu %%xmm14, 8*16(%0)\n\t"
570                 "movdqu %%xmm15, 9*16(%0)\n\t"
571                 :
572                 : "r" (win64tmp)
573                 : "memory" );
574 #endif
575
576   /* Preload hash and H1. */
577   asm volatile ("movdqa %[be_mask], %%xmm7\n\t"
578                 "movdqu %[hash], %%xmm1\n\t"
579                 "movdqa %[hsub], %%xmm0\n\t"
580                 "pshufb %%xmm7, %%xmm1\n\t" /* be => le */
581                 :
582                 : [hash] "m" (*result),
583                   [be_mask] "m" (*be_mask),
584                   [hsub] "m" (*c->u_mode.gcm.u_ghash_key.key)
585                 : "memory" );
586
587 #ifdef __x86_64__
588   if (nblocks >= 4)
589     {
590       asm volatile ("movdqa %%xmm7, %%xmm15\n\t"
591                     :
592                     :
593                     : "memory" );
594
595       while (nblocks >= 8)
596         {
597           gfmul_pclmul_aggr8 (buf, c->u_mode.gcm.gcm_table);
598
599           buf += 8 * blocksize;
600           nblocks -= 8;
601         }
602
603       if (nblocks >= 4)
604         {
605           gfmul_pclmul_aggr4 (buf, c->u_mode.gcm.gcm_table);
606
607           buf += 4 * blocksize;
608           nblocks -= 4;
609         }
610
611 #ifndef __WIN64__
612       /* Clear used x86-64/XMM registers. */
613       asm volatile( "pxor %%xmm8, %%xmm8\n\t"
614                     "pxor %%xmm9, %%xmm9\n\t"
615                     "pxor %%xmm10, %%xmm10\n\t"
616                     "pxor %%xmm11, %%xmm11\n\t"
617                     "pxor %%xmm12, %%xmm12\n\t"
618                     "pxor %%xmm13, %%xmm13\n\t"
619                     "pxor %%xmm14, %%xmm14\n\t"
620                     "pxor %%xmm15, %%xmm15\n\t"
621                     ::: "memory" );
622 #endif
623     }
624 #endif
625
626   while (nblocks)
627     {
628       asm volatile ("movdqu %[buf], %%xmm2\n\t"
629                     "pshufb %[be_mask], %%xmm2\n\t" /* be => le */
630                     "pxor %%xmm2, %%xmm1\n\t"
631                     :
632                     : [buf] "m" (*buf), [be_mask] "m" (*be_mask)
633                     : "memory" );
634
635       gfmul_pclmul ();
636
637       buf += blocksize;
638       nblocks--;
639     }
640
641   /* Store hash. */
642   asm volatile ("pshufb %[be_mask], %%xmm1\n\t" /* be => le */
643                 "movdqu %%xmm1, %[hash]\n\t"
644                 : [hash] "=m" (*result)
645                 : [be_mask] "m" (*be_mask)
646                 : "memory" );
647
648 #if defined(__x86_64__) && defined(__WIN64__)
649   /* Clear/restore used registers. */
650   asm volatile( "pxor %%xmm0, %%xmm0\n\t"
651                 "pxor %%xmm1, %%xmm1\n\t"
652                 "pxor %%xmm2, %%xmm2\n\t"
653                 "pxor %%xmm3, %%xmm3\n\t"
654                 "pxor %%xmm4, %%xmm4\n\t"
655                 "pxor %%xmm5, %%xmm5\n\t"
656                 "movdqu 0*16(%0), %%xmm6\n\t"
657                 "movdqu 1*16(%0), %%xmm7\n\t"
658                 "movdqu 2*16(%0), %%xmm8\n\t"
659                 "movdqu 3*16(%0), %%xmm9\n\t"
660                 "movdqu 4*16(%0), %%xmm10\n\t"
661                 "movdqu 5*16(%0), %%xmm11\n\t"
662                 "movdqu 6*16(%0), %%xmm12\n\t"
663                 "movdqu 7*16(%0), %%xmm13\n\t"
664                 "movdqu 8*16(%0), %%xmm14\n\t"
665                 "movdqu 9*16(%0), %%xmm15\n\t"
666                 :
667                 : "r" (win64tmp)
668                 : "memory" );
669 #else
670   /* Clear used registers. */
671   asm volatile( "pxor %%xmm0, %%xmm0\n\t"
672                 "pxor %%xmm1, %%xmm1\n\t"
673                 "pxor %%xmm2, %%xmm2\n\t"
674                 "pxor %%xmm3, %%xmm3\n\t"
675                 "pxor %%xmm4, %%xmm4\n\t"
676                 "pxor %%xmm5, %%xmm5\n\t"
677                 "pxor %%xmm6, %%xmm6\n\t"
678                 "pxor %%xmm7, %%xmm7\n\t"
679                 ::: "memory" );
680 #endif
681
682   return 0;
683 }
684
685 #if __clang__
686 #  pragma clang attribute pop
687 #endif
688
689 #endif /* GCM_USE_INTEL_PCLMUL */