Skip to main content

fast_des/
des_optimized.rs

1use std::{
2    arch::x86_64::{__m256i, __m512i, _mm256_xor_si256, _mm512_xor_si512},
3    mem::transmute,
4    ops::{BitAnd, BitOr, Shl, Shr},
5};
6
7use crate::{
8    ZERO,
9    constants::{EO, IP, IP_INVO, PC_1O, PC_2O, PO},
10    sboxes::{
11        sbox_avx2::{
12            s1_avx_2, s2_avx_2, s3_avx_2, s4_avx_2, s5_avx_2, s6_avx_2, s7_avx_2, s8_avx_2,
13        },
14        sbox_avx512::{
15            s1_avx_512, s2_avx_512, s3_avx_512, s4_avx_512, s5_avx_512, s6_avx_512, s7_avx_512,
16            s8_avx_512,
17        },
18        sbox_optimized::{s1, s2, s3, s4, s5, s6, s7, s8},
19    },
20};
21use bitsliced_op::transpose_64x64;
22use wide::u64x8;
23
24//slice[i] contains bit with index i of all 64 slices
25// a column is equal to one item/number
26pub fn compute_pc1_optimized(k_slices: &[u64x8; 64]) -> ([u64x8; 28], [u64x8; 28]) {
27    let mut c0 = [ZERO; 28];
28    let mut d0 = [ZERO; 28];
29
30    for (i, &src) in PC_1O.iter().enumerate() {
31        if i < 28 {
32            c0[i] = k_slices[src as usize];
33        } else {
34            d0[i - 28] = k_slices[src as usize];
35        }
36    }
37
38    (c0, d0)
39}
40
41const SHIFTS: [u32; 16] = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];
42
43pub fn create_subkeys_optimized(c0: &mut [u64x8; 28], d0: &mut [u64x8; 28]) -> [[u64x8; 48]; 16] {
44    let mut subkeys = [[ZERO; 48]; 16];
45
46    for (index, s) in SHIFTS.iter().enumerate() {
47        c0.rotate_left(*s as usize);
48        d0.rotate_left(*s as usize);
49        for (i, &src) in PC_2O.iter().enumerate() {
50            if src < 28 {
51                subkeys[index][i] = c0[src as usize]
52            } else {
53                subkeys[index][i] = d0[(src - 28) as usize];
54            }
55        }
56    }
57
58    subkeys
59}
60
61//TODO: create a version where IP is precomputed
62pub fn encrypt_optimized(plaintext: u64, subkeys: [[u64x8; 48]; 16], output: &mut [u64x8; 64]) {
63    let ip = permute_bits_pc(&IP, plaintext, 64);
64    //repeat and transpose IP
65    let ip_bitsliced = transpose_64x64(&[ip; 64]);
66    let mut l: [u64x8; 32] = std::array::from_fn(|i| u64x8::splat(ip_bitsliced[i]));
67    let mut r: [u64x8; 32] = std::array::from_fn(|i| u64x8::splat(ip_bitsliced[i + 32]));
68
69    for i in 0..16 {
70        let (new_l, new_r) = feistel_function_optimized(l, r, subkeys[i]);
71        l = new_l;
72        r = new_r;
73    }
74    let mut r_l = [ZERO; 64];
75    r_l[..32].copy_from_slice(&r);
76    r_l[32..].copy_from_slice(&l);
77    for (i, &src) in IP_INVO.iter().enumerate() {
78        output[i] = r_l[src as usize];
79    }
80}
81
82#[inline(always)]
83fn feistel_function_optimized(
84    l: [u64x8; 32],
85    r: [u64x8; 32],
86    subkey: [u64x8; 48],
87) -> ([u64x8; 32], [u64x8; 32]) {
88    let new_l = r;
89    let mut e = [ZERO; 48];
90    for (i, &src) in EO.iter().enumerate() {
91        e[i] = r[src as usize];
92    }
93    for i in 0..48 {
94        e[i] ^= subkey[i];
95    }
96    let mut output: [u64x8; 32] = [ZERO; 32];
97
98    let s1_output = s1(e[0], e[1], e[2], e[3], e[4], e[5]);
99    let s2_output = s2(e[6], e[7], e[8], e[9], e[10], e[11]);
100    let s3_output = s3(e[12], e[13], e[14], e[15], e[16], e[17]);
101    let s4_output = s4(e[18], e[19], e[20], e[21], e[22], e[23]);
102    let s5_output = s5(e[24], e[25], e[26], e[27], e[28], e[29]);
103    let s6_output = s6(e[30], e[31], e[32], e[33], e[34], e[35]);
104    let s7_output = s7(e[36], e[37], e[38], e[39], e[40], e[41]);
105    let s8_output = s8(e[42], e[43], e[44], e[45], e[46], e[47]);
106    // s1
107    output[0] = s1_output.0;
108    output[1] = s1_output.1;
109    output[2] = s1_output.2;
110    output[3] = s1_output.3;
111
112    // s2
113    output[4] = s2_output.0;
114    output[5] = s2_output.1;
115    output[6] = s2_output.2;
116    output[7] = s2_output.3;
117
118    // s3
119    output[8] = s3_output.0;
120    output[9] = s3_output.1;
121    output[10] = s3_output.2;
122    output[11] = s3_output.3;
123
124    // s4
125    output[12] = s4_output.0;
126    output[13] = s4_output.1;
127    output[14] = s4_output.2;
128    output[15] = s4_output.3;
129
130    // s5
131    output[16] = s5_output.0;
132    output[17] = s5_output.1;
133    output[18] = s5_output.2;
134    output[19] = s5_output.3;
135
136    // s6
137    output[20] = s6_output.0;
138    output[21] = s6_output.1;
139    output[22] = s6_output.2;
140    output[23] = s6_output.3;
141
142    // s7
143    output[24] = s7_output.0;
144    output[25] = s7_output.1;
145    output[26] = s7_output.2;
146    output[27] = s7_output.3;
147
148    // s8
149    output[28] = s8_output.0;
150    output[29] = s8_output.1;
151    output[30] = s8_output.2;
152    output[31] = s8_output.3;
153    let mut new_r = [ZERO; 32];
154    for (i, &src) in PO.iter().enumerate() {
155        new_r[i] = output[src as usize];
156    }
157    //inline array modification to avoid extra allocation
158    for i in 0..32 {
159        new_r[i] = l[i] ^ new_r[i];
160    }
161    (new_l, new_r)
162}
163
164const SUBKEY_SCHEDULE: [[usize; 48]; 16] = [
165    //0:
166    [
167        9, 50, 33, 59, 48, 16, 32, 56, 1, 8, 18, 41, 2, 34, 25, 24, 43, 57, 58, 0, 35, 26, 17, 40,
168        21, 27, 38, 53, 36, 3, 46, 29, 4, 52, 22, 28, 60, 20, 37, 62, 14, 19, 44, 13, 12, 61, 54,
169        30,
170    ],
171    //1:
172    [
173        1, 42, 25, 51, 40, 8, 24, 48, 58, 0, 10, 33, 59, 26, 17, 16, 35, 49, 50, 57, 56, 18, 9, 32,
174        13, 19, 30, 45, 28, 62, 38, 21, 27, 44, 14, 20, 52, 12, 29, 54, 6, 11, 36, 5, 4, 53, 46,
175        22,
176    ],
177    //2:
178    [
179        50, 26, 9, 35, 24, 57, 8, 32, 42, 49, 59, 17, 43, 10, 1, 0, 48, 33, 34, 41, 40, 2, 58, 16,
180        60, 3, 14, 29, 12, 46, 22, 5, 11, 28, 61, 4, 36, 27, 13, 38, 53, 62, 20, 52, 19, 37, 30, 6,
181    ],
182    //3:
183    [
184        34, 10, 58, 48, 8, 41, 57, 16, 26, 33, 43, 1, 56, 59, 50, 49, 32, 17, 18, 25, 24, 51, 42,
185        0, 44, 54, 61, 13, 27, 30, 6, 52, 62, 12, 45, 19, 20, 11, 60, 22, 37, 46, 4, 36, 3, 21, 14,
186        53,
187    ],
188    //4:
189    [
190        18, 59, 42, 32, 57, 25, 41, 0, 10, 17, 56, 50, 40, 43, 34, 33, 16, 1, 2, 9, 8, 35, 26, 49,
191        28, 38, 45, 60, 11, 14, 53, 36, 46, 27, 29, 3, 4, 62, 44, 6, 21, 30, 19, 20, 54, 5, 61, 37,
192    ],
193    //5:
194    [
195        2, 43, 26, 16, 41, 9, 25, 49, 59, 1, 40, 34, 24, 56, 18, 17, 0, 50, 51, 58, 57, 48, 10, 33,
196        12, 22, 29, 44, 62, 61, 37, 20, 30, 11, 13, 54, 19, 46, 28, 53, 5, 14, 3, 4, 38, 52, 45,
197        21,
198    ],
199    //6:
200    [
201        51, 56, 10, 0, 25, 58, 9, 33, 43, 50, 24, 18, 8, 40, 2, 1, 49, 34, 35, 42, 41, 32, 59, 17,
202        27, 6, 13, 28, 46, 45, 21, 4, 14, 62, 60, 38, 3, 30, 12, 37, 52, 61, 54, 19, 22, 36, 29, 5,
203    ],
204    //7:
205    [
206        35, 40, 59, 49, 9, 42, 58, 17, 56, 34, 8, 2, 57, 24, 51, 50, 33, 18, 48, 26, 25, 16, 43, 1,
207        11, 53, 60, 12, 30, 29, 5, 19, 61, 46, 44, 22, 54, 14, 27, 21, 36, 45, 38, 3, 6, 20, 13,
208        52,
209    ],
210    //8:
211    [
212        56, 32, 51, 41, 1, 34, 50, 9, 48, 26, 0, 59, 49, 16, 43, 42, 25, 10, 40, 18, 17, 8, 35, 58,
213        3, 45, 52, 4, 22, 21, 60, 11, 53, 38, 36, 14, 46, 6, 19, 13, 28, 37, 30, 62, 61, 12, 5, 44,
214    ],
215    //9:
216    [
217        40, 16, 35, 25, 50, 18, 34, 58, 32, 10, 49, 43, 33, 0, 56, 26, 9, 59, 24, 2, 1, 57, 48, 42,
218        54, 29, 36, 19, 6, 5, 44, 62, 37, 22, 20, 61, 30, 53, 3, 60, 12, 21, 14, 46, 45, 27, 52,
219        28,
220    ],
221    //10:
222    [
223        24, 0, 48, 9, 34, 2, 18, 42, 16, 59, 33, 56, 17, 49, 40, 10, 58, 43, 8, 51, 50, 41, 32, 26,
224        38, 13, 20, 3, 53, 52, 28, 46, 21, 6, 4, 45, 14, 37, 54, 44, 27, 5, 61, 30, 29, 11, 36, 12,
225    ],
226    //11:
227    [
228        8, 49, 32, 58, 18, 51, 2, 26, 0, 43, 17, 40, 1, 33, 24, 59, 42, 56, 57, 35, 34, 25, 16, 10,
229        22, 60, 4, 54, 37, 36, 12, 30, 5, 53, 19, 29, 61, 21, 38, 28, 11, 52, 45, 14, 13, 62, 20,
230        27,
231    ],
232    //12:
233    [
234        57, 33, 16, 42, 2, 35, 51, 10, 49, 56, 1, 24, 50, 17, 8, 43, 26, 40, 41, 48, 18, 9, 0, 59,
235        6, 44, 19, 38, 21, 20, 27, 14, 52, 37, 3, 13, 45, 5, 22, 12, 62, 36, 29, 61, 60, 46, 4, 11,
236    ],
237    //13:
238    [
239        41, 17, 0, 26, 51, 48, 35, 59, 33, 40, 50, 8, 34, 1, 57, 56, 10, 24, 25, 32, 2, 58, 49, 43,
240        53, 28, 3, 22, 5, 4, 11, 61, 36, 21, 54, 60, 29, 52, 6, 27, 46, 20, 13, 45, 44, 30, 19, 62,
241    ],
242    //14:
243    [
244        25, 1, 49, 10, 35, 32, 48, 43, 17, 24, 34, 57, 18, 50, 41, 40, 59, 8, 9, 16, 51, 42, 33,
245        56, 37, 12, 54, 6, 52, 19, 62, 45, 20, 5, 38, 44, 13, 36, 53, 11, 30, 4, 60, 29, 28, 14, 3,
246        46,
247    ],
248    //15:
249    [
250        17, 58, 41, 2, 56, 24, 40, 35, 9, 16, 26, 49, 10, 42, 33, 32, 51, 0, 1, 8, 43, 34, 25, 48,
251        29, 4, 46, 61, 44, 11, 54, 37, 12, 60, 30, 36, 5, 28, 45, 3, 22, 27, 52, 21, 20, 6, 62, 38,
252    ],
253];
254
255pub fn encrypt_simd(plaintext: u64, keys: &mut [u64x8; 64]) {
256    let ip = permute_bits_pc(&IP, plaintext, 64);
257    let mut l: [u64x8; 32] = [ZERO; 32];
258    let mut r: [u64x8; 32] = [ZERO; 32];
259    for i in 0..32 {
260        let bit_l = (ip >> (63 - i)) & 1;
261        let bit_r = (ip >> (31 - i)) & 1;
262
263        l[i] = u64x8::splat(0u64.wrapping_sub(bit_l));
264        r[i] = u64x8::splat(0u64.wrapping_sub(bit_r));
265    }
266
267    // round 0
268    unsafe {
269        feistel_function_simd(&mut l, &mut r, keys, 0);
270    }
271    // round 1
272    unsafe {
273        feistel_function_simd(&mut r, &mut l, keys, 1);
274    }
275    // round 2
276    unsafe {
277        feistel_function_simd(&mut l, &mut r, keys, 2);
278    }
279    // round 3
280    unsafe {
281        feistel_function_simd(&mut r, &mut l, keys, 3);
282    }
283    // round 4
284    unsafe {
285        feistel_function_simd(&mut l, &mut r, keys, 4);
286    }
287    // round 5
288    unsafe {
289        feistel_function_simd(&mut r, &mut l, keys, 5);
290    }
291    // round 6
292    unsafe {
293        feistel_function_simd(&mut l, &mut r, keys, 6);
294    }
295    // round 7
296    unsafe {
297        feistel_function_simd(&mut r, &mut l, keys, 7);
298    }
299    // round 8
300    unsafe {
301        feistel_function_simd(&mut l, &mut r, keys, 8);
302    }
303    // round 9
304    unsafe {
305        feistel_function_simd(&mut r, &mut l, keys, 9);
306    }
307    // round 10
308    unsafe {
309        feistel_function_simd(&mut l, &mut r, keys, 10);
310    }
311    // round 11
312    unsafe {
313        feistel_function_simd(&mut r, &mut l, keys, 11);
314    }
315    // round 12
316    unsafe {
317        feistel_function_simd(&mut l, &mut r, keys, 12);
318    }
319    // round 13
320    unsafe {
321        feistel_function_simd(&mut r, &mut l, keys, 13);
322    }
323    // round 14
324    unsafe {
325        feistel_function_simd(&mut l, &mut r, keys, 14);
326    }
327    // round 15
328    unsafe {
329        feistel_function_simd(&mut r, &mut l, keys, 15);
330    }
331
332    //final permutation
333    let keys_ptr = keys.as_mut_ptr();
334    for i in 0..64 {
335        unsafe {
336            std::ptr::write(
337                keys_ptr.add(i),
338                if IP_INVO[i] < 32 {
339                    r[IP_INVO[i]]
340                } else {
341                    l[IP_INVO[i] - 32]
342                },
343            );
344        }
345    }
346}
347
348#[inline(always)]
349pub unsafe fn feistel_function_simd(
350    l: &mut [u64x8; 32],
351    r: &mut [u64x8; 32],
352    keys: &[u64x8; 64],
353    round: usize,
354) {
355    //s1 expand
356    let mut e0 = r[31] ^ keys[SUBKEY_SCHEDULE[round][0]];
357    let mut e1 = r[0] ^ keys[SUBKEY_SCHEDULE[round][1]];
358    let mut e2 = r[1] ^ keys[SUBKEY_SCHEDULE[round][2]];
359    let mut e3 = r[2] ^ keys[SUBKEY_SCHEDULE[round][3]];
360    let mut e4 = r[3] ^ keys[SUBKEY_SCHEDULE[round][4]];
361    let mut e5 = r[4] ^ keys[SUBKEY_SCHEDULE[round][5]];
362
363    //s2 expand
364    let mut f0 = r[3] ^ keys[SUBKEY_SCHEDULE[round][6]];
365    let mut f1 = r[4] ^ keys[SUBKEY_SCHEDULE[round][7]];
366    let mut f2 = r[5] ^ keys[SUBKEY_SCHEDULE[round][8]];
367    let mut f3 = r[6] ^ keys[SUBKEY_SCHEDULE[round][9]];
368    let mut f4 = r[7] ^ keys[SUBKEY_SCHEDULE[round][10]];
369    let mut f5 = r[8] ^ keys[SUBKEY_SCHEDULE[round][11]];
370
371    //s3 expand
372    let mut g0 = r[7] ^ keys[SUBKEY_SCHEDULE[round][12]];
373    let mut g1 = r[8] ^ keys[SUBKEY_SCHEDULE[round][13]];
374    let mut g2 = r[9] ^ keys[SUBKEY_SCHEDULE[round][14]];
375    let mut g3 = r[10] ^ keys[SUBKEY_SCHEDULE[round][15]];
376    let mut g4 = r[11] ^ keys[SUBKEY_SCHEDULE[round][16]];
377    let mut g5 = r[12] ^ keys[SUBKEY_SCHEDULE[round][17]];
378
379    //s4 expand
380    let mut h0 = r[11] ^ keys[SUBKEY_SCHEDULE[round][18]];
381    let mut h1 = r[12] ^ keys[SUBKEY_SCHEDULE[round][19]];
382    let mut h2 = r[13] ^ keys[SUBKEY_SCHEDULE[round][20]];
383    let mut h3 = r[14] ^ keys[SUBKEY_SCHEDULE[round][21]];
384    let mut h4 = r[15] ^ keys[SUBKEY_SCHEDULE[round][22]];
385    let mut h5 = r[16] ^ keys[SUBKEY_SCHEDULE[round][23]];
386
387    //s1 compute
388    //use inner block to free o registers
389    {
390        let (o0, o1, o2, o3) = s1(e0, e1, e2, e3, e4, e5);
391        l[8] = l[8] ^ o0;
392        l[16] = l[16] ^ o1;
393        l[22] = l[22] ^ o2;
394        l[30] = l[30] ^ o3;
395    }
396
397    //s2 compute
398    {
399        let (o0, o1, o2, o3) = s2(f0, f1, f2, f3, f4, f5);
400        l[12] = l[12] ^ o0;
401        l[27] = l[27] ^ o1;
402        l[1] = l[1] ^ o2;
403        l[17] = l[17] ^ o3;
404    }
405
406    //s3 compute
407    {
408        let (o0, o1, o2, o3) = s3(g0, g1, g2, g3, g4, g5);
409        l[23] = l[23] ^ o0;
410        l[15] = l[15] ^ o1;
411        l[29] = l[29] ^ o2;
412        l[5] = l[5] ^ o3;
413    }
414
415    //s4 compute
416    {
417        let (o0, o1, o2, o3) = s4(h0, h1, h2, h3, h4, h5);
418        l[25] = l[25] ^ o0;
419        l[19] = l[19] ^ o1;
420        l[9] = l[9] ^ o2;
421        l[0] = l[0] ^ o3;
422    }
423
424    //s5 expand
425    e0 = r[15] ^ keys[SUBKEY_SCHEDULE[round][24]];
426    e1 = r[16] ^ keys[SUBKEY_SCHEDULE[round][25]];
427    e2 = r[17] ^ keys[SUBKEY_SCHEDULE[round][26]];
428    e3 = r[18] ^ keys[SUBKEY_SCHEDULE[round][27]];
429    e4 = r[19] ^ keys[SUBKEY_SCHEDULE[round][28]];
430    e5 = r[20] ^ keys[SUBKEY_SCHEDULE[round][29]];
431
432    //s6 expand
433    f0 = r[19] ^ keys[SUBKEY_SCHEDULE[round][30]];
434    f1 = r[20] ^ keys[SUBKEY_SCHEDULE[round][31]];
435    f2 = r[21] ^ keys[SUBKEY_SCHEDULE[round][32]];
436    f3 = r[22] ^ keys[SUBKEY_SCHEDULE[round][33]];
437    f4 = r[23] ^ keys[SUBKEY_SCHEDULE[round][34]];
438    f5 = r[24] ^ keys[SUBKEY_SCHEDULE[round][35]];
439
440    //s7 expand
441    g0 = r[23] ^ keys[SUBKEY_SCHEDULE[round][36]];
442    g1 = r[24] ^ keys[SUBKEY_SCHEDULE[round][37]];
443    g2 = r[25] ^ keys[SUBKEY_SCHEDULE[round][38]];
444    g3 = r[26] ^ keys[SUBKEY_SCHEDULE[round][39]];
445    g4 = r[27] ^ keys[SUBKEY_SCHEDULE[round][40]];
446    g5 = r[28] ^ keys[SUBKEY_SCHEDULE[round][41]];
447
448    //s8 expand
449    h0 = r[27] ^ keys[SUBKEY_SCHEDULE[round][42]];
450    h1 = r[28] ^ keys[SUBKEY_SCHEDULE[round][43]];
451    h2 = r[29] ^ keys[SUBKEY_SCHEDULE[round][44]];
452    h3 = r[30] ^ keys[SUBKEY_SCHEDULE[round][45]];
453    h4 = r[31] ^ keys[SUBKEY_SCHEDULE[round][46]];
454    h5 = r[0] ^ keys[SUBKEY_SCHEDULE[round][47]];
455
456    //s5 compute
457    {
458        let (o0, o1, o2, o3) = s5(e0, e1, e2, e3, e4, e5);
459        l[7] = l[7] ^ o0;
460        l[13] = l[13] ^ o1;
461        l[24] = l[24] ^ o2;
462        l[2] = l[2] ^ o3;
463    }
464
465    //s6 compute
466    {
467        let (o0, o1, o2, o3) = s6(f0, f1, f2, f3, f4, f5);
468        l[3] = l[3] ^ o0;
469        l[28] = l[28] ^ o1;
470        l[10] = l[10] ^ o2;
471        l[18] = l[18] ^ o3;
472    }
473
474    //s7 compute
475    {
476        let (o0, o1, o2, o3) = s7(g0, g1, g2, g3, g4, g5);
477        l[31] = l[31] ^ o0;
478        l[11] = l[11] ^ o1;
479        l[21] = l[21] ^ o2;
480        l[6] = l[6] ^ o3;
481    }
482
483    //s8 compute
484    {
485        let (o0, o1, o2, o3) = s8(h0, h1, h2, h3, h4, h5);
486        l[4] = l[4] ^ o0;
487        l[26] = l[26] ^ o1;
488        l[14] = l[14] ^ o2;
489        l[20] = l[20] ^ o3;
490    }
491}
492
493const ALL_ONES_AVX: __m512i = unsafe { transmute([!0u64; 8]) };
494const ZERO_AVX: __m512i = unsafe { transmute([0u64; 8]) };
495
496#[inline(always)]
497pub fn encrypt_avx_512(keys: &mut [__m512i; 64]) {
498    //assume pre calculated l and r for IP
499    //TODO: round 0 can simply read from 2 registers (zero's or all ones), the rounds after need to work with l and r fully
500    let mut l: [__m512i; 32] = [
501        ZERO_AVX,
502        ALL_ONES_AVX,
503        ALL_ONES_AVX,
504        ALL_ONES_AVX,
505        ALL_ONES_AVX,
506        ZERO_AVX,
507        ZERO_AVX,
508        ZERO_AVX,
509        ZERO_AVX,
510        ALL_ONES_AVX,
511        ZERO_AVX,
512        ALL_ONES_AVX,
513        ZERO_AVX,
514        ALL_ONES_AVX,
515        ZERO_AVX,
516        ALL_ONES_AVX,
517        ZERO_AVX,
518        ALL_ONES_AVX,
519        ALL_ONES_AVX,
520        ALL_ONES_AVX,
521        ALL_ONES_AVX,
522        ZERO_AVX,
523        ZERO_AVX,
524        ZERO_AVX,
525        ZERO_AVX,
526        ALL_ONES_AVX,
527        ZERO_AVX,
528        ALL_ONES_AVX,
529        ZERO_AVX,
530        ALL_ONES_AVX,
531        ZERO_AVX,
532        ALL_ONES_AVX,
533    ];
534    let mut r: [__m512i; 32] = [
535        ALL_ONES_AVX,
536        ZERO_AVX,
537        ZERO_AVX,
538        ZERO_AVX,
539        ZERO_AVX,
540        ZERO_AVX,
541        ZERO_AVX,
542        ZERO_AVX,
543        ZERO_AVX,
544        ALL_ONES_AVX,
545        ALL_ONES_AVX,
546        ZERO_AVX,
547        ZERO_AVX,
548        ALL_ONES_AVX,
549        ALL_ONES_AVX,
550        ZERO_AVX,
551        ALL_ONES_AVX,
552        ZERO_AVX,
553        ZERO_AVX,
554        ZERO_AVX,
555        ZERO_AVX,
556        ZERO_AVX,
557        ZERO_AVX,
558        ZERO_AVX,
559        ZERO_AVX,
560        ALL_ONES_AVX,
561        ALL_ONES_AVX,
562        ZERO_AVX,
563        ZERO_AVX,
564        ALL_ONES_AVX,
565        ALL_ONES_AVX,
566        ZERO_AVX,
567    ];
568    // round 0
569    unsafe {
570        feistel_avx_512(&mut l, &mut r, keys, 0);
571    }
572    // round 1
573    unsafe {
574        feistel_avx_512(&mut r, &mut l, keys, 1);
575    }
576    // round 2
577    unsafe {
578        feistel_avx_512(&mut l, &mut r, keys, 2);
579    }
580    // round 3
581    unsafe {
582        feistel_avx_512(&mut r, &mut l, keys, 3);
583    }
584    // round 4
585    unsafe {
586        feistel_avx_512(&mut l, &mut r, keys, 4);
587    }
588    // round 5
589    unsafe {
590        feistel_avx_512(&mut r, &mut l, keys, 5);
591    }
592    // round 6
593    unsafe {
594        feistel_avx_512(&mut l, &mut r, keys, 6);
595    }
596    // round 7
597    unsafe {
598        feistel_avx_512(&mut r, &mut l, keys, 7);
599    }
600    // round 8
601    unsafe {
602        feistel_avx_512(&mut l, &mut r, keys, 8);
603    }
604    // round 9
605    unsafe {
606        feistel_avx_512(&mut r, &mut l, keys, 9);
607    }
608    // round 10
609    unsafe {
610        feistel_avx_512(&mut l, &mut r, keys, 10);
611    }
612    // round 11
613    unsafe {
614        feistel_avx_512(&mut r, &mut l, keys, 11);
615    }
616    // round 12
617    unsafe {
618        feistel_avx_512(&mut l, &mut r, keys, 12);
619    }
620    // round 13
621    unsafe {
622        feistel_avx_512(&mut r, &mut l, keys, 13);
623    }
624    // round 14
625    unsafe {
626        feistel_avx_512(&mut l, &mut r, keys, 14);
627    }
628    // round 15
629    unsafe {
630        feistel_avx_512(&mut r, &mut l, keys, 15);
631    }
632
633    //final permutation
634    unsafe {
635        let out = keys.as_mut_ptr();
636
637        *out.add(0) = l[7];
638        *out.add(1) = r[7];
639        *out.add(2) = l[15];
640        *out.add(3) = r[15];
641        *out.add(4) = l[23];
642        *out.add(5) = r[23];
643        *out.add(6) = l[31];
644        *out.add(7) = r[31];
645
646        *out.add(8) = l[6];
647        *out.add(9) = r[6];
648        *out.add(10) = l[14];
649        *out.add(11) = r[14];
650        *out.add(12) = l[22];
651        *out.add(13) = r[22];
652        *out.add(14) = l[30];
653        *out.add(15) = r[30];
654
655        *out.add(16) = l[5];
656        *out.add(17) = r[5];
657        *out.add(18) = l[13];
658        *out.add(19) = r[13];
659        *out.add(20) = l[21];
660        *out.add(21) = r[21];
661        *out.add(22) = l[29];
662        *out.add(23) = r[29];
663
664        *out.add(24) = l[4];
665        *out.add(25) = r[4];
666        *out.add(26) = l[12];
667        *out.add(27) = r[12];
668        *out.add(28) = l[20];
669        *out.add(29) = r[20];
670        *out.add(30) = l[28];
671        *out.add(31) = r[28];
672
673        *out.add(32) = l[3];
674        *out.add(33) = r[3];
675        *out.add(34) = l[11];
676        *out.add(35) = r[11];
677        *out.add(36) = l[19];
678        *out.add(37) = r[19];
679        *out.add(38) = l[27];
680        *out.add(39) = r[27];
681
682        *out.add(40) = l[2];
683        *out.add(41) = r[2];
684        *out.add(42) = l[10];
685        *out.add(43) = r[10];
686        *out.add(44) = l[18];
687        *out.add(45) = r[18];
688        *out.add(46) = l[26];
689        *out.add(47) = r[26];
690
691        *out.add(48) = l[1];
692        *out.add(49) = r[1];
693        *out.add(50) = l[9];
694        *out.add(51) = r[9];
695        *out.add(52) = l[17];
696        *out.add(53) = r[17];
697        *out.add(54) = l[25];
698        *out.add(55) = r[25];
699
700        *out.add(56) = l[0];
701        *out.add(57) = r[0];
702        *out.add(58) = l[8];
703        *out.add(59) = r[8];
704        *out.add(60) = l[16];
705        *out.add(61) = r[16];
706        *out.add(62) = l[24];
707        *out.add(63) = r[24];
708    }
709}
710
711#[inline(always)]
712pub unsafe fn feistel_avx_512(
713    l: &mut [__m512i; 32],
714    r: &mut [__m512i; 32],
715    keys: &[__m512i; 64],
716    round: usize,
717) {
718    unsafe {
719        //s1 expand
720        let mut e0 = _mm512_xor_si512(r[31], keys[SUBKEY_SCHEDULE[round][0]]);
721        let mut e1 = _mm512_xor_si512(r[0], keys[SUBKEY_SCHEDULE[round][1]]);
722        let mut e2 = _mm512_xor_si512(r[1], keys[SUBKEY_SCHEDULE[round][2]]);
723        let mut e3 = _mm512_xor_si512(r[2], keys[SUBKEY_SCHEDULE[round][3]]);
724        let mut e4 = _mm512_xor_si512(r[3], keys[SUBKEY_SCHEDULE[round][4]]);
725        let mut e5 = _mm512_xor_si512(r[4], keys[SUBKEY_SCHEDULE[round][5]]);
726
727        //s2 expand
728        let mut f0 = _mm512_xor_si512(r[3], keys[SUBKEY_SCHEDULE[round][6]]);
729        let mut f1 = _mm512_xor_si512(r[4], keys[SUBKEY_SCHEDULE[round][7]]);
730        let mut f2 = _mm512_xor_si512(r[5], keys[SUBKEY_SCHEDULE[round][8]]);
731        let mut f3 = _mm512_xor_si512(r[6], keys[SUBKEY_SCHEDULE[round][9]]);
732        let mut f4 = _mm512_xor_si512(r[7], keys[SUBKEY_SCHEDULE[round][10]]);
733        let mut f5 = _mm512_xor_si512(r[8], keys[SUBKEY_SCHEDULE[round][11]]);
734
735        //s3 expand
736        let mut g0 = _mm512_xor_si512(r[7], keys[SUBKEY_SCHEDULE[round][12]]);
737        let mut g1 = _mm512_xor_si512(r[8], keys[SUBKEY_SCHEDULE[round][13]]);
738        let mut g2 = _mm512_xor_si512(r[9], keys[SUBKEY_SCHEDULE[round][14]]);
739        let mut g3 = _mm512_xor_si512(r[10], keys[SUBKEY_SCHEDULE[round][15]]);
740        let mut g4 = _mm512_xor_si512(r[11], keys[SUBKEY_SCHEDULE[round][16]]);
741        let mut g5 = _mm512_xor_si512(r[12], keys[SUBKEY_SCHEDULE[round][17]]);
742
743        //s4 expand
744        let mut h0 = _mm512_xor_si512(r[11], keys[SUBKEY_SCHEDULE[round][18]]);
745        let mut h1 = _mm512_xor_si512(r[12], keys[SUBKEY_SCHEDULE[round][19]]);
746        let mut h2 = _mm512_xor_si512(r[13], keys[SUBKEY_SCHEDULE[round][20]]);
747        let mut h3 = _mm512_xor_si512(r[14], keys[SUBKEY_SCHEDULE[round][21]]);
748        let mut h4 = _mm512_xor_si512(r[15], keys[SUBKEY_SCHEDULE[round][22]]);
749        let mut h5 = _mm512_xor_si512(r[16], keys[SUBKEY_SCHEDULE[round][23]]);
750
751        //s1 compute
752        //use inner block to free o registers
753        {
754            let (o0, o1, o2, o3) = s1_avx_512(e0, e1, e2, e3, e4, e5);
755            l[8] = _mm512_xor_si512(l[8], o0);
756            l[16] = _mm512_xor_si512(l[16], o1);
757            l[22] = _mm512_xor_si512(l[22], o2);
758            l[30] = _mm512_xor_si512(l[30], o3);
759        }
760
761        //s2 compute
762        {
763            let (o0, o1, o2, o3) = s2_avx_512(f0, f1, f2, f3, f4, f5);
764            l[12] = _mm512_xor_si512(l[12], o0);
765            l[27] = _mm512_xor_si512(l[27], o1);
766            l[1] = _mm512_xor_si512(l[1], o2);
767            l[17] = _mm512_xor_si512(l[17], o3);
768        }
769
770        //s3 compute
771        {
772            let (o0, o1, o2, o3) = s3_avx_512(g0, g1, g2, g3, g4, g5);
773            l[23] = _mm512_xor_si512(l[23], o0);
774            l[15] = _mm512_xor_si512(l[15], o1);
775            l[29] = _mm512_xor_si512(l[29], o2);
776            l[5] = _mm512_xor_si512(l[5], o3);
777        }
778
779        //s4 compute
780        {
781            let (o0, o1, o2, o3) = s4_avx_512(h0, h1, h2, h3, h4, h5);
782            l[25] = _mm512_xor_si512(l[25], o0);
783            l[19] = _mm512_xor_si512(l[19], o1);
784            l[9] = _mm512_xor_si512(l[9], o2);
785            l[0] = _mm512_xor_si512(l[0], o3);
786        }
787
788        //s5 expand
789        e0 = _mm512_xor_si512(r[15], keys[SUBKEY_SCHEDULE[round][24]]);
790        e1 = _mm512_xor_si512(r[16], keys[SUBKEY_SCHEDULE[round][25]]);
791        e2 = _mm512_xor_si512(r[17], keys[SUBKEY_SCHEDULE[round][26]]);
792        e3 = _mm512_xor_si512(r[18], keys[SUBKEY_SCHEDULE[round][27]]);
793        e4 = _mm512_xor_si512(r[19], keys[SUBKEY_SCHEDULE[round][28]]);
794        e5 = _mm512_xor_si512(r[20], keys[SUBKEY_SCHEDULE[round][29]]);
795
796        //s6 expand
797        f0 = _mm512_xor_si512(r[19], keys[SUBKEY_SCHEDULE[round][30]]);
798        f1 = _mm512_xor_si512(r[20], keys[SUBKEY_SCHEDULE[round][31]]);
799        f2 = _mm512_xor_si512(r[21], keys[SUBKEY_SCHEDULE[round][32]]);
800        f3 = _mm512_xor_si512(r[22], keys[SUBKEY_SCHEDULE[round][33]]);
801        f4 = _mm512_xor_si512(r[23], keys[SUBKEY_SCHEDULE[round][34]]);
802        f5 = _mm512_xor_si512(r[24], keys[SUBKEY_SCHEDULE[round][35]]);
803
804        //s7 expand
805        g0 = _mm512_xor_si512(r[23], keys[SUBKEY_SCHEDULE[round][36]]);
806        g1 = _mm512_xor_si512(r[24], keys[SUBKEY_SCHEDULE[round][37]]);
807        g2 = _mm512_xor_si512(r[25], keys[SUBKEY_SCHEDULE[round][38]]);
808        g3 = _mm512_xor_si512(r[26], keys[SUBKEY_SCHEDULE[round][39]]);
809        g4 = _mm512_xor_si512(r[27], keys[SUBKEY_SCHEDULE[round][40]]);
810        g5 = _mm512_xor_si512(r[28], keys[SUBKEY_SCHEDULE[round][41]]);
811
812        //s8 expand
813        h0 = _mm512_xor_si512(r[27], keys[SUBKEY_SCHEDULE[round][42]]);
814        h1 = _mm512_xor_si512(r[28], keys[SUBKEY_SCHEDULE[round][43]]);
815        h2 = _mm512_xor_si512(r[29], keys[SUBKEY_SCHEDULE[round][44]]);
816        h3 = _mm512_xor_si512(r[30], keys[SUBKEY_SCHEDULE[round][45]]);
817        h4 = _mm512_xor_si512(r[31], keys[SUBKEY_SCHEDULE[round][46]]);
818        h5 = _mm512_xor_si512(r[0], keys[SUBKEY_SCHEDULE[round][47]]);
819
820        //s5 compute
821        {
822            let (o0, o1, o2, o3) = s5_avx_512(e0, e1, e2, e3, e4, e5);
823            l[7] = _mm512_xor_si512(l[7], o0);
824            l[13] = _mm512_xor_si512(l[13], o1);
825            l[24] = _mm512_xor_si512(l[24], o2);
826            l[2] = _mm512_xor_si512(l[2], o3);
827        }
828
829        //s6 compute
830        {
831            let (o0, o1, o2, o3) = s6_avx_512(f0, f1, f2, f3, f4, f5);
832            l[3] = _mm512_xor_si512(l[3], o0);
833            l[28] = _mm512_xor_si512(l[28], o1);
834            l[10] = _mm512_xor_si512(l[10], o2);
835            l[18] = _mm512_xor_si512(l[18], o3);
836        }
837
838        //s7 compute
839        {
840            let (o0, o1, o2, o3) = s7_avx_512(g0, g1, g2, g3, g4, g5);
841            l[31] = _mm512_xor_si512(l[31], o0);
842            l[11] = _mm512_xor_si512(l[11], o1);
843            l[21] = _mm512_xor_si512(l[21], o2);
844            l[6] = _mm512_xor_si512(l[6], o3);
845        }
846
847        //s8 compute
848        {
849            let (o0, o1, o2, o3) = s8_avx_512(h0, h1, h2, h3, h4, h5);
850            l[4] = _mm512_xor_si512(l[4], o0);
851            l[26] = _mm512_xor_si512(l[26], o1);
852            l[14] = _mm512_xor_si512(l[14], o2);
853            l[20] = _mm512_xor_si512(l[20], o3);
854        }
855    }
856}
857
858//AVX 2
859const ALL_ONES_AVX_2: __m256i = unsafe { transmute([!0u64; 4]) };
860const ZERO_AVX_2: __m256i = unsafe { transmute([0u64; 4]) };
861
862#[inline(always)]
863pub fn encrypt_avx_2(keys: &mut [__m256i; 64]) {
864    //assume pre calculated l and r for IP
865    //TODO: round 0 can simply read from 2 registers (zero's or all ones), the rounds after need to work with l and r fully
866    let mut l: [__m256i; 32] = [
867        ZERO_AVX_2,
868        ALL_ONES_AVX_2,
869        ALL_ONES_AVX_2,
870        ALL_ONES_AVX_2,
871        ALL_ONES_AVX_2,
872        ZERO_AVX_2,
873        ZERO_AVX_2,
874        ZERO_AVX_2,
875        ZERO_AVX_2,
876        ALL_ONES_AVX_2,
877        ZERO_AVX_2,
878        ALL_ONES_AVX_2,
879        ZERO_AVX_2,
880        ALL_ONES_AVX_2,
881        ZERO_AVX_2,
882        ALL_ONES_AVX_2,
883        ZERO_AVX_2,
884        ALL_ONES_AVX_2,
885        ALL_ONES_AVX_2,
886        ALL_ONES_AVX_2,
887        ALL_ONES_AVX_2,
888        ZERO_AVX_2,
889        ZERO_AVX_2,
890        ZERO_AVX_2,
891        ZERO_AVX_2,
892        ALL_ONES_AVX_2,
893        ZERO_AVX_2,
894        ALL_ONES_AVX_2,
895        ZERO_AVX_2,
896        ALL_ONES_AVX_2,
897        ZERO_AVX_2,
898        ALL_ONES_AVX_2,
899    ];
900    let mut r: [__m256i; 32] = [
901        ALL_ONES_AVX_2,
902        ZERO_AVX_2,
903        ZERO_AVX_2,
904        ZERO_AVX_2,
905        ZERO_AVX_2,
906        ZERO_AVX_2,
907        ZERO_AVX_2,
908        ZERO_AVX_2,
909        ZERO_AVX_2,
910        ALL_ONES_AVX_2,
911        ALL_ONES_AVX_2,
912        ZERO_AVX_2,
913        ZERO_AVX_2,
914        ALL_ONES_AVX_2,
915        ALL_ONES_AVX_2,
916        ZERO_AVX_2,
917        ALL_ONES_AVX_2,
918        ZERO_AVX_2,
919        ZERO_AVX_2,
920        ZERO_AVX_2,
921        ZERO_AVX_2,
922        ZERO_AVX_2,
923        ZERO_AVX_2,
924        ZERO_AVX_2,
925        ZERO_AVX_2,
926        ALL_ONES_AVX_2,
927        ALL_ONES_AVX_2,
928        ZERO_AVX_2,
929        ZERO_AVX_2,
930        ALL_ONES_AVX_2,
931        ALL_ONES_AVX_2,
932        ZERO_AVX_2,
933    ];
934    // round 0
935    unsafe {
936        feistel_avx_2(&mut l, &mut r, keys, 0);
937    }
938    // round 1
939    unsafe {
940        feistel_avx_2(&mut r, &mut l, keys, 1);
941    }
942    // round 2
943    unsafe {
944        feistel_avx_2(&mut l, &mut r, keys, 2);
945    }
946    // round 3
947    unsafe {
948        feistel_avx_2(&mut r, &mut l, keys, 3);
949    }
950    // round 4
951    unsafe {
952        feistel_avx_2(&mut l, &mut r, keys, 4);
953    }
954    // round 5
955    unsafe {
956        feistel_avx_2(&mut r, &mut l, keys, 5);
957    }
958    // round 6
959    unsafe {
960        feistel_avx_2(&mut l, &mut r, keys, 6);
961    }
962    // round 7
963    unsafe {
964        feistel_avx_2(&mut r, &mut l, keys, 7);
965    }
966    // round 8
967    unsafe {
968        feistel_avx_2(&mut l, &mut r, keys, 8);
969    }
970    // round 9
971    unsafe {
972        feistel_avx_2(&mut r, &mut l, keys, 9);
973    }
974    // round 10
975    unsafe {
976        feistel_avx_2(&mut l, &mut r, keys, 10);
977    }
978    // round 11
979    unsafe {
980        feistel_avx_2(&mut r, &mut l, keys, 11);
981    }
982    // round 12
983    unsafe {
984        feistel_avx_2(&mut l, &mut r, keys, 12);
985    }
986    // round 13
987    unsafe {
988        feistel_avx_2(&mut r, &mut l, keys, 13);
989    }
990    // round 14
991    unsafe {
992        feistel_avx_2(&mut l, &mut r, keys, 14);
993    }
994    // round 15
995    unsafe {
996        feistel_avx_2(&mut r, &mut l, keys, 15);
997    }
998
999    //final permutation
1000    unsafe {
1001        let out = keys.as_mut_ptr();
1002
1003        *out.add(0) = l[7];
1004        *out.add(1) = r[7];
1005        *out.add(2) = l[15];
1006        *out.add(3) = r[15];
1007        *out.add(4) = l[23];
1008        *out.add(5) = r[23];
1009        *out.add(6) = l[31];
1010        *out.add(7) = r[31];
1011
1012        *out.add(8) = l[6];
1013        *out.add(9) = r[6];
1014        *out.add(10) = l[14];
1015        *out.add(11) = r[14];
1016        *out.add(12) = l[22];
1017        *out.add(13) = r[22];
1018        *out.add(14) = l[30];
1019        *out.add(15) = r[30];
1020
1021        *out.add(16) = l[5];
1022        *out.add(17) = r[5];
1023        *out.add(18) = l[13];
1024        *out.add(19) = r[13];
1025        *out.add(20) = l[21];
1026        *out.add(21) = r[21];
1027        *out.add(22) = l[29];
1028        *out.add(23) = r[29];
1029
1030        *out.add(24) = l[4];
1031        *out.add(25) = r[4];
1032        *out.add(26) = l[12];
1033        *out.add(27) = r[12];
1034        *out.add(28) = l[20];
1035        *out.add(29) = r[20];
1036        *out.add(30) = l[28];
1037        *out.add(31) = r[28];
1038
1039        *out.add(32) = l[3];
1040        *out.add(33) = r[3];
1041        *out.add(34) = l[11];
1042        *out.add(35) = r[11];
1043        *out.add(36) = l[19];
1044        *out.add(37) = r[19];
1045        *out.add(38) = l[27];
1046        *out.add(39) = r[27];
1047
1048        *out.add(40) = l[2];
1049        *out.add(41) = r[2];
1050        *out.add(42) = l[10];
1051        *out.add(43) = r[10];
1052        *out.add(44) = l[18];
1053        *out.add(45) = r[18];
1054        *out.add(46) = l[26];
1055        *out.add(47) = r[26];
1056
1057        *out.add(48) = l[1];
1058        *out.add(49) = r[1];
1059        *out.add(50) = l[9];
1060        *out.add(51) = r[9];
1061        *out.add(52) = l[17];
1062        *out.add(53) = r[17];
1063        *out.add(54) = l[25];
1064        *out.add(55) = r[25];
1065
1066        *out.add(56) = l[0];
1067        *out.add(57) = r[0];
1068        *out.add(58) = l[8];
1069        *out.add(59) = r[8];
1070        *out.add(60) = l[16];
1071        *out.add(61) = r[16];
1072        *out.add(62) = l[24];
1073        *out.add(63) = r[24];
1074    }
1075}
1076
1077#[inline(always)]
1078pub unsafe fn feistel_avx_2(
1079    l: &mut [__m256i; 32],
1080    r: &mut [__m256i; 32],
1081    keys: &[__m256i; 64],
1082    round: usize,
1083) {
1084    unsafe {
1085        //s1 expand
1086        let mut e0 = _mm256_xor_si256(r[31], keys[SUBKEY_SCHEDULE[round][0]]);
1087        let mut e1 = _mm256_xor_si256(r[0], keys[SUBKEY_SCHEDULE[round][1]]);
1088        let mut e2 = _mm256_xor_si256(r[1], keys[SUBKEY_SCHEDULE[round][2]]);
1089        let mut e3 = _mm256_xor_si256(r[2], keys[SUBKEY_SCHEDULE[round][3]]);
1090        let mut e4 = _mm256_xor_si256(r[3], keys[SUBKEY_SCHEDULE[round][4]]);
1091        let mut e5 = _mm256_xor_si256(r[4], keys[SUBKEY_SCHEDULE[round][5]]);
1092
1093        //s2 expand
1094        let mut f0 = _mm256_xor_si256(r[3], keys[SUBKEY_SCHEDULE[round][6]]);
1095        let mut f1 = _mm256_xor_si256(r[4], keys[SUBKEY_SCHEDULE[round][7]]);
1096        let mut f2 = _mm256_xor_si256(r[5], keys[SUBKEY_SCHEDULE[round][8]]);
1097        let mut f3 = _mm256_xor_si256(r[6], keys[SUBKEY_SCHEDULE[round][9]]);
1098        let mut f4 = _mm256_xor_si256(r[7], keys[SUBKEY_SCHEDULE[round][10]]);
1099        let mut f5 = _mm256_xor_si256(r[8], keys[SUBKEY_SCHEDULE[round][11]]);
1100
1101        //s3 expand
1102        let mut g0 = _mm256_xor_si256(r[7], keys[SUBKEY_SCHEDULE[round][12]]);
1103        let mut g1 = _mm256_xor_si256(r[8], keys[SUBKEY_SCHEDULE[round][13]]);
1104        let mut g2 = _mm256_xor_si256(r[9], keys[SUBKEY_SCHEDULE[round][14]]);
1105        let mut g3 = _mm256_xor_si256(r[10], keys[SUBKEY_SCHEDULE[round][15]]);
1106        let mut g4 = _mm256_xor_si256(r[11], keys[SUBKEY_SCHEDULE[round][16]]);
1107        let mut g5 = _mm256_xor_si256(r[12], keys[SUBKEY_SCHEDULE[round][17]]);
1108
1109        //s4 expand
1110        let mut h0 = _mm256_xor_si256(r[11], keys[SUBKEY_SCHEDULE[round][18]]);
1111        let mut h1 = _mm256_xor_si256(r[12], keys[SUBKEY_SCHEDULE[round][19]]);
1112        let mut h2 = _mm256_xor_si256(r[13], keys[SUBKEY_SCHEDULE[round][20]]);
1113        let mut h3 = _mm256_xor_si256(r[14], keys[SUBKEY_SCHEDULE[round][21]]);
1114        let mut h4 = _mm256_xor_si256(r[15], keys[SUBKEY_SCHEDULE[round][22]]);
1115        let mut h5 = _mm256_xor_si256(r[16], keys[SUBKEY_SCHEDULE[round][23]]);
1116
1117        //s1 compute
1118        //use inner block to free o registers
1119        {
1120            let (o0, o1, o2, o3) = s1_avx_2(e0, e1, e2, e3, e4, e5);
1121            l[8] = _mm256_xor_si256(l[8], o0);
1122            l[16] = _mm256_xor_si256(l[16], o1);
1123            l[22] = _mm256_xor_si256(l[22], o2);
1124            l[30] = _mm256_xor_si256(l[30], o3);
1125        }
1126
1127        //s2 compute
1128        {
1129            let (o0, o1, o2, o3) = s2_avx_2(f0, f1, f2, f3, f4, f5);
1130            l[12] = _mm256_xor_si256(l[12], o0);
1131            l[27] = _mm256_xor_si256(l[27], o1);
1132            l[1] = _mm256_xor_si256(l[1], o2);
1133            l[17] = _mm256_xor_si256(l[17], o3);
1134        }
1135
1136        //s3 compute
1137        {
1138            let (o0, o1, o2, o3) = s3_avx_2(g0, g1, g2, g3, g4, g5);
1139            l[23] = _mm256_xor_si256(l[23], o0);
1140            l[15] = _mm256_xor_si256(l[15], o1);
1141            l[29] = _mm256_xor_si256(l[29], o2);
1142            l[5] = _mm256_xor_si256(l[5], o3);
1143        }
1144
1145        //s4 compute
1146        {
1147            let (o0, o1, o2, o3) = s4_avx_2(h0, h1, h2, h3, h4, h5);
1148            l[25] = _mm256_xor_si256(l[25], o0);
1149            l[19] = _mm256_xor_si256(l[19], o1);
1150            l[9] = _mm256_xor_si256(l[9], o2);
1151            l[0] = _mm256_xor_si256(l[0], o3);
1152        }
1153
1154        //s5 expand
1155        e0 = _mm256_xor_si256(r[15], keys[SUBKEY_SCHEDULE[round][24]]);
1156        e1 = _mm256_xor_si256(r[16], keys[SUBKEY_SCHEDULE[round][25]]);
1157        e2 = _mm256_xor_si256(r[17], keys[SUBKEY_SCHEDULE[round][26]]);
1158        e3 = _mm256_xor_si256(r[18], keys[SUBKEY_SCHEDULE[round][27]]);
1159        e4 = _mm256_xor_si256(r[19], keys[SUBKEY_SCHEDULE[round][28]]);
1160        e5 = _mm256_xor_si256(r[20], keys[SUBKEY_SCHEDULE[round][29]]);
1161
1162        //s6 expand
1163        f0 = _mm256_xor_si256(r[19], keys[SUBKEY_SCHEDULE[round][30]]);
1164        f1 = _mm256_xor_si256(r[20], keys[SUBKEY_SCHEDULE[round][31]]);
1165        f2 = _mm256_xor_si256(r[21], keys[SUBKEY_SCHEDULE[round][32]]);
1166        f3 = _mm256_xor_si256(r[22], keys[SUBKEY_SCHEDULE[round][33]]);
1167        f4 = _mm256_xor_si256(r[23], keys[SUBKEY_SCHEDULE[round][34]]);
1168        f5 = _mm256_xor_si256(r[24], keys[SUBKEY_SCHEDULE[round][35]]);
1169
1170        //s7 expand
1171        g0 = _mm256_xor_si256(r[23], keys[SUBKEY_SCHEDULE[round][36]]);
1172        g1 = _mm256_xor_si256(r[24], keys[SUBKEY_SCHEDULE[round][37]]);
1173        g2 = _mm256_xor_si256(r[25], keys[SUBKEY_SCHEDULE[round][38]]);
1174        g3 = _mm256_xor_si256(r[26], keys[SUBKEY_SCHEDULE[round][39]]);
1175        g4 = _mm256_xor_si256(r[27], keys[SUBKEY_SCHEDULE[round][40]]);
1176        g5 = _mm256_xor_si256(r[28], keys[SUBKEY_SCHEDULE[round][41]]);
1177
1178        //s8 expand
1179        h0 = _mm256_xor_si256(r[27], keys[SUBKEY_SCHEDULE[round][42]]);
1180        h1 = _mm256_xor_si256(r[28], keys[SUBKEY_SCHEDULE[round][43]]);
1181        h2 = _mm256_xor_si256(r[29], keys[SUBKEY_SCHEDULE[round][44]]);
1182        h3 = _mm256_xor_si256(r[30], keys[SUBKEY_SCHEDULE[round][45]]);
1183        h4 = _mm256_xor_si256(r[31], keys[SUBKEY_SCHEDULE[round][46]]);
1184        h5 = _mm256_xor_si256(r[0], keys[SUBKEY_SCHEDULE[round][47]]);
1185
1186        //s5 compute
1187        {
1188            let (o0, o1, o2, o3) = s5_avx_2(e0, e1, e2, e3, e4, e5);
1189            l[7] = _mm256_xor_si256(l[7], o0);
1190            l[13] = _mm256_xor_si256(l[13], o1);
1191            l[24] = _mm256_xor_si256(l[24], o2);
1192            l[2] = _mm256_xor_si256(l[2], o3);
1193        }
1194
1195        //s6 compute
1196        {
1197            let (o0, o1, o2, o3) = s6_avx_2(f0, f1, f2, f3, f4, f5);
1198            l[3] = _mm256_xor_si256(l[3], o0);
1199            l[28] = _mm256_xor_si256(l[28], o1);
1200            l[10] = _mm256_xor_si256(l[10], o2);
1201            l[18] = _mm256_xor_si256(l[18], o3);
1202        }
1203
1204        //s7 compute
1205        {
1206            let (o0, o1, o2, o3) = s7_avx_2(g0, g1, g2, g3, g4, g5);
1207            l[31] = _mm256_xor_si256(l[31], o0);
1208            l[11] = _mm256_xor_si256(l[11], o1);
1209            l[21] = _mm256_xor_si256(l[21], o2);
1210            l[6] = _mm256_xor_si256(l[6], o3);
1211        }
1212
1213        //s8 compute
1214        {
1215            let (o0, o1, o2, o3) = s8_avx_2(h0, h1, h2, h3, h4, h5);
1216            l[4] = _mm256_xor_si256(l[4], o0);
1217            l[26] = _mm256_xor_si256(l[26], o1);
1218            l[14] = _mm256_xor_si256(l[14], o2);
1219            l[20] = _mm256_xor_si256(l[20], o3);
1220        }
1221    }
1222}
1223
1224fn permute_bits_pc(p_box: &[u64], input: u64, input_length: usize) -> u64 {
1225    let p_box_length = p_box.len();
1226    let mut output: u64 = 0;
1227    for i in 0..p_box_length {
1228        output |= permute_bits::<u64>(input, input_length, p_box[i] as usize, p_box_length, i + 1);
1229    }
1230    output
1231}
1232
1233fn permute_bits<T>(
1234    input: T,
1235    input_length: usize,
1236    input_index: usize,
1237    output_length: usize,
1238    output_index: usize,
1239) -> T
1240where
1241    T: Copy
1242        + Shl<usize, Output = T>
1243        + Shr<usize, Output = T>
1244        + BitAnd<Output = T>
1245        + BitOr<Output = T>
1246        + From<u64>,
1247{
1248    ((input >> (input_length - input_index)) & T::from(1)) << (output_length - output_index)
1249}