07a64a4c1bb42cbee7744fadc33cf2b6c9e17c34
[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 static inline void
179 do_ssse3_prepare_decryption (RIJNDAEL_context *ctx,
180                              byte ssse3_state[SSSE3_STATE_SIZE])
181 {
182   unsigned int keybits = (ctx->rounds - 10) * 32 + 128;
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 void
194 _gcry_aes_ssse3_prepare_decryption (RIJNDAEL_context *ctx)
195 {
196   byte ssse3_state[SSSE3_STATE_SIZE];
197
198   do_ssse3_prepare_decryption(ctx, ssse3_state);
199 }
200
201
202 /* Encrypt one block using the Intel SSSE3 instructions.  Block is input
203 * and output through SSE register xmm0. */
204 static inline void
205 do_vpaes_ssse3_enc (const RIJNDAEL_context *ctx, unsigned int nrounds)
206 {
207   _gcry_aes_ssse3_encrypt_core(ctx->keyschenc32, nrounds);
208 }
209
210
211 /* Decrypt one block using the Intel SSSE3 instructions.  Block is input
212 * and output through SSE register xmm0. */
213 static inline void
214 do_vpaes_ssse3_dec (const RIJNDAEL_context *ctx, unsigned int nrounds)
215 {
216   _gcry_aes_ssse3_decrypt_core(ctx->keyschdec32, nrounds);
217 }
218
219
220 unsigned int
221 _gcry_aes_ssse3_encrypt (const RIJNDAEL_context *ctx, unsigned char *dst,
222                         const unsigned char *src)
223 {
224   unsigned int nrounds = ctx->rounds;
225   byte ssse3_state[SSSE3_STATE_SIZE];
226
227   vpaes_ssse3_prepare_enc ();
228   asm volatile ("movdqu %[src], %%xmm0\n\t"
229                 :
230                 : [src] "m" (*src)
231                 : "memory" );
232   do_vpaes_ssse3_enc (ctx, nrounds);
233   asm volatile ("movdqu %%xmm0, %[dst]\n\t"
234                 : [dst] "=m" (*dst)
235                 :
236                 : "memory" );
237   vpaes_ssse3_cleanup ();
238   return 0;
239 }
240
241
242 void
243 _gcry_aes_ssse3_cfb_enc (RIJNDAEL_context *ctx, unsigned char *iv,
244                          unsigned char *outbuf, const unsigned char *inbuf,
245                          size_t nblocks)
246 {
247   unsigned int nrounds = ctx->rounds;
248   byte ssse3_state[SSSE3_STATE_SIZE];
249
250   vpaes_ssse3_prepare_enc ();
251
252   asm volatile ("movdqu %[iv], %%xmm0\n\t"
253                 : /* No output */
254                 : [iv] "m" (*iv)
255                 : "memory" );
256
257   for ( ;nblocks; nblocks-- )
258     {
259       do_vpaes_ssse3_enc (ctx, nrounds);
260
261       asm volatile ("movdqu %[inbuf], %%xmm1\n\t"
262                     "pxor %%xmm1, %%xmm0\n\t"
263                     "movdqu %%xmm0, %[outbuf]\n\t"
264                     : [outbuf] "=m" (*outbuf)
265                     : [inbuf] "m" (*inbuf)
266                     : "memory" );
267
268       outbuf += BLOCKSIZE;
269       inbuf  += BLOCKSIZE;
270     }
271
272   asm volatile ("movdqu %%xmm0, %[iv]\n\t"
273                 : [iv] "=m" (*iv)
274                 :
275                 : "memory" );
276
277   vpaes_ssse3_cleanup ();
278 }
279
280
281 void
282 _gcry_aes_ssse3_cbc_enc (RIJNDAEL_context *ctx, unsigned char *iv,
283                          unsigned char *outbuf, const unsigned char *inbuf,
284                          size_t nblocks, int cbc_mac)
285 {
286   unsigned int nrounds = ctx->rounds;
287   byte ssse3_state[SSSE3_STATE_SIZE];
288
289   vpaes_ssse3_prepare_enc ();
290
291   asm volatile ("movdqu %[iv], %%xmm7\n\t"
292                 : /* No output */
293                 : [iv] "m" (*iv)
294                 : "memory" );
295
296   for ( ;nblocks; nblocks-- )
297     {
298       asm volatile ("movdqu %[inbuf], %%xmm0\n\t"
299                     "pxor %%xmm7, %%xmm0\n\t"
300                     : /* No output */
301                     : [inbuf] "m" (*inbuf)
302                     : "memory" );
303
304       do_vpaes_ssse3_enc (ctx, nrounds);
305
306       asm volatile ("movdqa %%xmm0, %%xmm7\n\t"
307                     "movdqu %%xmm0, %[outbuf]\n\t"
308                     : [outbuf] "=m" (*outbuf)
309                     :
310                     : "memory" );
311
312       inbuf += BLOCKSIZE;
313       if (!cbc_mac)
314         outbuf += BLOCKSIZE;
315     }
316
317   asm volatile ("movdqu %%xmm7, %[iv]\n\t"
318                 : [iv] "=m" (*iv)
319                 :
320                 : "memory" );
321
322   vpaes_ssse3_cleanup ();
323 }
324
325
326 void
327 _gcry_aes_ssse3_ctr_enc (RIJNDAEL_context *ctx, unsigned char *ctr,
328                          unsigned char *outbuf, const unsigned char *inbuf,
329                          size_t nblocks)
330 {
331   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
332     { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
333   unsigned int nrounds = ctx->rounds;
334   byte ssse3_state[SSSE3_STATE_SIZE];
335   u64 ctrlow;
336
337   vpaes_ssse3_prepare_enc ();
338
339   asm volatile ("movdqa %[mask], %%xmm6\n\t" /* Preload mask */
340                 "movdqa (%[ctr]), %%xmm7\n\t"  /* Preload CTR */
341                 "movq 8(%[ctr]), %q[ctrlow]\n\t"
342                 "bswapq %q[ctrlow]\n\t"
343                 : [ctrlow] "=r" (ctrlow)
344                 : [mask] "m" (*be_mask),
345                   [ctr] "r" (ctr)
346                 : "memory", "cc");
347
348   for ( ;nblocks; nblocks-- )
349     {
350       asm volatile ("movdqa %%xmm7, %%xmm0\n\t"     /* xmm0 := CTR (xmm7)  */
351                     "pcmpeqd %%xmm1, %%xmm1\n\t"
352                     "psrldq $8, %%xmm1\n\t"         /* xmm1 = -1 */
353
354                     "pshufb %%xmm6, %%xmm7\n\t"
355                     "psubq  %%xmm1, %%xmm7\n\t"     /* xmm7++ (big endian) */
356
357                     /* detect if 64-bit carry handling is needed */
358                     "incq   %q[ctrlow]\n\t"
359                     "jnz    .Lno_carry%=\n\t"
360
361                     "pslldq $8, %%xmm1\n\t"         /* move lower 64-bit to high */
362                     "psubq   %%xmm1, %%xmm7\n\t"    /* add carry to upper 64bits */
363
364                     ".Lno_carry%=:\n\t"
365
366                     "pshufb %%xmm6, %%xmm7\n\t"
367                     : [ctrlow] "+r" (ctrlow)
368                     :
369                     : "cc", "memory");
370
371       do_vpaes_ssse3_enc (ctx, nrounds);
372
373       asm volatile ("movdqu %[src], %%xmm1\n\t"      /* xmm1 := input   */
374                     "pxor %%xmm1, %%xmm0\n\t"        /* EncCTR ^= input  */
375                     "movdqu %%xmm0, %[dst]"          /* Store EncCTR.    */
376                     : [dst] "=m" (*outbuf)
377                     : [src] "m" (*inbuf)
378                     : "memory");
379
380       outbuf += BLOCKSIZE;
381       inbuf  += BLOCKSIZE;
382     }
383
384   asm volatile ("movdqu %%xmm7, %[ctr]\n\t"   /* Update CTR (mem).       */
385                 : [ctr] "=m" (*ctr)
386                 :
387                 : "memory" );
388
389   vpaes_ssse3_cleanup ();
390 }
391
392
393 unsigned int
394 _gcry_aes_ssse3_decrypt (const RIJNDAEL_context *ctx, unsigned char *dst,
395                          const unsigned char *src)
396 {
397   unsigned int nrounds = ctx->rounds;
398   byte ssse3_state[SSSE3_STATE_SIZE];
399
400   vpaes_ssse3_prepare_dec ();
401   asm volatile ("movdqu %[src], %%xmm0\n\t"
402                 :
403                 : [src] "m" (*src)
404                 : "memory" );
405   do_vpaes_ssse3_dec (ctx, nrounds);
406   asm volatile ("movdqu %%xmm0, %[dst]\n\t"
407                 : [dst] "=m" (*dst)
408                 :
409                 : "memory" );
410   vpaes_ssse3_cleanup ();
411   return 0;
412 }
413
414
415 void
416 _gcry_aes_ssse3_cfb_dec (RIJNDAEL_context *ctx, unsigned char *iv,
417                          unsigned char *outbuf, const unsigned char *inbuf,
418                          size_t nblocks)
419 {
420   unsigned int nrounds = ctx->rounds;
421   byte ssse3_state[SSSE3_STATE_SIZE];
422
423   vpaes_ssse3_prepare_enc ();
424
425   asm volatile ("movdqu %[iv], %%xmm0\n\t"
426                 : /* No output */
427                 : [iv] "m" (*iv)
428                 : "memory" );
429
430   for ( ;nblocks; nblocks-- )
431     {
432       do_vpaes_ssse3_enc (ctx, nrounds);
433
434       asm volatile ("movdqa %%xmm0, %%xmm6\n\t"
435                     "movdqu %[inbuf], %%xmm0\n\t"
436                     "pxor %%xmm0, %%xmm6\n\t"
437                     "movdqu %%xmm6, %[outbuf]\n\t"
438                     : [outbuf] "=m" (*outbuf)
439                     : [inbuf] "m" (*inbuf)
440                     : "memory" );
441
442       outbuf += BLOCKSIZE;
443       inbuf  += BLOCKSIZE;
444     }
445
446   asm volatile ("movdqu %%xmm0, %[iv]\n\t"
447                 : [iv] "=m" (*iv)
448                 :
449                 : "memory" );
450
451   vpaes_ssse3_cleanup ();
452 }
453
454
455 void
456 _gcry_aes_ssse3_cbc_dec (RIJNDAEL_context *ctx, unsigned char *iv,
457                          unsigned char *outbuf, const unsigned char *inbuf,
458                          size_t nblocks)
459 {
460   unsigned int nrounds = ctx->rounds;
461   byte ssse3_state[SSSE3_STATE_SIZE];
462
463   if ( !ctx->decryption_prepared )
464     {
465       do_ssse3_prepare_decryption ( ctx, ssse3_state );
466       ctx->decryption_prepared = 1;
467     }
468
469   vpaes_ssse3_prepare_dec ();
470
471   asm volatile ("movdqu %[iv], %%xmm7\n\t"      /* use xmm7 as fast IV storage */
472                 : /* No output */
473                 : [iv] "m" (*iv)
474                 : "memory");
475
476   for ( ;nblocks; nblocks-- )
477     {
478       asm volatile ("movdqu %[inbuf], %%xmm0\n\t"
479                     "movdqa %%xmm0, %%xmm6\n\t"    /* use xmm6 as savebuf */
480                     : /* No output */
481                     : [inbuf] "m" (*inbuf)
482                     : "memory");
483
484       do_vpaes_ssse3_dec (ctx, nrounds);
485
486       asm volatile ("pxor %%xmm7, %%xmm0\n\t"   /* xor IV with output */
487                     "movdqu %%xmm0, %[outbuf]\n\t"
488                     "movdqu %%xmm6, %%xmm7\n\t" /* store savebuf as new IV */
489                     : [outbuf] "=m" (*outbuf)
490                     :
491                     : "memory");
492
493       outbuf += BLOCKSIZE;
494       inbuf  += BLOCKSIZE;
495     }
496
497   asm volatile ("movdqu %%xmm7, %[iv]\n\t"      /* store IV */
498                 : /* No output */
499                 : [iv] "m" (*iv)
500                 : "memory");
501
502   vpaes_ssse3_cleanup ();
503 }
504
505
506 static void
507 ssse3_ocb_enc (gcry_cipher_hd_t c, void *outbuf_arg,
508                const void *inbuf_arg, size_t nblocks)
509 {
510   RIJNDAEL_context *ctx = (void *)&c->context.c;
511   unsigned char *outbuf = outbuf_arg;
512   const unsigned char *inbuf = inbuf_arg;
513   u64 n = c->u_mode.ocb.data_nblocks;
514   unsigned int nrounds = ctx->rounds;
515   byte ssse3_state[SSSE3_STATE_SIZE];
516
517   vpaes_ssse3_prepare_enc ();
518
519   /* Preload Offset and Checksum */
520   asm volatile ("movdqu %[iv], %%xmm7\n\t"
521                 "movdqu %[ctr], %%xmm6\n\t"
522                 : /* No output */
523                 : [iv] "m" (*c->u_iv.iv),
524                   [ctr] "m" (*c->u_ctr.ctr)
525                 : "memory" );
526
527   for ( ;nblocks; nblocks-- )
528     {
529       const unsigned char *l;
530
531       l = ocb_get_l(c, ++n);
532
533       /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
534       /* Checksum_i = Checksum_{i-1} xor P_i  */
535       /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
536       asm volatile ("movdqu %[l],     %%xmm1\n\t"
537                     "movdqu %[inbuf], %%xmm0\n\t"
538                     "pxor   %%xmm1,   %%xmm7\n\t"
539                     "pxor   %%xmm0,   %%xmm6\n\t"
540                     "pxor   %%xmm7,   %%xmm0\n\t"
541                     :
542                     : [l] "m" (*l),
543                       [inbuf] "m" (*inbuf)
544                     : "memory" );
545
546       do_vpaes_ssse3_enc (ctx, nrounds);
547
548       asm volatile ("pxor   %%xmm7, %%xmm0\n\t"
549                     "movdqu %%xmm0, %[outbuf]\n\t"
550                     : [outbuf] "=m" (*outbuf)
551                     :
552                     : "memory" );
553
554       inbuf += BLOCKSIZE;
555       outbuf += BLOCKSIZE;
556     }
557
558   c->u_mode.ocb.data_nblocks = n;
559   asm volatile ("movdqu %%xmm7, %[iv]\n\t"
560                 "movdqu %%xmm6, %[ctr]\n\t"
561                 : [iv] "=m" (*c->u_iv.iv),
562                   [ctr] "=m" (*c->u_ctr.ctr)
563                 :
564                 : "memory" );
565
566   vpaes_ssse3_cleanup ();
567 }
568
569 static void
570 ssse3_ocb_dec (gcry_cipher_hd_t c, void *outbuf_arg,
571                const void *inbuf_arg, size_t nblocks)
572 {
573   RIJNDAEL_context *ctx = (void *)&c->context.c;
574   unsigned char *outbuf = outbuf_arg;
575   const unsigned char *inbuf = inbuf_arg;
576   u64 n = c->u_mode.ocb.data_nblocks;
577   unsigned int nrounds = ctx->rounds;
578   byte ssse3_state[SSSE3_STATE_SIZE];
579
580   if ( !ctx->decryption_prepared )
581     {
582       do_ssse3_prepare_decryption ( ctx, ssse3_state );
583       ctx->decryption_prepared = 1;
584     }
585
586   vpaes_ssse3_prepare_dec ();
587
588   /* Preload Offset and Checksum */
589   asm volatile ("movdqu %[iv], %%xmm7\n\t"
590                 "movdqu %[ctr], %%xmm6\n\t"
591                 : /* No output */
592                 : [iv] "m" (*c->u_iv.iv),
593                   [ctr] "m" (*c->u_ctr.ctr)
594                 : "memory" );
595
596   for ( ;nblocks; nblocks-- )
597     {
598       const unsigned char *l;
599
600       l = ocb_get_l(c, ++n);
601
602       /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
603       /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)  */
604       /* Checksum_i = Checksum_{i-1} xor P_i  */
605       asm volatile ("movdqu %[l],     %%xmm1\n\t"
606                     "movdqu %[inbuf], %%xmm0\n\t"
607                     "pxor   %%xmm1,   %%xmm7\n\t"
608                     "pxor   %%xmm7,   %%xmm0\n\t"
609                     :
610                     : [l] "m" (*l),
611                       [inbuf] "m" (*inbuf)
612                     : "memory" );
613
614       do_vpaes_ssse3_dec (ctx, nrounds);
615
616       asm volatile ("pxor   %%xmm7, %%xmm0\n\t"
617                     "pxor   %%xmm0, %%xmm6\n\t"
618                     "movdqu %%xmm0, %[outbuf]\n\t"
619                     : [outbuf] "=m" (*outbuf)
620                     :
621                     : "memory" );
622
623       inbuf += BLOCKSIZE;
624       outbuf += BLOCKSIZE;
625     }
626
627   c->u_mode.ocb.data_nblocks = n;
628   asm volatile ("movdqu %%xmm7, %[iv]\n\t"
629                 "movdqu %%xmm6, %[ctr]\n\t"
630                 : [iv] "=m" (*c->u_iv.iv),
631                   [ctr] "=m" (*c->u_ctr.ctr)
632                 :
633                 : "memory" );
634
635   vpaes_ssse3_cleanup ();
636 }
637
638
639 size_t
640 _gcry_aes_ssse3_ocb_crypt(gcry_cipher_hd_t c, void *outbuf_arg,
641                           const void *inbuf_arg, size_t nblocks, int encrypt)
642 {
643   if (encrypt)
644     ssse3_ocb_enc(c, outbuf_arg, inbuf_arg, nblocks);
645   else
646     ssse3_ocb_dec(c, outbuf_arg, inbuf_arg, nblocks);
647
648   return 0;
649 }
650
651
652 size_t
653 _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
654                           size_t nblocks)
655 {
656   RIJNDAEL_context *ctx = (void *)&c->context.c;
657   const unsigned char *abuf = abuf_arg;
658   u64 n = c->u_mode.ocb.aad_nblocks;
659   unsigned int nrounds = ctx->rounds;
660   byte ssse3_state[SSSE3_STATE_SIZE];
661
662   vpaes_ssse3_prepare_enc ();
663
664   /* Preload Offset and Sum */
665   asm volatile ("movdqu %[iv], %%xmm7\n\t"
666                 "movdqu %[ctr], %%xmm6\n\t"
667                 : /* No output */
668                 : [iv] "m" (*c->u_mode.ocb.aad_offset),
669                   [ctr] "m" (*c->u_mode.ocb.aad_sum)
670                 : "memory" );
671
672   for ( ;nblocks; nblocks-- )
673     {
674       const unsigned char *l;
675
676       l = ocb_get_l(c, ++n);
677
678       /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
679       /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
680       asm volatile ("movdqu %[l],     %%xmm1\n\t"
681                     "movdqu %[abuf],  %%xmm0\n\t"
682                     "pxor   %%xmm1,   %%xmm7\n\t"
683                     "pxor   %%xmm7,   %%xmm0\n\t"
684                     :
685                     : [l] "m" (*l),
686                       [abuf] "m" (*abuf)
687                     : "memory" );
688
689       do_vpaes_ssse3_enc (ctx, nrounds);
690
691       asm volatile ("pxor   %%xmm0,   %%xmm6\n\t"
692                     :
693                     :
694                     : "memory" );
695
696       abuf += BLOCKSIZE;
697     }
698
699   c->u_mode.ocb.aad_nblocks = n;
700   asm volatile ("movdqu %%xmm7, %[iv]\n\t"
701                 "movdqu %%xmm6, %[ctr]\n\t"
702                 : [iv] "=m" (*c->u_mode.ocb.aad_offset),
703                   [ctr] "=m" (*c->u_mode.ocb.aad_sum)
704                 :
705                 : "memory" );
706
707   vpaes_ssse3_cleanup ();
708
709   return 0;
710 }
711
712 #endif /* USE_SSSE3 */