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