Disallow compiler from generating SSE instructions in mixed C+asm source
[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 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
41
42 /*
43  Intel PCLMUL ghash based on white paper:
44   "Intel® Carry-Less Multiplication Instruction and its Usage for Computing the
45    GCM Mode - Rev 2.01"; Shay Gueron, Michael E. Kounavis.
46  */
47 static inline void gfmul_pclmul(void)
48 {
49   /* Input: XMM0 and XMM1, Output: XMM1. Input XMM0 stays unmodified.
50      Input must be converted to little-endian.
51    */
52   asm volatile (/* gfmul, xmm0 has operator a and xmm1 has operator b. */
53                 "pshufd $78, %%xmm0, %%xmm2\n\t"
54                 "pshufd $78, %%xmm1, %%xmm4\n\t"
55                 "pxor %%xmm0, %%xmm2\n\t" /* xmm2 holds a0+a1 */
56                 "pxor %%xmm1, %%xmm4\n\t" /* xmm4 holds b0+b1 */
57
58                 "movdqa %%xmm0, %%xmm3\n\t"
59                 "pclmulqdq $0, %%xmm1, %%xmm3\n\t"  /* xmm3 holds a0*b0 */
60                 "movdqa %%xmm0, %%xmm6\n\t"
61                 "pclmulqdq $17, %%xmm1, %%xmm6\n\t" /* xmm6 holds a1*b1 */
62                 "movdqa %%xmm3, %%xmm5\n\t"
63                 "pclmulqdq $0, %%xmm2, %%xmm4\n\t"  /* xmm4 holds (a0+a1)*(b0+b1) */
64
65                 "pxor %%xmm6, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */
66                 "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */
67                 "movdqa %%xmm4, %%xmm5\n\t"
68                 "psrldq $8, %%xmm4\n\t"
69                 "pslldq $8, %%xmm5\n\t"
70                 "pxor %%xmm5, %%xmm3\n\t"
71                 "pxor %%xmm4, %%xmm6\n\t" /* <xmm6:xmm3> holds the result of the
72                                              carry-less multiplication of xmm0
73                                              by xmm1 */
74
75                 /* shift the result by one bit position to the left cope for
76                    the fact that bits are reversed */
77                 "movdqa %%xmm3, %%xmm4\n\t"
78                 "movdqa %%xmm6, %%xmm5\n\t"
79                 "pslld $1, %%xmm3\n\t"
80                 "pslld $1, %%xmm6\n\t"
81                 "psrld $31, %%xmm4\n\t"
82                 "psrld $31, %%xmm5\n\t"
83                 "movdqa %%xmm4, %%xmm1\n\t"
84                 "pslldq $4, %%xmm5\n\t"
85                 "pslldq $4, %%xmm4\n\t"
86                 "psrldq $12, %%xmm1\n\t"
87                 "por %%xmm4, %%xmm3\n\t"
88                 "por %%xmm5, %%xmm6\n\t"
89                 "por %%xmm6, %%xmm1\n\t"
90
91                 /* first phase of the reduction */
92                 "movdqa %%xmm3, %%xmm6\n\t"
93                 "movdqa %%xmm3, %%xmm7\n\t"
94                 "pslld $31, %%xmm6\n\t"  /* packed right shifting << 31 */
95                 "movdqa %%xmm3, %%xmm5\n\t"
96                 "pslld $30, %%xmm7\n\t"  /* packed right shifting shift << 30 */
97                 "pslld $25, %%xmm5\n\t"  /* packed right shifting shift << 25 */
98                 "pxor %%xmm7, %%xmm6\n\t" /* xor the shifted versions */
99                 "pxor %%xmm5, %%xmm6\n\t"
100                 "movdqa %%xmm6, %%xmm7\n\t"
101                 "pslldq $12, %%xmm6\n\t"
102                 "psrldq $4, %%xmm7\n\t"
103                 "pxor %%xmm6, %%xmm3\n\t" /* first phase of the reduction
104                                              complete */
105
106                 /* second phase of the reduction */
107                 "movdqa %%xmm3, %%xmm2\n\t"
108                 "movdqa %%xmm3, %%xmm4\n\t"
109                 "psrld $1, %%xmm2\n\t"    /* packed left shifting >> 1 */
110                 "movdqa %%xmm3, %%xmm5\n\t"
111                 "psrld $2, %%xmm4\n\t"    /* packed left shifting >> 2 */
112                 "psrld $7, %%xmm5\n\t"    /* packed left shifting >> 7 */
113                 "pxor %%xmm4, %%xmm2\n\t" /* xor the shifted versions */
114                 "pxor %%xmm5, %%xmm2\n\t"
115                 "pxor %%xmm7, %%xmm2\n\t"
116                 "pxor %%xmm2, %%xmm3\n\t"
117                 "pxor %%xmm3, %%xmm1\n\t" /* the result is in xmm1 */
118                 ::: "cc" );
119 }
120
121
122 #ifdef __x86_64__
123 static inline void gfmul_pclmul_aggr4(void)
124 {
125   /* Input:
126       H¹: XMM0          X_i            : XMM6
127       H²: XMM8          X_(i-1)        : XMM3
128       H³: XMM9          X_(i-2)        : XMM2
129       H⁴: XMM10         X_(i-3)⊕Y_(i-4): XMM1
130      Output:
131       Y_i: XMM1
132      Inputs XMM0 stays unmodified.
133      Input must be converted to little-endian.
134    */
135   asm volatile (/* perform clmul and merge results... */
136                 "pshufd $78, %%xmm10, %%xmm11\n\t"
137                 "pshufd $78, %%xmm1, %%xmm12\n\t"
138                 "pxor %%xmm10, %%xmm11\n\t" /* xmm11 holds 4:a0+a1 */
139                 "pxor %%xmm1, %%xmm12\n\t" /* xmm12 holds 4:b0+b1 */
140
141                 "pshufd $78, %%xmm9, %%xmm13\n\t"
142                 "pshufd $78, %%xmm2, %%xmm14\n\t"
143                 "pxor %%xmm9, %%xmm13\n\t" /* xmm13 holds 3:a0+a1 */
144                 "pxor %%xmm2, %%xmm14\n\t" /* xmm14 holds 3:b0+b1 */
145
146                 "pshufd $78, %%xmm8, %%xmm5\n\t"
147                 "pshufd $78, %%xmm3, %%xmm15\n\t"
148                 "pxor %%xmm8, %%xmm5\n\t" /* xmm1 holds 2:a0+a1 */
149                 "pxor %%xmm3, %%xmm15\n\t" /* xmm2 holds 2:b0+b1 */
150
151                 "movdqa %%xmm10, %%xmm4\n\t"
152                 "movdqa %%xmm9, %%xmm7\n\t"
153                 "pclmulqdq $0, %%xmm1, %%xmm4\n\t"   /* xmm4 holds 4:a0*b0 */
154                 "pclmulqdq $0, %%xmm2, %%xmm7\n\t"   /* xmm7 holds 3:a0*b0 */
155                 "pclmulqdq $17, %%xmm10, %%xmm1\n\t" /* xmm1 holds 4:a1*b1 */
156                 "pclmulqdq $17, %%xmm9, %%xmm2\n\t"  /* xmm9 holds 3:a1*b1 */
157                 "pclmulqdq $0, %%xmm11, %%xmm12\n\t" /* xmm12 holds 4:(a0+a1)*(b0+b1) */
158                 "pclmulqdq $0, %%xmm13, %%xmm14\n\t" /* xmm14 holds 3:(a0+a1)*(b0+b1) */
159
160                 "pshufd $78, %%xmm0, %%xmm10\n\t"
161                 "pshufd $78, %%xmm6, %%xmm11\n\t"
162                 "pxor %%xmm0, %%xmm10\n\t" /* xmm10 holds 1:a0+a1 */
163                 "pxor %%xmm6, %%xmm11\n\t" /* xmm11 holds 1:b0+b1 */
164
165                 "pxor %%xmm4, %%xmm7\n\t"   /* xmm7 holds 3+4:a0*b0 */
166                 "pxor %%xmm2, %%xmm1\n\t"   /* xmm1 holds 3+4:a1*b1 */
167                 "pxor %%xmm14, %%xmm12\n\t" /* xmm12 holds 3+4:(a0+a1)*(b0+b1) */
168
169                 "movdqa %%xmm8, %%xmm13\n\t"
170                 "pclmulqdq $0, %%xmm3, %%xmm13\n\t"  /* xmm13 holds 2:a0*b0 */
171                 "pclmulqdq $17, %%xmm8, %%xmm3\n\t"  /* xmm3 holds 2:a1*b1 */
172                 "pclmulqdq $0, %%xmm5, %%xmm15\n\t" /* xmm15 holds 2:(a0+a1)*(b0+b1) */
173
174                 "pxor %%xmm13, %%xmm7\n\t" /* xmm7 holds 2+3+4:a0*b0 */
175                 "pxor %%xmm3, %%xmm1\n\t"  /* xmm1 holds 2+3+4:a1*b1 */
176                 "pxor %%xmm15, %%xmm12\n\t" /* xmm12 holds 2+3+4:(a0+a1)*(b0+b1) */
177
178                 "movdqa %%xmm0, %%xmm3\n\t"
179                 "pclmulqdq $0, %%xmm6, %%xmm3\n\t"  /* xmm3 holds 1:a0*b0 */
180                 "pclmulqdq $17, %%xmm0, %%xmm6\n\t" /* xmm6 holds 1:a1*b1 */
181                 "movdqa %%xmm11, %%xmm4\n\t"
182                 "pclmulqdq $0, %%xmm10, %%xmm4\n\t" /* xmm4 holds 1:(a0+a1)*(b0+b1) */
183
184                 "pxor %%xmm7, %%xmm3\n\t"  /* xmm3 holds 1+2+3+4:a0*b0 */
185                 "pxor %%xmm1, %%xmm6\n\t"  /* xmm6 holds 1+2+3+4:a1*b1 */
186                 "pxor %%xmm12, %%xmm4\n\t" /* xmm4 holds 1+2+3+4:(a0+a1)*(b0+b1) */
187
188                 /* aggregated reduction... */
189                 "movdqa %%xmm3, %%xmm5\n\t"
190                 "pxor %%xmm6, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */
191                 "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */
192                 "movdqa %%xmm4, %%xmm5\n\t"
193                 "psrldq $8, %%xmm4\n\t"
194                 "pslldq $8, %%xmm5\n\t"
195                 "pxor %%xmm5, %%xmm3\n\t"
196                 "pxor %%xmm4, %%xmm6\n\t" /* <xmm6:xmm3> holds the result of the
197                                              carry-less multiplication of xmm0
198                                              by xmm1 */
199
200                 /* shift the result by one bit position to the left cope for
201                    the fact that bits are reversed */
202                 "movdqa %%xmm3, %%xmm4\n\t"
203                 "movdqa %%xmm6, %%xmm5\n\t"
204                 "pslld $1, %%xmm3\n\t"
205                 "pslld $1, %%xmm6\n\t"
206                 "psrld $31, %%xmm4\n\t"
207                 "psrld $31, %%xmm5\n\t"
208                 "movdqa %%xmm4, %%xmm1\n\t"
209                 "pslldq $4, %%xmm5\n\t"
210                 "pslldq $4, %%xmm4\n\t"
211                 "psrldq $12, %%xmm1\n\t"
212                 "por %%xmm4, %%xmm3\n\t"
213                 "por %%xmm5, %%xmm6\n\t"
214                 "por %%xmm6, %%xmm1\n\t"
215
216                 /* first phase of the reduction */
217                 "movdqa %%xmm3, %%xmm6\n\t"
218                 "movdqa %%xmm3, %%xmm7\n\t"
219                 "pslld $31, %%xmm6\n\t"  /* packed right shifting << 31 */
220                 "movdqa %%xmm3, %%xmm5\n\t"
221                 "pslld $30, %%xmm7\n\t"  /* packed right shifting shift << 30 */
222                 "pslld $25, %%xmm5\n\t"  /* packed right shifting shift << 25 */
223                 "pxor %%xmm7, %%xmm6\n\t" /* xor the shifted versions */
224                 "pxor %%xmm5, %%xmm6\n\t"
225                 "movdqa %%xmm6, %%xmm7\n\t"
226                 "pslldq $12, %%xmm6\n\t"
227                 "psrldq $4, %%xmm7\n\t"
228                 "pxor %%xmm6, %%xmm3\n\t" /* first phase of the reduction
229                                              complete */
230
231                 /* second phase of the reduction */
232                 "movdqa %%xmm3, %%xmm2\n\t"
233                 "movdqa %%xmm3, %%xmm4\n\t"
234                 "psrld $1, %%xmm2\n\t"    /* packed left shifting >> 1 */
235                 "movdqa %%xmm3, %%xmm5\n\t"
236                 "psrld $2, %%xmm4\n\t"    /* packed left shifting >> 2 */
237                 "psrld $7, %%xmm5\n\t"    /* packed left shifting >> 7 */
238                 "pxor %%xmm4, %%xmm2\n\t" /* xor the shifted versions */
239                 "pxor %%xmm5, %%xmm2\n\t"
240                 "pxor %%xmm7, %%xmm2\n\t"
241                 "pxor %%xmm2, %%xmm3\n\t"
242                 "pxor %%xmm3, %%xmm1\n\t" /* the result is in xmm1 */
243                 :::"cc");
244 }
245 #endif
246
247
248 void
249 _gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c)
250 {
251   u64 tmp[2];
252
253   /* Swap endianness of hsub. */
254   tmp[0] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 8);
255   tmp[1] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 0);
256   buf_cpy (c->u_mode.gcm.u_ghash_key.key, tmp, GCRY_GCM_BLOCK_LEN);
257
258 #ifdef __x86_64__
259   asm volatile ("movdqu %[h_1], %%xmm0\n\t"
260                 "movdqa %%xmm0, %%xmm1\n\t"
261                 :
262                 : [h_1] "m" (*tmp));
263
264   gfmul_pclmul (); /* H•H => H² */
265
266   asm volatile ("movdqu %%xmm1, 0*16(%[h_234])\n\t"
267                 "movdqa %%xmm1, %%xmm8\n\t"
268                 :
269                 : [h_234] "r" (c->u_mode.gcm.gcm_table)
270                 : "memory");
271
272   gfmul_pclmul (); /* H•H² => H³ */
273
274   asm volatile ("movdqa %%xmm8, %%xmm0\n\t"
275                 "movdqu %%xmm1, 1*16(%[h_234])\n\t"
276                 "movdqa %%xmm8, %%xmm1\n\t"
277                 :
278                 : [h_234] "r" (c->u_mode.gcm.gcm_table)
279                 : "memory");
280
281   gfmul_pclmul (); /* H²•H² => H⁴ */
282
283   asm volatile ("movdqu %%xmm1, 2*16(%[h_234])\n\t"
284                 :
285                 : [h_234] "r" (c->u_mode.gcm.gcm_table)
286                 : "memory");
287
288   /* Clear used registers. */
289   asm volatile( "pxor %%xmm0, %%xmm0\n\t"
290                 "pxor %%xmm1, %%xmm1\n\t"
291                 "pxor %%xmm2, %%xmm2\n\t"
292                 "pxor %%xmm3, %%xmm3\n\t"
293                 "pxor %%xmm4, %%xmm4\n\t"
294                 "pxor %%xmm5, %%xmm5\n\t"
295                 "pxor %%xmm6, %%xmm6\n\t"
296                 "pxor %%xmm7, %%xmm7\n\t"
297                 "pxor %%xmm8, %%xmm8\n\t"
298                 ::: "cc" );
299 #endif
300
301   wipememory (tmp, sizeof(tmp));
302 }
303
304
305 unsigned int
306 _gcry_ghash_intel_pclmul (gcry_cipher_hd_t c, byte *result, const byte *buf,
307                           size_t nblocks)
308 {
309   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
310     { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
311   const unsigned int blocksize = GCRY_GCM_BLOCK_LEN;
312
313   if (nblocks == 0)
314     return 0;
315
316   /* Preload hash and H1. */
317   asm volatile ("movdqu %[hash], %%xmm1\n\t"
318                 "movdqa %[hsub], %%xmm0\n\t"
319                 "pshufb %[be_mask], %%xmm1\n\t" /* be => le */
320                 :
321                 : [hash] "m" (*result), [be_mask] "m" (*be_mask),
322                   [hsub] "m" (*c->u_mode.gcm.u_ghash_key.key));
323
324 #ifdef __x86_64__
325   if (nblocks >= 4)
326     {
327       do
328         {
329           asm volatile ("movdqa %[be_mask], %%xmm4\n\t"
330                         "movdqu 0*16(%[buf]), %%xmm5\n\t"
331                         "movdqu 1*16(%[buf]), %%xmm2\n\t"
332                         "movdqu 2*16(%[buf]), %%xmm3\n\t"
333                         "movdqu 3*16(%[buf]), %%xmm6\n\t"
334                         "pshufb %%xmm4, %%xmm5\n\t" /* be => le */
335
336                         /* Load H2, H3, H4. */
337                         "movdqu 2*16(%[h_234]), %%xmm10\n\t"
338                         "movdqu 1*16(%[h_234]), %%xmm9\n\t"
339                         "movdqu 0*16(%[h_234]), %%xmm8\n\t"
340
341                         "pxor %%xmm5, %%xmm1\n\t"
342                         "pshufb %%xmm4, %%xmm2\n\t" /* be => le */
343                         "pshufb %%xmm4, %%xmm3\n\t" /* be => le */
344                         "pshufb %%xmm4, %%xmm6\n\t" /* be => le */
345                         :
346                         : [buf] "r" (buf), [be_mask] "m" (*be_mask),
347                           [h_234] "r" (c->u_mode.gcm.gcm_table));
348
349           gfmul_pclmul_aggr4 ();
350
351           buf += 4 * blocksize;
352           nblocks -= 4;
353         }
354       while (nblocks >= 4);
355
356       /* Clear used x86-64/XMM registers. */
357       asm volatile( "pxor %%xmm8, %%xmm8\n\t"
358                     "pxor %%xmm9, %%xmm9\n\t"
359                     "pxor %%xmm10, %%xmm10\n\t"
360                     "pxor %%xmm11, %%xmm11\n\t"
361                     "pxor %%xmm12, %%xmm12\n\t"
362                     "pxor %%xmm13, %%xmm13\n\t"
363                     "pxor %%xmm14, %%xmm14\n\t"
364                     "pxor %%xmm15, %%xmm15\n\t"
365                     ::: "cc" );
366     }
367 #endif
368
369   while (nblocks--)
370     {
371       asm volatile ("movdqu %[buf], %%xmm2\n\t"
372                     "pshufb %[be_mask], %%xmm2\n\t" /* be => le */
373                     "pxor %%xmm2, %%xmm1\n\t"
374                     :
375                     : [buf] "m" (*buf), [be_mask] "m" (*be_mask));
376
377       gfmul_pclmul ();
378
379       buf += blocksize;
380     }
381
382   /* Store hash. */
383   asm volatile ("pshufb %[be_mask], %%xmm1\n\t" /* be => le */
384                 "movdqu %%xmm1, %[hash]\n\t"
385                 : [hash] "=m" (*result)
386                 : [be_mask] "m" (*be_mask));
387
388   /* Clear used registers. */
389   asm volatile( "pxor %%xmm0, %%xmm0\n\t"
390                 "pxor %%xmm1, %%xmm1\n\t"
391                 "pxor %%xmm2, %%xmm2\n\t"
392                 "pxor %%xmm3, %%xmm3\n\t"
393                 "pxor %%xmm4, %%xmm4\n\t"
394                 "pxor %%xmm5, %%xmm5\n\t"
395                 "pxor %%xmm6, %%xmm6\n\t"
396                 "pxor %%xmm7, %%xmm7\n\t"
397                 ::: "cc" );
398
399   return 0;
400 }
401
402 #endif /* GCM_USE_INTEL_PCLMUL */