1 /*
2 * CAST-128
3 * (C) 1999-2007 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/cast128.h>
9 #include <botan/internal/cast_sboxes.h>
10 #include <botan/loadstor.h>
11 #include <botan/rotate.h>
12 
13 namespace Botan {
14 
15 namespace {
16 
17 /*
18 * CAST-128 Round Type 1
19 */
F1(uint32_t R,uint32_t MK,uint8_t RK)20 inline uint32_t F1(uint32_t R, uint32_t MK, uint8_t RK)
21    {
22    const uint32_t T = rotl_var(MK + R, RK);
23    return (CAST_SBOX1[get_byte(0, T)] ^ CAST_SBOX2[get_byte(1, T)]) -
24            CAST_SBOX3[get_byte(2, T)] + CAST_SBOX4[get_byte(3, T)];
25    }
26 
27 /*
28 * CAST-128 Round Type 2
29 */
F2(uint32_t R,uint32_t MK,uint8_t RK)30 inline uint32_t F2(uint32_t R, uint32_t MK, uint8_t RK)
31    {
32    const uint32_t T = rotl_var(MK ^ R, RK);
33    return (CAST_SBOX1[get_byte(0, T)]  - CAST_SBOX2[get_byte(1, T)] +
34            CAST_SBOX3[get_byte(2, T)]) ^ CAST_SBOX4[get_byte(3, T)];
35    }
36 
37 /*
38 * CAST-128 Round Type 3
39 */
F3(uint32_t R,uint32_t MK,uint8_t RK)40 inline uint32_t F3(uint32_t R, uint32_t MK, uint8_t RK)
41    {
42    const uint32_t T = rotl_var(MK - R, RK);
43    return ((CAST_SBOX1[get_byte(0, T)]  + CAST_SBOX2[get_byte(1, T)]) ^
44             CAST_SBOX3[get_byte(2, T)]) - CAST_SBOX4[get_byte(3, T)];
45    }
46 
47 }
48 
49 /*
50 * CAST-128 Encryption
51 */
encrypt_n(const uint8_t in[],uint8_t out[],size_t blocks) const52 void CAST_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
53    {
54    verify_key_set(m_RK.empty() == false);
55 
56    while(blocks >= 2)
57       {
58       uint32_t L0, R0, L1, R1;
59       load_be(in, L0, R0, L1, R1);
60 
61       L0 ^= F1(R0, m_MK[ 0], m_RK[ 0]);
62       L1 ^= F1(R1, m_MK[ 0], m_RK[ 0]);
63       R0 ^= F2(L0, m_MK[ 1], m_RK[ 1]);
64       R1 ^= F2(L1, m_MK[ 1], m_RK[ 1]);
65       L0 ^= F3(R0, m_MK[ 2], m_RK[ 2]);
66       L1 ^= F3(R1, m_MK[ 2], m_RK[ 2]);
67       R0 ^= F1(L0, m_MK[ 3], m_RK[ 3]);
68       R1 ^= F1(L1, m_MK[ 3], m_RK[ 3]);
69       L0 ^= F2(R0, m_MK[ 4], m_RK[ 4]);
70       L1 ^= F2(R1, m_MK[ 4], m_RK[ 4]);
71       R0 ^= F3(L0, m_MK[ 5], m_RK[ 5]);
72       R1 ^= F3(L1, m_MK[ 5], m_RK[ 5]);
73       L0 ^= F1(R0, m_MK[ 6], m_RK[ 6]);
74       L1 ^= F1(R1, m_MK[ 6], m_RK[ 6]);
75       R0 ^= F2(L0, m_MK[ 7], m_RK[ 7]);
76       R1 ^= F2(L1, m_MK[ 7], m_RK[ 7]);
77       L0 ^= F3(R0, m_MK[ 8], m_RK[ 8]);
78       L1 ^= F3(R1, m_MK[ 8], m_RK[ 8]);
79       R0 ^= F1(L0, m_MK[ 9], m_RK[ 9]);
80       R1 ^= F1(L1, m_MK[ 9], m_RK[ 9]);
81       L0 ^= F2(R0, m_MK[10], m_RK[10]);
82       L1 ^= F2(R1, m_MK[10], m_RK[10]);
83       R0 ^= F3(L0, m_MK[11], m_RK[11]);
84       R1 ^= F3(L1, m_MK[11], m_RK[11]);
85       L0 ^= F1(R0, m_MK[12], m_RK[12]);
86       L1 ^= F1(R1, m_MK[12], m_RK[12]);
87       R0 ^= F2(L0, m_MK[13], m_RK[13]);
88       R1 ^= F2(L1, m_MK[13], m_RK[13]);
89       L0 ^= F3(R0, m_MK[14], m_RK[14]);
90       L1 ^= F3(R1, m_MK[14], m_RK[14]);
91       R0 ^= F1(L0, m_MK[15], m_RK[15]);
92       R1 ^= F1(L1, m_MK[15], m_RK[15]);
93 
94       store_be(out, R0, L0, R1, L1);
95 
96       blocks -= 2;
97       out += 2 * BLOCK_SIZE;
98       in  += 2 * BLOCK_SIZE;
99       }
100 
101    if(blocks)
102       {
103       uint32_t L, R;
104       load_be(in, L, R);
105 
106       L ^= F1(R, m_MK[ 0], m_RK[ 0]);
107       R ^= F2(L, m_MK[ 1], m_RK[ 1]);
108       L ^= F3(R, m_MK[ 2], m_RK[ 2]);
109       R ^= F1(L, m_MK[ 3], m_RK[ 3]);
110       L ^= F2(R, m_MK[ 4], m_RK[ 4]);
111       R ^= F3(L, m_MK[ 5], m_RK[ 5]);
112       L ^= F1(R, m_MK[ 6], m_RK[ 6]);
113       R ^= F2(L, m_MK[ 7], m_RK[ 7]);
114       L ^= F3(R, m_MK[ 8], m_RK[ 8]);
115       R ^= F1(L, m_MK[ 9], m_RK[ 9]);
116       L ^= F2(R, m_MK[10], m_RK[10]);
117       R ^= F3(L, m_MK[11], m_RK[11]);
118       L ^= F1(R, m_MK[12], m_RK[12]);
119       R ^= F2(L, m_MK[13], m_RK[13]);
120       L ^= F3(R, m_MK[14], m_RK[14]);
121       R ^= F1(L, m_MK[15], m_RK[15]);
122 
123       store_be(out, R, L);
124       }
125    }
126 
127 /*
128 * CAST-128 Decryption
129 */
decrypt_n(const uint8_t in[],uint8_t out[],size_t blocks) const130 void CAST_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const
131    {
132    verify_key_set(m_RK.empty() == false);
133 
134    while(blocks >= 2)
135       {
136       uint32_t L0, R0, L1, R1;
137       load_be(in, L0, R0, L1, R1);
138 
139       L0 ^= F1(R0, m_MK[15], m_RK[15]);
140       L1 ^= F1(R1, m_MK[15], m_RK[15]);
141       R0 ^= F3(L0, m_MK[14], m_RK[14]);
142       R1 ^= F3(L1, m_MK[14], m_RK[14]);
143       L0 ^= F2(R0, m_MK[13], m_RK[13]);
144       L1 ^= F2(R1, m_MK[13], m_RK[13]);
145       R0 ^= F1(L0, m_MK[12], m_RK[12]);
146       R1 ^= F1(L1, m_MK[12], m_RK[12]);
147       L0 ^= F3(R0, m_MK[11], m_RK[11]);
148       L1 ^= F3(R1, m_MK[11], m_RK[11]);
149       R0 ^= F2(L0, m_MK[10], m_RK[10]);
150       R1 ^= F2(L1, m_MK[10], m_RK[10]);
151       L0 ^= F1(R0, m_MK[ 9], m_RK[ 9]);
152       L1 ^= F1(R1, m_MK[ 9], m_RK[ 9]);
153       R0 ^= F3(L0, m_MK[ 8], m_RK[ 8]);
154       R1 ^= F3(L1, m_MK[ 8], m_RK[ 8]);
155       L0 ^= F2(R0, m_MK[ 7], m_RK[ 7]);
156       L1 ^= F2(R1, m_MK[ 7], m_RK[ 7]);
157       R0 ^= F1(L0, m_MK[ 6], m_RK[ 6]);
158       R1 ^= F1(L1, m_MK[ 6], m_RK[ 6]);
159       L0 ^= F3(R0, m_MK[ 5], m_RK[ 5]);
160       L1 ^= F3(R1, m_MK[ 5], m_RK[ 5]);
161       R0 ^= F2(L0, m_MK[ 4], m_RK[ 4]);
162       R1 ^= F2(L1, m_MK[ 4], m_RK[ 4]);
163       L0 ^= F1(R0, m_MK[ 3], m_RK[ 3]);
164       L1 ^= F1(R1, m_MK[ 3], m_RK[ 3]);
165       R0 ^= F3(L0, m_MK[ 2], m_RK[ 2]);
166       R1 ^= F3(L1, m_MK[ 2], m_RK[ 2]);
167       L0 ^= F2(R0, m_MK[ 1], m_RK[ 1]);
168       L1 ^= F2(R1, m_MK[ 1], m_RK[ 1]);
169       R0 ^= F1(L0, m_MK[ 0], m_RK[ 0]);
170       R1 ^= F1(L1, m_MK[ 0], m_RK[ 0]);
171 
172       store_be(out, R0, L0, R1, L1);
173 
174       blocks -= 2;
175       out += 2 * BLOCK_SIZE;
176       in  += 2 * BLOCK_SIZE;
177       }
178 
179    if(blocks)
180       {
181       uint32_t L, R;
182       load_be(in, L, R);
183 
184       L ^= F1(R, m_MK[15], m_RK[15]);
185       R ^= F3(L, m_MK[14], m_RK[14]);
186       L ^= F2(R, m_MK[13], m_RK[13]);
187       R ^= F1(L, m_MK[12], m_RK[12]);
188       L ^= F3(R, m_MK[11], m_RK[11]);
189       R ^= F2(L, m_MK[10], m_RK[10]);
190       L ^= F1(R, m_MK[ 9], m_RK[ 9]);
191       R ^= F3(L, m_MK[ 8], m_RK[ 8]);
192       L ^= F2(R, m_MK[ 7], m_RK[ 7]);
193       R ^= F1(L, m_MK[ 6], m_RK[ 6]);
194       L ^= F3(R, m_MK[ 5], m_RK[ 5]);
195       R ^= F2(L, m_MK[ 4], m_RK[ 4]);
196       L ^= F1(R, m_MK[ 3], m_RK[ 3]);
197       R ^= F3(L, m_MK[ 2], m_RK[ 2]);
198       L ^= F2(R, m_MK[ 1], m_RK[ 1]);
199       R ^= F1(L, m_MK[ 0], m_RK[ 0]);
200 
201       store_be(out, R, L);
202       }
203    }
204 
205 /*
206 * CAST-128 Key Schedule
207 */
key_schedule(const uint8_t key[],size_t length)208 void CAST_128::key_schedule(const uint8_t key[], size_t length)
209    {
210    m_MK.resize(48);
211    m_RK.resize(48);
212 
213    secure_vector<uint8_t> key16(16);
214    copy_mem(key16.data(), key, length);
215 
216    secure_vector<uint32_t> X(4);
217    for(size_t i = 0; i != 4; ++i)
218       X[i] = load_be<uint32_t>(key16.data(), i);
219 
220    cast_ks(m_MK, X);
221 
222    secure_vector<uint32_t> RK32(48);
223    cast_ks(RK32, X);
224 
225    for(size_t i = 0; i != 16; ++i)
226       m_RK[i] = RK32[i] % 32;
227    }
228 
clear()229 void CAST_128::clear()
230    {
231    zap(m_MK);
232    zap(m_RK);
233    }
234 
235 /*
236 * S-Box Based Key Expansion
237 */
cast_ks(secure_vector<uint32_t> & K,secure_vector<uint32_t> & X)238 void CAST_128::cast_ks(secure_vector<uint32_t>& K,
239                        secure_vector<uint32_t>& X)
240    {
241    alignas(64) static const uint32_t S5[256] = {
242       0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5,
243       0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00,
244       0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD,
245       0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF,
246       0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB,
247       0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725,
248       0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040,
249       0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7,
250       0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2,
251       0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC,
252       0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399,
253       0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774,
254       0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966,
255       0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468,
256       0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9,
257       0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910,
258       0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616,
259       0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4,
260       0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419,
261       0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049,
262       0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9,
263       0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6,
264       0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C,
265       0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE,
266       0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715,
267       0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6,
268       0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D,
269       0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4,
270       0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA,
271       0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487,
272       0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4,
273       0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5,
274       0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C,
275       0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78,
276       0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87,
277       0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801,
278       0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110,
279       0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58,
280       0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3,
281       0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20,
282       0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D,
283       0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55,
284       0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 };
285 
286    alignas(64) static const uint32_t S6[256] = {
287       0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4,
288       0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9,
289       0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD,
290       0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367,
291       0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F,
292       0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C,
293       0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0,
294       0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3,
295       0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941,
296       0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D,
297       0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223,
298       0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9,
299       0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6,
300       0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A,
301       0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7,
302       0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC,
303       0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89,
304       0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE,
305       0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0,
306       0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F,
307       0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4,
308       0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853,
309       0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87,
310       0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F,
311       0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585,
312       0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751,
313       0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75,
314       0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13,
315       0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283,
316       0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459,
317       0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF,
318       0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891,
319       0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0,
320       0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB,
321       0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200,
322       0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084,
323       0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF,
324       0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B,
325       0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869,
326       0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5,
327       0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB,
328       0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454,
329       0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F };
330 
331    alignas(64) static const uint32_t S7[256] = {
332       0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912,
333       0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82,
334       0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9,
335       0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43,
336       0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4,
337       0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9,
338       0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE,
339       0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516,
340       0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7,
341       0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E,
342       0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E,
343       0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756,
344       0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9,
345       0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B,
346       0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3,
347       0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688,
348       0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C,
349       0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802,
350       0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778,
351       0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7,
352       0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE,
353       0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858,
354       0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310,
355       0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A,
356       0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476,
357       0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF,
358       0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70,
359       0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962,
360       0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A,
361       0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07,
362       0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C,
363       0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C,
364       0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E,
365       0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378,
366       0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E,
367       0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE,
368       0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301,
369       0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2,
370       0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4,
371       0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914,
372       0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021,
373       0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA,
374       0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 };
375 
376    alignas(64) static const uint32_t S8[256] = {
377       0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B,
378       0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174,
379       0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C,
380       0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD,
381       0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7,
382       0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164,
383       0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D,
384       0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862,
385       0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8,
386       0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6,
387       0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04,
388       0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E,
389       0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38,
390       0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8,
391       0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354,
392       0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42,
393       0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160,
394       0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB,
395       0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2,
396       0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225,
397       0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98,
398       0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441,
399       0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4,
400       0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054,
401       0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5,
402       0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C,
403       0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5,
404       0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C,
405       0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B,
406       0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4,
407       0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084,
408       0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101,
409       0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A,
410       0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF,
411       0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77,
412       0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A,
413       0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F,
414       0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819,
415       0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3,
416       0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C,
417       0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1,
418       0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D,
419       0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E };
420 
421    class ByteReader final
422       {
423       public:
424          uint8_t operator()(size_t i) const
425             {
426             return static_cast<uint8_t>(m_X[i/4] >> (8*(3 - (i%4))));
427             }
428 
429          explicit ByteReader(const uint32_t* x) : m_X(x) {}
430       private:
431          const uint32_t* m_X;
432       };
433 
434    secure_vector<uint32_t> Z(4);
435    ByteReader x(X.data()), z(Z.data());
436 
437    Z[0]  = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)];
438    Z[1]  = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)];
439    Z[2]  = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)];
440    Z[3]  = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)];
441    K[ 0] = S5[z( 8)] ^ S6[z( 9)] ^ S7[z( 7)] ^ S8[z( 6)] ^ S5[z( 2)];
442    K[ 1] = S5[z(10)] ^ S6[z(11)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S6[z( 6)];
443    K[ 2] = S5[z(12)] ^ S6[z(13)] ^ S7[z( 3)] ^ S8[z( 2)] ^ S7[z( 9)];
444    K[ 3] = S5[z(14)] ^ S6[z(15)] ^ S7[z( 1)] ^ S8[z( 0)] ^ S8[z(12)];
445    X[0]  = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)];
446    X[1]  = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)];
447    X[2]  = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)];
448    X[3]  = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)];
449    K[ 4] = S5[x( 3)] ^ S6[x( 2)] ^ S7[x(12)] ^ S8[x(13)] ^ S5[x( 8)];
450    K[ 5] = S5[x( 1)] ^ S6[x( 0)] ^ S7[x(14)] ^ S8[x(15)] ^ S6[x(13)];
451    K[ 6] = S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 8)] ^ S8[x( 9)] ^ S7[x( 3)];
452    K[ 7] = S5[x( 5)] ^ S6[x( 4)] ^ S7[x(10)] ^ S8[x(11)] ^ S8[x( 7)];
453    Z[0]  = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)];
454    Z[1]  = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)];
455    Z[2]  = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)];
456    Z[3]  = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)];
457    K[ 8] = S5[z( 3)] ^ S6[z( 2)] ^ S7[z(12)] ^ S8[z(13)] ^ S5[z( 9)];
458    K[ 9] = S5[z( 1)] ^ S6[z( 0)] ^ S7[z(14)] ^ S8[z(15)] ^ S6[z(12)];
459    K[10] = S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 8)] ^ S8[z( 9)] ^ S7[z( 2)];
460    K[11] = S5[z( 5)] ^ S6[z( 4)] ^ S7[z(10)] ^ S8[z(11)] ^ S8[z( 6)];
461    X[0]  = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)];
462    X[1]  = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)];
463    X[2]  = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)];
464    X[3]  = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)];
465    K[12] = S5[x( 8)] ^ S6[x( 9)] ^ S7[x( 7)] ^ S8[x( 6)] ^ S5[x( 3)];
466    K[13] = S5[x(10)] ^ S6[x(11)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S6[x( 7)];
467    K[14] = S5[x(12)] ^ S6[x(13)] ^ S7[x( 3)] ^ S8[x( 2)] ^ S7[x( 8)];
468    K[15] = S5[x(14)] ^ S6[x(15)] ^ S7[x( 1)] ^ S8[x( 0)] ^ S8[x(13)];
469    }
470 
471 }
472