1 module dcrypt.crypto.engines.serpent;
2 
3 import dcrypt.crypto.blockcipher;
4 import dcrypt.util.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++] = bytesToWord(key[off..$]);
121 		}
122 
123 		if (off == 0)
124 		{
125 			kPad[length++] = bytesToWord(key);
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 	@nogc
331 	pure nothrow uint bytesToWord(in ubyte[]  src)
332 	{
333 		return (((src[0]) << 24) | ((src[1]) <<  16) |
334 			((src[2]) << 8) | ((src[3])));
335 	}
336 
337 	@nogc
338 	pure nothrow void wordToBytes(uint word, ubyte[]  dst)
339 	{
340 		dst[3] = cast(ubyte)(word);
341 		dst[2] = cast(ubyte)(word >>> 8);
342 		dst[1] = cast(ubyte)(word >>> 16);
343 		dst[0]     = cast(ubyte)(word >>> 24);
344 	}
345 
346 	/**
347 	 * Encrypt one block of plaintext.
348 	 *
349 	 */
350 	private void encryptBlock(in ubyte[]  input, ubyte[]  output) nothrow @nogc
351 	{
352 		X3 = bytesToWord(input[0..4]);
353 		X2 = bytesToWord(input[4..8]);
354 		X1 = bytesToWord(input[8..12]);
355 		X0 = bytesToWord(input[12..16]);
356 
357 		sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3);
358 		LT();
359 		sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3);
360 		LT();
361 		sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3);
362 		LT();
363 		sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3);
364 		LT();
365 		sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3);
366 		LT();
367 		sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3);
368 		LT();
369 		sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3);
370 		LT();
371 		sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3);
372 		LT();
373 		sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3);
374 		LT();
375 		sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3);
376 		LT();
377 		sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3);
378 		LT();
379 		sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3);
380 		LT();
381 		sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3);
382 		LT();
383 		sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3);
384 		LT();
385 		sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3);
386 		LT();
387 		sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3);
388 		LT();
389 		sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3);
390 		LT();
391 		sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3);
392 		LT();
393 		sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3);
394 		LT();
395 		sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3);
396 		LT();
397 		sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3);
398 		LT();
399 		sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3);
400 		LT();
401 		sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3);
402 		LT();
403 		sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3);
404 		LT();
405 		sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3);
406 		LT();
407 		sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3);
408 		LT();
409 		sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3);
410 		LT();
411 		sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3);
412 		LT();
413 		sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3);
414 		LT();
415 		sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3);
416 		LT();
417 		sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3);
418 		LT();
419 		sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
420 
421 		wordToBytes(wKey[131] ^ X3, output[0..4]);
422 		wordToBytes(wKey[130] ^ X2, output[4..8]);
423 		wordToBytes(wKey[129] ^ X1, output[8..12]);
424 		wordToBytes(wKey[128] ^ X0, output[12..16]);
425 	}
426 
427 	/**
428 	 * Decrypt one block of ciphertext.
429 	 *
430 	 */
431 	private void decryptBlock(in ubyte[]  input, ubyte[]  output) nothrow @nogc
432 	{
433 		X3 = wKey[131] ^ bytesToWord(input[0..4]);
434 		X2 = wKey[130] ^ bytesToWord(input[4..8]);
435 		X1 = wKey[129] ^ bytesToWord(input[8..12]);
436 		X0 = wKey[128] ^ bytesToWord(input[12..16]);
437 
438 		ib7(X0, X1, X2, X3);
439 		X0 ^= wKey[124];
440 		X1 ^= wKey[125];
441 		X2 ^= wKey[126];
442 		X3 ^= wKey[127];
443 		inverseLT();
444 		ib6(X0, X1, X2, X3);
445 		X0 ^= wKey[120];
446 		X1 ^= wKey[121];
447 		X2 ^= wKey[122];
448 		X3 ^= wKey[123];
449 		inverseLT();
450 		ib5(X0, X1, X2, X3);
451 		X0 ^= wKey[116];
452 		X1 ^= wKey[117];
453 		X2 ^= wKey[118];
454 		X3 ^= wKey[119];
455 		inverseLT();
456 		ib4(X0, X1, X2, X3);
457 		X0 ^= wKey[112];
458 		X1 ^= wKey[113];
459 		X2 ^= wKey[114];
460 		X3 ^= wKey[115];
461 		inverseLT();
462 		ib3(X0, X1, X2, X3);
463 		X0 ^= wKey[108];
464 		X1 ^= wKey[109];
465 		X2 ^= wKey[110];
466 		X3 ^= wKey[111];
467 		inverseLT();
468 		ib2(X0, X1, X2, X3);
469 		X0 ^= wKey[104];
470 		X1 ^= wKey[105];
471 		X2 ^= wKey[106];
472 		X3 ^= wKey[107];
473 		inverseLT();
474 		ib1(X0, X1, X2, X3);
475 		X0 ^= wKey[100];
476 		X1 ^= wKey[101];
477 		X2 ^= wKey[102];
478 		X3 ^= wKey[103];
479 		inverseLT();
480 		ib0(X0, X1, X2, X3);
481 		X0 ^= wKey[96];
482 		X1 ^= wKey[97];
483 		X2 ^= wKey[98];
484 		X3 ^= wKey[99];
485 		inverseLT();
486 		ib7(X0, X1, X2, X3);
487 		X0 ^= wKey[92];
488 		X1 ^= wKey[93];
489 		X2 ^= wKey[94];
490 		X3 ^= wKey[95];
491 		inverseLT();
492 		ib6(X0, X1, X2, X3);
493 		X0 ^= wKey[88];
494 		X1 ^= wKey[89];
495 		X2 ^= wKey[90];
496 		X3 ^= wKey[91];
497 		inverseLT();
498 		ib5(X0, X1, X2, X3);
499 		X0 ^= wKey[84];
500 		X1 ^= wKey[85];
501 		X2 ^= wKey[86];
502 		X3 ^= wKey[87];
503 		inverseLT();
504 		ib4(X0, X1, X2, X3);
505 		X0 ^= wKey[80];
506 		X1 ^= wKey[81];
507 		X2 ^= wKey[82];
508 		X3 ^= wKey[83];
509 		inverseLT();
510 		ib3(X0, X1, X2, X3);
511 		X0 ^= wKey[76];
512 		X1 ^= wKey[77];
513 		X2 ^= wKey[78];
514 		X3 ^= wKey[79];
515 		inverseLT();
516 		ib2(X0, X1, X2, X3);
517 		X0 ^= wKey[72];
518 		X1 ^= wKey[73];
519 		X2 ^= wKey[74];
520 		X3 ^= wKey[75];
521 		inverseLT();
522 		ib1(X0, X1, X2, X3);
523 		X0 ^= wKey[68];
524 		X1 ^= wKey[69];
525 		X2 ^= wKey[70];
526 		X3 ^= wKey[71];
527 		inverseLT();
528 		ib0(X0, X1, X2, X3);
529 		X0 ^= wKey[64];
530 		X1 ^= wKey[65];
531 		X2 ^= wKey[66];
532 		X3 ^= wKey[67];
533 		inverseLT();
534 		ib7(X0, X1, X2, X3);
535 		X0 ^= wKey[60];
536 		X1 ^= wKey[61];
537 		X2 ^= wKey[62];
538 		X3 ^= wKey[63];
539 		inverseLT();
540 		ib6(X0, X1, X2, X3);
541 		X0 ^= wKey[56];
542 		X1 ^= wKey[57];
543 		X2 ^= wKey[58];
544 		X3 ^= wKey[59];
545 		inverseLT();
546 		ib5(X0, X1, X2, X3);
547 		X0 ^= wKey[52];
548 		X1 ^= wKey[53];
549 		X2 ^= wKey[54];
550 		X3 ^= wKey[55];
551 		inverseLT();
552 		ib4(X0, X1, X2, X3);
553 		X0 ^= wKey[48];
554 		X1 ^= wKey[49];
555 		X2 ^= wKey[50];
556 		X3 ^= wKey[51];
557 		inverseLT();
558 		ib3(X0, X1, X2, X3);
559 		X0 ^= wKey[44];
560 		X1 ^= wKey[45];
561 		X2 ^= wKey[46];
562 		X3 ^= wKey[47];
563 		inverseLT();
564 		ib2(X0, X1, X2, X3);
565 		X0 ^= wKey[40];
566 		X1 ^= wKey[41];
567 		X2 ^= wKey[42];
568 		X3 ^= wKey[43];
569 		inverseLT();
570 		ib1(X0, X1, X2, X3);
571 		X0 ^= wKey[36];
572 		X1 ^= wKey[37];
573 		X2 ^= wKey[38];
574 		X3 ^= wKey[39];
575 		inverseLT();
576 		ib0(X0, X1, X2, X3);
577 		X0 ^= wKey[32];
578 		X1 ^= wKey[33];
579 		X2 ^= wKey[34];
580 		X3 ^= wKey[35];
581 		inverseLT();
582 		ib7(X0, X1, X2, X3);
583 		X0 ^= wKey[28];
584 		X1 ^= wKey[29];
585 		X2 ^= wKey[30];
586 		X3 ^= wKey[31];
587 		inverseLT();
588 		ib6(X0, X1, X2, X3);
589 		X0 ^= wKey[24];
590 		X1 ^= wKey[25];
591 		X2 ^= wKey[26];
592 		X3 ^= wKey[27];
593 		inverseLT();
594 		ib5(X0, X1, X2, X3);
595 		X0 ^= wKey[20];
596 		X1 ^= wKey[21];
597 		X2 ^= wKey[22];
598 		X3 ^= wKey[23];
599 		inverseLT();
600 		ib4(X0, X1, X2, X3);
601 		X0 ^= wKey[16];
602 		X1 ^= wKey[17];
603 		X2 ^= wKey[18];
604 		X3 ^= wKey[19];
605 		inverseLT();
606 		ib3(X0, X1, X2, X3);
607 		X0 ^= wKey[12];
608 		X1 ^= wKey[13];
609 		X2 ^= wKey[14];
610 		X3 ^= wKey[15];
611 		inverseLT();
612 		ib2(X0, X1, X2, X3);
613 		X0 ^= wKey[8];
614 		X1 ^= wKey[9];
615 		X2 ^= wKey[10];
616 		X3 ^= wKey[11];
617 		inverseLT();
618 		ib1(X0, X1, X2, X3);
619 		X0 ^= wKey[4];
620 		X1 ^= wKey[5];
621 		X2 ^= wKey[6];
622 		X3 ^= wKey[7];
623 		inverseLT();
624 		ib0(X0, X1, X2, X3);
625 
626 		wordToBytes(X3 ^ wKey[3], output[0..4]);
627 		wordToBytes(X2 ^ wKey[2], output[4..8]);
628 		wordToBytes(X1 ^ wKey[1], output[8..12]);
629 		wordToBytes(X0 ^ wKey[0], output[12..16]);
630 	}
631 
632 	/**
633 	 * The sboxes below are based on the work of Brian Gladman and
634 	 * Sam Simpson, whose original notice appears below.
635 	 * <p>
636 	 * For further details see:
637 	 *      http://fp.gladman.plus.com/cryptography_technology/serpent/
638 	 */
639 
640 	/* Partially optimised Serpent S Box boolean functions derived  */
641 	/* using a recursive descent analyser but without a full search */
642 	/* of all subtrees. This set of S boxes is the result of work    */
643 	/* by Sam Simpson and Brian Gladman using the spare time on a    */
644 	/* cluster of high capacity servers to search for S boxes with    */
645 	/* this customised search engine. There are now an average of    */
646 	/* 15.375 terms    per S box.                                        */
647 	/*                                                              */
648 	/* Copyright:   Dr B. R Gladman (gladman@seven77.demon.co.uk)   */
649 	/*                and Sam Simpson (s.simpson@mia.co.uk)            */
650 	/*              17th December 1998                                */
651 	/*                                                              */
652 	/* We hereby give permission for information in this file to be */
653 	/* used freely subject only to acknowledgement of its origin.    */
654 
655 	/**
656 	 * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
657 	 */
658 	nothrow @nogc {
659 		void sb0(uint a, uint b, uint c, uint d)
660 		{
661 			uint    t1 = a ^ d;
662 			uint    t3 = c ^ t1;
663 			uint    t4 = b ^ t3;
664 			X3 = (a & d) ^ t4;
665 			uint    t7 = a ^ (b & t1);
666 			X2 = t4 ^ (c | t7);
667 			uint    t12 = X3 & (t3 ^ t7);
668 			X1 = (~t3) ^ t12;
669 			X0 = t12 ^ (~t7);
670 		}
671 
672 		/**
673 		 * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
674 		 */ 
675 		void ib0(uint a, uint b, uint c, uint d)
676 		{
677 			uint    t1 = ~a;
678 			uint    t2 = a ^ b;
679 			uint    t4 = d ^ (t1 | t2);
680 			uint    t5 = c ^ t4;
681 			X2 = t2 ^ t5;
682 			uint    t8 = t1 ^ (d & t2);
683 			X1 = t4 ^ (X2 & t8);
684 			X3 = (a & t4) ^ (t5 | X1);
685 			X0 = X3 ^ (t5 ^ t8);
686 		}
687 
688 		/**
689 		 * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
690 		 */
691 		void sb1(uint a, uint b, uint c, uint d) 
692 		{
693 			uint    t2 = b ^ (~a);
694 			uint    t5 = c ^ (a | t2);
695 			X2 = d ^ t5;
696 			uint    t7 = b ^ (d | t2);
697 			uint    t8 = t2 ^ X2;
698 			X3 = t8 ^ (t5 & t7);
699 			uint    t11 = t5 ^ t7;
700 			X1 = X3 ^ t11;
701 			X0 = t5 ^ (t8 & t11);
702 		}
703 
704 		/**
705 		 * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
706 		 */
707 		void ib1(uint a, uint b, uint c, uint d)
708 		{
709 			uint    t1 = b ^ d;
710 			uint    t3 = a ^ (b & t1);
711 			uint    t4 = t1 ^ t3;
712 			X3 = c ^ t4;
713 			uint    t7 = b ^ (t1 & t3);
714 			uint    t8 = X3 | t7;
715 			X1 = t3 ^ t8;
716 			uint    t10 = ~X1;
717 			uint    t11 = X3 ^ t7;
718 			X0 = t10 ^ t11;
719 			X2 = t4 ^ (t10 | t11);
720 		}
721 
722 		/**
723 		 * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
724 		 */
725 		void sb2(uint a, uint b, uint c, uint d) 
726 		{
727 			uint    t1 = ~a;
728 			uint    t2 = b ^ d;
729 			uint    t3 = c & t1;
730 			X0 = t2 ^ t3;
731 			uint    t5 = c ^ t1;
732 			uint    t6 = c ^ X0;
733 			uint    t7 = b & t6;
734 			X3 = t5 ^ t7;
735 			X2 = a ^ ((d | t7) & (X0 | t5));
736 			X1 = (t2 ^ X3) ^ (X2 ^ (d | t1));
737 		}
738 
739 		/**
740 		 * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
741 		 */
742 		void ib2(uint a, uint b, uint c, uint d)
743 		{
744 			uint    t1 = b ^ d;
745 			uint    t2 = ~t1;
746 			uint    t3 = a ^ c;
747 			uint    t4 = c ^ t1;
748 			uint    t5 = b & t4;
749 			X0 = t3 ^ t5;
750 			uint    t7 = a | t2;
751 			uint    t8 = d ^ t7;
752 			uint    t9 = t3 | t8;
753 			X3 = t1 ^ t9;
754 			uint    t11 = ~t4;
755 			uint    t12 = X0 | X3;
756 			X1 = t11 ^ t12;
757 			X2 = (d & t11) ^ (t3 ^ t12);
758 		}
759 
760 		/**
761 		 * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
762 		 */
763 		void sb3(uint a, uint b, uint c, uint d)
764 		{
765 			uint    t1 = a ^ b;
766 			uint    t2 = a & c;
767 			uint    t3 = a | d;
768 			uint    t4 = c ^ d;
769 			uint    t5 = t1 & t3;
770 			uint    t6 = t2 | t5;
771 			X2 = t4 ^ t6;
772 			uint    t8 = b ^ t3;
773 			uint    t9 = t6 ^ t8;
774 			uint    t10 = t4 & t9;
775 			X0 = t1 ^ t10;
776 			uint    t12 = X2 & X0;
777 			X1 = t9 ^ t12;
778 			X3 = (b | d) ^ (t4 ^ t12);
779 		}
780 
781 		/**
782 		 * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
783 		 */
784 		void ib3(uint a, uint b, uint c, uint d) 
785 		{
786 			uint    t1 = a | b;
787 			uint    t2 = b ^ c;
788 			uint    t3 = b & t2;
789 			uint    t4 = a ^ t3;
790 			uint    t5 = c ^ t4;
791 			uint    t6 = d | t4;
792 			X0 = t2 ^ t6;
793 			uint    t8 = t2 | t6;
794 			uint    t9 = d ^ t8;
795 			X2 = t5 ^ t9;
796 			uint    t11 = t1 ^ t9;
797 			uint    t12 = X0 & t11;
798 			X3 = t4 ^ t12;
799 			X1 = X3 ^ (X0 ^ t11);
800 		}
801 
802 		/**
803 		 * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
804 		 */
805 		void sb4(uint a, uint b, uint c, uint d)
806 		{
807 			uint    t1 = a ^ d;
808 			uint    t2 = d & t1;
809 			uint    t3 = c ^ t2;
810 			uint    t4 = b | t3;
811 			X3 = t1 ^ t4;
812 			uint    t6 = ~b;
813 			uint    t7 = t1 | t6;
814 			X0 = t3 ^ t7;
815 			uint    t9 = a & X0;
816 			uint    t10 = t1 ^ t6;
817 			uint    t11 = t4 & t10;
818 			X2 = t9 ^ t11;
819 			X1 = (a ^ t3) ^ (t10 & X2);
820 		}
821 
822 		/**
823 		 * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
824 		 */
825 		void ib4(uint a, uint b, uint c, uint d)
826 		{
827 			uint    t1 = c | d;
828 			uint    t2 = a & t1;
829 			uint    t3 = b ^ t2;
830 			uint    t4 = a & t3;
831 			uint    t5 = c ^ t4;
832 			X1 = d ^ t5;
833 			uint    t7 = ~a;
834 			uint    t8 = t5 & X1;
835 			X3 = t3 ^ t8;
836 			uint    t10 = X1 | t7;
837 			uint    t11 = d ^ t10;
838 			X0 = X3 ^ t11;
839 			X2 = (t3 & t11) ^ (X1 ^ t7);
840 		}
841 
842 		/**
843 		 * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
844 		 */
845 		void sb5(uint a, uint b, uint c, uint d)
846 		{
847 			uint    t1 = ~a;
848 			uint    t2 = a ^ b;
849 			uint    t3 = a ^ d;
850 			uint    t4 = c ^ t1;
851 			uint    t5 = t2 | t3;
852 			X0 = t4 ^ t5;
853 			uint    t7 = d & X0;
854 			uint    t8 = t2 ^ X0;
855 			X1 = t7 ^ t8;
856 			uint    t10 = t1 | X0;
857 			uint    t11 = t2 | t7;
858 			uint    t12 = t3 ^ t10;
859 			X2 = t11 ^ t12;
860 			X3 = (b ^ t7) ^ (X1 & t12);
861 		}
862 
863 		/**
864 		 * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
865 		 */
866 		void ib5(uint a, uint b, uint c, uint d)
867 		{
868 			uint    t1 = ~c;
869 			uint    t2 = b & t1;
870 			uint    t3 = d ^ t2;
871 			uint    t4 = a & t3;
872 			uint    t5 = b ^ t1;
873 			X3 = t4 ^ t5;
874 			uint    t7 = b | X3;
875 			uint    t8 = a & t7;
876 			X1 = t3 ^ t8;
877 			uint    t10 = a | d;
878 			uint    t11 = t1 ^ t7;
879 			X0 = t10 ^ t11;
880 			X2 = (b & t10) ^ (t4 | (a ^ c));
881 		}
882 
883 		/**
884 		 * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
885 		 */
886 		void sb6(uint a, uint b, uint c, uint d)
887 		{
888 			uint    t1 = ~a;
889 			uint    t2 = a ^ d;
890 			uint    t3 = b ^ t2;
891 			uint    t4 = t1 | t2;
892 			uint    t5 = c ^ t4;
893 			X1 = b ^ t5;
894 			uint    t7 = t2 | X1;
895 			uint    t8 = d ^ t7;
896 			uint    t9 = t5 & t8;
897 			X2 = t3 ^ t9;
898 			uint    t11 = t5 ^ t8;
899 			X0 = X2 ^ t11;
900 			X3 = (~t5) ^ (t3 & t11);
901 		}
902 
903 		/**
904 		 * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
905 		 */
906 		void ib6(uint a, uint b, uint c, uint d)
907 		{
908 			uint    t1 = ~a;
909 			uint    t2 = a ^ b;
910 			uint    t3 = c ^ t2;
911 			uint    t4 = c | t1;
912 			uint    t5 = d ^ t4;
913 			X1 = t3 ^ t5;
914 			uint    t7 = t3 & t5;
915 			uint    t8 = t2 ^ t7;
916 			uint    t9 = b | t8;
917 			X3 = t5 ^ t9;
918 			uint    t11 = b | X3;
919 			X0 = t8 ^ t11;
920 			X2 = (d & t1) ^ (t3 ^ t11);
921 		}
922 
923 		/**
924 		 * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
925 		 */
926 		void sb7(uint a, uint b, uint c, uint d)
927 		{
928 			uint    t1 = b ^ c;
929 			uint    t2 = c & t1;
930 			uint    t3 = d ^ t2;
931 			uint    t4 = a ^ t3;
932 			uint    t5 = d | t1;
933 			uint    t6 = t4 & t5;
934 			X1 = b ^ t6;
935 			uint    t8 = t3 | X1;
936 			uint    t9 = a & t4;
937 			X3 = t1 ^ t9;
938 			uint    t11 = t4 ^ t8;
939 			uint    t12 = X3 & t11;
940 			X2 = t3 ^ t12;
941 			X0 = (~t11) ^ (X3 & X2);
942 		}
943 
944 		/**
945 		 * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
946 		 */
947 		void ib7(uint a, uint b, uint c, uint d)
948 		{
949 			uint t3 = c | (a & b);
950 			uint    t4 = d & (a | b);
951 			X3 = t3 ^ t4;
952 			uint    t6 = ~d;
953 			uint    t7 = b ^ t4;
954 			uint    t9 = t7 | (X3 ^ t6);
955 			X1 = a ^ t9;
956 			X0 = (c ^ t7) ^ (d | X1);
957 			X2 = (t3 ^ X1) ^ (X0 ^ (a & X3));
958 		}
959 		
960 		/**
961 		 * Apply the linear transformation to the register set.
962 		 */
963 		void LT()
964 		{
965 			uint x0  = rotateLeft(X0, 13);
966 			uint x2  = rotateLeft(X2, 3);
967 			uint x1  = X1 ^ x0 ^ x2 ;
968 			uint x3  = X3 ^ x2 ^ x0 << 3;
969 
970 			X1  = rotateLeft(x1, 1);
971 			X3  = rotateLeft(x3, 7);
972 			X0  = rotateLeft(x0 ^ X1 ^ X3, 5);
973 			X2  = rotateLeft(x2 ^ X3 ^ (X1 << 7), 22);
974 		}
975 
976 		/**
977 		 * Apply the inverse of the linear transformation to the register set.
978 		 */
979 		void inverseLT()
980 		{
981 			uint x2 = rotateRight(X2, 22) ^ X3 ^ (X1 << 7);
982 			uint x0 = rotateRight(X0, 5) ^ X1 ^ X3;
983 			uint x3 = rotateRight(X3, 7);
984 			uint x1 = rotateRight(X1, 1);
985 			X3 = x3 ^ x2 ^ x0 << 3;
986 			X1 = x1 ^ x0 ^ x2;
987 			X2 = rotateRight(x2, 3);
988 			X0 = rotateRight(x0, 13);
989 		}
990 	}
991 }