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