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