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