build: Fix build with !HAVE_PTHREAD
[libgcrypt.git] / cipher / rijndael-ssse3-amd64.c
1 /* SSSE3 vector permutation AES for Libgcrypt
2  * Copyright (C) 2014-2017 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  * The code is based on the public domain library libvpaes version 0.5
21  * available at http://crypto.stanford.edu/vpaes/ and which carries
22  * this notice:
23  *
24  *     libvpaes: constant-time SSSE3 AES encryption and decryption.
25  *     version 0.5
26  *
27  *     By Mike Hamburg, Stanford University, 2009.  Public domain.
28  *     I wrote essentially all of this code.  I did not write the test
29  *     vectors; they are the NIST known answer tests.  I hereby release all
30  *     the code and documentation here that I wrote into the public domain.
31  *
32  *     This is an implementation of AES following my paper,
33  *       "Accelerating AES with Vector Permute Instructions"
34  *       CHES 2009; http://shiftleft.org/papers/vector_aes/
35  */
36
37 #include <config.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h> /* for memcmp() */
41
42 #include "types.h"  /* for byte and u32 typedefs */
43 #include "g10lib.h"
44 #include "cipher.h"
45 #include "bufhelp.h"
46 #include "cipher-selftest.h"
47 #include "rijndael-internal.h"
48 #include "./cipher-internal.h"
49
50
51 #ifdef USE_SSSE3
52
53
54 #if _GCRY_GCC_VERSION >= 40400 /* 4.4 */
55 /* Prevent compiler from issuing SSE instructions between asm blocks. */
56 #  pragma GCC target("no-sse")
57 #endif
58 #if __clang__
59 #  pragma clang attribute push (__attribute__((target("no-sse"))), apply_to = function)
60 #endif
61
62
63 #define ALWAYS_INLINE inline __attribute__((always_inline))
64 #define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function))
65
66 #define ASM_FUNC_ATTR        NO_INSTRUMENT_FUNCTION
67 #define ASM_FUNC_ATTR_INLINE ASM_FUNC_ATTR ALWAYS_INLINE
68
69
70 /* Copy of ocb_get_l needed here as GCC is unable to inline ocb_get_l
71    because of 'pragma target'. */
72 static ASM_FUNC_ATTR_INLINE const unsigned char *
73 aes_ocb_get_l (gcry_cipher_hd_t c, u64 n)
74 {
75   unsigned long ntz;
76
77   /* Assumes that N != 0. */
78   asm ("rep;bsfl %k[low], %k[ntz]\n\t"
79         : [ntz] "=r" (ntz)
80         : [low] "r" ((unsigned long)n)
81         : "cc");
82
83   return c->u_mode.ocb.L[ntz];
84 }
85
86
87 /* Assembly functions in rijndael-ssse3-amd64-asm.S. Note that these
88    have custom calling convention (additional XMM parameters). */
89 extern void _gcry_aes_ssse3_enc_preload(void);
90 extern void _gcry_aes_ssse3_dec_preload(void);
91 extern void _gcry_aes_ssse3_schedule_core(const void *key, u64 keybits,
92                                           void *buffer, u64 decrypt,
93                                           u64 rotoffs);
94 extern void _gcry_aes_ssse3_encrypt_core(const void *key, u64 nrounds);
95 extern void _gcry_aes_ssse3_decrypt_core(const void *key, u64 nrounds);
96
97
98
99 /* Two macros to be called prior and after the use of SSSE3
100    instructions.  There should be no external function calls between
101    the use of these macros.  There purpose is to make sure that the
102    SSE registers are cleared and won't reveal any information about
103    the key or the data.  */
104 #ifdef HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS
105 # define SSSE3_STATE_SIZE (16 * 10)
106 /* XMM6-XMM15 are callee-saved registers on WIN64. */
107 # define vpaes_ssse3_prepare() \
108     asm volatile ("movdqu %%xmm6,  0*16(%0)\n\t" \
109                   "movdqu %%xmm7,  1*16(%0)\n\t" \
110                   "movdqu %%xmm8,  2*16(%0)\n\t" \
111                   "movdqu %%xmm9,  3*16(%0)\n\t" \
112                   "movdqu %%xmm10, 4*16(%0)\n\t" \
113                   "movdqu %%xmm11, 5*16(%0)\n\t" \
114                   "movdqu %%xmm12, 6*16(%0)\n\t" \
115                   "movdqu %%xmm13, 7*16(%0)\n\t" \
116                   "movdqu %%xmm14, 8*16(%0)\n\t" \
117                   "movdqu %%xmm15, 9*16(%0)\n\t" \
118                   : \
119                   : "r" (ssse3_state) \
120                   : "memory" )
121 # define vpaes_ssse3_cleanup() \
122     asm volatile ("pxor %%xmm0,  %%xmm0 \n\t" \
123                   "pxor %%xmm1,  %%xmm1 \n\t" \
124                   "pxor %%xmm2,  %%xmm2 \n\t" \
125                   "pxor %%xmm3,  %%xmm3 \n\t" \
126                   "pxor %%xmm4,  %%xmm4 \n\t" \
127                   "pxor %%xmm5,  %%xmm5 \n\t" \
128                   "movdqu 0*16(%0), %%xmm6 \n\t" \
129                   "movdqu 1*16(%0), %%xmm7 \n\t" \
130                   "movdqu 2*16(%0), %%xmm8 \n\t" \
131                   "movdqu 3*16(%0), %%xmm9 \n\t" \
132                   "movdqu 4*16(%0), %%xmm10 \n\t" \
133                   "movdqu 5*16(%0), %%xmm11 \n\t" \
134                   "movdqu 6*16(%0), %%xmm12 \n\t" \
135                   "movdqu 7*16(%0), %%xmm13 \n\t" \
136                   "movdqu 8*16(%0), %%xmm14 \n\t" \
137                   "movdqu 9*16(%0), %%xmm15 \n\t" \
138                   : \
139                   : "r" (ssse3_state) \
140                   : "memory" )
141 #else
142 # define SSSE3_STATE_SIZE 1
143 # define vpaes_ssse3_prepare() (void)ssse3_state
144 # define vpaes_ssse3_cleanup() \
145     asm volatile ("pxor %%xmm0,  %%xmm0 \n\t" \
146                   "pxor %%xmm1,  %%xmm1 \n\t" \
147                   "pxor %%xmm2,  %%xmm2 \n\t" \
148                   "pxor %%xmm3,  %%xmm3 \n\t" \
149                   "pxor %%xmm4,  %%xmm4 \n\t" \
150                   "pxor %%xmm5,  %%xmm5 \n\t" \
151                   "pxor %%xmm6,  %%xmm6 \n\t" \
152                   "pxor %%xmm7,  %%xmm7 \n\t" \
153                   "pxor %%xmm8,  %%xmm8 \n\t" \
154                   ::: "memory" )
155 #endif
156
157 #define vpaes_ssse3_prepare_enc() \
158     vpaes_ssse3_prepare(); \
159     _gcry_aes_ssse3_enc_preload();
160
161 #define vpaes_ssse3_prepare_dec() \
162     vpaes_ssse3_prepare(); \
163     _gcry_aes_ssse3_dec_preload();
164
165
166 void ASM_FUNC_ATTR
167 _gcry_aes_ssse3_do_setkey (RIJNDAEL_context *ctx, const byte *key)
168 {
169   unsigned int keybits = (ctx->rounds - 10) * 32 + 128;
170   byte ssse3_state[SSSE3_STATE_SIZE];
171
172   vpaes_ssse3_prepare();
173
174   _gcry_aes_ssse3_schedule_core(key, keybits, &ctx->keyschenc32[0][0], 0, 48);
175
176   /* Save key for setting up decryption. */
177   if (keybits > 192)
178     asm volatile ("movdqu   (%[src]), %%xmm0\n\t"
179                   "movdqu 16(%[src]), %%xmm1\n\t"
180                   "movdqu %%xmm0,   (%[dst])\n\t"
181                   "movdqu %%xmm1, 16(%[dst])\n\t"
182                   : /* No output */
183                   : [dst] "r" (&ctx->keyschdec32[0][0]), [src] "r" (key)
184                   : "memory" );
185   else if (keybits == 192)
186     asm volatile ("movdqu   (%[src]), %%xmm0\n\t"
187                   "movq   16(%[src]), %%xmm1\n\t"
188                   "movdqu %%xmm0,   (%[dst])\n\t"
189                   "movq   %%xmm1, 16(%[dst])\n\t"
190                   : /* No output */
191                   : [dst] "r" (&ctx->keyschdec32[0][0]), [src] "r" (key)
192                   : "memory" );
193   else
194     asm volatile ("movdqu (%[src]), %%xmm0\n\t"
195                   "movdqu %%xmm0, (%[dst])\n\t"
196                   : /* No output */
197                   : [dst] "r" (&ctx->keyschdec32[0][0]), [src] "r" (key)
198                   : "memory" );
199
200   vpaes_ssse3_cleanup();
201 }
202
203
204 /* Make a decryption key from an encryption key. */
205 static ASM_FUNC_ATTR_INLINE void
206 do_ssse3_prepare_decryption (RIJNDAEL_context *ctx,
207                              byte ssse3_state[SSSE3_STATE_SIZE])
208 {
209   unsigned int keybits = (ctx->rounds - 10) * 32 + 128;
210
211   vpaes_ssse3_prepare();
212
213   _gcry_aes_ssse3_schedule_core(&ctx->keyschdec32[0][0], keybits,
214                                 &ctx->keyschdec32[ctx->rounds][0], 1,
215                                 (keybits == 192) ? 0 : 32);
216
217   vpaes_ssse3_cleanup();
218 }
219
220 void ASM_FUNC_ATTR
221 _gcry_aes_ssse3_prepare_decryption (RIJNDAEL_context *ctx)
222 {
223   byte ssse3_state[SSSE3_STATE_SIZE];
224
225   do_ssse3_prepare_decryption(ctx, ssse3_state);
226 }
227
228
229 /* Encrypt one block using the Intel SSSE3 instructions.  Block is input
230 * and output through SSE register xmm0. */
231 static ASM_FUNC_ATTR_INLINE void
232 do_vpaes_ssse3_enc (const RIJNDAEL_context *ctx, unsigned int nrounds)
233 {
234   _gcry_aes_ssse3_encrypt_core(ctx->keyschenc32, nrounds);
235 }
236
237
238 /* Decrypt one block using the Intel SSSE3 instructions.  Block is input
239 * and output through SSE register xmm0. */
240 static ASM_FUNC_ATTR_INLINE void
241 do_vpaes_ssse3_dec (const RIJNDAEL_context *ctx, unsigned int nrounds)
242 {
243   _gcry_aes_ssse3_decrypt_core(ctx->keyschdec32, nrounds);
244 }
245
246
247 unsigned int ASM_FUNC_ATTR
248 _gcry_aes_ssse3_encrypt (const RIJNDAEL_context *ctx, unsigned char *dst,
249                         const unsigned char *src)
250 {
251   unsigned int nrounds = ctx->rounds;
252   byte ssse3_state[SSSE3_STATE_SIZE];
253
254   vpaes_ssse3_prepare_enc ();
255   asm volatile ("movdqu %[src], %%xmm0\n\t"
256                 :
257                 : [src] "m" (*src)
258                 : "memory" );
259   do_vpaes_ssse3_enc (ctx, nrounds);
260   asm volatile ("movdqu %%xmm0, %[dst]\n\t"
261                 : [dst] "=m" (*dst)
262                 :
263                 : "memory" );
264   vpaes_ssse3_cleanup ();
265   return 0;
266 }
267
268
269 void ASM_FUNC_ATTR
270 _gcry_aes_ssse3_cfb_enc (RIJNDAEL_context *ctx, unsigned char *iv,
271                          unsigned char *outbuf, const unsigned char *inbuf,
272                          size_t nblocks)
273 {
274   unsigned int nrounds = ctx->rounds;
275   byte ssse3_state[SSSE3_STATE_SIZE];
276
277   vpaes_ssse3_prepare_enc ();
278
279   asm volatile ("movdqu %[iv], %%xmm0\n\t"
280                 : /* No output */
281                 : [iv] "m" (*iv)
282                 : "memory" );
283
284   for ( ;nblocks; nblocks-- )
285     {
286       do_vpaes_ssse3_enc (ctx, nrounds);
287
288       asm volatile ("movdqu %[inbuf], %%xmm1\n\t"
289                     "pxor %%xmm1, %%xmm0\n\t"
290                     "movdqu %%xmm0, %[outbuf]\n\t"
291                     : [outbuf] "=m" (*outbuf)
292                     : [inbuf] "m" (*inbuf)
293                     : "memory" );
294
295       outbuf += BLOCKSIZE;
296       inbuf  += BLOCKSIZE;
297     }
298
299   asm volatile ("movdqu %%xmm0, %[iv]\n\t"
300                 : [iv] "=m" (*iv)
301                 :
302                 : "memory" );
303
304   vpaes_ssse3_cleanup ();
305 }
306
307
308 void ASM_FUNC_ATTR
309 _gcry_aes_ssse3_cbc_enc (RIJNDAEL_context *ctx, unsigned char *iv,
310                          unsigned char *outbuf, const unsigned char *inbuf,
311                          size_t nblocks, int cbc_mac)
312 {
313   unsigned int nrounds = ctx->rounds;
314   byte ssse3_state[SSSE3_STATE_SIZE];
315
316   vpaes_ssse3_prepare_enc ();
317
318   asm volatile ("movdqu %[iv], %%xmm7\n\t"
319                 : /* No output */
320                 : [iv] "m" (*iv)
321                 : "memory" );
322
323   for ( ;nblocks; nblocks-- )
324     {
325       asm volatile ("movdqu %[inbuf], %%xmm0\n\t"
326                     "pxor %%xmm7, %%xmm0\n\t"
327                     : /* No output */
328                     : [inbuf] "m" (*inbuf)
329                     : "memory" );
330
331       do_vpaes_ssse3_enc (ctx, nrounds);
332
333       asm volatile ("movdqa %%xmm0, %%xmm7\n\t"
334                     "movdqu %%xmm0, %[outbuf]\n\t"
335                     : [outbuf] "=m" (*outbuf)
336                     :
337                     : "memory" );
338
339       inbuf += BLOCKSIZE;
340       if (!cbc_mac)
341         outbuf += BLOCKSIZE;
342     }
343
344   asm volatile ("movdqu %%xmm7, %[iv]\n\t"
345                 : [iv] "=m" (*iv)
346                 :
347                 : "memory" );
348
349   vpaes_ssse3_cleanup ();
350 }
351
352
353 void ASM_FUNC_ATTR
354 _gcry_aes_ssse3_ctr_enc (RIJNDAEL_context *ctx, unsigned char *ctr,
355                          unsigned char *outbuf, const unsigned char *inbuf,
356                          size_t nblocks)
357 {
358   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
359     { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
360   unsigned int nrounds = ctx->rounds;
361   byte ssse3_state[SSSE3_STATE_SIZE];
362   u64 ctrlow;
363
364   vpaes_ssse3_prepare_enc ();
365
366   asm volatile ("movdqa %[mask], %%xmm6\n\t" /* Preload mask */
367                 "movdqa (%[ctr]), %%xmm7\n\t"  /* Preload CTR */
368                 "movq 8(%[ctr]), %q[ctrlow]\n\t"
369                 "bswapq %q[ctrlow]\n\t"
370                 : [ctrlow] "=r" (ctrlow)
371                 : [mask] "m" (*be_mask),
372                   [ctr] "r" (ctr)
373                 : "memory", "cc");
374
375   for ( ;nblocks; nblocks-- )
376     {
377       asm volatile ("movdqa %%xmm7, %%xmm0\n\t"     /* xmm0 := CTR (xmm7)  */
378                     "pcmpeqd %%xmm1, %%xmm1\n\t"
379                     "psrldq $8, %%xmm1\n\t"         /* xmm1 = -1 */
380
381                     "pshufb %%xmm6, %%xmm7\n\t"
382                     "psubq  %%xmm1, %%xmm7\n\t"     /* xmm7++ (big endian) */
383
384                     /* detect if 64-bit carry handling is needed */
385                     "incq   %q[ctrlow]\n\t"
386                     "jnz    .Lno_carry%=\n\t"
387
388                     "pslldq $8, %%xmm1\n\t"         /* move lower 64-bit to high */
389                     "psubq   %%xmm1, %%xmm7\n\t"    /* add carry to upper 64bits */
390
391                     ".Lno_carry%=:\n\t"
392
393                     "pshufb %%xmm6, %%xmm7\n\t"
394                     : [ctrlow] "+r" (ctrlow)
395                     :
396                     : "cc", "memory");
397
398       do_vpaes_ssse3_enc (ctx, nrounds);
399
400       asm volatile ("movdqu %[src], %%xmm1\n\t"      /* xmm1 := input   */
401                     "pxor %%xmm1, %%xmm0\n\t"        /* EncCTR ^= input  */
402                     "movdqu %%xmm0, %[dst]"          /* Store EncCTR.    */
403                     : [dst] "=m" (*outbuf)
404                     : [src] "m" (*inbuf)
405                     : "memory");
406
407       outbuf += BLOCKSIZE;
408       inbuf  += BLOCKSIZE;
409     }
410
411   asm volatile ("movdqu %%xmm7, %[ctr]\n\t"   /* Update CTR (mem).       */
412                 : [ctr] "=m" (*ctr)
413                 :
414                 : "memory" );
415
416   vpaes_ssse3_cleanup ();
417 }
418
419
420 unsigned int ASM_FUNC_ATTR
421 _gcry_aes_ssse3_decrypt (const RIJNDAEL_context *ctx, unsigned char *dst,
422                          const unsigned char *src)
423 {
424   unsigned int nrounds = ctx->rounds;
425   byte ssse3_state[SSSE3_STATE_SIZE];
426
427   vpaes_ssse3_prepare_dec ();
428   asm volatile ("movdqu %[src], %%xmm0\n\t"
429                 :
430                 : [src] "m" (*src)
431                 : "memory" );
432   do_vpaes_ssse3_dec (ctx, nrounds);
433   asm volatile ("movdqu %%xmm0, %[dst]\n\t"
434                 : [dst] "=m" (*dst)
435                 :
436                 : "memory" );
437   vpaes_ssse3_cleanup ();
438   return 0;
439 }
440
441
442 void ASM_FUNC_ATTR
443 _gcry_aes_ssse3_cfb_dec (RIJNDAEL_context *ctx, unsigned char *iv,
444                          unsigned char *outbuf, const unsigned char *inbuf,
445                          size_t nblocks)
446 {
447   unsigned int nrounds = ctx->rounds;
448   byte ssse3_state[SSSE3_STATE_SIZE];
449
450   vpaes_ssse3_prepare_enc ();
451
452   asm volatile ("movdqu %[iv], %%xmm0\n\t"
453                 : /* No output */
454                 : [iv] "m" (*iv)
455                 : "memory" );
456
457   for ( ;nblocks; nblocks-- )
458     {
459       do_vpaes_ssse3_enc (ctx, nrounds);
460
461       asm volatile ("movdqa %%xmm0, %%xmm6\n\t"
462                     "movdqu %[inbuf], %%xmm0\n\t"
463                     "pxor %%xmm0, %%xmm6\n\t"
464                     "movdqu %%xmm6, %[outbuf]\n\t"
465                     : [outbuf] "=m" (*outbuf)
466                     : [inbuf] "m" (*inbuf)
467                     : "memory" );
468
469       outbuf += BLOCKSIZE;
470       inbuf  += BLOCKSIZE;
471     }
472
473   asm volatile ("movdqu %%xmm0, %[iv]\n\t"
474                 : [iv] "=m" (*iv)
475                 :
476                 : "memory" );
477
478   vpaes_ssse3_cleanup ();
479 }
480
481
482 void ASM_FUNC_ATTR
483 _gcry_aes_ssse3_cbc_dec (RIJNDAEL_context *ctx, unsigned char *iv,
484                          unsigned char *outbuf, const unsigned char *inbuf,
485                          size_t nblocks)
486 {
487   unsigned int nrounds = ctx->rounds;
488   byte ssse3_state[SSSE3_STATE_SIZE];
489
490   if ( !ctx->decryption_prepared )
491     {
492       do_ssse3_prepare_decryption ( ctx, ssse3_state );
493       ctx->decryption_prepared = 1;
494     }
495
496   vpaes_ssse3_prepare_dec ();
497
498   asm volatile ("movdqu %[iv], %%xmm7\n\t"      /* use xmm7 as fast IV storage */
499                 : /* No output */
500                 : [iv] "m" (*iv)
501                 : "memory");
502
503   for ( ;nblocks; nblocks-- )
504     {
505       asm volatile ("movdqu %[inbuf], %%xmm0\n\t"
506                     "movdqa %%xmm0, %%xmm6\n\t"    /* use xmm6 as savebuf */
507                     : /* No output */
508                     : [inbuf] "m" (*inbuf)
509                     : "memory");
510
511       do_vpaes_ssse3_dec (ctx, nrounds);
512
513       asm volatile ("pxor %%xmm7, %%xmm0\n\t"   /* xor IV with output */
514                     "movdqu %%xmm0, %[outbuf]\n\t"
515                     "movdqu %%xmm6, %%xmm7\n\t" /* store savebuf as new IV */
516                     : [outbuf] "=m" (*outbuf)
517                     :
518                     : "memory");
519
520       outbuf += BLOCKSIZE;
521       inbuf  += BLOCKSIZE;
522     }
523
524   asm volatile ("movdqu %%xmm7, %[iv]\n\t"      /* store IV */
525                 : /* No output */
526                 : [iv] "m" (*iv)
527                 : "memory");
528
529   vpaes_ssse3_cleanup ();
530 }
531
532
533 static void ASM_FUNC_ATTR
534 ssse3_ocb_enc (gcry_cipher_hd_t c, void *outbuf_arg,
535                const void *inbuf_arg, size_t nblocks)
536 {
537   RIJNDAEL_context *ctx = (void *)&c->context.c;
538   unsigned char *outbuf = outbuf_arg;
539   const unsigned char *inbuf = inbuf_arg;
540   u64 n = c->u_mode.ocb.data_nblocks;
541   unsigned int nrounds = ctx->rounds;
542   byte ssse3_state[SSSE3_STATE_SIZE];
543
544   vpaes_ssse3_prepare_enc ();
545
546   /* Preload Offset and Checksum */
547   asm volatile ("movdqu %[iv], %%xmm7\n\t"
548                 "movdqu %[ctr], %%xmm6\n\t"
549                 : /* No output */
550                 : [iv] "m" (*c->u_iv.iv),
551                   [ctr] "m" (*c->u_ctr.ctr)
552                 : "memory" );
553
554   for ( ;nblocks; nblocks-- )
555     {
556       const unsigned char *l;
557
558       l = aes_ocb_get_l(c, ++n);
559
560       /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
561       /* Checksum_i = Checksum_{i-1} xor P_i  */
562       /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
563       asm volatile ("movdqu %[l],     %%xmm1\n\t"
564                     "movdqu %[inbuf], %%xmm0\n\t"
565                     "pxor   %%xmm1,   %%xmm7\n\t"
566                     "pxor   %%xmm0,   %%xmm6\n\t"
567                     "pxor   %%xmm7,   %%xmm0\n\t"
568                     :
569                     : [l] "m" (*l),
570                       [inbuf] "m" (*inbuf)
571                     : "memory" );
572
573       do_vpaes_ssse3_enc (ctx, nrounds);
574
575       asm volatile ("pxor   %%xmm7, %%xmm0\n\t"
576                     "movdqu %%xmm0, %[outbuf]\n\t"
577                     : [outbuf] "=m" (*outbuf)
578                     :
579                     : "memory" );
580
581       inbuf += BLOCKSIZE;
582       outbuf += BLOCKSIZE;
583     }
584
585   c->u_mode.ocb.data_nblocks = n;
586   asm volatile ("movdqu %%xmm7, %[iv]\n\t"
587                 "movdqu %%xmm6, %[ctr]\n\t"
588                 : [iv] "=m" (*c->u_iv.iv),
589                   [ctr] "=m" (*c->u_ctr.ctr)
590                 :
591                 : "memory" );
592
593   vpaes_ssse3_cleanup ();
594 }
595
596 static void ASM_FUNC_ATTR
597 ssse3_ocb_dec (gcry_cipher_hd_t c, void *outbuf_arg,
598                const void *inbuf_arg, size_t nblocks)
599 {
600   RIJNDAEL_context *ctx = (void *)&c->context.c;
601   unsigned char *outbuf = outbuf_arg;
602   const unsigned char *inbuf = inbuf_arg;
603   u64 n = c->u_mode.ocb.data_nblocks;
604   unsigned int nrounds = ctx->rounds;
605   byte ssse3_state[SSSE3_STATE_SIZE];
606
607   if ( !ctx->decryption_prepared )
608     {
609       do_ssse3_prepare_decryption ( ctx, ssse3_state );
610       ctx->decryption_prepared = 1;
611     }
612
613   vpaes_ssse3_prepare_dec ();
614
615   /* Preload Offset and Checksum */
616   asm volatile ("movdqu %[iv], %%xmm7\n\t"
617                 "movdqu %[ctr], %%xmm6\n\t"
618                 : /* No output */
619                 : [iv] "m" (*c->u_iv.iv),
620                   [ctr] "m" (*c->u_ctr.ctr)
621                 : "memory" );
622
623   for ( ;nblocks; nblocks-- )
624     {
625       const unsigned char *l;
626
627       l = aes_ocb_get_l(c, ++n);
628
629       /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
630       /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)  */
631       /* Checksum_i = Checksum_{i-1} xor P_i  */
632       asm volatile ("movdqu %[l],     %%xmm1\n\t"
633                     "movdqu %[inbuf], %%xmm0\n\t"
634                     "pxor   %%xmm1,   %%xmm7\n\t"
635                     "pxor   %%xmm7,   %%xmm0\n\t"
636                     :
637                     : [l] "m" (*l),
638                       [inbuf] "m" (*inbuf)
639                     : "memory" );
640
641       do_vpaes_ssse3_dec (ctx, nrounds);
642
643       asm volatile ("pxor   %%xmm7, %%xmm0\n\t"
644                     "pxor   %%xmm0, %%xmm6\n\t"
645                     "movdqu %%xmm0, %[outbuf]\n\t"
646                     : [outbuf] "=m" (*outbuf)
647                     :
648                     : "memory" );
649
650       inbuf += BLOCKSIZE;
651       outbuf += BLOCKSIZE;
652     }
653
654   c->u_mode.ocb.data_nblocks = n;
655   asm volatile ("movdqu %%xmm7, %[iv]\n\t"
656                 "movdqu %%xmm6, %[ctr]\n\t"
657                 : [iv] "=m" (*c->u_iv.iv),
658                   [ctr] "=m" (*c->u_ctr.ctr)
659                 :
660                 : "memory" );
661
662   vpaes_ssse3_cleanup ();
663 }
664
665
666 size_t ASM_FUNC_ATTR
667 _gcry_aes_ssse3_ocb_crypt(gcry_cipher_hd_t c, void *outbuf_arg,
668                           const void *inbuf_arg, size_t nblocks, int encrypt)
669 {
670   if (encrypt)
671     ssse3_ocb_enc(c, outbuf_arg, inbuf_arg, nblocks);
672   else
673     ssse3_ocb_dec(c, outbuf_arg, inbuf_arg, nblocks);
674
675   return 0;
676 }
677
678
679 size_t ASM_FUNC_ATTR
680 _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
681                           size_t nblocks)
682 {
683   RIJNDAEL_context *ctx = (void *)&c->context.c;
684   const unsigned char *abuf = abuf_arg;
685   u64 n = c->u_mode.ocb.aad_nblocks;
686   unsigned int nrounds = ctx->rounds;
687   byte ssse3_state[SSSE3_STATE_SIZE];
688
689   vpaes_ssse3_prepare_enc ();
690
691   /* Preload Offset and Sum */
692   asm volatile ("movdqu %[iv], %%xmm7\n\t"
693                 "movdqu %[ctr], %%xmm6\n\t"
694                 : /* No output */
695                 : [iv] "m" (*c->u_mode.ocb.aad_offset),
696                   [ctr] "m" (*c->u_mode.ocb.aad_sum)
697                 : "memory" );
698
699   for ( ;nblocks; nblocks-- )
700     {
701       const unsigned char *l;
702
703       l = aes_ocb_get_l(c, ++n);
704
705       /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
706       /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
707       asm volatile ("movdqu %[l],     %%xmm1\n\t"
708                     "movdqu %[abuf],  %%xmm0\n\t"
709                     "pxor   %%xmm1,   %%xmm7\n\t"
710                     "pxor   %%xmm7,   %%xmm0\n\t"
711                     :
712                     : [l] "m" (*l),
713                       [abuf] "m" (*abuf)
714                     : "memory" );
715
716       do_vpaes_ssse3_enc (ctx, nrounds);
717
718       asm volatile ("pxor   %%xmm0,   %%xmm6\n\t"
719                     :
720                     :
721                     : "memory" );
722
723       abuf += BLOCKSIZE;
724     }
725
726   c->u_mode.ocb.aad_nblocks = n;
727   asm volatile ("movdqu %%xmm7, %[iv]\n\t"
728                 "movdqu %%xmm6, %[ctr]\n\t"
729                 : [iv] "=m" (*c->u_mode.ocb.aad_offset),
730                   [ctr] "=m" (*c->u_mode.ocb.aad_sum)
731                 :
732                 : "memory" );
733
734   vpaes_ssse3_cleanup ();
735
736   return 0;
737 }
738
739 #if __clang__
740 #  pragma clang attribute pop
741 #endif
742
743 #endif /* USE_SSSE3 */