/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 | | } |