1 module dcrypt.blockcipher.serpent;
2 
3 import dcrypt.blockcipher.blockcipher;
4 import dcrypt.bitmanip;
5 
6 /// Test serpent engine. Test vectors generated with BouncyCastle implementation.
7 unittest {
8 	
9 	string[] keys = [
10 		x"01010101010101010101010101010101",
11 		x"0101010101010101010101010101010101010101",
12 		x"010101010101010101010101010101010101010101010101",
13 		x"01010101010101010101010101010101010101010101010101010101",
14 		x"0101010101010101010101010101010101010101010101010101010101010101",
15 	];
16 	string[] plains = [
17 		x"01010101010101010101010101010101",
18 		x"01010101010101010101010101010101",
19 		x"01010101010101010101010101010101",
20 		x"01010101010101010101010101010101",
21 		x"01010101010101010101010101010101",
22 	];
23 	string[] ciphers = [
24 		x"63fc6f65f3f71e6d99d981be6de30751",
25 		x"bc794e453a1b0bfd2475f2a40bf842ba",
26 		x"292a63c6d15db833f38b40b153cc303c",
27 		x"80808b4b6e93b6ff929a6105b508acbe",
28 		x"4827fcff24454cf889642a5bb12397ec",
29 	];
30 	
31 	SerpentEngine t = new SerpentEngine();
32 	blockCipherTest(t, keys, plains, ciphers);
33 }
34 
35 alias BlockCipherWrapper!Serpent SerpentEngine;
36 
37 /**
38  * Serpent is a 128-bit 32-round block cipher with variable key lengths,
39  * including 128, 192 and 256 bit keys conjectured to be at least as
40  * secure as three-key triple-DES.
41  * <p>
42  * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
43  * candidate algorithm for the NIST AES Quest.>
44  * <p>
45  * For full details see the <a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">The Serpent home page</a>
46  */
47 @safe
48 public struct Serpent
49 {
50 
51 	public enum name = "Serpent";
52 	public enum blockSize = 16;
53 
54 	private {
55 		enum ROUNDS = 32;
56 		enum uint PHI  = 0x9E3779B9;       // (sqrt(5) - 1) * 2**31
57 
58 		uint X0, X1, X2, X3;    // registers
59 		uint[(ROUNDS + 1) * 4] wKey;
60 
61 		bool encrypting;
62 		bool initialized = false;
63 	}
64 
65 	/// Params:
66 	/// forEncryption = `false`: decrypt, `true`: encrypt
67 	/// userKey = Secret key.
68 	/// iv = Not used.
69 	void start(bool forEncryption, in ubyte[] userKey, in ubyte[] iv = null) nothrow @nogc
70 	{
71 		this.encrypting = forEncryption;
72 		makeWorkingKey(userKey);
73 		initialized = true;
74 	}
75 
76 	public uint processBlock(in ubyte[]  input, ubyte[]  output) nothrow @nogc
77 	in {
78 		assert(initialized, "Serpent engine not initialized");
79 		assert(blockSize<=input.length, "input buffer too short");
80 		assert(blockSize<=output.length, "output buffer too short");
81 	}
82 	body {
83 		if (encrypting)
84 		{
85 			encryptBlock(input, output);
86 		}
87 		else
88 		{
89 			decryptBlock(input, output);
90 		}
91 
92 		return blockSize;
93 	}
94 
95 	public void reset() pure nothrow @nogc
96 	{
97 	}
98 	
99 private:
100 	/**
101 	 * Expand a user-supplied key material into a session key.
102 	 *
103 	 * Params:
104 	 * key  The user-key bytes (multiples of 4) to use.
105 	 */
106 	private void makeWorkingKey(in ubyte[] key) nothrow @nogc
107 	in {
108 		assert(key.length % 4 == 0, "key must be a multiple of 4 bytes");
109 	}
110 	body {
111 		//
112 		// pad key to 256 bits
113 		//
114 		uint[16]   kPad;
115 		size_t     off = 0;
116 		uint     length = 0;
117 
118 		for (off = key.length - 4; off > 0; off -= 4)
119 		{
120 			kPad[length++] = fromBigEndian!uint(key[off..off+4]);
121 		}
122 
123 		if (off == 0)
124 		{
125 			kPad[length++] = fromBigEndian!uint(key[0..4]);
126 			if (length < 8)
127 			{
128 				kPad[length] = 1;
129 			}
130 		}
131 		else
132 		{
133 			assert(false, "key must be a multiple of 4 bytes");
134 		}
135 
136 		//
137 		// expand the padded key up to 33 x 128 bits of key material
138 		//
139 		enum amount = (ROUNDS + 1) * 4;
140 		alias wKey w;
141 
142 		//
143 		// compute w0 to w7 from w-8 to w-1
144 		//
145 		foreach (i;8..16)
146 		{
147 			kPad[i] = rotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11);
148 		}
149 
150 		w[0..8] = kPad[8..16];
151 
152 		//
153 		// compute w8 to w136
154 		//
155 		foreach(i;8..amount)
156 		{
157 			w[i] = rotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
158 		}
159 
160 		//
161 		// create the working keys by processing w with the Sbox and IP
162 		//
163 		sb3(w[0], w[1], w[2], w[3]);
164 		w[0] = X0;
165 		w[1] = X1;
166 		w[2] = X2;
167 		w[3] = X3;
168 		sb2(w[4], w[5], w[6], w[7]);
169 		w[4] = X0;
170 		w[5] = X1;
171 		w[6] = X2;
172 		w[7] = X3;
173 		sb1(w[8], w[9], w[10], w[11]);
174 		w[8] = X0;
175 		w[9] = X1;
176 		w[10] = X2;
177 		w[11] = X3;
178 		sb0(w[12], w[13], w[14], w[15]);
179 		w[12] = X0;
180 		w[13] = X1;
181 		w[14] = X2;
182 		w[15] = X3;
183 		sb7(w[16], w[17], w[18], w[19]);
184 		w[16] = X0;
185 		w[17] = X1;
186 		w[18] = X2;
187 		w[19] = X3;
188 		sb6(w[20], w[21], w[22], w[23]);
189 		w[20] = X0;
190 		w[21] = X1;
191 		w[22] = X2;
192 		w[23] = X3;
193 		sb5(w[24], w[25], w[26], w[27]);
194 		w[24] = X0;
195 		w[25] = X1;
196 		w[26] = X2;
197 		w[27] = X3;
198 		sb4(w[28], w[29], w[30], w[31]);
199 		w[28] = X0;
200 		w[29] = X1;
201 		w[30] = X2;
202 		w[31] = X3;
203 		sb3(w[32], w[33], w[34], w[35]);
204 		w[32] = X0;
205 		w[33] = X1;
206 		w[34] = X2;
207 		w[35] = X3;
208 		sb2(w[36], w[37], w[38], w[39]);
209 		w[36] = X0;
210 		w[37] = X1;
211 		w[38] = X2;
212 		w[39] = X3;
213 		sb1(w[40], w[41], w[42], w[43]);
214 		w[40] = X0;
215 		w[41] = X1;
216 		w[42] = X2;
217 		w[43] = X3;
218 		sb0(w[44], w[45], w[46], w[47]);
219 		w[44] = X0;
220 		w[45] = X1;
221 		w[46] = X2;
222 		w[47] = X3;
223 		sb7(w[48], w[49], w[50], w[51]);
224 		w[48] = X0;
225 		w[49] = X1;
226 		w[50] = X2;
227 		w[51] = X3;
228 		sb6(w[52], w[53], w[54], w[55]);
229 		w[52] = X0;
230 		w[53] = X1;
231 		w[54] = X2;
232 		w[55] = X3;
233 		sb5(w[56], w[57], w[58], w[59]);
234 		w[56] = X0;
235 		w[57] = X1;
236 		w[58] = X2;
237 		w[59] = X3;
238 		sb4(w[60], w[61], w[62], w[63]);
239 		w[60] = X0;
240 		w[61] = X1;
241 		w[62] = X2;
242 		w[63] = X3;
243 		sb3(w[64], w[65], w[66], w[67]);
244 		w[64] = X0;
245 		w[65] = X1;
246 		w[66] = X2;
247 		w[67] = X3;
248 		sb2(w[68], w[69], w[70], w[71]);
249 		w[68] = X0;
250 		w[69] = X1;
251 		w[70] = X2;
252 		w[71] = X3;
253 		sb1(w[72], w[73], w[74], w[75]);
254 		w[72] = X0;
255 		w[73] = X1;
256 		w[74] = X2;
257 		w[75] = X3;
258 		sb0(w[76], w[77], w[78], w[79]);
259 		w[76] = X0;
260 		w[77] = X1;
261 		w[78] = X2;
262 		w[79] = X3;
263 		sb7(w[80], w[81], w[82], w[83]);
264 		w[80] = X0;
265 		w[81] = X1;
266 		w[82] = X2;
267 		w[83] = X3;
268 		sb6(w[84], w[85], w[86], w[87]);
269 		w[84] = X0;
270 		w[85] = X1;
271 		w[86] = X2;
272 		w[87] = X3;
273 		sb5(w[88], w[89], w[90], w[91]);
274 		w[88] = X0;
275 		w[89] = X1;
276 		w[90] = X2;
277 		w[91] = X3;
278 		sb4(w[92], w[93], w[94], w[95]);
279 		w[92] = X0;
280 		w[93] = X1;
281 		w[94] = X2;
282 		w[95] = X3;
283 		sb3(w[96], w[97], w[98], w[99]);
284 		w[96] = X0;
285 		w[97] = X1;
286 		w[98] = X2;
287 		w[99] = X3;
288 		sb2(w[100], w[101], w[102], w[103]);
289 		w[100] = X0;
290 		w[101] = X1;
291 		w[102] = X2;
292 		w[103] = X3;
293 		sb1(w[104], w[105], w[106], w[107]);
294 		w[104] = X0;
295 		w[105] = X1;
296 		w[106] = X2;
297 		w[107] = X3;
298 		sb0(w[108], w[109], w[110], w[111]);
299 		w[108] = X0;
300 		w[109] = X1;
301 		w[110] = X2;
302 		w[111] = X3;
303 		sb7(w[112], w[113], w[114], w[115]);
304 		w[112] = X0;
305 		w[113] = X1;
306 		w[114] = X2;
307 		w[115] = X3;
308 		sb6(w[116], w[117], w[118], w[119]);
309 		w[116] = X0;
310 		w[117] = X1;
311 		w[118] = X2;
312 		w[119] = X3;
313 		sb5(w[120], w[121], w[122], w[123]);
314 		w[120] = X0;
315 		w[121] = X1;
316 		w[122] = X2;
317 		w[123] = X3;
318 		sb4(w[124], w[125], w[126], w[127]);
319 		w[124] = X0;
320 		w[125] = X1;
321 		w[126] = X2;
322 		w[127] = X3;
323 		sb3(w[128], w[129], w[130], w[131]);
324 		w[128] = X0;
325 		w[129] = X1;
326 		w[130] = X2;
327 		w[131] = X3;
328 	}
329 
330 	/**
331 	 * Encrypt one block of plaintext.
332 	 *
333 	 */
334 	private void encryptBlock(in ubyte[]  input, ubyte[]  output) nothrow @nogc
335 	{
336 		X3 = fromBigEndian!uint(input[0..4]);
337 		X2 = fromBigEndian!uint(input[4..8]);
338 		X1 = fromBigEndian!uint(input[8..12]);
339 		X0 = fromBigEndian!uint(input[12..16]);
340 
341 		sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3);
342 		LT();
343 		sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3);
344 		LT();
345 		sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3);
346 		LT();
347 		sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3);
348 		LT();
349 		sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3);
350 		LT();
351 		sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3);
352 		LT();
353 		sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3);
354 		LT();
355 		sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3);
356 		LT();
357 		sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3);
358 		LT();
359 		sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3);
360 		LT();
361 		sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3);
362 		LT();
363 		sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3);
364 		LT();
365 		sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3);
366 		LT();
367 		sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3);
368 		LT();
369 		sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3);
370 		LT();
371 		sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3);
372 		LT();
373 		sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3);
374 		LT();
375 		sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3);
376 		LT();
377 		sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3);
378 		LT();
379 		sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3);
380 		LT();
381 		sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3);
382 		LT();
383 		sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3);
384 		LT();
385 		sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3);
386 		LT();
387 		sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3);
388 		LT();
389 		sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3);
390 		LT();
391 		sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3);
392 		LT();
393 		sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3);
394 		LT();
395 		sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3);
396 		LT();
397 		sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3);
398 		LT();
399 		sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3);
400 		LT();
401 		sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3);
402 		LT();
403 		sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
404 
405 		toBigEndian!uint(wKey[131] ^ X3, output[0..4]);
406 		toBigEndian!uint(wKey[130] ^ X2, output[4..8]);
407 		toBigEndian!uint(wKey[129] ^ X1, output[8..12]);
408 		toBigEndian!uint(wKey[128] ^ X0, output[12..16]);
409 	}
410 
411 	/**
412 	 * Decrypt one block of ciphertext.
413 	 *
414 	 */
415 	private void decryptBlock(in ubyte[]  input, ubyte[]  output) nothrow @nogc
416 	{
417 		X3 = wKey[131] ^ fromBigEndian!uint(input[0..4]);
418 		X2 = wKey[130] ^ fromBigEndian!uint(input[4..8]);
419 		X1 = wKey[129] ^ fromBigEndian!uint(input[8..12]);
420 		X0 = wKey[128] ^ fromBigEndian!uint(input[12..16]);
421 
422 		ib7(X0, X1, X2, X3);
423 		X0 ^= wKey[124];
424 		X1 ^= wKey[125];
425 		X2 ^= wKey[126];
426 		X3 ^= wKey[127];
427 		inverseLT();
428 		ib6(X0, X1, X2, X3);
429 		X0 ^= wKey[120];
430 		X1 ^= wKey[121];
431 		X2 ^= wKey[122];
432 		X3 ^= wKey[123];
433 		inverseLT();
434 		ib5(X0, X1, X2, X3);
435 		X0 ^= wKey[116];
436 		X1 ^= wKey[117];
437 		X2 ^= wKey[118];
438 		X3 ^= wKey[119];
439 		inverseLT();
440 		ib4(X0, X1, X2, X3);
441 		X0 ^= wKey[112];
442 		X1 ^= wKey[113];
443 		X2 ^= wKey[114];
444 		X3 ^= wKey[115];
445 		inverseLT();
446 		ib3(X0, X1, X2, X3);
447 		X0 ^= wKey[108];
448 		X1 ^= wKey[109];
449 		X2 ^= wKey[110];
450 		X3 ^= wKey[111];
451 		inverseLT();
452 		ib2(X0, X1, X2, X3);
453 		X0 ^= wKey[104];
454 		X1 ^= wKey[105];
455 		X2 ^= wKey[106];
456 		X3 ^= wKey[107];
457 		inverseLT();
458 		ib1(X0, X1, X2, X3);
459 		X0 ^= wKey[100];
460 		X1 ^= wKey[101];
461 		X2 ^= wKey[102];
462 		X3 ^= wKey[103];
463 		inverseLT();
464 		ib0(X0, X1, X2, X3);
465 		X0 ^= wKey[96];
466 		X1 ^= wKey[97];
467 		X2 ^= wKey[98];
468 		X3 ^= wKey[99];
469 		inverseLT();
470 		ib7(X0, X1, X2, X3);
471 		X0 ^= wKey[92];
472 		X1 ^= wKey[93];
473 		X2 ^= wKey[94];
474 		X3 ^= wKey[95];
475 		inverseLT();
476 		ib6(X0, X1, X2, X3);
477 		X0 ^= wKey[88];
478 		X1 ^= wKey[89];
479 		X2 ^= wKey[90];
480 		X3 ^= wKey[91];
481 		inverseLT();
482 		ib5(X0, X1, X2, X3);
483 		X0 ^= wKey[84];
484 		X1 ^= wKey[85];
485 		X2 ^= wKey[86];
486 		X3 ^= wKey[87];
487 		inverseLT();
488 		ib4(X0, X1, X2, X3);
489 		X0 ^= wKey[80];
490 		X1 ^= wKey[81];
491 		X2 ^= wKey[82];
492 		X3 ^= wKey[83];
493 		inverseLT();
494 		ib3(X0, X1, X2, X3);
495 		X0 ^= wKey[76];
496 		X1 ^= wKey[77];
497 		X2 ^= wKey[78];
498 		X3 ^= wKey[79];
499 		inverseLT();
500 		ib2(X0, X1, X2, X3);
501 		X0 ^= wKey[72];
502 		X1 ^= wKey[73];
503 		X2 ^= wKey[74];
504 		X3 ^= wKey[75];
505 		inverseLT();
506 		ib1(X0, X1, X2, X3);
507 		X0 ^= wKey[68];
508 		X1 ^= wKey[69];
509 		X2 ^= wKey[70];
510 		X3 ^= wKey[71];
511 		inverseLT();
512 		ib0(X0, X1, X2, X3);
513 		X0 ^= wKey[64];
514 		X1 ^= wKey[65];
515 		X2 ^= wKey[66];
516 		X3 ^= wKey[67];
517 		inverseLT();
518 		ib7(X0, X1, X2, X3);
519 		X0 ^= wKey[60];
520 		X1 ^= wKey[61];
521 		X2 ^= wKey[62];
522 		X3 ^= wKey[63];
523 		inverseLT();
524 		ib6(X0, X1, X2, X3);
525 		X0 ^= wKey[56];
526 		X1 ^= wKey[57];
527 		X2 ^= wKey[58];
528 		X3 ^= wKey[59];
529 		inverseLT();
530 		ib5(X0, X1, X2, X3);
531 		X0 ^= wKey[52];
532 		X1 ^= wKey[53];
533 		X2 ^= wKey[54];
534 		X3 ^= wKey[55];
535 		inverseLT();
536 		ib4(X0, X1, X2, X3);
537 		X0 ^= wKey[48];
538 		X1 ^= wKey[49];
539 		X2 ^= wKey[50];
540 		X3 ^= wKey[51];
541 		inverseLT();
542 		ib3(X0, X1, X2, X3);
543 		X0 ^= wKey[44];
544 		X1 ^= wKey[45];
545 		X2 ^= wKey[46];
546 		X3 ^= wKey[47];
547 		inverseLT();
548 		ib2(X0, X1, X2, X3);
549 		X0 ^= wKey[40];
550 		X1 ^= wKey[41];
551 		X2 ^= wKey[42];
552 		X3 ^= wKey[43];
553 		inverseLT();
554 		ib1(X0, X1, X2, X3);
555 		X0 ^= wKey[36];
556 		X1 ^= wKey[37];
557 		X2 ^= wKey[38];
558 		X3 ^= wKey[39];
559 		inverseLT();
560 		ib0(X0, X1, X2, X3);
561 		X0 ^= wKey[32];
562 		X1 ^= wKey[33];
563 		X2 ^= wKey[34];
564 		X3 ^= wKey[35];
565 		inverseLT();
566 		ib7(X0, X1, X2, X3);
567 		X0 ^= wKey[28];
568 		X1 ^= wKey[29];
569 		X2 ^= wKey[30];
570 		X3 ^= wKey[31];
571 		inverseLT();
572 		ib6(X0, X1, X2, X3);
573 		X0 ^= wKey[24];
574 		X1 ^= wKey[25];
575 		X2 ^= wKey[26];
576 		X3 ^= wKey[27];
577 		inverseLT();
578 		ib5(X0, X1, X2, X3);
579 		X0 ^= wKey[20];
580 		X1 ^= wKey[21];
581 		X2 ^= wKey[22];
582 		X3 ^= wKey[23];
583 		inverseLT();
584 		ib4(X0, X1, X2, X3);
585 		X0 ^= wKey[16];
586 		X1 ^= wKey[17];
587 		X2 ^= wKey[18];
588 		X3 ^= wKey[19];
589 		inverseLT();
590 		ib3(X0, X1, X2, X3);
591 		X0 ^= wKey[12];
592 		X1 ^= wKey[13];
593 		X2 ^= wKey[14];
594 		X3 ^= wKey[15];
595 		inverseLT();
596 		ib2(X0, X1, X2, X3);
597 		X0 ^= wKey[8];
598 		X1 ^= wKey[9];
599 		X2 ^= wKey[10];
600 		X3 ^= wKey[11];
601 		inverseLT();
602 		ib1(X0, X1, X2, X3);
603 		X0 ^= wKey[4];
604 		X1 ^= wKey[5];
605 		X2 ^= wKey[6];
606 		X3 ^= wKey[7];
607 		inverseLT();
608 		ib0(X0, X1, X2, X3);
609 
610 		toBigEndian!uint(X3 ^ wKey[3], output[0..4]);
611 		toBigEndian!uint(X2 ^ wKey[2], output[4..8]);
612 		toBigEndian!uint(X1 ^ wKey[1], output[8..12]);
613 		toBigEndian!uint(X0 ^ wKey[0], output[12..16]);
614 	}
615 
616 	/**
617 	 * The sboxes below are based on the work of Brian Gladman and
618 	 * Sam Simpson, whose original notice appears below.
619 	 * <p>
620 	 * For further details see:
621 	 *      http://fp.gladman.plus.com/cryptography_technology/serpent/
622 	 */
623 
624 	/* Partially optimised Serpent S Box boolean functions derived  */
625 	/* using a recursive descent analyser but without a full search */
626 	/* of all subtrees. This set of S boxes is the result of work    */
627 	/* by Sam Simpson and Brian Gladman using the spare time on a    */
628 	/* cluster of high capacity servers to search for S boxes with    */
629 	/* this customised search engine. There are now an average of    */
630 	/* 15.375 terms    per S box.                                        */
631 	/*                                                              */
632 	/* Copyright:   Dr B. R Gladman (gladman@seven77.demon.co.uk)   */
633 	/*                and Sam Simpson (s.simpson@mia.co.uk)            */
634 	/*              17th December 1998                                */
635 	/*                                                              */
636 	/* We hereby give permission for information in this file to be */
637 	/* used freely subject only to acknowledgement of its origin.    */
638 
639 	/**
640 	 * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
641 	 */
642 	nothrow @nogc {
643 		void sb0(uint a, uint b, uint c, uint d)
644 		{
645 			uint    t1 = a ^ d;
646 			uint    t3 = c ^ t1;
647 			uint    t4 = b ^ t3;
648 			X3 = (a & d) ^ t4;
649 			uint    t7 = a ^ (b & t1);
650 			X2 = t4 ^ (c | t7);
651 			uint    t12 = X3 & (t3 ^ t7);
652 			X1 = (~t3) ^ t12;
653 			X0 = t12 ^ (~t7);
654 		}
655 
656 		/**
657 		 * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
658 		 */ 
659 		void ib0(uint a, uint b, uint c, uint d)
660 		{
661 			uint    t1 = ~a;
662 			uint    t2 = a ^ b;
663 			uint    t4 = d ^ (t1 | t2);
664 			uint    t5 = c ^ t4;
665 			X2 = t2 ^ t5;
666 			uint    t8 = t1 ^ (d & t2);
667 			X1 = t4 ^ (X2 & t8);
668 			X3 = (a & t4) ^ (t5 | X1);
669 			X0 = X3 ^ (t5 ^ t8);
670 		}
671 
672 		/**
673 		 * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
674 		 */
675 		void sb1(uint a, uint b, uint c, uint d) 
676 		{
677 			uint    t2 = b ^ (~a);
678 			uint    t5 = c ^ (a | t2);
679 			X2 = d ^ t5;
680 			uint    t7 = b ^ (d | t2);
681 			uint    t8 = t2 ^ X2;
682 			X3 = t8 ^ (t5 & t7);
683 			uint    t11 = t5 ^ t7;
684 			X1 = X3 ^ t11;
685 			X0 = t5 ^ (t8 & t11);
686 		}
687 
688 		/**
689 		 * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
690 		 */
691 		void ib1(uint a, uint b, uint c, uint d)
692 		{
693 			uint    t1 = b ^ d;
694 			uint    t3 = a ^ (b & t1);
695 			uint    t4 = t1 ^ t3;
696 			X3 = c ^ t4;
697 			uint    t7 = b ^ (t1 & t3);
698 			uint    t8 = X3 | t7;
699 			X1 = t3 ^ t8;
700 			uint    t10 = ~X1;
701 			uint    t11 = X3 ^ t7;
702 			X0 = t10 ^ t11;
703 			X2 = t4 ^ (t10 | t11);
704 		}
705 
706 		/**
707 		 * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
708 		 */
709 		void sb2(uint a, uint b, uint c, uint d) 
710 		{
711 			uint    t1 = ~a;
712 			uint    t2 = b ^ d;
713 			uint    t3 = c & t1;
714 			X0 = t2 ^ t3;
715 			uint    t5 = c ^ t1;
716 			uint    t6 = c ^ X0;
717 			uint    t7 = b & t6;
718 			X3 = t5 ^ t7;
719 			X2 = a ^ ((d | t7) & (X0 | t5));
720 			X1 = (t2 ^ X3) ^ (X2 ^ (d | t1));
721 		}
722 
723 		/**
724 		 * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
725 		 */
726 		void ib2(uint a, uint b, uint c, uint d)
727 		{
728 			uint    t1 = b ^ d;
729 			uint    t2 = ~t1;
730 			uint    t3 = a ^ c;
731 			uint    t4 = c ^ t1;
732 			uint    t5 = b & t4;
733 			X0 = t3 ^ t5;
734 			uint    t7 = a | t2;
735 			uint    t8 = d ^ t7;
736 			uint    t9 = t3 | t8;
737 			X3 = t1 ^ t9;
738 			uint    t11 = ~t4;
739 			uint    t12 = X0 | X3;
740 			X1 = t11 ^ t12;
741 			X2 = (d & t11) ^ (t3 ^ t12);
742 		}
743 
744 		/**
745 		 * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
746 		 */
747 		void sb3(uint a, uint b, uint c, uint d)
748 		{
749 			uint    t1 = a ^ b;
750 			uint    t2 = a & c;
751 			uint    t3 = a | d;
752 			uint    t4 = c ^ d;
753 			uint    t5 = t1 & t3;
754 			uint    t6 = t2 | t5;
755 			X2 = t4 ^ t6;
756 			uint    t8 = b ^ t3;
757 			uint    t9 = t6 ^ t8;
758 			uint    t10 = t4 & t9;
759 			X0 = t1 ^ t10;
760 			uint    t12 = X2 & X0;
761 			X1 = t9 ^ t12;
762 			X3 = (b | d) ^ (t4 ^ t12);
763 		}
764 
765 		/**
766 		 * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
767 		 */
768 		void ib3(uint a, uint b, uint c, uint d) 
769 		{
770 			uint    t1 = a | b;
771 			uint    t2 = b ^ c;
772 			uint    t3 = b & t2;
773 			uint    t4 = a ^ t3;
774 			uint    t5 = c ^ t4;
775 			uint    t6 = d | t4;
776 			X0 = t2 ^ t6;
777 			uint    t8 = t2 | t6;
778 			uint    t9 = d ^ t8;
779 			X2 = t5 ^ t9;
780 			uint    t11 = t1 ^ t9;
781 			uint    t12 = X0 & t11;
782 			X3 = t4 ^ t12;
783 			X1 = X3 ^ (X0 ^ t11);
784 		}
785 
786 		/**
787 		 * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
788 		 */
789 		void sb4(uint a, uint b, uint c, uint d)
790 		{
791 			uint    t1 = a ^ d;
792 			uint    t2 = d & t1;
793 			uint    t3 = c ^ t2;
794 			uint    t4 = b | t3;
795 			X3 = t1 ^ t4;
796 			uint    t6 = ~b;
797 			uint    t7 = t1 | t6;
798 			X0 = t3 ^ t7;
799 			uint    t9 = a & X0;
800 			uint    t10 = t1 ^ t6;
801 			uint    t11 = t4 & t10;
802 			X2 = t9 ^ t11;
803 			X1 = (a ^ t3) ^ (t10 & X2);
804 		}
805 
806 		/**
807 		 * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
808 		 */
809 		void ib4(uint a, uint b, uint c, uint d)
810 		{
811 			uint    t1 = c | d;
812 			uint    t2 = a & t1;
813 			uint    t3 = b ^ t2;
814 			uint    t4 = a & t3;
815 			uint    t5 = c ^ t4;
816 			X1 = d ^ t5;
817 			uint    t7 = ~a;
818 			uint    t8 = t5 & X1;
819 			X3 = t3 ^ t8;
820 			uint    t10 = X1 | t7;
821 			uint    t11 = d ^ t10;
822 			X0 = X3 ^ t11;
823 			X2 = (t3 & t11) ^ (X1 ^ t7);
824 		}
825 
826 		/**
827 		 * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
828 		 */
829 		void sb5(uint a, uint b, uint c, uint d)
830 		{
831 			uint    t1 = ~a;
832 			uint    t2 = a ^ b;
833 			uint    t3 = a ^ d;
834 			uint    t4 = c ^ t1;
835 			uint    t5 = t2 | t3;
836 			X0 = t4 ^ t5;
837 			uint    t7 = d & X0;
838 			uint    t8 = t2 ^ X0;
839 			X1 = t7 ^ t8;
840 			uint    t10 = t1 | X0;
841 			uint    t11 = t2 | t7;
842 			uint    t12 = t3 ^ t10;
843 			X2 = t11 ^ t12;
844 			X3 = (b ^ t7) ^ (X1 & t12);
845 		}
846 
847 		/**
848 		 * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
849 		 */
850 		void ib5(uint a, uint b, uint c, uint d)
851 		{
852 			uint    t1 = ~c;
853 			uint    t2 = b & t1;
854 			uint    t3 = d ^ t2;
855 			uint    t4 = a & t3;
856 			uint    t5 = b ^ t1;
857 			X3 = t4 ^ t5;
858 			uint    t7 = b | X3;
859 			uint    t8 = a & t7;
860 			X1 = t3 ^ t8;
861 			uint    t10 = a | d;
862 			uint    t11 = t1 ^ t7;
863 			X0 = t10 ^ t11;
864 			X2 = (b & t10) ^ (t4 | (a ^ c));
865 		}
866 
867 		/**
868 		 * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
869 		 */
870 		void sb6(uint a, uint b, uint c, uint d)
871 		{
872 			uint    t1 = ~a;
873 			uint    t2 = a ^ d;
874 			uint    t3 = b ^ t2;
875 			uint    t4 = t1 | t2;
876 			uint    t5 = c ^ t4;
877 			X1 = b ^ t5;
878 			uint    t7 = t2 | X1;
879 			uint    t8 = d ^ t7;
880 			uint    t9 = t5 & t8;
881 			X2 = t3 ^ t9;
882 			uint    t11 = t5 ^ t8;
883 			X0 = X2 ^ t11;
884 			X3 = (~t5) ^ (t3 & t11);
885 		}
886 
887 		/**
888 		 * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
889 		 */
890 		void ib6(uint a, uint b, uint c, uint d)
891 		{
892 			uint    t1 = ~a;
893 			uint    t2 = a ^ b;
894 			uint    t3 = c ^ t2;
895 			uint    t4 = c | t1;
896 			uint    t5 = d ^ t4;
897 			X1 = t3 ^ t5;
898 			uint    t7 = t3 & t5;
899 			uint    t8 = t2 ^ t7;
900 			uint    t9 = b | t8;
901 			X3 = t5 ^ t9;
902 			uint    t11 = b | X3;
903 			X0 = t8 ^ t11;
904 			X2 = (d & t1) ^ (t3 ^ t11);
905 		}
906 
907 		/**
908 		 * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
909 		 */
910 		void sb7(uint a, uint b, uint c, uint d)
911 		{
912 			uint    t1 = b ^ c;
913 			uint    t2 = c & t1;
914 			uint    t3 = d ^ t2;
915 			uint    t4 = a ^ t3;
916 			uint    t5 = d | t1;
917 			uint    t6 = t4 & t5;
918 			X1 = b ^ t6;
919 			uint    t8 = t3 | X1;
920 			uint    t9 = a & t4;
921 			X3 = t1 ^ t9;
922 			uint    t11 = t4 ^ t8;
923 			uint    t12 = X3 & t11;
924 			X2 = t3 ^ t12;
925 			X0 = (~t11) ^ (X3 & X2);
926 		}
927 
928 		/**
929 		 * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
930 		 */
931 		void ib7(uint a, uint b, uint c, uint d)
932 		{
933 			uint t3 = c | (a & b);
934 			uint    t4 = d & (a | b);
935 			X3 = t3 ^ t4;
936 			uint    t6 = ~d;
937 			uint    t7 = b ^ t4;
938 			uint    t9 = t7 | (X3 ^ t6);
939 			X1 = a ^ t9;
940 			X0 = (c ^ t7) ^ (d | X1);
941 			X2 = (t3 ^ X1) ^ (X0 ^ (a & X3));
942 		}
943 		
944 		/**
945 		 * Apply the linear transformation to the register set.
946 		 */
947 		void LT()
948 		{
949 			uint x0  = rotateLeft(X0, 13);
950 			uint x2  = rotateLeft(X2, 3);
951 			uint x1  = X1 ^ x0 ^ x2 ;
952 			uint x3  = X3 ^ x2 ^ x0 << 3;
953 
954 			X1  = rotateLeft(x1, 1);
955 			X3  = rotateLeft(x3, 7);
956 			X0  = rotateLeft(x0 ^ X1 ^ X3, 5);
957 			X2  = rotateLeft(x2 ^ X3 ^ (X1 << 7), 22);
958 		}
959 
960 		/**
961 		 * Apply the inverse of the linear transformation to the register set.
962 		 */
963 		void inverseLT()
964 		{
965 			uint x2 = rotateRight(X2, 22) ^ X3 ^ (X1 << 7);
966 			uint x0 = rotateRight(X0, 5) ^ X1 ^ X3;
967 			uint x3 = rotateRight(X3, 7);
968 			uint x1 = rotateRight(X1, 1);
969 			X3 = x3 ^ x2 ^ x0 << 3;
970 			X1 = x1 ^ x0 ^ x2;
971 			X2 = rotateRight(x2, 3);
972 			X0 = rotateRight(x0, 13);
973 		}
974 	}
975 }