Coverage Report

Created: 2020-05-23 13:54

/src/botan/src/lib/block/threefish_512/threefish_512.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Threefish-512
3
* (C) 2013,2014,2016 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/threefish_512.h>
9
#include <botan/loadstor.h>
10
#include <botan/rotate.h>
11
#include <botan/cpuid.h>
12
13
namespace Botan {
14
15
#define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \
16
0
   do {                                                              \
17
0
      X0 += X4;                                                      \
18
0
      X1 += X5;                                                      \
19
0
      X2 += X6;                                                      \
20
0
      X3 += X7;                                                      \
21
0
      X4 = rotl<ROT1>(X4);                                           \
22
0
      X5 = rotl<ROT2>(X5);                                           \
23
0
      X6 = rotl<ROT3>(X6);                                           \
24
0
      X7 = rotl<ROT4>(X7);                                           \
25
0
      X4 ^= X0;                                                      \
26
0
      X5 ^= X1;                                                      \
27
0
      X6 ^= X2;                                                      \
28
0
      X7 ^= X3;                                                      \
29
0
   } while(0)
30
31
#define THREEFISH_INJECT_KEY(r)              \
32
0
   do {                                      \
33
0
      X0 += m_K[(r  ) % 9];                  \
34
0
      X1 += m_K[(r+1) % 9];                  \
35
0
      X2 += m_K[(r+2) % 9];                  \
36
0
      X3 += m_K[(r+3) % 9];                  \
37
0
      X4 += m_K[(r+4) % 9];                  \
38
0
      X5 += m_K[(r+5) % 9] + m_T[(r  ) % 3]; \
39
0
      X6 += m_K[(r+6) % 9] + m_T[(r+1) % 3]; \
40
0
      X7 += m_K[(r+7) % 9] + (r);            \
41
0
   } while(0)
42
43
#define THREEFISH_ENC_8_ROUNDS(R1,R2)                         \
44
0
   do {                                                       \
45
0
      THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37); \
46
0
      THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42); \
47
0
      THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39); \
48
0
      THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56); \
49
0
      THREEFISH_INJECT_KEY(R1);                               \
50
0
                                                              \
51
0
      THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24); \
52
0
      THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17); \
53
0
      THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43); \
54
0
      THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3,  8,35,56,22); \
55
0
      THREEFISH_INJECT_KEY(R2);                               \
56
0
   } while(0)
57
58
void Threefish_512::skein_feedfwd(const secure_vector<uint64_t>& M,
59
                                  const secure_vector<uint64_t>& T)
60
0
   {
61
0
   BOTAN_ASSERT(m_K.size() == 9, "Key was set");
62
0
   BOTAN_ASSERT(M.size() == 8, "Single block");
63
0
64
0
   m_T[0] = T[0];
65
0
   m_T[1] = T[1];
66
0
   m_T[2] = T[0] ^ T[1];
67
0
68
0
   uint64_t X0 = M[0];
69
0
   uint64_t X1 = M[1];
70
0
   uint64_t X2 = M[2];
71
0
   uint64_t X3 = M[3];
72
0
   uint64_t X4 = M[4];
73
0
   uint64_t X5 = M[5];
74
0
   uint64_t X6 = M[6];
75
0
   uint64_t X7 = M[7];
76
0
77
0
   THREEFISH_INJECT_KEY(0);
78
0
79
0
   THREEFISH_ENC_8_ROUNDS(1,2);
80
0
   THREEFISH_ENC_8_ROUNDS(3,4);
81
0
   THREEFISH_ENC_8_ROUNDS(5,6);
82
0
   THREEFISH_ENC_8_ROUNDS(7,8);
83
0
   THREEFISH_ENC_8_ROUNDS(9,10);
84
0
   THREEFISH_ENC_8_ROUNDS(11,12);
85
0
   THREEFISH_ENC_8_ROUNDS(13,14);
86
0
   THREEFISH_ENC_8_ROUNDS(15,16);
87
0
   THREEFISH_ENC_8_ROUNDS(17,18);
88
0
89
0
   m_K[0] = M[0] ^ X0;
90
0
   m_K[1] = M[1] ^ X1;
91
0
   m_K[2] = M[2] ^ X2;
92
0
   m_K[3] = M[3] ^ X3;
93
0
   m_K[4] = M[4] ^ X4;
94
0
   m_K[5] = M[5] ^ X5;
95
0
   m_K[6] = M[6] ^ X6;
96
0
   m_K[7] = M[7] ^ X7;
97
0
98
0
   m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^
99
0
            m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22;
100
0
   }
101
102
size_t Threefish_512::parallelism() const
103
0
   {
104
0
#if defined(BOTAN_HAS_THREEFISH_512_AVX2)
105
0
   if(CPUID::has_avx2())
106
0
      {
107
0
      return 2;
108
0
      }
109
0
#endif
110
0
111
0
   return 1;
112
0
   }
113
114
std::string Threefish_512::provider() const
115
0
   {
116
0
#if defined(BOTAN_HAS_THREEFISH_512_AVX2)
117
0
   if(CPUID::has_avx2())
118
0
      {
119
0
      return "avx2";
120
0
      }
121
0
#endif
122
0
123
0
   return "base";
124
0
   }
125
126
void Threefish_512::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
127
0
   {
128
0
   verify_key_set(m_K.empty() == false);
129
0
130
0
#if defined(BOTAN_HAS_THREEFISH_512_AVX2)
131
0
   if(CPUID::has_avx2())
132
0
      {
133
0
      return avx2_encrypt_n(in, out, blocks);
134
0
      }
135
0
#endif
136
0
137
0
   BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i)
138
0
      {
139
0
      uint64_t X0, X1, X2, X3, X4, X5, X6, X7;
140
0
      load_le(in + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7);
141
0
142
0
      THREEFISH_INJECT_KEY(0);
143
0
144
0
      THREEFISH_ENC_8_ROUNDS(1,2);
145
0
      THREEFISH_ENC_8_ROUNDS(3,4);
146
0
      THREEFISH_ENC_8_ROUNDS(5,6);
147
0
      THREEFISH_ENC_8_ROUNDS(7,8);
148
0
      THREEFISH_ENC_8_ROUNDS(9,10);
149
0
      THREEFISH_ENC_8_ROUNDS(11,12);
150
0
      THREEFISH_ENC_8_ROUNDS(13,14);
151
0
      THREEFISH_ENC_8_ROUNDS(15,16);
152
0
      THREEFISH_ENC_8_ROUNDS(17,18);
153
0
154
0
      store_le(out + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7);
155
0
      }
156
0
   }
157
158
#undef THREEFISH_ENC_8_ROUNDS
159
#undef THREEFISH_INJECT_KEY
160
#undef THREEFISH_ROUND
161
162
void Threefish_512::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
163
0
   {
164
0
   verify_key_set(m_K.empty() == false);
165
0
166
0
#if defined(BOTAN_HAS_THREEFISH_512_AVX2)
167
0
   if(CPUID::has_avx2())
168
0
      {
169
0
      return avx2_decrypt_n(in, out, blocks);
170
0
      }
171
0
#endif
172
0
173
0
#define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \
174
0
   do {                                                              \
175
0
      X4 ^= X0;                                                      \
176
0
      X5 ^= X1;                                                      \
177
0
      X6 ^= X2;                                                      \
178
0
      X7 ^= X3;                                                      \
179
0
      X4 = rotr<ROT1>(X4);                                           \
180
0
      X5 = rotr<ROT2>(X5);                                           \
181
0
      X6 = rotr<ROT3>(X6);                                           \
182
0
      X7 = rotr<ROT4>(X7);                                           \
183
0
      X0 -= X4;                                                      \
184
0
      X1 -= X5;                                                      \
185
0
      X2 -= X6;                                                      \
186
0
      X3 -= X7;                                                      \
187
0
   } while(0)
188
0
189
0
#define THREEFISH_INJECT_KEY(r)              \
190
0
   do {                                      \
191
0
      X0 -= m_K[(r  ) % 9];                  \
192
0
      X1 -= m_K[(r+1) % 9];                  \
193
0
      X2 -= m_K[(r+2) % 9];                  \
194
0
      X3 -= m_K[(r+3) % 9];                  \
195
0
      X4 -= m_K[(r+4) % 9];                  \
196
0
      X5 -= m_K[(r+5) % 9] + m_T[(r  ) % 3]; \
197
0
      X6 -= m_K[(r+6) % 9] + m_T[(r+1) % 3]; \
198
0
      X7 -= m_K[(r+7) % 9] + (r);            \
199
0
   } while(0)
200
0
201
0
#define THREEFISH_DEC_8_ROUNDS(R1,R2)                         \
202
0
   do {                                                       \
203
0
      THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3,  8,35,56,22); \
204
0
      THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43); \
205
0
      THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17); \
206
0
      THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24); \
207
0
      THREEFISH_INJECT_KEY(R1);                               \
208
0
                                                              \
209
0
      THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56); \
210
0
      THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39); \
211
0
      THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42); \
212
0
      THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37); \
213
0
      THREEFISH_INJECT_KEY(R2);                               \
214
0
   } while(0)
215
0
216
0
   BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i)
217
0
      {
218
0
      uint64_t X0, X1, X2, X3, X4, X5, X6, X7;
219
0
      load_le(in + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7);
220
0
221
0
      THREEFISH_INJECT_KEY(18);
222
0
223
0
      THREEFISH_DEC_8_ROUNDS(17,16);
224
0
      THREEFISH_DEC_8_ROUNDS(15,14);
225
0
      THREEFISH_DEC_8_ROUNDS(13,12);
226
0
      THREEFISH_DEC_8_ROUNDS(11,10);
227
0
      THREEFISH_DEC_8_ROUNDS(9,8);
228
0
      THREEFISH_DEC_8_ROUNDS(7,6);
229
0
      THREEFISH_DEC_8_ROUNDS(5,4);
230
0
      THREEFISH_DEC_8_ROUNDS(3,2);
231
0
      THREEFISH_DEC_8_ROUNDS(1,0);
232
0
233
0
      store_le(out + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7);
234
0
      }
235
0
236
0
#undef THREEFISH_DEC_8_ROUNDS
237
0
#undef THREEFISH_INJECT_KEY
238
0
#undef THREEFISH_ROUND
239
0
   }
240
241
void Threefish_512::set_tweak(const uint8_t tweak[], size_t len)
242
0
   {
243
0
   BOTAN_ARG_CHECK(len == 16, "Threefish-512 requires 128 bit tweak");
244
0
245
0
   m_T.resize(3);
246
0
   m_T[0] = load_le<uint64_t>(tweak, 0);
247
0
   m_T[1] = load_le<uint64_t>(tweak, 1);
248
0
   m_T[2] = m_T[0] ^ m_T[1];
249
0
   }
250
251
void Threefish_512::key_schedule(const uint8_t key[], size_t)
252
0
   {
253
0
   // todo: define key schedule for smaller keys
254
0
   m_K.resize(9);
255
0
256
0
   for(size_t i = 0; i != 8; ++i)
257
0
      m_K[i] = load_le<uint64_t>(key, i);
258
0
259
0
   m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^
260
0
            m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22;
261
0
262
0
   // Reset tweak to all zeros on key reset
263
0
   m_T.resize(3);
264
0
   zeroise(m_T);
265
0
   }
266
267
void Threefish_512::clear()
268
0
   {
269
0
   zap(m_K);
270
0
   zap(m_T);
271
0
   }
272
273
}