5a2349e1e454e9c1c65bc83f8c775a55ecc52f31
[libgcrypt.git] / cipher / sha1-intel-shaext.c
1 /* sha1-intel-shaext.S - SHAEXT accelerated SHA-1 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_SHA1) && \
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 /*
87  * Transform nblks*64 bytes (nblks*16 32-bit words) at DATA.
88  */
89 unsigned int
90 _gcry_sha1_transform_intel_shaext(void *state, const unsigned char *data,
91                                   size_t nblks)
92 {
93   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
94     { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
95   char save_buf[2 * 16 + 15];
96   char *abcd_save;
97   char *e_save;
98   shaext_prepare_variable;
99
100   if (nblks == 0)
101     return 0;
102
103   shaext_prepare ();
104
105   asm volatile ("" : "=r" (abcd_save) : "0" (save_buf) : "memory");
106   abcd_save = abcd_save + (-(uintptr_t)abcd_save & 15);
107   e_save = abcd_save + 16;
108
109   /* byteswap mask => XMM7 */
110   asm volatile ("movdqa %[mask], %%xmm7\n\t" /* Preload mask */
111                 :
112                 : [mask] "m" (*be_mask)
113                 : "memory");
114
115   /* Load state.. ABCD => XMM4, E => XMM5 */
116   asm volatile ("movd 16(%[state]), %%xmm5\n\t"
117                 "movdqu (%[state]), %%xmm4\n\t"
118                 "pslldq $12, %%xmm5\n\t"
119                 "pshufd $0x1b, %%xmm4, %%xmm4\n\t"
120                 "movdqa %%xmm5, (%[e_save])\n\t"
121                 "movdqa %%xmm4, (%[abcd_save])\n\t"
122                 :
123                 : [state] "r" (state), [abcd_save] "r" (abcd_save),
124                   [e_save] "r" (e_save)
125                 : "memory" );
126
127   /* DATA => XMM[0..4] */
128   asm volatile ("movdqu 0(%[data]), %%xmm0\n\t"
129                 "movdqu 16(%[data]), %%xmm1\n\t"
130                 "movdqu 32(%[data]), %%xmm2\n\t"
131                 "movdqu 48(%[data]), %%xmm3\n\t"
132                 "pshufb %%xmm7, %%xmm0\n\t"
133                 "pshufb %%xmm7, %%xmm1\n\t"
134                 "pshufb %%xmm7, %%xmm2\n\t"
135                 "pshufb %%xmm7, %%xmm3\n\t"
136                 :
137                 : [data] "r" (data)
138                 : "memory" );
139   data += 64;
140
141   while (1)
142     {
143       /* Round 0..3 */
144       asm volatile ("paddd %%xmm0, %%xmm5\n\t"
145                     "movdqa %%xmm4, %%xmm6\n\t" /* ABCD => E1 */
146                     "sha1rnds4 $0, %%xmm5, %%xmm4\n\t"
147                     ::: "memory" );
148
149       /* Round 4..7 */
150       asm volatile ("sha1nexte %%xmm1, %%xmm6\n\t"
151                     "movdqa %%xmm4, %%xmm5\n\t"
152                     "sha1rnds4 $0, %%xmm6, %%xmm4\n\t"
153                     "sha1msg1 %%xmm1, %%xmm0\n\t"
154                     ::: "memory" );
155
156       /* Round 8..11 */
157       asm volatile ("sha1nexte %%xmm2, %%xmm5\n\t"
158                     "movdqa %%xmm4, %%xmm6\n\t"
159                     "sha1rnds4 $0, %%xmm5, %%xmm4\n\t"
160                     "sha1msg1 %%xmm2, %%xmm1\n\t"
161                     "pxor %%xmm2, %%xmm0\n\t"
162                     ::: "memory" );
163
164 #define ROUND(imm, E0, E1, MSG0, MSG1, MSG2, MSG3) \
165       asm volatile ("sha1nexte %%"MSG0", %%"E0"\n\t" \
166                     "movdqa %%xmm4, %%"E1"\n\t" \
167                     "sha1msg2 %%"MSG0", %%"MSG1"\n\t" \
168                     "sha1rnds4 $"imm", %%"E0", %%xmm4\n\t" \
169                     "sha1msg1 %%"MSG0", %%"MSG3"\n\t" \
170                     "pxor %%"MSG0", %%"MSG2"\n\t" \
171                     ::: "memory" )
172
173       /* Rounds 12..15 to 64..67 */
174       ROUND("0", "xmm6", "xmm5", "xmm3", "xmm0", "xmm1", "xmm2");
175       ROUND("0", "xmm5", "xmm6", "xmm0", "xmm1", "xmm2", "xmm3");
176       ROUND("1", "xmm6", "xmm5", "xmm1", "xmm2", "xmm3", "xmm0");
177       ROUND("1", "xmm5", "xmm6", "xmm2", "xmm3", "xmm0", "xmm1");
178       ROUND("1", "xmm6", "xmm5", "xmm3", "xmm0", "xmm1", "xmm2");
179       ROUND("1", "xmm5", "xmm6", "xmm0", "xmm1", "xmm2", "xmm3");
180       ROUND("1", "xmm6", "xmm5", "xmm1", "xmm2", "xmm3", "xmm0");
181       ROUND("2", "xmm5", "xmm6", "xmm2", "xmm3", "xmm0", "xmm1");
182       ROUND("2", "xmm6", "xmm5", "xmm3", "xmm0", "xmm1", "xmm2");
183       ROUND("2", "xmm5", "xmm6", "xmm0", "xmm1", "xmm2", "xmm3");
184       ROUND("2", "xmm6", "xmm5", "xmm1", "xmm2", "xmm3", "xmm0");
185       ROUND("2", "xmm5", "xmm6", "xmm2", "xmm3", "xmm0", "xmm1");
186       ROUND("3", "xmm6", "xmm5", "xmm3", "xmm0", "xmm1", "xmm2");
187       ROUND("3", "xmm5", "xmm6", "xmm0", "xmm1", "xmm2", "xmm3");
188
189       if (--nblks == 0)
190         break;
191
192       /* Round 68..71 */
193       asm volatile ("movdqu 0(%[data]), %%xmm0\n\t"
194                     "sha1nexte %%xmm1, %%xmm6\n\t"
195                     "movdqa %%xmm4, %%xmm5\n\t"
196                     "sha1msg2 %%xmm1, %%xmm2\n\t"
197                     "sha1rnds4 $3, %%xmm6, %%xmm4\n\t"
198                     "pxor %%xmm1, %%xmm3\n\t"
199                     "pshufb %%xmm7, %%xmm0\n\t"
200                     :
201                     : [data] "r" (data)
202                     : "memory" );
203
204       /* Round 72..75 */
205       asm volatile ("movdqu 16(%[data]), %%xmm1\n\t"
206                     "sha1nexte %%xmm2, %%xmm5\n\t"
207                     "movdqa %%xmm4, %%xmm6\n\t"
208                     "sha1msg2 %%xmm2, %%xmm3\n\t"
209                     "sha1rnds4 $3, %%xmm5, %%xmm4\n\t"
210                     "pshufb %%xmm7, %%xmm1\n\t"
211                     :
212                     : [data] "r" (data)
213                     : "memory" );
214
215       /* Round 76..79 */
216       asm volatile ("movdqu 32(%[data]), %%xmm2\n\t"
217                     "sha1nexte %%xmm3, %%xmm6\n\t"
218                     "movdqa %%xmm4, %%xmm5\n\t"
219                     "sha1rnds4 $3, %%xmm6, %%xmm4\n\t"
220                     "pshufb %%xmm7, %%xmm2\n\t"
221                     :
222                     : [data] "r" (data)
223                     : "memory" );
224
225       /* Merge states, store current. */
226       asm volatile ("movdqu 48(%[data]), %%xmm3\n\t"
227                     "sha1nexte (%[e_save]), %%xmm5\n\t"
228                     "paddd (%[abcd_save]), %%xmm4\n\t"
229                     "pshufb %%xmm7, %%xmm3\n\t"
230                     "movdqa %%xmm5, (%[e_save])\n\t"
231                     "movdqa %%xmm4, (%[abcd_save])\n\t"
232                     :
233                     : [abcd_save] "r" (abcd_save), [e_save] "r" (e_save),
234                       [data] "r" (data)
235                     : "memory" );
236
237       data += 64;
238     }
239
240   /* Round 68..71 */
241   asm volatile ("sha1nexte %%xmm1, %%xmm6\n\t"
242                 "movdqa %%xmm4, %%xmm5\n\t"
243                 "sha1msg2 %%xmm1, %%xmm2\n\t"
244                 "sha1rnds4 $3, %%xmm6, %%xmm4\n\t"
245                 "pxor %%xmm1, %%xmm3\n\t"
246                 ::: "memory" );
247
248   /* Round 72..75 */
249   asm volatile ("sha1nexte %%xmm2, %%xmm5\n\t"
250                 "movdqa %%xmm4, %%xmm6\n\t"
251                 "sha1msg2 %%xmm2, %%xmm3\n\t"
252                 "sha1rnds4 $3, %%xmm5, %%xmm4\n\t"
253                 ::: "memory" );
254
255   /* Round 76..79 */
256   asm volatile ("sha1nexte %%xmm3, %%xmm6\n\t"
257                 "movdqa %%xmm4, %%xmm5\n\t"
258                 "sha1rnds4 $3, %%xmm6, %%xmm4\n\t"
259                 ::: "memory" );
260
261   /* Merge states. */
262   asm volatile ("sha1nexte (%[e_save]), %%xmm5\n\t"
263                 "paddd (%[abcd_save]), %%xmm4\n\t"
264                 :
265                 : [abcd_save] "r" (abcd_save), [e_save] "r" (e_save)
266                 : "memory" );
267
268   /* Save state */
269   asm volatile ("pshufd $0x1b, %%xmm4, %%xmm4\n\t"
270                 "psrldq $12, %%xmm5\n\t"
271                 "movdqu %%xmm4, (%[state])\n\t"
272                 "movd %%xmm5, 16(%[state])\n\t"
273                 :
274                 : [state] "r" (state)
275                 : "memory" );
276
277   shaext_cleanup (abcd_save, e_save);
278   return 0;
279 }
280
281 #endif /* HAVE_GCC_INLINE_ASM_SHA_EXT */