0c107bb4c7cc83df9987dbebc329498af288e0e7
[libgcrypt.git] / cipher / sha256-intel-shaext.c
1 /* sha256-intel-shaext.S - SHAEXT accelerated SHA-256 transform function
2  * Copyright (C) 2018 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include "types.h"
23
24 #if defined(HAVE_GCC_INLINE_ASM_SHAEXT) && \
25     defined(HAVE_GCC_INLINE_ASM_SSE41) && defined(USE_SHA256) && \
26     defined(ENABLE_SHAEXT_SUPPORT)
27
28 #if _GCRY_GCC_VERSION >= 40400 /* 4.4 */
29 /* Prevent compiler from issuing SSE instructions between asm blocks. */
30 #  pragma GCC target("no-sse")
31 #endif
32
33 /* Two macros to be called prior and after the use of SHA-EXT
34    instructions.  There should be no external function calls between
35    the use of these macros.  There purpose is to make sure that the
36    SSE regsiters are cleared and won't reveal any information about
37    the key or the data.  */
38 #ifdef __WIN64__
39 /* XMM6-XMM15 are callee-saved registers on WIN64. */
40 # define shaext_prepare_variable char win64tmp[2*16]
41 # define shaext_prepare_variable_size sizeof(win64tmp)
42 # define shaext_prepare()                                               \
43    do { asm volatile ("movdqu %%xmm6, (%0)\n"                           \
44                       "movdqu %%xmm7, (%1)\n"                           \
45                       :                                                 \
46                       : "r" (&win64tmp[0]), "r" (&win64tmp[16])         \
47                       : "memory");                                      \
48    } while (0)
49 # define shaext_cleanup(tmp0,tmp1)                                      \
50    do { asm volatile ("movdqu (%0), %%xmm6\n"                           \
51                       "movdqu (%1), %%xmm7\n"                           \
52                       "pxor %%xmm0, %%xmm0\n"                           \
53                       "pxor %%xmm1, %%xmm1\n"                           \
54                       "pxor %%xmm2, %%xmm2\n"                           \
55                       "pxor %%xmm3, %%xmm3\n"                           \
56                       "pxor %%xmm4, %%xmm4\n"                           \
57                       "pxor %%xmm5, %%xmm5\n"                           \
58                       "movdqa %%xmm0, (%2)\n\t"                         \
59                       "movdqa %%xmm0, (%3)\n\t"                         \
60                       :                                                 \
61                       : "r" (&win64tmp[0]), "r" (&win64tmp[16]),        \
62                         "r" (tmp0), "r" (tmp1)                          \
63                       : "memory");                                      \
64    } while (0)
65 #else
66 # define shaext_prepare_variable
67 # define shaext_prepare_variable_size 0
68 # define shaext_prepare() do { } while (0)
69 # define shaext_cleanup(tmp0,tmp1)                                      \
70    do { asm volatile ("pxor %%xmm0, %%xmm0\n"                           \
71                       "pxor %%xmm1, %%xmm1\n"                           \
72                       "pxor %%xmm2, %%xmm2\n"                           \
73                       "pxor %%xmm3, %%xmm3\n"                           \
74                       "pxor %%xmm4, %%xmm4\n"                           \
75                       "pxor %%xmm5, %%xmm5\n"                           \
76                       "pxor %%xmm6, %%xmm6\n"                           \
77                       "pxor %%xmm7, %%xmm7\n"                           \
78                       "movdqa %%xmm0, (%0)\n\t"                         \
79                       "movdqa %%xmm0, (%1)\n\t"                         \
80                       :                                                 \
81                       : "r" (tmp0), "r" (tmp1)                          \
82                       : "memory");                                      \
83    } while (0)
84 #endif
85
86 typedef struct u128_s
87 {
88   u32 a, b, c, d;
89 } u128_t;
90
91 /*
92  * Transform nblks*64 bytes (nblks*16 32-bit words) at DATA.
93  */
94 unsigned int
95 _gcry_sha256_transform_intel_shaext(u32 state[8], const unsigned char *data,
96                                     size_t nblks)
97 {
98   static const unsigned char bshuf_mask[16] __attribute__ ((aligned (16))) =
99     { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 };
100   static const u128_t K[16] __attribute__ ((aligned (16))) =
101   {
102     { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5 },
103     { 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5 },
104     { 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3 },
105     { 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174 },
106     { 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc },
107     { 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da },
108     { 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7 },
109     { 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967 },
110     { 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13 },
111     { 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85 },
112     { 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3 },
113     { 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070 },
114     { 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5 },
115     { 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3 },
116     { 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208 },
117     { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }
118   };
119   char save_buf[2 * 16 + 15];
120   char *abef_save;
121   char *cdgh_save;
122   shaext_prepare_variable;
123
124   if (nblks == 0)
125     return 0;
126
127   shaext_prepare ();
128
129   asm volatile ("" : "=r" (abef_save) : "0" (save_buf) : "memory");
130   abef_save = abef_save + (-(uintptr_t)abef_save & 15);
131   cdgh_save = abef_save + 16;
132
133   /* byteswap mask => XMM7 */
134   asm volatile ("movdqa %[mask], %%xmm7\n\t" /* Preload mask */
135                 :
136                 : [mask] "m" (*bshuf_mask)
137                 : "memory");
138
139   /* Load state.. ABEF_SAVE => STATE0 XMM1, CDGH_STATE => STATE1 XMM2 */
140   asm volatile ("movups 16(%[state]), %%xmm1\n\t" /* HGFE (xmm=EFGH) */
141                 "movups  0(%[state]), %%xmm0\n\t" /* DCBA (xmm=ABCD) */
142                 "movaps %%xmm1, %%xmm2\n\t"
143                 "shufps $0x11, %%xmm0, %%xmm1\n\t" /* ABEF (xmm=FEBA) */
144                 "shufps $0xbb, %%xmm0, %%xmm2\n\t" /* CDGH (xmm=HGDC) */
145                 :
146                 : [state] "r" (state)
147                 : "memory" );
148
149   /* Load message */
150   asm volatile ("movdqu 0*16(%[data]), %%xmm3\n\t"
151                 "movdqu 1*16(%[data]), %%xmm4\n\t"
152                 "movdqu 2*16(%[data]), %%xmm5\n\t"
153                 "movdqu 3*16(%[data]), %%xmm6\n\t"
154                 "pshufb %%xmm7, %%xmm3\n\t"
155                 "pshufb %%xmm7, %%xmm4\n\t"
156                 "pshufb %%xmm7, %%xmm5\n\t"
157                 "pshufb %%xmm7, %%xmm6\n\t"
158                 :
159                 : [data] "r" (data)
160                 : "memory" );
161   data += 64;
162
163   do
164     {
165       /* Save state */
166       asm volatile ("movdqa %%xmm1, (%[abef_save])\n\t"
167                     "movdqa %%xmm2, (%[cdgh_save])\n\t"
168                     :
169                     : [abef_save] "r" (abef_save), [cdgh_save] "r" (cdgh_save)
170                     : "memory" );
171
172       /* Round 0..3 */
173       asm volatile ("movdqa %%xmm3, %%xmm0\n\t"
174                       "paddd %[constants], %%xmm0\n\t"
175                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
176                       "psrldq $8, %%xmm0\n\t"
177                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
178                     :
179                     : [constants] "m" (K[0].a)
180                     : "memory" );
181
182       /* Round 4..7 */
183       asm volatile ("movdqa %%xmm4, %%xmm0\n\t"
184                       "paddd %[constants], %%xmm0\n\t"
185                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
186                       "psrldq $8, %%xmm0\n\t"
187                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
188                     "sha256msg1 %%xmm4, %%xmm3\n\t"
189                     :
190                     : [constants] "m" (K[1].a)
191                     : "memory" );
192
193       /* Round 8..11 */
194       asm volatile ("movdqa %%xmm5, %%xmm0\n\t"
195                       "paddd %[constants], %%xmm0\n\t"
196                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
197                       "psrldq $8, %%xmm0\n\t"
198                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
199                     "sha256msg1 %%xmm5, %%xmm4\n\t"
200                     :
201                     : [constants] "m" (K[2].a)
202                     : "memory" );
203
204 #define ROUND(k, MSG0, MSG1, MSG2, MSG3) \
205       asm volatile ("movdqa %%"MSG0", %%xmm0\n\t" \
206                       "paddd %[constants], %%xmm0\n\t" \
207                       "sha256rnds2 %%xmm1, %%xmm2\n\t" \
208                     "movdqa %%"MSG0", %%xmm7\n\t" \
209                     "palignr $4, %%"MSG3", %%xmm7\n\t" \
210                     "paddd %%xmm7, %%"MSG1"\n\t" \
211                     "sha256msg2 %%"MSG0", %%"MSG1"\n\t" \
212                       "psrldq $8, %%xmm0\n\t" \
213                       "sha256rnds2 %%xmm2, %%xmm1\n\t" \
214                     "sha256msg1 %%"MSG0", %%"MSG3"\n\t" \
215                     : \
216                     : [constants] "m" (K[k].a) \
217                     : "memory" )
218
219       /* Rounds 12..15 to 48..51 */
220       ROUND(3, "xmm6", "xmm3", "xmm4", "xmm5");
221       ROUND(4, "xmm3", "xmm4", "xmm5", "xmm6");
222       ROUND(5, "xmm4", "xmm5", "xmm6", "xmm3");
223       ROUND(6, "xmm5", "xmm6", "xmm3", "xmm4");
224       ROUND(7, "xmm6", "xmm3", "xmm4", "xmm5");
225       ROUND(8, "xmm3", "xmm4", "xmm5", "xmm6");
226       ROUND(9, "xmm4", "xmm5", "xmm6", "xmm3");
227       ROUND(10, "xmm5", "xmm6", "xmm3", "xmm4");
228       ROUND(11, "xmm6", "xmm3", "xmm4", "xmm5");
229       ROUND(12, "xmm3", "xmm4", "xmm5", "xmm6");
230
231       if (--nblks == 0)
232         break;
233
234       /* Round 52..55 */
235       asm volatile ("movdqa %%xmm4, %%xmm0\n\t"
236                       "paddd %[constants], %%xmm0\n\t"
237                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
238                     "movdqa %%xmm4, %%xmm7\n\t"
239                     "palignr $4, %%xmm3, %%xmm7\n\t"
240                     "movdqu 0*16(%[data]), %%xmm3\n\t"
241                     "paddd %%xmm7, %%xmm5\n\t"
242                     "sha256msg2 %%xmm4, %%xmm5\n\t"
243                       "psrldq $8, %%xmm0\n\t"
244                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
245                     :
246                     : [constants] "m" (K[13].a), [data] "r" (data)
247                     : "memory" );
248
249       /* Round 56..59 */
250       asm volatile ("movdqa %%xmm5, %%xmm0\n\t"
251                       "paddd %[constants], %%xmm0\n\t"
252                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
253                     "movdqa %%xmm5, %%xmm7\n\t"
254                     "palignr $4, %%xmm4, %%xmm7\n\t"
255                     "movdqu 1*16(%[data]), %%xmm4\n\t"
256                     "paddd %%xmm7, %%xmm6\n\t"
257                     "movdqa %[mask], %%xmm7\n\t" /* Reload mask */
258                     "sha256msg2 %%xmm5, %%xmm6\n\t"
259                     "movdqu 2*16(%[data]), %%xmm5\n\t"
260                       "psrldq $8, %%xmm0\n\t"
261                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
262                     :
263                     : [constants] "m" (K[14].a), [mask] "m" (*bshuf_mask),
264                       [data] "r" (data)
265                     : "memory" );
266
267       /* Round 60..63 */
268       asm volatile ("movdqa %%xmm6, %%xmm0\n\t"
269                     "pshufb %%xmm7, %%xmm3\n\t"
270                     "movdqu 3*16(%[data]), %%xmm6\n\t"
271                       "paddd %[constants], %%xmm0\n\t"
272                     "pshufb %%xmm7, %%xmm4\n\t"
273                       "sha256rnds2 %%xmm1, %%xmm2\n\t"
274                       "psrldq $8, %%xmm0\n\t"
275                     "pshufb %%xmm7, %%xmm5\n\t"
276                       "sha256rnds2 %%xmm2, %%xmm1\n\t"
277                     :
278                     : [constants] "m" (K[15].a), [data] "r" (data)
279                     : "memory" );
280       data += 64;
281
282       /* Merge states */
283       asm volatile ("paddd (%[abef_save]), %%xmm1\n\t"
284                     "paddd (%[cdgh_save]), %%xmm2\n\t"
285                     "pshufb %%xmm7, %%xmm6\n\t"
286                     :
287                     : [abef_save] "r" (abef_save), [cdgh_save] "r" (cdgh_save)
288                     : "memory" );
289     }
290   while (1);
291
292   /* Round 52..55 */
293   asm volatile ("movdqa %%xmm4, %%xmm0\n\t"
294                   "paddd %[constants], %%xmm0\n\t"
295                   "sha256rnds2 %%xmm1, %%xmm2\n\t"
296                 "movdqa %%xmm4, %%xmm7\n\t"
297                 "palignr $4, %%xmm3, %%xmm7\n\t"
298                 "paddd %%xmm7, %%xmm5\n\t"
299                 "sha256msg2 %%xmm4, %%xmm5\n\t"
300                   "psrldq $8, %%xmm0\n\t"
301                   "sha256rnds2 %%xmm2, %%xmm1\n\t"
302                 :
303                 : [constants] "m" (K[13].a)
304                 : "memory" );
305
306   /* Round 56..59 */
307   asm volatile ("movdqa %%xmm5, %%xmm0\n\t"
308                   "paddd %[constants], %%xmm0\n\t"
309                   "sha256rnds2 %%xmm1, %%xmm2\n\t"
310                 "movdqa %%xmm5, %%xmm7\n\t"
311                 "palignr $4, %%xmm4, %%xmm7\n\t"
312                 "paddd %%xmm7, %%xmm6\n\t"
313                 "movdqa %[mask], %%xmm7\n\t" /* Reload mask */
314                 "sha256msg2 %%xmm5, %%xmm6\n\t"
315                   "psrldq $8, %%xmm0\n\t"
316                   "sha256rnds2 %%xmm2, %%xmm1\n\t"
317                 :
318                 : [constants] "m" (K[14].a), [mask] "m" (*bshuf_mask)
319                 : "memory" );
320
321   /* Round 60..63 */
322   asm volatile ("movdqa %%xmm6, %%xmm0\n\t"
323                   "paddd %[constants], %%xmm0\n\t"
324                   "sha256rnds2 %%xmm1, %%xmm2\n\t"
325                   "psrldq $8, %%xmm0\n\t"
326                   "sha256rnds2 %%xmm2, %%xmm1\n\t"
327                 :
328                 : [constants] "m" (K[15].a)
329                 : "memory" );
330
331   /* Merge states */
332   asm volatile ("paddd (%[abef_save]), %%xmm1\n\t"
333                 "paddd (%[cdgh_save]), %%xmm2\n\t"
334                 :
335                 : [abef_save] "r" (abef_save), [cdgh_save] "r" (cdgh_save)
336                 : "memory" );
337
338   /* Save state (XMM1=FEBA, XMM2=HGDC) */
339   asm volatile ("movaps %%xmm1, %%xmm0\n\t"
340                 "shufps $0x11, %%xmm2, %%xmm1\n\t" /* xmm=ABCD */
341                 "shufps $0xbb, %%xmm2, %%xmm0\n\t" /* xmm=EFGH */
342                 "movups %%xmm1, 16(%[state])\n\t"
343                 "movups %%xmm0,  0(%[state])\n\t"
344                 :
345                 : [state] "r" (state)
346                 : "memory" );
347
348   shaext_cleanup (abef_save, cdgh_save);
349   return 0;
350 }
351
352 #endif /* HAVE_GCC_INLINE_ASM_SHA_EXT */