1 /**
2 * Serpent
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.block.serpent;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_SERPENT):
15 
16 import botan.block.block_cipher;
17 import botan.utils.loadstor;
18 import botan.utils.rotate;
19 import botan.utils.types;
20 import botan.utils.mem_ops;
21 
22 /**
23 * Serpent, an AES finalist
24 */
25 class Serpent : BlockCipherFixedParams!(16, 16, 32, 8), BlockCipher, SymmetricAlgorithm
26 {
27 public:
28     /*
29     * Serpent Encryption
30     */
31     override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks)
32     {
33         foreach (size_t i; 0 .. blocks)
34         {
35             uint B0 = loadLittleEndian!uint(input, 0);
36             uint B1 = loadLittleEndian!uint(input, 1);
37             uint B2 = loadLittleEndian!uint(input, 2);
38             uint B3 = loadLittleEndian!uint(input, 3);
39             
40             mixin(key_xor!( 0)); mixin(SBoxE1!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
41             mixin(key_xor!( 1)); mixin(SBoxE2!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
42             mixin(key_xor!( 2)); mixin(SBoxE3!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
43             mixin(key_xor!( 3)); mixin(SBoxE4!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
44             mixin(key_xor!( 4)); mixin(SBoxE5!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
45             mixin(key_xor!( 5)); mixin(SBoxE6!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
46             mixin(key_xor!( 6)); mixin(SBoxE7!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
47             mixin(key_xor!( 7)); mixin(SBoxE8!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
48             mixin(key_xor!( 8)); mixin(SBoxE1!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
49             mixin(key_xor!( 9)); mixin(SBoxE2!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
50             mixin(key_xor!(10)); mixin(SBoxE3!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
51             mixin(key_xor!(11)); mixin(SBoxE4!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
52             mixin(key_xor!(12)); mixin(SBoxE5!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
53             mixin(key_xor!(13)); mixin(SBoxE6!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
54             mixin(key_xor!(14)); mixin(SBoxE7!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
55             mixin(key_xor!(15)); mixin(SBoxE8!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
56             mixin(key_xor!(16)); mixin(SBoxE1!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
57             mixin(key_xor!(17)); mixin(SBoxE2!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
58             mixin(key_xor!(18)); mixin(SBoxE3!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
59             mixin(key_xor!(19)); mixin(SBoxE4!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
60             mixin(key_xor!(20)); mixin(SBoxE5!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
61             mixin(key_xor!(21)); mixin(SBoxE6!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
62             mixin(key_xor!(22)); mixin(SBoxE7!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
63             mixin(key_xor!(23)); mixin(SBoxE8!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
64             mixin(key_xor!(24)); mixin(SBoxE1!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
65             mixin(key_xor!(25)); mixin(SBoxE2!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
66             mixin(key_xor!(26)); mixin(SBoxE3!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
67             mixin(key_xor!(27)); mixin(SBoxE4!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
68             mixin(key_xor!(28)); mixin(SBoxE5!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
69             mixin(key_xor!(29)); mixin(SBoxE6!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
70             mixin(key_xor!(30)); mixin(SBoxE7!("B0", "B1", "B2", "B3")); transform(B0,B1,B2,B3);
71             mixin(key_xor!(31)); mixin(SBoxE8!("B0", "B1", "B2", "B3")); mixin(key_xor!(32));
72             
73             storeLittleEndian(output, B0, B1, B2, B3);
74             
75             input += BLOCK_SIZE;
76             output += BLOCK_SIZE;
77         }
78     }
79 
80     /*
81     * Serpent Decryption
82     */
83     override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks)
84     {
85         foreach (size_t i; 0 .. blocks)
86         {
87             uint B0 = loadLittleEndian!uint(input, 0);
88             uint B1 = loadLittleEndian!uint(input, 1);
89             uint B2 = loadLittleEndian!uint(input, 2);
90             uint B3 = loadLittleEndian!uint(input, 3);
91             
92             mixin(key_xor!(32));  mixin(SBoxD8); mixin(key_xor!(31));
93             i_transform(B0,B1,B2,B3); mixin(SBoxD7); mixin(key_xor!(30));
94             i_transform(B0,B1,B2,B3); mixin(SBoxD6); mixin(key_xor!(29));
95             i_transform(B0,B1,B2,B3); mixin(SBoxD5); mixin(key_xor!(28));
96             i_transform(B0,B1,B2,B3); mixin(SBoxD4); mixin(key_xor!(27));
97             i_transform(B0,B1,B2,B3); mixin(SBoxD3); mixin(key_xor!(26));
98             i_transform(B0,B1,B2,B3); mixin(SBoxD2); mixin(key_xor!(25));
99             i_transform(B0,B1,B2,B3); mixin(SBoxD1); mixin(key_xor!(24));
100             i_transform(B0,B1,B2,B3); mixin(SBoxD8); mixin(key_xor!(23));
101             i_transform(B0,B1,B2,B3); mixin(SBoxD7); mixin(key_xor!(22));
102             i_transform(B0,B1,B2,B3); mixin(SBoxD6); mixin(key_xor!(21));
103             i_transform(B0,B1,B2,B3); mixin(SBoxD5); mixin(key_xor!(20));
104             i_transform(B0,B1,B2,B3); mixin(SBoxD4); mixin(key_xor!(19));
105             i_transform(B0,B1,B2,B3); mixin(SBoxD3); mixin(key_xor!(18));
106             i_transform(B0,B1,B2,B3); mixin(SBoxD2); mixin(key_xor!(17));
107             i_transform(B0,B1,B2,B3); mixin(SBoxD1); mixin(key_xor!(16));
108             i_transform(B0,B1,B2,B3); mixin(SBoxD8); mixin(key_xor!(15));
109             i_transform(B0,B1,B2,B3); mixin(SBoxD7); mixin(key_xor!(14));
110             i_transform(B0,B1,B2,B3); mixin(SBoxD6); mixin(key_xor!(13));
111             i_transform(B0,B1,B2,B3); mixin(SBoxD5); mixin(key_xor!(12));
112             i_transform(B0,B1,B2,B3); mixin(SBoxD4); mixin(key_xor!(11));
113             i_transform(B0,B1,B2,B3); mixin(SBoxD3); mixin(key_xor!(10));
114             i_transform(B0,B1,B2,B3); mixin(SBoxD2); mixin(key_xor!( 9));
115             i_transform(B0,B1,B2,B3); mixin(SBoxD1); mixin(key_xor!( 8));
116             i_transform(B0,B1,B2,B3); mixin(SBoxD8); mixin(key_xor!( 7));
117             i_transform(B0,B1,B2,B3); mixin(SBoxD7); mixin(key_xor!( 6));
118             i_transform(B0,B1,B2,B3); mixin(SBoxD6); mixin(key_xor!( 5));
119             i_transform(B0,B1,B2,B3); mixin(SBoxD5); mixin(key_xor!( 4));
120             i_transform(B0,B1,B2,B3); mixin(SBoxD4); mixin(key_xor!( 3));
121             i_transform(B0,B1,B2,B3); mixin(SBoxD3); mixin(key_xor!( 2));
122             i_transform(B0,B1,B2,B3); mixin(SBoxD2); mixin(key_xor!( 1));
123             i_transform(B0,B1,B2,B3); mixin(SBoxD1); mixin(key_xor!( 0));
124             
125             storeLittleEndian(output, B0, B1, B2, B3);
126             
127             input += BLOCK_SIZE;
128             output += BLOCK_SIZE;
129         }
130     }
131 
132     override void clear()
133     {
134         zap(m_round_key);
135     }
136 
137     override @property string name() const { return "Serpent"; }
138     override @property size_t parallelism() const { return 1; }
139     override BlockCipher clone() const { return new Serpent; }
140     override size_t blockSize() const { return super.blockSize(); }
141     override KeyLengthSpecification keySpec() const { return super.keySpec(); }
142 protected:
143     /**
144     * For use by subclasses using SIMD, asm, etc
145     * Returns: const reference to the key schedule
146     */
147     ref const(SecureVector!uint) getRoundKeys() const
148     { return m_round_key; }
149 
150     /**
151     * For use by subclasses that implement the key schedule
152     * Params:
153     *  ks = is the new key schedule value to set
154     */
155     void setRoundKeys(in uint[132] ks)
156     {
157         m_round_key[] = ks.ptr[0 .. 132];
158     }
159 
160     /*
161     * Serpent Key Schedule
162     */
163     override void keySchedule(const(ubyte)* key, size_t length)
164     {
165         const uint PHI = 0x9E3779B9;
166         
167         SecureVector!uint W = SecureVector!uint(140);
168         foreach (size_t i; 0 .. (length / 4))
169             W[i] = loadLittleEndian!uint(key, i);
170         
171         W[length / 4] |= uint(1) << ((length%4)*8);
172         
173         foreach (size_t i; 8 .. 140)
174         {
175             uint wi = cast(uint) (W[i-8] ^ W[i-5] ^ W[i-3] ^ W[i-1] ^ PHI ^ (cast(uint) i - 8));
176             W[i] = rotateLeft(wi, 11);
177         }
178 
179         mixin(SBoxE4!("W[  8]", "W[  9]", "W[ 10]", "W[ 11]")); mixin(SBoxE3!("W[ 12]", "W[ 13]", "W[ 14]", "W[ 15]"));
180         mixin(SBoxE2!("W[ 16]", "W[ 17]", "W[ 18]", "W[ 19]")); mixin(SBoxE1!("W[ 20]", "W[ 21]", "W[ 22]", "W[ 23]"));
181         mixin(SBoxE8!("W[ 24]", "W[ 25]", "W[ 26]", "W[ 27]")); mixin(SBoxE7!("W[ 28]", "W[ 29]", "W[ 30]", "W[ 31]"));
182         mixin(SBoxE6!("W[ 32]", "W[ 33]", "W[ 34]", "W[ 35]")); mixin(SBoxE5!("W[ 36]", "W[ 37]", "W[ 38]", "W[ 39]"));
183         mixin(SBoxE4!("W[ 40]", "W[ 41]", "W[ 42]", "W[ 43]")); mixin(SBoxE3!("W[ 44]", "W[ 45]", "W[ 46]", "W[ 47]"));
184         mixin(SBoxE2!("W[ 48]", "W[ 49]", "W[ 50]", "W[ 51]")); mixin(SBoxE1!("W[ 52]", "W[ 53]", "W[ 54]", "W[ 55]"));
185         mixin(SBoxE8!("W[ 56]", "W[ 57]", "W[ 58]", "W[ 59]")); mixin(SBoxE7!("W[ 60]", "W[ 61]", "W[ 62]", "W[ 63]"));
186         mixin(SBoxE6!("W[ 64]", "W[ 65]", "W[ 66]", "W[ 67]")); mixin(SBoxE5!("W[ 68]", "W[ 69]", "W[ 70]", "W[ 71]"));
187         mixin(SBoxE4!("W[ 72]", "W[ 73]", "W[ 74]", "W[ 75]")); mixin(SBoxE3!("W[ 76]", "W[ 77]", "W[ 78]", "W[ 79]"));
188         mixin(SBoxE2!("W[ 80]", "W[ 81]", "W[ 82]", "W[ 83]")); mixin(SBoxE1!("W[ 84]", "W[ 85]", "W[ 86]", "W[ 87]"));
189         mixin(SBoxE8!("W[ 88]", "W[ 89]", "W[ 90]", "W[ 91]")); mixin(SBoxE7!("W[ 92]", "W[ 93]", "W[ 94]", "W[ 95]"));
190         mixin(SBoxE6!("W[ 96]", "W[ 97]", "W[ 98]", "W[ 99]")); mixin(SBoxE5!("W[100]", "W[101]", "W[102]", "W[103]"));
191         mixin(SBoxE4!("W[104]", "W[105]", "W[106]", "W[107]")); mixin(SBoxE3!("W[108]", "W[109]", "W[110]", "W[111]"));
192         mixin(SBoxE2!("W[112]", "W[113]", "W[114]", "W[115]")); mixin(SBoxE1!("W[116]", "W[117]", "W[118]", "W[119]"));
193         mixin(SBoxE8!("W[120]", "W[121]", "W[122]", "W[123]")); mixin(SBoxE7!("W[124]", "W[125]", "W[126]", "W[127]"));
194         mixin(SBoxE6!("W[128]", "W[129]", "W[130]", "W[131]")); mixin(SBoxE5!("W[132]", "W[133]", "W[134]", "W[135]"));
195         mixin(SBoxE4!("W[136]", "W[137]", "W[138]", "W[139]"));
196         
197         m_round_key[] = W.ptr[8 .. 140];
198     }
199 
200     SecureVector!uint m_round_key;
201 }
202 
203 
204 package:
205 
206 enum string SBoxE1(string B0, string B1, string B2, string B3) =
207     `{` ~ B3 ~ ` ^= ` ~ B0 ~ `;
208     auto B4 = ` ~ B1 ~ `;
209     ` ~ B1 ~ ` &= ` ~ B3 ~ `;
210     B4 ^= ` ~ B2 ~ `;
211     ` ~ B1 ~ ` ^= ` ~ B0 ~ `;
212     ` ~ B0 ~ ` |= ` ~ B3 ~ `;
213     ` ~ B0 ~ ` ^= B4;
214     B4 ^= ` ~ B3 ~ `;
215     ` ~ B3 ~ ` ^= ` ~ B2 ~ `;
216     ` ~ B2 ~ ` |= ` ~ B1 ~ `;
217     ` ~ B2 ~ ` ^= B4;
218     B4 = ~B4;
219     B4 |= ` ~ B1 ~ `;
220     ` ~ B1 ~ ` ^= ` ~ B3 ~ `;
221     ` ~ B1 ~ ` ^= B4;
222     ` ~ B3 ~ ` |= ` ~ B0 ~ `;
223     ` ~ B1 ~ ` ^= ` ~ B3 ~ `;
224     B4 ^= ` ~ B3 ~ `;
225     ` ~ B3 ~ ` = ` ~ B0 ~ `;
226     ` ~ B0 ~ ` = ` ~ B1 ~ `;
227     ` ~ B1 ~ ` = B4; }`;
228 
229 enum string SBoxE2(string B0, string B1, string B2, string B3) =
230     `{` ~ B0 ~ ` = ~` ~ B0 ~ `;
231     ` ~ B2 ~ ` = ~` ~ B2 ~ `;
232     auto B4 = ` ~ B0 ~ `;
233     ` ~ B0 ~ ` &= ` ~ B1 ~ `;
234     ` ~ B2 ~ ` ^= ` ~ B0 ~ `;
235     ` ~ B0 ~ ` |= ` ~ B3 ~ `;
236     ` ~ B3 ~ ` ^= ` ~ B2 ~ `;
237     ` ~ B1 ~ ` ^= ` ~ B0 ~ `;
238     ` ~ B0 ~ ` ^= B4;
239     B4 |= ` ~ B1 ~ `;
240     ` ~ B1 ~ ` ^= ` ~ B3 ~ `;
241     ` ~ B2 ~ ` |= ` ~ B0 ~ `;
242     ` ~ B2 ~ ` &= B4;
243     ` ~ B0 ~ ` ^= ` ~ B1 ~ `;
244     ` ~ B1 ~ ` &= ` ~ B2 ~ `;
245     ` ~ B1 ~ ` ^= ` ~ B0 ~ `;
246     ` ~ B0 ~ ` &= ` ~ B2 ~ `;
247     B4 ^= ` ~ B0 ~ `;
248     ` ~ B0 ~ ` = ` ~ B2 ~ `;
249     ` ~ B2 ~ ` = ` ~ B3 ~ `;
250     ` ~ B3 ~ ` = ` ~ B1 ~ `;
251     ` ~ B1 ~ ` = B4;}`;
252 
253 enum string SBoxE3(string B0, string B1, string B2, string B3) =
254     `{auto B4 = ` ~ B0 ~ `;
255     ` ~ B0 ~ ` &= ` ~ B2 ~ `;
256     ` ~ B0 ~ ` ^= ` ~ B3 ~ `;
257     ` ~ B2 ~ ` ^= ` ~ B1 ~ `;
258     ` ~ B2 ~ ` ^= ` ~ B0 ~ `;
259     ` ~ B3 ~ ` |= B4;
260     ` ~ B3 ~ ` ^= ` ~ B1 ~ `;
261     B4 ^= ` ~ B2 ~ `;
262     ` ~ B1 ~ ` = ` ~ B3 ~ `;
263     ` ~ B3 ~ ` |= B4;
264     ` ~ B3 ~ ` ^= ` ~ B0 ~ `;
265     ` ~ B0 ~ ` &= ` ~ B1 ~ `;
266     B4 ^= ` ~ B0 ~ `;
267     ` ~ B1 ~ ` ^= ` ~ B3 ~ `;
268     ` ~ B1 ~ ` ^= B4;
269     ` ~ B0 ~ ` = ` ~ B2 ~ `;
270     ` ~ B2 ~ ` = ` ~ B1 ~ `;
271     ` ~ B1 ~ ` = ` ~ B3 ~ `;
272     ` ~ B3 ~ ` = ~B4;}`;
273 
274 enum string SBoxE4(string B0, string B1, string B2, string B3) =
275     `{auto B4 = ` ~ B0 ~ `;
276     ` ~ B0 ~ ` |= ` ~ B3 ~ `;
277     ` ~ B3 ~ ` ^= ` ~ B1 ~ `;
278     ` ~ B1 ~ ` &= B4;
279     B4 ^= ` ~ B2 ~ `;
280     ` ~ B2 ~ ` ^= ` ~ B3 ~ `;
281     ` ~ B3 ~ ` &= ` ~ B0 ~ `;
282     B4 |= ` ~ B1 ~ `;
283     ` ~ B3 ~ ` ^= B4;
284     ` ~ B0 ~ ` ^= ` ~ B1 ~ `;
285     B4 &= ` ~ B0 ~ `;
286     ` ~ B1 ~ ` ^= ` ~ B3 ~ `;
287     B4 ^= ` ~ B2 ~ `;
288     ` ~ B1 ~ ` |= ` ~ B0 ~ `;
289     ` ~ B1 ~ ` ^= ` ~ B2 ~ `;
290     ` ~ B0 ~ ` ^= ` ~ B3 ~ `;
291     ` ~ B2 ~ ` = ` ~ B1 ~ `;
292     ` ~ B1 ~ ` |= ` ~ B3 ~ `;
293     ` ~ B0 ~ ` ^= ` ~ B1 ~ `;
294     ` ~ B1 ~ ` = ` ~ B2 ~ `;
295     ` ~ B2 ~ ` = ` ~ B3 ~ `;
296     ` ~ B3 ~ ` = B4;}`;
297 
298 enum string SBoxE5(string B0, string B1, string B2, string B3) =
299     `{` ~ B1 ~ ` ^= ` ~ B3 ~ `;
300     ` ~ B3 ~ ` = ~` ~ B3 ~ `;
301     ` ~ B2 ~ ` ^= ` ~ B3 ~ `;
302     ` ~ B3 ~ ` ^= ` ~ B0 ~ `;
303     auto B4 = ` ~ B1 ~ `;
304     ` ~ B1 ~ ` &= ` ~ B3 ~ `;
305     ` ~ B1 ~ ` ^= ` ~ B2 ~ `;
306     B4 ^= ` ~ B3 ~ `;
307     ` ~ B0 ~ ` ^= B4;
308     ` ~ B2 ~ ` &= B4;
309     ` ~ B2 ~ ` ^= ` ~ B0 ~ `;
310     ` ~ B0 ~ ` &= ` ~ B1 ~ `;
311     ` ~ B3 ~ ` ^= ` ~ B0 ~ `;
312     B4 |= ` ~ B1 ~ `;
313     B4 ^= ` ~ B0 ~ `;
314     ` ~ B0 ~ ` |= ` ~ B3 ~ `;
315     ` ~ B0 ~ ` ^= ` ~ B2 ~ `;
316     ` ~ B2 ~ ` &= ` ~ B3 ~ `;
317     ` ~ B0 ~ ` = ~` ~ B0 ~ `;
318     B4 ^= ` ~ B2 ~ `;
319     ` ~ B2 ~ ` = ` ~ B0 ~ `;
320     ` ~ B0 ~ ` = ` ~ B1 ~ `;
321     ` ~ B1 ~ ` = B4;}`;
322 
323 enum string SBoxE6(string B0, string B1, string B2, string B3) =
324     `{` ~ B0 ~ ` ^= ` ~ B1 ~ `;
325     ` ~ B1 ~ ` ^= ` ~ B3 ~ `;
326     ` ~ B3 ~ ` = ~` ~ B3 ~ `;
327     auto B4 = ` ~ B1 ~ `;
328     ` ~ B1 ~ ` &= ` ~ B0 ~ `;
329     ` ~ B2 ~ ` ^= ` ~ B3 ~ `;
330     ` ~ B1 ~ ` ^= ` ~ B2 ~ `;
331     ` ~ B2 ~ ` |= B4;
332     B4 ^= ` ~ B3 ~ `;
333     ` ~ B3 ~ ` &= ` ~ B1 ~ `;
334     ` ~ B3 ~ ` ^= ` ~ B0 ~ `;
335     B4 ^= ` ~ B1 ~ `;
336     B4 ^= ` ~ B2 ~ `;
337     ` ~ B2 ~ ` ^= ` ~ B0 ~ `;
338     ` ~ B0 ~ ` &= ` ~ B3 ~ `;
339     ` ~ B2 ~ ` = ~` ~ B2 ~ `;
340     ` ~ B0 ~ ` ^= B4;
341     B4 |= ` ~ B3 ~ `;
342     B4 ^= ` ~ B2 ~ `;
343     ` ~ B2 ~ ` = ` ~ B0 ~ `;
344     ` ~ B0 ~ ` = ` ~ B1 ~ `;
345     ` ~ B1 ~ ` = ` ~ B3 ~ `;
346     ` ~ B3 ~ ` = B4;}`;
347 
348 enum string SBoxE7(string B0, string B1, string B2, string B3) =
349     `{` ~ B2 ~ ` = ~` ~ B2 ~ `;
350     auto B4 = ` ~ B3 ~ `;
351     ` ~ B3 ~ ` &= ` ~ B0 ~ `;
352     ` ~ B0 ~ ` ^= B4;
353     ` ~ B3 ~ ` ^= ` ~ B2 ~ `;
354     ` ~ B2 ~ ` |= B4;
355     ` ~ B1 ~ ` ^= ` ~ B3 ~ `;
356     ` ~ B2 ~ ` ^= ` ~ B0 ~ `;
357     ` ~ B0 ~ ` |= ` ~ B1 ~ `;
358     ` ~ B2 ~ ` ^= ` ~ B1 ~ `;
359     B4 ^= ` ~ B0 ~ `;
360     ` ~ B0 ~ ` |= ` ~ B3 ~ `;
361     ` ~ B0 ~ ` ^= ` ~ B2 ~ `;
362     B4 ^= ` ~ B3 ~ `;
363     B4 ^= ` ~ B0 ~ `;
364     ` ~ B3 ~ ` = ~` ~ B3 ~ `;
365     ` ~ B2 ~ ` &= B4;
366     ` ~ B3 ~ ` ^= ` ~ B2 ~ `;
367     ` ~ B2 ~ ` = B4;}`;
368 
369 enum string SBoxE8(string B0, string B1, string B2, string B3) =
370     `{auto B4 = ` ~ B1 ~ `;
371     ` ~ B1 ~ ` |= ` ~ B2 ~ `;
372     ` ~ B1 ~ ` ^= ` ~ B3 ~ `;
373     B4 ^= ` ~ B2 ~ `;
374     ` ~ B2 ~ ` ^= ` ~ B1 ~ `;
375     ` ~ B3 ~ ` |= B4;
376     ` ~ B3 ~ ` &= ` ~ B0 ~ `;
377     B4 ^= ` ~ B2 ~ `;
378     ` ~ B3 ~ ` ^= ` ~ B1 ~ `;
379     ` ~ B1 ~ ` |= B4;
380     ` ~ B1 ~ ` ^= ` ~ B0 ~ `;
381     ` ~ B0 ~ ` |= B4;
382     ` ~ B0 ~ ` ^= ` ~ B2 ~ `;
383     ` ~ B1 ~ ` ^= B4;
384     ` ~ B2 ~ ` ^= ` ~ B1 ~ `;
385     ` ~ B1 ~ ` &= ` ~ B0 ~ `;
386     ` ~ B1 ~ ` ^= B4;
387     ` ~ B2 ~ ` = ~` ~ B2 ~ `;
388     ` ~ B2 ~ ` |= ` ~ B0 ~ `;
389     B4 ^= ` ~ B2 ~ `;
390     ` ~ B2 ~ ` = ` ~ B1 ~ `;
391     ` ~ B1 ~ ` = ` ~ B3 ~ `;
392     ` ~ B3 ~ ` = ` ~ B0 ~ `;
393     ` ~ B0 ~ ` = B4;}`;
394 
395 enum string SBoxD1 =
396     `{B2 = ~B2;
397     auto B4 = B1;
398     B1 |= B0;
399     B4 = ~B4;
400     B1 ^= B2;
401     B2 |= B4;
402     B1 ^= B3;
403     B0 ^= B4;
404     B2 ^= B0;
405     B0 &= B3;
406     B4 ^= B0;
407     B0 |= B1;
408     B0 ^= B2;
409     B3 ^= B4;
410     B2 ^= B1;
411     B3 ^= B0;
412     B3 ^= B1;
413     B2 &= B3;
414     B4 ^= B2;
415     B2 = B1;
416     B1 = B4;}`;
417 
418 enum string SBoxD2 =
419     `{auto B4 = B1;
420     B1 ^= B3;
421     B3 &= B1;
422     B4 ^= B2;
423     B3 ^= B0;
424     B0 |= B1;
425     B2 ^= B3;
426     B0 ^= B4;
427     B0 |= B2;
428     B1 ^= B3;
429     B0 ^= B1;
430     B1 |= B3;
431     B1 ^= B0;
432     B4 = ~B4;
433     B4 ^= B1;
434     B1 |= B0;
435     B1 ^= B0;
436     B1 |= B4;
437     B3 ^= B1;
438     B1 = B0;
439     B0 = B4;
440     B4 = B2;
441     B2 = B3;
442     B3 = B4;}`;
443 
444 enum string SBoxD3 =
445     `{B2 ^= B3;
446     B3 ^= B0;
447     auto B4 = B3;
448     B3 &= B2;
449     B3 ^= B1;
450     B1 |= B2;
451     B1 ^= B4;
452     B4 &= B3;
453     B2 ^= B3;
454     B4 &= B0;
455     B4 ^= B2;
456     B2 &= B1;
457     B2 |= B0;
458     B3 = ~B3;
459     B2 ^= B3;
460     B0 ^= B3;
461     B0 &= B1;
462     B3 ^= B4;
463     B3 ^= B0;
464     B0 = B1;
465     B1 = B4;}`;
466 
467 enum string SBoxD4 =
468     `{auto B4 = B2;
469     B2 ^= B1;
470     B0 ^= B2;
471     B4 &= B2;
472     B4 ^= B0;
473     B0 &= B1;
474     B1 ^= B3;
475     B3 |= B4;
476     B2 ^= B3;
477     B0 ^= B3;
478     B1 ^= B4;
479     B3 &= B2;
480     B3 ^= B1;
481     B1 ^= B0;
482     B1 |= B2;
483     B0 ^= B3;
484     B1 ^= B4;
485     B0 ^= B1;
486     B4 = B0;
487     B0 = B2;
488     B2 = B3;
489     B3 = B4;}`;
490 
491 enum string SBoxD5 =
492     `{auto B4 = B2;
493     B2 &= B3;
494     B2 ^= B1;
495     B1 |= B3;
496     B1 &= B0;
497     B4 ^= B2;
498     B4 ^= B1;
499     B1 &= B2;
500     B0 = ~B0;
501     B3 ^= B4;
502     B1 ^= B3;
503     B3 &= B0;
504     B3 ^= B2;
505     B0 ^= B1;
506     B2 &= B0;
507     B3 ^= B0;
508     B2 ^= B4;
509     B2 |= B3;
510     B3 ^= B0;
511     B2 ^= B1;
512     B1 = B3;
513     B3 = B4;}`;
514 
515 enum string SBoxD6 =
516     `{B1 = ~B1;
517     auto B4 = B3;
518     B2 ^= B1;
519     B3 |= B0;
520     B3 ^= B2;
521     B2 |= B1;
522     B2 &= B0;
523     B4 ^= B3;
524     B2 ^= B4;
525     B4 |= B0;
526     B4 ^= B1;
527     B1 &= B2;
528     B1 ^= B3;
529     B4 ^= B2;
530     B3 &= B4;
531     B4 ^= B1;
532     B3 ^= B4;
533     B4 = ~B4;
534     B3 ^= B0;
535     B0 = B1;
536     B1 = B4;
537     B4 = B3;
538     B3 = B2;
539     B2 = B4;}`;
540 
541 enum string SBoxD7 =
542     `{B0 ^= B2;
543     auto B4 = B2;
544     B2 &= B0;
545     B4 ^= B3;
546     B2 = ~B2;
547     B3 ^= B1;
548     B2 ^= B3;
549     B4 |= B0;
550     B0 ^= B2;
551     B3 ^= B4;
552     B4 ^= B1;
553     B1 &= B3;
554     B1 ^= B0;
555     B0 ^= B3;
556     B0 |= B2;
557     B3 ^= B1;
558     B4 ^= B0;
559     B0 = B1;
560     B1 = B2;
561     B2 = B4;}`;
562 
563 enum string SBoxD8 =
564     `{auto B4 = B2;
565     B2 ^= B0;
566     B0 &= B3;
567     B4 |= B3;
568     B2 = ~B2;
569     B3 ^= B1;
570     B1 |= B0;
571     B0 ^= B2;
572     B2 &= B4;
573     B3 &= B4;
574     B1 ^= B2;
575     B2 ^= B0;
576     B0 |= B2;
577     B4 ^= B1;
578     B0 ^= B3;
579     B3 ^= B4;
580     B4 |= B0;
581     B3 ^= B2;
582     B4 ^= B2;
583     B2 = B1;
584     B1 = B0;
585     B0 = B3;
586     B3 = B4;}`;
587 
588 private:
589 
590 /*
591 * Serpent's Linear Transformation
592 */
593 void transform(ref uint B0, ref uint B1, ref uint B2, ref uint B3)
594 {
595     B0  = rotateLeft(B0, 13);    B2  = rotateLeft(B2, 3);
596     B1 ^= B0 ^ B2;B3 ^= B2 ^ (B0 << 3);
597     B1  = rotateLeft(B1, 1);     B3  = rotateLeft(B3, 7);
598     B0 ^= B1 ^ B3;B2 ^= B3 ^ (B1 << 7);
599     B0  = rotateLeft(B0, 5);     B2  = rotateLeft(B2, 22);
600 }
601 
602 /*
603 * Serpent's Inverse Linear Transformation
604 */
605 void i_transform(ref uint B0, ref uint B1, ref uint B2, ref uint B3)
606 {
607     B2  = rotateRight(B2, 22);  B0  = rotateRight(B0, 5);
608     B2 ^= B3 ^ (B1 << 7);          B0 ^= B1 ^ B3;
609     B3  = rotateRight(B3, 7);    B1  = rotateRight(B1, 1);
610     B3 ^= B2 ^ (B0 << 3);          B1 ^= B0 ^ B2;
611     B2  = rotateRight(B2, 3);    B0  = rotateRight(B0, 13);
612 }
613 /*
614 * XOR a key block with a data block
615 */
616 enum string key_xor(ubyte round) =
617     `B0 ^= m_round_key[4*` ~ round.stringof ~ `  ];
618     B1 ^= m_round_key[4*` ~ round.stringof ~ `+1];
619     B2 ^= m_round_key[4*` ~ round.stringof ~ `+2];
620     B3 ^= m_round_key[4*` ~ round.stringof ~ `+3];`;