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