Skinny-C
 All Data Structures Files Functions Variables Groups Pages
mantis-ctr-vec128.c
1 /*
2  * Copyright (C) 2017 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "mantis-cipher.h"
24 #include "mantis-ctr-internal.h"
25 #include "skinny-internal.h"
26 #include <stdlib.h>
27 
28 #if SKINNY_VEC128_MATH
29 
30 /* This implementation encrypts eight blocks at a time */
31 #define MANTIS_CTR_BLOCK_SIZE (MANTIS_BLOCK_SIZE * 8)
32 
34 typedef struct
35 {
37  MantisKey_t ks;
38 
40  SkinnyVector8x16_t counter[4];
41 
43  unsigned char ecounter[MANTIS_CTR_BLOCK_SIZE];
44 
46  unsigned offset;
47 
49  void *base_ptr;
50 
51 } MantisCTRVec128Ctx_t;
52 
53 static int mantis_ctr_vec128_init(MantisCTR_t *ctr)
54 {
55  MantisCTRVec128Ctx_t *ctx;
56  void *base_ptr;
57  if ((ctx = skinny_calloc(sizeof(MantisCTRVec128Ctx_t), &base_ptr)) == NULL)
58  return 0;
59  ctx->base_ptr = base_ptr;
60  ctx->offset = MANTIS_CTR_BLOCK_SIZE;
61  ctr->ctx = ctx;
62  return 1;
63 }
64 
65 static void mantis_ctr_vec128_cleanup(MantisCTR_t *ctr)
66 {
67  if (ctr->ctx) {
68  MantisCTRVec128Ctx_t *ctx = ctr->ctx;
69  void *base_ptr = ctx->base_ptr;
70  skinny_cleanse(ctx, sizeof(MantisCTRVec128Ctx_t));
71  free(base_ptr);
72  ctr->ctx = 0;
73  }
74 }
75 
76 static int mantis_ctr_vec128_set_key
77  (MantisCTR_t *ctr, const void *key, unsigned size, unsigned rounds)
78 {
79  MantisCTRVec128Ctx_t *ctx;
80 
81  /* Validate the parameters */
82  if (!key)
83  return 0;
84  ctx = ctr->ctx;
85  if (!ctx)
86  return 0;
87 
88  /* Populate the underlying key schedule */
89  if (!mantis_set_key(&(ctx->ks), key, size, rounds, MANTIS_ENCRYPT))
90  return 0;
91 
92  /* Reset the keystream */
93  ctx->offset = MANTIS_CTR_BLOCK_SIZE;
94  return 1;
95 }
96 
97 static int mantis_ctr_vec128_set_tweak
98  (MantisCTR_t *ctr, const void *tweak, unsigned tweak_size)
99 {
100  MantisCTRVec128Ctx_t *ctx;
101 
102  /* Validate the parameters */
103  ctx = ctr->ctx;
104  if (!ctx)
105  return 0;
106 
107  /* Populate the underlying tweak */
108  if (!mantis_set_tweak(&(ctx->ks), tweak, tweak_size))
109  return 0;
110 
111  /* Reset the keystream */
112  ctx->offset = MANTIS_CTR_BLOCK_SIZE;
113  return 1;
114 }
115 
116 /* Increment a specific column in an array of row vectors */
117 STATIC_INLINE void mantis_ctr_increment
118  (SkinnyVector8x16_t *counter, unsigned column, unsigned inc)
119 {
120  uint8_t *ctr = ((uint8_t *)counter) + column * 2;
121  uint8_t *ptr;
122  unsigned index;
123  for (index = 8; index > 0; ) {
124  --index;
125  ptr = ctr + (index & 0x06) * 8;
126 #if SKINNY_LITTLE_ENDIAN
127  ptr += index & 0x01;
128 #else
129  ptr += 1 - (index & 0x01);
130 #endif
131  inc += ptr[0];
132  ptr[0] = (uint8_t)inc;
133  inc >>= 8;
134  }
135 }
136 
137 static int mantis_ctr_vec128_set_counter
138  (MantisCTR_t *ctr, const void *counter, unsigned size)
139 {
140  MantisCTRVec128Ctx_t *ctx;
141  unsigned char block[MANTIS_BLOCK_SIZE];
142 
143  /* Validate the parameters */
144  if (size > MANTIS_BLOCK_SIZE)
145  return 0;
146  ctx = ctr->ctx;
147  if (!ctx)
148  return 0;
149 
150  /* Set the counter and reset the keystream to a block boundary */
151  if (counter) {
152  memset(block, 0, MANTIS_BLOCK_SIZE - size);
153  memcpy(block + MANTIS_BLOCK_SIZE - size, counter, size);
154  } else {
155  memset(block, 0, MANTIS_BLOCK_SIZE);
156  }
157  ctx->offset = MANTIS_CTR_BLOCK_SIZE;
158 
159  /* Load the counter block and convert into row vectors */
160  ctx->counter[0] = skinny_to_vec8x16(READ_WORD16(block, 0));
161  ctx->counter[1] = skinny_to_vec8x16(READ_WORD16(block, 2));
162  ctx->counter[2] = skinny_to_vec8x16(READ_WORD16(block, 4));
163  ctx->counter[3] = skinny_to_vec8x16(READ_WORD16(block, 6));
164 
165  /* Increment the second through seventh columns of each row vector */
166  mantis_ctr_increment(ctx->counter, 1, 1);
167  mantis_ctr_increment(ctx->counter, 2, 2);
168  mantis_ctr_increment(ctx->counter, 3, 3);
169  mantis_ctr_increment(ctx->counter, 4, 4);
170  mantis_ctr_increment(ctx->counter, 5, 5);
171  mantis_ctr_increment(ctx->counter, 6, 6);
172  mantis_ctr_increment(ctx->counter, 7, 7);
173 
174  /* Clean up and exit */
175  skinny_cleanse(block, sizeof(block));
176  return 1;
177 }
178 
182 typedef union
183 {
184  SkinnyVector8x16_t row[4];
185 
186 } MantisVectorCells_t;
187 
188 STATIC_INLINE SkinnyVector8x16_t mantis_sbox(SkinnyVector8x16_t d)
189 {
190  /*
191  * MIDORI Sb0 from section 4.2 of https://eprint.iacr.org/2015/1142.pdf
192  *
193  * {a, b, c, d} -> {aout, bout, cout, dout} where a/aout is the MSB.
194  *
195  * aout = NAND(NAND(~c, NAND(a, b)), (a | d))
196  * bout = NAND(NOR(NOR(a, d), (b & c)), NAND((a & c), d))
197  * cout = NAND(NAND(b, d), (NOR(b, d) | a))
198  * dout = NOR(NOR(a, (b | c)), NAND(NAND(a, b), (c | d)))
199  */
200  SkinnyVector8x16_t a = (d >> 3);
201  SkinnyVector8x16_t b = (d >> 2);
202  SkinnyVector8x16_t c = (d >> 1);
203  SkinnyVector8x16_t not_a = ~a;
204  SkinnyVector8x16_t ab = not_a | (~b);
205  SkinnyVector8x16_t ad = not_a & (~d);
206  SkinnyVector8x16_t aout = (((~c) & ab) | ad);
207  SkinnyVector8x16_t bout = ad | (b & c) | (a & c & d);
208  SkinnyVector8x16_t cout = (b & d) | ((b | d) & not_a);
209  SkinnyVector8x16_t dout = (a | b | c) & ab & (c | d);
210  return ((aout & 0x1111U) << 3) | ((bout & 0x1111U) << 2) |
211  ((cout & 0x1111U) << 1) | (dout & 0x1111U);
212 }
213 
214 STATIC_INLINE void mantis_update_tweak(MantisCells_t *tweak)
215 {
216  /* h = [6, 5, 14, 15, 0, 1, 2, 3, 7, 12, 13, 4, 8, 9, 10, 11] */
217  uint16_t row1 = tweak->row[1];
218  uint16_t row3 = tweak->row[3];
219  tweak->row[1] = tweak->row[0];
220  tweak->row[3] = tweak->row[2];
221  tweak->row[0] = ((row1 >> 8) & 0x00F0U) |
222  (row1 & 0x000FU) |
223  (row3 & 0xFF00U);
224  tweak->row[2] = ((row1 << 4) & 0x0F00U) |
225  ((row1 >> 4) & 0x00F0U) |
226  ((row3 >> 4) & 0x000FU) |
227  ((row3 << 12) & 0xF000U);
228 }
229 
230 STATIC_INLINE void mantis_update_tweak_inverse(MantisCells_t *tweak)
231 {
232  /* h' = [4, 5, 6, 7, 11, 1, 0, 8, 12, 13, 14, 15, 9, 10, 2, 3] */
233  uint16_t row0 = tweak->row[0];
234  uint16_t row2 = tweak->row[2];
235  tweak->row[0] = tweak->row[1];
236  tweak->row[2] = tweak->row[3];
237  tweak->row[1] = ((row2 >> 4) & 0x00F0U) |
238  ((row2 << 4) & 0x0F00U) |
239  (row0 & 0x000FU) |
240  ((row0 << 8) & 0xF000U);
241  tweak->row[3] = (row0 & 0xFF00U) |
242  ((row2 << 4) & 0x00F0U) |
243  ((row2 >> 12) & 0x000FU);
244 }
245 
246 STATIC_INLINE void mantis_shift_rows(MantisVectorCells_t *state)
247 {
248  /* P = [0, 11, 6, 13, 10, 1, 12, 7, 5, 14, 3, 8, 15, 4, 9, 2] */
249  SkinnyVector8x16_t row0 = state->row[0];
250  SkinnyVector8x16_t row1 = state->row[1];
251  SkinnyVector8x16_t row2 = state->row[2];
252  SkinnyVector8x16_t row3 = state->row[3];
253  state->row[0] = (row0 & 0x00F0U) |
254  (row1 & 0xF000U) |
255  ((row2 >> 8) & 0x000FU) |
256  ((row3 << 8) & 0x0F00U);
257  state->row[1] = (row0 & 0x000FU) |
258  (row1 & 0x0F00U) |
259  ((row2 >> 8) & 0x00F0U) |
260  ((row3 << 8) & 0xF000U);
261  state->row[2] = ((row0 << 4) & 0xF000U) |
262  ((row1 << 4) & 0x00F0U) |
263  ((row2 << 4) & 0x0F00U) |
264  ((row3 >> 12) & 0x000FU);
265  state->row[3] = ((row0 >> 4) & 0x0F00U) |
266  ((row1 >> 4) & 0x000FU) |
267  ((row2 << 12) & 0xF000U) |
268  ((row3 >> 4) & 0x00F0U);
269 }
270 
271 STATIC_INLINE void mantis_shift_rows_inverse(MantisVectorCells_t *state)
272 {
273  /* P' = [0, 5, 15, 10, 13, 8, 2, 7, 11, 14, 4, 1, 6, 3, 9, 12] */
274  SkinnyVector8x16_t row0 = state->row[0];
275  SkinnyVector8x16_t row1 = state->row[1];
276  SkinnyVector8x16_t row2 = state->row[2];
277  SkinnyVector8x16_t row3 = state->row[3];
278  state->row[0] = (row0 & 0x00F0U) |
279  (row1 & 0x000FU) |
280  ((row2 >> 4) & 0x0F00U) |
281  ((row3 << 4) & 0xF000U);
282  state->row[1] = (row0 & 0xF000U) |
283  (row1 & 0x0F00U) |
284  ((row2 >> 4) & 0x000FU) |
285  ((row3 << 4) & 0x00F0U);
286  state->row[2] = ((row0 << 8) & 0x0F00U) |
287  ((row1 << 8) & 0xF000U) |
288  ((row2 >> 4) & 0x00F0U) |
289  ((row3 >> 12) & 0x000FU);
290  state->row[3] = ((row0 >> 8) & 0x000FU) |
291  ((row1 >> 8) & 0x00F0U) |
292  ((row2 << 12) & 0xF000U) |
293  ((row3 << 4) & 0x0F00U);
294 }
295 
296 STATIC_INLINE void mantis_mix_columns(MantisVectorCells_t *state)
297 {
298  SkinnyVector8x16_t t0 = state->row[0];
299  SkinnyVector8x16_t t1 = state->row[1];
300  SkinnyVector8x16_t t2 = state->row[2];
301  SkinnyVector8x16_t t3 = state->row[3];
302  state->row[0] = t1 ^ t2 ^ t3;
303  state->row[1] = t0 ^ t2 ^ t3;
304  state->row[2] = t0 ^ t1 ^ t3;
305  state->row[3] = t0 ^ t1 ^ t2;
306 }
307 
308 /* Extract the 16 bits for a row from a 64-bit round constant */
309 #define RC_EXTRACT_ROW(x,shift) \
310  (((((uint16_t)((x) >> ((shift) + 8))) & 0xFF)) | \
311  ((((uint16_t)((x) >> ((shift)))) & 0xFF) << 8))
312 
313 /* Extract the rows from a 64-bit round constant */
314 #define RC(x) \
315  {RC_EXTRACT_ROW((x), 48), RC_EXTRACT_ROW((x), 32), \
316  RC_EXTRACT_ROW((x), 16), RC_EXTRACT_ROW((x), 0)}
317 
318 /* Alpha constant for adjusting k1 for the inverse rounds */
319 #define ALPHA 0x243F6A8885A308D3ULL
320 #define ALPHA_ROW0 (RC_EXTRACT_ROW(ALPHA, 48))
321 #define ALPHA_ROW1 (RC_EXTRACT_ROW(ALPHA, 32))
322 #define ALPHA_ROW2 (RC_EXTRACT_ROW(ALPHA, 16))
323 #define ALPHA_ROW3 (RC_EXTRACT_ROW(ALPHA, 0))
324 
325 /* Round constants for Mantis, split up into 16-bit row values */
326 static uint16_t const rc[MANTIS_MAX_ROUNDS][4] = {
327  RC(0x13198A2E03707344ULL),
328  RC(0xA4093822299F31D0ULL),
329  RC(0x082EFA98EC4E6C89ULL),
330  RC(0x452821E638D01377ULL),
331  RC(0xBE5466CF34E90C6CULL),
332  RC(0xC0AC29B7C97C50DDULL),
333  RC(0x3F84D5B5B5470917ULL),
334  RC(0x9216D5D98979FB1BULL)
335 };
336 
337 static void mantis_ecb_encrypt_eight
338  (void *output, const SkinnyVector8x16_t *input, const MantisKey_t *ks)
339 {
340  const uint16_t *r = rc[0];
341  MantisCells_t tweak = ks->tweak;
342  MantisCells_t k1 = ks->k1;
343  MantisVectorCells_t state;
344  unsigned index;
345 
346  /* Read the rows of all eight counter blocks into memory */
347  state.row[0] = input[0];
348  state.row[1] = input[1];
349  state.row[2] = input[2];
350  state.row[3] = input[3];
351 
352  /* XOR the initial whitening key k0 with the state,
353  together with k1 and the initial tweak value */
354  state.row[0] ^= ks->k0.row[0] ^ k1.row[0] ^ tweak.row[0];
355  state.row[1] ^= ks->k0.row[1] ^ k1.row[1] ^ tweak.row[1];
356  state.row[2] ^= ks->k0.row[2] ^ k1.row[2] ^ tweak.row[2];
357  state.row[3] ^= ks->k0.row[3] ^ k1.row[3] ^ tweak.row[3];
358 
359  /* Perform all forward rounds */
360  for (index = ks->rounds; index > 0; --index) {
361  /* Update the tweak with the forward h function */
362  mantis_update_tweak(&tweak);
363 
364  /* Apply the S-box */
365  state.row[0] = mantis_sbox(state.row[0]);
366  state.row[1] = mantis_sbox(state.row[1]);
367  state.row[2] = mantis_sbox(state.row[2]);
368  state.row[3] = mantis_sbox(state.row[3]);
369 
370  /* Add the round constant */
371  state.row[0] ^= r[0];
372  state.row[1] ^= r[1];
373  state.row[2] ^= r[2];
374  state.row[3] ^= r[3];
375  r += 4;
376 
377  /* XOR with the key and tweak */
378  state.row[0] ^= k1.row[0] ^ tweak.row[0];
379  state.row[1] ^= k1.row[1] ^ tweak.row[1];
380  state.row[2] ^= k1.row[2] ^ tweak.row[2];
381  state.row[3] ^= k1.row[3] ^ tweak.row[3];
382 
383  /* Shift the rows */
384  mantis_shift_rows(&state);
385 
386  /* Mix the columns */
387  mantis_mix_columns(&state);
388  }
389 
390  /* Half-way there: sbox, mix, sbox */
391  state.row[0] = mantis_sbox(state.row[0]);
392  state.row[1] = mantis_sbox(state.row[1]);
393  state.row[2] = mantis_sbox(state.row[2]);
394  state.row[3] = mantis_sbox(state.row[3]);
395  mantis_mix_columns(&state);
396  state.row[0] = mantis_sbox(state.row[0]);
397  state.row[1] = mantis_sbox(state.row[1]);
398  state.row[2] = mantis_sbox(state.row[2]);
399  state.row[3] = mantis_sbox(state.row[3]);
400 
401  /* Convert k1 into k1 XOR alpha for the reverse rounds */
402  k1.row[0] ^= ALPHA_ROW0;
403  k1.row[1] ^= ALPHA_ROW1;
404  k1.row[2] ^= ALPHA_ROW2;
405  k1.row[3] ^= ALPHA_ROW3;
406 
407  /* Perform all reverse rounds */
408  for (index = ks->rounds; index > 0; --index) {
409  /* Inverse mix of the columns (same as the forward mix) */
410  mantis_mix_columns(&state);
411 
412  /* Inverse shift of the rows */
413  mantis_shift_rows_inverse(&state);
414 
415  /* XOR with the key and tweak */
416  state.row[0] ^= k1.row[0] ^ tweak.row[0];
417  state.row[1] ^= k1.row[1] ^ tweak.row[1];
418  state.row[2] ^= k1.row[2] ^ tweak.row[2];
419  state.row[3] ^= k1.row[3] ^ tweak.row[3];
420 
421  /* Add the round constant */
422  r -= 4;
423  state.row[0] ^= r[0];
424  state.row[1] ^= r[1];
425  state.row[2] ^= r[2];
426  state.row[3] ^= r[3];
427 
428  /* Apply the inverse S-box (which is the same as the forward S-box) */
429  state.row[0] = mantis_sbox(state.row[0]);
430  state.row[1] = mantis_sbox(state.row[1]);
431  state.row[2] = mantis_sbox(state.row[2]);
432  state.row[3] = mantis_sbox(state.row[3]);
433 
434  /* Update the tweak with the reverse h function */
435  mantis_update_tweak_inverse(&tweak);
436  }
437 
438  /* XOR the final whitening key k0prime with the state,
439  together with k1alpha and the final tweak value */
440  state.row[0] ^= ks->k0prime.row[0] ^ k1.row[0] ^ tweak.row[0];
441  state.row[1] ^= ks->k0prime.row[1] ^ k1.row[1] ^ tweak.row[1];
442  state.row[2] ^= ks->k0prime.row[2] ^ k1.row[2] ^ tweak.row[2];
443  state.row[3] ^= ks->k0prime.row[3] ^ k1.row[3] ^ tweak.row[3];
444 
445  /* Write the rows of all eight blocks back to memory.
446  Note: In this case, direct WRITE_WORD16() calls seem to give
447  better performance than rearranging the vectors and performing
448  an unaligned vector write */
449 #if 0 /* SKINNY_LITTLE_ENDIAN && SKINNY_UNALIGNED */
450  *((SkinnyVector8x16U_t *)output) =
451  (SkinnyVector8x16_t){state.row[0][0], state.row[1][0],
452  state.row[2][0], state.row[3][0],
453  state.row[0][1], state.row[1][1],
454  state.row[2][1], state.row[3][1]};
455  *((SkinnyVector8x16U_t *)(output + 16)) =
456  (SkinnyVector8x16_t){state.row[0][2], state.row[1][2],
457  state.row[2][2], state.row[3][2],
458  state.row[0][3], state.row[1][3],
459  state.row[2][3], state.row[3][3]};
460  *((SkinnyVector8x16U_t *)(output + 32)) =
461  (SkinnyVector8x16_t){state.row[0][4], state.row[1][4],
462  state.row[2][4], state.row[3][4],
463  state.row[0][5], state.row[1][5],
464  state.row[2][5], state.row[3][5]};
465  *((SkinnyVector8x16U_t *)(output + 48)) =
466  (SkinnyVector8x16_t){state.row[0][6], state.row[1][6],
467  state.row[2][6], state.row[3][6],
468  state.row[0][7], state.row[1][7],
469  state.row[2][7], state.row[3][7]};
470 #else
471  WRITE_WORD16(output, 0, state.row[0][0]);
472  WRITE_WORD16(output, 2, state.row[1][0]);
473  WRITE_WORD16(output, 4, state.row[2][0]);
474  WRITE_WORD16(output, 6, state.row[3][0]);
475  WRITE_WORD16(output, 8, state.row[0][1]);
476  WRITE_WORD16(output, 10, state.row[1][1]);
477  WRITE_WORD16(output, 12, state.row[2][1]);
478  WRITE_WORD16(output, 14, state.row[3][1]);
479  WRITE_WORD16(output, 16, state.row[0][2]);
480  WRITE_WORD16(output, 18, state.row[1][2]);
481  WRITE_WORD16(output, 20, state.row[2][2]);
482  WRITE_WORD16(output, 22, state.row[3][2]);
483  WRITE_WORD16(output, 24, state.row[0][3]);
484  WRITE_WORD16(output, 26, state.row[1][3]);
485  WRITE_WORD16(output, 28, state.row[2][3]);
486  WRITE_WORD16(output, 30, state.row[3][3]);
487  WRITE_WORD16(output, 32, state.row[0][4]);
488  WRITE_WORD16(output, 34, state.row[1][4]);
489  WRITE_WORD16(output, 36, state.row[2][4]);
490  WRITE_WORD16(output, 38, state.row[3][4]);
491  WRITE_WORD16(output, 40, state.row[0][5]);
492  WRITE_WORD16(output, 42, state.row[1][5]);
493  WRITE_WORD16(output, 44, state.row[2][5]);
494  WRITE_WORD16(output, 46, state.row[3][5]);
495  WRITE_WORD16(output, 48, state.row[0][6]);
496  WRITE_WORD16(output, 50, state.row[1][6]);
497  WRITE_WORD16(output, 52, state.row[2][6]);
498  WRITE_WORD16(output, 54, state.row[3][6]);
499  WRITE_WORD16(output, 56, state.row[0][7]);
500  WRITE_WORD16(output, 58, state.row[1][7]);
501  WRITE_WORD16(output, 60, state.row[2][7]);
502  WRITE_WORD16(output, 62, state.row[3][7]);
503 #endif
504 }
505 
506 static int mantis_ctr_vec128_encrypt
507  (void *output, const void *input, size_t size, MantisCTR_t *ctr)
508 {
509  MantisCTRVec128Ctx_t *ctx;
510  uint8_t *out = (uint8_t *)output;
511  const uint8_t *in = (const uint8_t *)input;
512 
513  /* Validate the parameters */
514  if (!output || !input)
515  return 0;
516  ctx = ctr->ctx;
517  if (!ctx)
518  return 0;
519 
520  /* Encrypt the input in CTR mode to create the output */
521  while (size > 0) {
522  if (ctx->offset >= MANTIS_CTR_BLOCK_SIZE) {
523  /* We need a new keystream block */
524  mantis_ecb_encrypt_eight(ctx->ecounter, ctx->counter, &(ctx->ks));
525  mantis_ctr_increment(ctx->counter, 0, 8);
526  mantis_ctr_increment(ctx->counter, 1, 8);
527  mantis_ctr_increment(ctx->counter, 2, 8);
528  mantis_ctr_increment(ctx->counter, 3, 8);
529  mantis_ctr_increment(ctx->counter, 4, 8);
530  mantis_ctr_increment(ctx->counter, 5, 8);
531  mantis_ctr_increment(ctx->counter, 6, 8);
532  mantis_ctr_increment(ctx->counter, 7, 8);
533 
534  /* XOR an entire keystream block in one go if possible */
535  if (size >= MANTIS_CTR_BLOCK_SIZE) {
536  skinny64_xor(out, in, ctx->ecounter);
537  skinny64_xor(out + MANTIS_BLOCK_SIZE,
538  in + MANTIS_BLOCK_SIZE,
539  ctx->ecounter + MANTIS_BLOCK_SIZE);
540  skinny64_xor(out + MANTIS_BLOCK_SIZE * 2,
541  in + MANTIS_BLOCK_SIZE * 2,
542  ctx->ecounter + MANTIS_BLOCK_SIZE * 2);
543  skinny64_xor(out + MANTIS_BLOCK_SIZE * 3,
544  in + MANTIS_BLOCK_SIZE * 3,
545  ctx->ecounter + MANTIS_BLOCK_SIZE * 3);
546  skinny64_xor(out + MANTIS_BLOCK_SIZE * 4,
547  in + MANTIS_BLOCK_SIZE * 4,
548  ctx->ecounter + MANTIS_BLOCK_SIZE * 4);
549  skinny64_xor(out + MANTIS_BLOCK_SIZE * 5,
550  in + MANTIS_BLOCK_SIZE * 5,
551  ctx->ecounter + MANTIS_BLOCK_SIZE * 5);
552  skinny64_xor(out + MANTIS_BLOCK_SIZE * 6,
553  in + MANTIS_BLOCK_SIZE * 6,
554  ctx->ecounter + MANTIS_BLOCK_SIZE * 6);
555  skinny64_xor(out + MANTIS_BLOCK_SIZE * 7,
556  in + MANTIS_BLOCK_SIZE * 7,
557  ctx->ecounter + MANTIS_BLOCK_SIZE * 7);
558  out += MANTIS_CTR_BLOCK_SIZE;
559  in += MANTIS_CTR_BLOCK_SIZE;
560  size -= MANTIS_CTR_BLOCK_SIZE;
561  } else {
562  /* Last partial block in the request */
563  skinny_xor(out, in, ctx->ecounter, size);
564  ctx->offset = size;
565  break;
566  }
567  } else {
568  /* Left-over keystream data from the last request */
569  size_t temp = MANTIS_CTR_BLOCK_SIZE - ctx->offset;
570  if (temp > size)
571  temp = size;
572  skinny_xor(out, in, ctx->ecounter + ctx->offset, temp);
573  ctx->offset += temp;
574  out += temp;
575  in += temp;
576  size -= temp;
577  }
578  }
579  return 1;
580 }
581 
583 MantisCTRVtable_t const _mantis_ctr_vec128 = {
584  mantis_ctr_vec128_init,
585  mantis_ctr_vec128_cleanup,
586  mantis_ctr_vec128_set_key,
587  mantis_ctr_vec128_set_tweak,
588  mantis_ctr_vec128_set_counter,
589  mantis_ctr_vec128_encrypt
590 };
591 
592 #else /* !SKINNY_VEC128_MATH */
593 
594 /* Stubbed out */
595 MantisCTRVtable_t const _mantis_ctr_vec128;
596 
597 #endif /* SKINNY_VEC128_MATH */
#define MANTIS_ENCRYPT
Mode that selects Mantis encryption when the key schedule is setup.
Definition: mantis-cipher.h:87
MantisCells_t tweak
int mantis_set_tweak(MantisKey_t *ks, const void *tweak, unsigned size)
Sets the tweak value for a previously-initialized key schedule.
MantisCells_t k1
#define MANTIS_MAX_ROUNDS
Maximum number of rounds for Mantis block ciphers.
Definition: mantis-cipher.h:82
#define MANTIS_BLOCK_SIZE
Size of a block for Mantis block ciphers.
Definition: mantis-cipher.h:59
unsigned rounds
int mantis_set_key(MantisKey_t *ks, const void *key, unsigned size, unsigned rounds, int mode)
Sets the key schedule for a Mantis block cipher.
MantisCells_t k0prime
State information for Mantis in CTR mode.
Key schedule for Mantis block ciphers.
MantisCells_t k0
Union that describes a 64-bit 4x4 array of cells.
Definition: mantis-cipher.h:97
uint16_t row[4]
Definition: mantis-cipher.h:99