Skip to main content

fast_des/
des_optimized.rs

1use std::{
2    arch::x86_64::{__m512i, _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    sbox_optimized::{s1, s2, s3, s4, s5, s6, s7, s8},
11    sbox_simd::{s1_avx, s2_avx, s3_avx, s4_avx, s5_avx, s6_avx, s7_avx, s8_avx},
12};
13use bitsliced_op::transpose_64x64;
14use wide::u64x8;
15
16//slice[i] contains bit with index i of all 64 slices
17// a column is equal to one item/number
18pub fn compute_pc1_optimized(k_slices: &[u64x8; 64]) -> ([u64x8; 28], [u64x8; 28]) {
19    let mut c0 = [ZERO; 28];
20    let mut d0 = [ZERO; 28];
21
22    for (i, &src) in PC_1O.iter().enumerate() {
23        if i < 28 {
24            c0[i] = k_slices[src as usize];
25        } else {
26            d0[i - 28] = k_slices[src as usize];
27        }
28    }
29
30    (c0, d0)
31}
32
33const SHIFTS: [u32; 16] = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];
34
35pub fn create_subkeys_optimized(c0: &mut [u64x8; 28], d0: &mut [u64x8; 28]) -> [[u64x8; 48]; 16] {
36    let mut subkeys = [[ZERO; 48]; 16];
37
38    for (index, s) in SHIFTS.iter().enumerate() {
39        c0.rotate_left(*s as usize);
40        d0.rotate_left(*s as usize);
41        for (i, &src) in PC_2O.iter().enumerate() {
42            if src < 28 {
43                subkeys[index][i] = c0[src as usize]
44            } else {
45                subkeys[index][i] = d0[(src - 28) as usize];
46            }
47        }
48    }
49
50    subkeys
51}
52
53//TODO: create a version where IP is precomputed
54pub fn encrypt_optimized(plaintext: u64, subkeys: [[u64x8; 48]; 16], output: &mut [u64x8; 64]) {
55    let ip = permute_bits_pc(&IP, plaintext, 64);
56    //repeat and transpose IP
57    let ip_bitsliced = transpose_64x64(&[ip; 64]);
58    let mut l: [u64x8; 32] = std::array::from_fn(|i| u64x8::splat(ip_bitsliced[i]));
59    let mut r: [u64x8; 32] = std::array::from_fn(|i| u64x8::splat(ip_bitsliced[i + 32]));
60
61    for i in 0..16 {
62        let (new_l, new_r) = feistel_function_optimized(l, r, subkeys[i]);
63        l = new_l;
64        r = new_r;
65    }
66    let mut r_l = [ZERO; 64];
67    r_l[..32].copy_from_slice(&r);
68    r_l[32..].copy_from_slice(&l);
69    for (i, &src) in IP_INVO.iter().enumerate() {
70        output[i] = r_l[src as usize];
71    }
72}
73
74#[inline(always)]
75fn feistel_function_optimized(
76    l: [u64x8; 32],
77    r: [u64x8; 32],
78    subkey: [u64x8; 48],
79) -> ([u64x8; 32], [u64x8; 32]) {
80    let new_l = r;
81    let mut e = [ZERO; 48];
82    for (i, &src) in EO.iter().enumerate() {
83        e[i] = r[src as usize];
84    }
85    for i in 0..48 {
86        e[i] ^= subkey[i];
87    }
88    let mut output: [u64x8; 32] = [ZERO; 32];
89
90    let s1_output = s1(e[0], e[1], e[2], e[3], e[4], e[5]);
91    let s2_output = s2(e[6], e[7], e[8], e[9], e[10], e[11]);
92    let s3_output = s3(e[12], e[13], e[14], e[15], e[16], e[17]);
93    let s4_output = s4(e[18], e[19], e[20], e[21], e[22], e[23]);
94    let s5_output = s5(e[24], e[25], e[26], e[27], e[28], e[29]);
95    let s6_output = s6(e[30], e[31], e[32], e[33], e[34], e[35]);
96    let s7_output = s7(e[36], e[37], e[38], e[39], e[40], e[41]);
97    let s8_output = s8(e[42], e[43], e[44], e[45], e[46], e[47]);
98    // s1
99    output[0] = s1_output.0;
100    output[1] = s1_output.1;
101    output[2] = s1_output.2;
102    output[3] = s1_output.3;
103
104    // s2
105    output[4] = s2_output.0;
106    output[5] = s2_output.1;
107    output[6] = s2_output.2;
108    output[7] = s2_output.3;
109
110    // s3
111    output[8] = s3_output.0;
112    output[9] = s3_output.1;
113    output[10] = s3_output.2;
114    output[11] = s3_output.3;
115
116    // s4
117    output[12] = s4_output.0;
118    output[13] = s4_output.1;
119    output[14] = s4_output.2;
120    output[15] = s4_output.3;
121
122    // s5
123    output[16] = s5_output.0;
124    output[17] = s5_output.1;
125    output[18] = s5_output.2;
126    output[19] = s5_output.3;
127
128    // s6
129    output[20] = s6_output.0;
130    output[21] = s6_output.1;
131    output[22] = s6_output.2;
132    output[23] = s6_output.3;
133
134    // s7
135    output[24] = s7_output.0;
136    output[25] = s7_output.1;
137    output[26] = s7_output.2;
138    output[27] = s7_output.3;
139
140    // s8
141    output[28] = s8_output.0;
142    output[29] = s8_output.1;
143    output[30] = s8_output.2;
144    output[31] = s8_output.3;
145    let mut new_r = [ZERO; 32];
146    for (i, &src) in PO.iter().enumerate() {
147        new_r[i] = output[src as usize];
148    }
149    //inline array modification to avoid extra allocation
150    for i in 0..32 {
151        new_r[i] = l[i] ^ new_r[i];
152    }
153    (new_l, new_r)
154}
155
156const SUBKEY_SCHEDULE: [[usize; 48]; 16] = [
157    //0:
158    [
159        9, 50, 33, 59, 48, 16, 32, 56, 1, 8, 18, 41, 2, 34, 25, 24, 43, 57, 58, 0, 35, 26, 17, 40,
160        21, 27, 38, 53, 36, 3, 46, 29, 4, 52, 22, 28, 60, 20, 37, 62, 14, 19, 44, 13, 12, 61, 54,
161        30,
162    ],
163    //1:
164    [
165        1, 42, 25, 51, 40, 8, 24, 48, 58, 0, 10, 33, 59, 26, 17, 16, 35, 49, 50, 57, 56, 18, 9, 32,
166        13, 19, 30, 45, 28, 62, 38, 21, 27, 44, 14, 20, 52, 12, 29, 54, 6, 11, 36, 5, 4, 53, 46,
167        22,
168    ],
169    //2:
170    [
171        50, 26, 9, 35, 24, 57, 8, 32, 42, 49, 59, 17, 43, 10, 1, 0, 48, 33, 34, 41, 40, 2, 58, 16,
172        60, 3, 14, 29, 12, 46, 22, 5, 11, 28, 61, 4, 36, 27, 13, 38, 53, 62, 20, 52, 19, 37, 30, 6,
173    ],
174    //3:
175    [
176        34, 10, 58, 48, 8, 41, 57, 16, 26, 33, 43, 1, 56, 59, 50, 49, 32, 17, 18, 25, 24, 51, 42,
177        0, 44, 54, 61, 13, 27, 30, 6, 52, 62, 12, 45, 19, 20, 11, 60, 22, 37, 46, 4, 36, 3, 21, 14,
178        53,
179    ],
180    //4:
181    [
182        18, 59, 42, 32, 57, 25, 41, 0, 10, 17, 56, 50, 40, 43, 34, 33, 16, 1, 2, 9, 8, 35, 26, 49,
183        28, 38, 45, 60, 11, 14, 53, 36, 46, 27, 29, 3, 4, 62, 44, 6, 21, 30, 19, 20, 54, 5, 61, 37,
184    ],
185    //5:
186    [
187        2, 43, 26, 16, 41, 9, 25, 49, 59, 1, 40, 34, 24, 56, 18, 17, 0, 50, 51, 58, 57, 48, 10, 33,
188        12, 22, 29, 44, 62, 61, 37, 20, 30, 11, 13, 54, 19, 46, 28, 53, 5, 14, 3, 4, 38, 52, 45,
189        21,
190    ],
191    //6:
192    [
193        51, 56, 10, 0, 25, 58, 9, 33, 43, 50, 24, 18, 8, 40, 2, 1, 49, 34, 35, 42, 41, 32, 59, 17,
194        27, 6, 13, 28, 46, 45, 21, 4, 14, 62, 60, 38, 3, 30, 12, 37, 52, 61, 54, 19, 22, 36, 29, 5,
195    ],
196    //7:
197    [
198        35, 40, 59, 49, 9, 42, 58, 17, 56, 34, 8, 2, 57, 24, 51, 50, 33, 18, 48, 26, 25, 16, 43, 1,
199        11, 53, 60, 12, 30, 29, 5, 19, 61, 46, 44, 22, 54, 14, 27, 21, 36, 45, 38, 3, 6, 20, 13,
200        52,
201    ],
202    //8:
203    [
204        56, 32, 51, 41, 1, 34, 50, 9, 48, 26, 0, 59, 49, 16, 43, 42, 25, 10, 40, 18, 17, 8, 35, 58,
205        3, 45, 52, 4, 22, 21, 60, 11, 53, 38, 36, 14, 46, 6, 19, 13, 28, 37, 30, 62, 61, 12, 5, 44,
206    ],
207    //9:
208    [
209        40, 16, 35, 25, 50, 18, 34, 58, 32, 10, 49, 43, 33, 0, 56, 26, 9, 59, 24, 2, 1, 57, 48, 42,
210        54, 29, 36, 19, 6, 5, 44, 62, 37, 22, 20, 61, 30, 53, 3, 60, 12, 21, 14, 46, 45, 27, 52,
211        28,
212    ],
213    //10:
214    [
215        24, 0, 48, 9, 34, 2, 18, 42, 16, 59, 33, 56, 17, 49, 40, 10, 58, 43, 8, 51, 50, 41, 32, 26,
216        38, 13, 20, 3, 53, 52, 28, 46, 21, 6, 4, 45, 14, 37, 54, 44, 27, 5, 61, 30, 29, 11, 36, 12,
217    ],
218    //11:
219    [
220        8, 49, 32, 58, 18, 51, 2, 26, 0, 43, 17, 40, 1, 33, 24, 59, 42, 56, 57, 35, 34, 25, 16, 10,
221        22, 60, 4, 54, 37, 36, 12, 30, 5, 53, 19, 29, 61, 21, 38, 28, 11, 52, 45, 14, 13, 62, 20,
222        27,
223    ],
224    //12:
225    [
226        57, 33, 16, 42, 2, 35, 51, 10, 49, 56, 1, 24, 50, 17, 8, 43, 26, 40, 41, 48, 18, 9, 0, 59,
227        6, 44, 19, 38, 21, 20, 27, 14, 52, 37, 3, 13, 45, 5, 22, 12, 62, 36, 29, 61, 60, 46, 4, 11,
228    ],
229    //13:
230    [
231        41, 17, 0, 26, 51, 48, 35, 59, 33, 40, 50, 8, 34, 1, 57, 56, 10, 24, 25, 32, 2, 58, 49, 43,
232        53, 28, 3, 22, 5, 4, 11, 61, 36, 21, 54, 60, 29, 52, 6, 27, 46, 20, 13, 45, 44, 30, 19, 62,
233    ],
234    //14:
235    [
236        25, 1, 49, 10, 35, 32, 48, 43, 17, 24, 34, 57, 18, 50, 41, 40, 59, 8, 9, 16, 51, 42, 33,
237        56, 37, 12, 54, 6, 52, 19, 62, 45, 20, 5, 38, 44, 13, 36, 53, 11, 30, 4, 60, 29, 28, 14, 3,
238        46,
239    ],
240    //15:
241    [
242        17, 58, 41, 2, 56, 24, 40, 35, 9, 16, 26, 49, 10, 42, 33, 32, 51, 0, 1, 8, 43, 34, 25, 48,
243        29, 4, 46, 61, 44, 11, 54, 37, 12, 60, 30, 36, 5, 28, 45, 3, 22, 27, 52, 21, 20, 6, 62, 38,
244    ],
245];
246
247pub fn encrypt_simd(plaintext: u64, keys: &mut [u64x8; 64]) {
248    let ip = permute_bits_pc(&IP, plaintext, 64);
249    let mut l: [u64x8; 32] = [ZERO; 32];
250    let mut r: [u64x8; 32] = [ZERO; 32];
251    for i in 0..32 {
252        let bit_l = (ip >> (63 - i)) & 1;
253        let bit_r = (ip >> (31 - i)) & 1;
254
255        l[i] = u64x8::splat(0u64.wrapping_sub(bit_l));
256        r[i] = u64x8::splat(0u64.wrapping_sub(bit_r));
257    }
258
259    // round 0
260    unsafe {
261        feistel_function_simd(&mut l, &mut r, keys, 0);
262    }
263    // round 1
264    unsafe {
265        feistel_function_simd(&mut r, &mut l, keys, 1);
266    }
267    // round 2
268    unsafe {
269        feistel_function_simd(&mut l, &mut r, keys, 2);
270    }
271    // round 3
272    unsafe {
273        feistel_function_simd(&mut r, &mut l, keys, 3);
274    }
275    // round 4
276    unsafe {
277        feistel_function_simd(&mut l, &mut r, keys, 4);
278    }
279    // round 5
280    unsafe {
281        feistel_function_simd(&mut r, &mut l, keys, 5);
282    }
283    // round 6
284    unsafe {
285        feistel_function_simd(&mut l, &mut r, keys, 6);
286    }
287    // round 7
288    unsafe {
289        feistel_function_simd(&mut r, &mut l, keys, 7);
290    }
291    // round 8
292    unsafe {
293        feistel_function_simd(&mut l, &mut r, keys, 8);
294    }
295    // round 9
296    unsafe {
297        feistel_function_simd(&mut r, &mut l, keys, 9);
298    }
299    // round 10
300    unsafe {
301        feistel_function_simd(&mut l, &mut r, keys, 10);
302    }
303    // round 11
304    unsafe {
305        feistel_function_simd(&mut r, &mut l, keys, 11);
306    }
307    // round 12
308    unsafe {
309        feistel_function_simd(&mut l, &mut r, keys, 12);
310    }
311    // round 13
312    unsafe {
313        feistel_function_simd(&mut r, &mut l, keys, 13);
314    }
315    // round 14
316    unsafe {
317        feistel_function_simd(&mut l, &mut r, keys, 14);
318    }
319    // round 15
320    unsafe {
321        feistel_function_simd(&mut r, &mut l, keys, 15);
322    }
323
324    //final permutation
325    let keys_ptr = keys.as_mut_ptr();
326    for i in 0..64 {
327        unsafe {
328            std::ptr::write(
329                keys_ptr.add(i),
330                if IP_INVO[i] < 32 {
331                    r[IP_INVO[i]]
332                } else {
333                    l[IP_INVO[i] - 32]
334                },
335            );
336        }
337    }
338}
339
340#[inline(always)]
341pub unsafe fn feistel_function_simd(
342    l: &mut [u64x8; 32],
343    r: &mut [u64x8; 32],
344    keys: &[u64x8; 64],
345    round: usize,
346) {
347    //s1 expand
348    let mut e0 = r[31] ^ keys[SUBKEY_SCHEDULE[round][0]];
349    let mut e1 = r[0] ^ keys[SUBKEY_SCHEDULE[round][1]];
350    let mut e2 = r[1] ^ keys[SUBKEY_SCHEDULE[round][2]];
351    let mut e3 = r[2] ^ keys[SUBKEY_SCHEDULE[round][3]];
352    let mut e4 = r[3] ^ keys[SUBKEY_SCHEDULE[round][4]];
353    let mut e5 = r[4] ^ keys[SUBKEY_SCHEDULE[round][5]];
354
355    //s2 expand
356    let mut f0 = r[3] ^ keys[SUBKEY_SCHEDULE[round][6]];
357    let mut f1 = r[4] ^ keys[SUBKEY_SCHEDULE[round][7]];
358    let mut f2 = r[5] ^ keys[SUBKEY_SCHEDULE[round][8]];
359    let mut f3 = r[6] ^ keys[SUBKEY_SCHEDULE[round][9]];
360    let mut f4 = r[7] ^ keys[SUBKEY_SCHEDULE[round][10]];
361    let mut f5 = r[8] ^ keys[SUBKEY_SCHEDULE[round][11]];
362
363    //s3 expand
364    let mut g0 = r[7] ^ keys[SUBKEY_SCHEDULE[round][12]];
365    let mut g1 = r[8] ^ keys[SUBKEY_SCHEDULE[round][13]];
366    let mut g2 = r[9] ^ keys[SUBKEY_SCHEDULE[round][14]];
367    let mut g3 = r[10] ^ keys[SUBKEY_SCHEDULE[round][15]];
368    let mut g4 = r[11] ^ keys[SUBKEY_SCHEDULE[round][16]];
369    let mut g5 = r[12] ^ keys[SUBKEY_SCHEDULE[round][17]];
370
371    //s4 expand
372    let mut h0 = r[11] ^ keys[SUBKEY_SCHEDULE[round][18]];
373    let mut h1 = r[12] ^ keys[SUBKEY_SCHEDULE[round][19]];
374    let mut h2 = r[13] ^ keys[SUBKEY_SCHEDULE[round][20]];
375    let mut h3 = r[14] ^ keys[SUBKEY_SCHEDULE[round][21]];
376    let mut h4 = r[15] ^ keys[SUBKEY_SCHEDULE[round][22]];
377    let mut h5 = r[16] ^ keys[SUBKEY_SCHEDULE[round][23]];
378
379    //s1 compute
380    //use inner block to free o registers
381    {
382        let (o0, o1, o2, o3) = s1(e0, e1, e2, e3, e4, e5);
383        l[8] = l[8] ^ o0;
384        l[16] = l[16] ^ o1;
385        l[22] = l[22] ^ o2;
386        l[30] = l[30] ^ o3;
387    }
388
389    //s2 compute
390    {
391        let (o0, o1, o2, o3) = s2(f0, f1, f2, f3, f4, f5);
392        l[12] = l[12] ^ o0;
393        l[27] = l[27] ^ o1;
394        l[1] = l[1] ^ o2;
395        l[17] = l[17] ^ o3;
396    }
397
398    //s3 compute
399    {
400        let (o0, o1, o2, o3) = s3(g0, g1, g2, g3, g4, g5);
401        l[23] = l[23] ^ o0;
402        l[15] = l[15] ^ o1;
403        l[29] = l[29] ^ o2;
404        l[5] = l[5] ^ o3;
405    }
406
407    //s4 compute
408    {
409        let (o0, o1, o2, o3) = s4(h0, h1, h2, h3, h4, h5);
410        l[25] = l[25] ^ o0;
411        l[19] = l[19] ^ o1;
412        l[9] = l[9] ^ o2;
413        l[0] = l[0] ^ o3;
414    }
415
416    //s5 expand
417    e0 = r[15] ^ keys[SUBKEY_SCHEDULE[round][24]];
418    e1 = r[16] ^ keys[SUBKEY_SCHEDULE[round][25]];
419    e2 = r[17] ^ keys[SUBKEY_SCHEDULE[round][26]];
420    e3 = r[18] ^ keys[SUBKEY_SCHEDULE[round][27]];
421    e4 = r[19] ^ keys[SUBKEY_SCHEDULE[round][28]];
422    e5 = r[20] ^ keys[SUBKEY_SCHEDULE[round][29]];
423
424    //s6 expand
425    f0 = r[19] ^ keys[SUBKEY_SCHEDULE[round][30]];
426    f1 = r[20] ^ keys[SUBKEY_SCHEDULE[round][31]];
427    f2 = r[21] ^ keys[SUBKEY_SCHEDULE[round][32]];
428    f3 = r[22] ^ keys[SUBKEY_SCHEDULE[round][33]];
429    f4 = r[23] ^ keys[SUBKEY_SCHEDULE[round][34]];
430    f5 = r[24] ^ keys[SUBKEY_SCHEDULE[round][35]];
431
432    //s7 expand
433    g0 = r[23] ^ keys[SUBKEY_SCHEDULE[round][36]];
434    g1 = r[24] ^ keys[SUBKEY_SCHEDULE[round][37]];
435    g2 = r[25] ^ keys[SUBKEY_SCHEDULE[round][38]];
436    g3 = r[26] ^ keys[SUBKEY_SCHEDULE[round][39]];
437    g4 = r[27] ^ keys[SUBKEY_SCHEDULE[round][40]];
438    g5 = r[28] ^ keys[SUBKEY_SCHEDULE[round][41]];
439
440    //s8 expand
441    h0 = r[27] ^ keys[SUBKEY_SCHEDULE[round][42]];
442    h1 = r[28] ^ keys[SUBKEY_SCHEDULE[round][43]];
443    h2 = r[29] ^ keys[SUBKEY_SCHEDULE[round][44]];
444    h3 = r[30] ^ keys[SUBKEY_SCHEDULE[round][45]];
445    h4 = r[31] ^ keys[SUBKEY_SCHEDULE[round][46]];
446    h5 = r[0] ^ keys[SUBKEY_SCHEDULE[round][47]];
447
448    //s5 compute
449    {
450        let (o0, o1, o2, o3) = s5(e0, e1, e2, e3, e4, e5);
451        l[7] = l[7] ^ o0;
452        l[13] = l[13] ^ o1;
453        l[24] = l[24] ^ o2;
454        l[2] = l[2] ^ o3;
455    }
456
457    //s6 compute
458    {
459        let (o0, o1, o2, o3) = s6(f0, f1, f2, f3, f4, f5);
460        l[3] = l[3] ^ o0;
461        l[28] = l[28] ^ o1;
462        l[10] = l[10] ^ o2;
463        l[18] = l[18] ^ o3;
464    }
465
466    //s7 compute
467    {
468        let (o0, o1, o2, o3) = s7(g0, g1, g2, g3, g4, g5);
469        l[31] = l[31] ^ o0;
470        l[11] = l[11] ^ o1;
471        l[21] = l[21] ^ o2;
472        l[6] = l[6] ^ o3;
473    }
474
475    //s8 compute
476    {
477        let (o0, o1, o2, o3) = s8(h0, h1, h2, h3, h4, h5);
478        l[4] = l[4] ^ o0;
479        l[26] = l[26] ^ o1;
480        l[14] = l[14] ^ o2;
481        l[20] = l[20] ^ o3;
482    }
483}
484
485const ALL_ONES_AVX: __m512i = unsafe { transmute([!0u64; 8]) };
486const ZERO_AVX: __m512i = unsafe { transmute([0u64; 8]) };
487
488#[inline(always)]
489pub fn encrypt_simd_avx(keys: &mut [__m512i; 64]) {
490    //assume pre calculated l and r for IP
491    //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
492    let mut l: [__m512i; 32] = [
493        ZERO_AVX,
494        ALL_ONES_AVX,
495        ALL_ONES_AVX,
496        ALL_ONES_AVX,
497        ALL_ONES_AVX,
498        ZERO_AVX,
499        ZERO_AVX,
500        ZERO_AVX,
501        ZERO_AVX,
502        ALL_ONES_AVX,
503        ZERO_AVX,
504        ALL_ONES_AVX,
505        ZERO_AVX,
506        ALL_ONES_AVX,
507        ZERO_AVX,
508        ALL_ONES_AVX,
509        ZERO_AVX,
510        ALL_ONES_AVX,
511        ALL_ONES_AVX,
512        ALL_ONES_AVX,
513        ALL_ONES_AVX,
514        ZERO_AVX,
515        ZERO_AVX,
516        ZERO_AVX,
517        ZERO_AVX,
518        ALL_ONES_AVX,
519        ZERO_AVX,
520        ALL_ONES_AVX,
521        ZERO_AVX,
522        ALL_ONES_AVX,
523        ZERO_AVX,
524        ALL_ONES_AVX,
525    ];
526    let mut r: [__m512i; 32] = [
527        ALL_ONES_AVX,
528        ZERO_AVX,
529        ZERO_AVX,
530        ZERO_AVX,
531        ZERO_AVX,
532        ZERO_AVX,
533        ZERO_AVX,
534        ZERO_AVX,
535        ZERO_AVX,
536        ALL_ONES_AVX,
537        ALL_ONES_AVX,
538        ZERO_AVX,
539        ZERO_AVX,
540        ALL_ONES_AVX,
541        ALL_ONES_AVX,
542        ZERO_AVX,
543        ALL_ONES_AVX,
544        ZERO_AVX,
545        ZERO_AVX,
546        ZERO_AVX,
547        ZERO_AVX,
548        ZERO_AVX,
549        ZERO_AVX,
550        ZERO_AVX,
551        ZERO_AVX,
552        ALL_ONES_AVX,
553        ALL_ONES_AVX,
554        ZERO_AVX,
555        ZERO_AVX,
556        ALL_ONES_AVX,
557        ALL_ONES_AVX,
558        ZERO_AVX,
559    ];
560    // round 0
561    unsafe {
562        feistel_function_avx(&mut l, &mut r, keys, 0);
563    }
564    // round 1
565    unsafe {
566        feistel_function_avx(&mut r, &mut l, keys, 1);
567    }
568    // round 2
569    unsafe {
570        feistel_function_avx(&mut l, &mut r, keys, 2);
571    }
572    // round 3
573    unsafe {
574        feistel_function_avx(&mut r, &mut l, keys, 3);
575    }
576    // round 4
577    unsafe {
578        feistel_function_avx(&mut l, &mut r, keys, 4);
579    }
580    // round 5
581    unsafe {
582        feistel_function_avx(&mut r, &mut l, keys, 5);
583    }
584    // round 6
585    unsafe {
586        feistel_function_avx(&mut l, &mut r, keys, 6);
587    }
588    // round 7
589    unsafe {
590        feistel_function_avx(&mut r, &mut l, keys, 7);
591    }
592    // round 8
593    unsafe {
594        feistel_function_avx(&mut l, &mut r, keys, 8);
595    }
596    // round 9
597    unsafe {
598        feistel_function_avx(&mut r, &mut l, keys, 9);
599    }
600    // round 10
601    unsafe {
602        feistel_function_avx(&mut l, &mut r, keys, 10);
603    }
604    // round 11
605    unsafe {
606        feistel_function_avx(&mut r, &mut l, keys, 11);
607    }
608    // round 12
609    unsafe {
610        feistel_function_avx(&mut l, &mut r, keys, 12);
611    }
612    // round 13
613    unsafe {
614        feistel_function_avx(&mut r, &mut l, keys, 13);
615    }
616    // round 14
617    unsafe {
618        feistel_function_avx(&mut l, &mut r, keys, 14);
619    }
620    // round 15
621    unsafe {
622        feistel_function_avx(&mut r, &mut l, keys, 15);
623    }
624
625    //final permutation
626    let keys_ptr = keys.as_mut_ptr();
627    for i in 0..64 {
628        unsafe {
629            std::ptr::write(
630                keys_ptr.add(i),
631                if IP_INVO[i] < 32 {
632                    r[IP_INVO[i]]
633                } else {
634                    l[IP_INVO[i] - 32]
635                },
636            );
637        }
638    }
639}
640
641#[inline(always)]
642pub unsafe fn feistel_function_avx(
643    l: &mut [__m512i; 32],
644    r: &mut [__m512i; 32],
645    keys: &[__m512i; 64],
646    round: usize,
647) {
648    unsafe {
649        //s1 expand
650        let mut e0 = _mm512_xor_si512(r[31], keys[SUBKEY_SCHEDULE[round][0]]);
651        let mut e1 = _mm512_xor_si512(r[0], keys[SUBKEY_SCHEDULE[round][1]]);
652        let mut e2 = _mm512_xor_si512(r[1], keys[SUBKEY_SCHEDULE[round][2]]);
653        let mut e3 = _mm512_xor_si512(r[2], keys[SUBKEY_SCHEDULE[round][3]]);
654        let mut e4 = _mm512_xor_si512(r[3], keys[SUBKEY_SCHEDULE[round][4]]);
655        let mut e5 = _mm512_xor_si512(r[4], keys[SUBKEY_SCHEDULE[round][5]]);
656
657        //s2 expand
658        let mut f0 = _mm512_xor_si512(r[3], keys[SUBKEY_SCHEDULE[round][6]]);
659        let mut f1 = _mm512_xor_si512(r[4], keys[SUBKEY_SCHEDULE[round][7]]);
660        let mut f2 = _mm512_xor_si512(r[5], keys[SUBKEY_SCHEDULE[round][8]]);
661        let mut f3 = _mm512_xor_si512(r[6], keys[SUBKEY_SCHEDULE[round][9]]);
662        let mut f4 = _mm512_xor_si512(r[7], keys[SUBKEY_SCHEDULE[round][10]]);
663        let mut f5 = _mm512_xor_si512(r[8], keys[SUBKEY_SCHEDULE[round][11]]);
664
665        //s3 expand
666        let mut g0 = _mm512_xor_si512(r[7], keys[SUBKEY_SCHEDULE[round][12]]);
667        let mut g1 = _mm512_xor_si512(r[8], keys[SUBKEY_SCHEDULE[round][13]]);
668        let mut g2 = _mm512_xor_si512(r[9], keys[SUBKEY_SCHEDULE[round][14]]);
669        let mut g3 = _mm512_xor_si512(r[10], keys[SUBKEY_SCHEDULE[round][15]]);
670        let mut g4 = _mm512_xor_si512(r[11], keys[SUBKEY_SCHEDULE[round][16]]);
671        let mut g5 = _mm512_xor_si512(r[12], keys[SUBKEY_SCHEDULE[round][17]]);
672
673        //s4 expand
674        let mut h0 = _mm512_xor_si512(r[11], keys[SUBKEY_SCHEDULE[round][18]]);
675        let mut h1 = _mm512_xor_si512(r[12], keys[SUBKEY_SCHEDULE[round][19]]);
676        let mut h2 = _mm512_xor_si512(r[13], keys[SUBKEY_SCHEDULE[round][20]]);
677        let mut h3 = _mm512_xor_si512(r[14], keys[SUBKEY_SCHEDULE[round][21]]);
678        let mut h4 = _mm512_xor_si512(r[15], keys[SUBKEY_SCHEDULE[round][22]]);
679        let mut h5 = _mm512_xor_si512(r[16], keys[SUBKEY_SCHEDULE[round][23]]);
680
681        //s1 compute
682        //use inner block to free o registers
683        {
684            let (o0, o1, o2, o3) = s1_avx(e0, e1, e2, e3, e4, e5);
685            l[8] = _mm512_xor_si512(l[8], o0);
686            l[16] = _mm512_xor_si512(l[16], o1);
687            l[22] = _mm512_xor_si512(l[22], o2);
688            l[30] = _mm512_xor_si512(l[30], o3);
689        }
690
691        //s2 compute
692        {
693            let (o0, o1, o2, o3) = s2_avx(f0, f1, f2, f3, f4, f5);
694            l[12] = _mm512_xor_si512(l[12], o0);
695            l[27] = _mm512_xor_si512(l[27], o1);
696            l[1] = _mm512_xor_si512(l[1], o2);
697            l[17] = _mm512_xor_si512(l[17], o3);
698        }
699
700        //s3 compute
701        {
702            let (o0, o1, o2, o3) = s3_avx(g0, g1, g2, g3, g4, g5);
703            l[23] = _mm512_xor_si512(l[23], o0);
704            l[15] = _mm512_xor_si512(l[15], o1);
705            l[29] = _mm512_xor_si512(l[29], o2);
706            l[5] = _mm512_xor_si512(l[5], o3);
707        }
708
709        //s4 compute
710        {
711            let (o0, o1, o2, o3) = s4_avx(h0, h1, h2, h3, h4, h5);
712            l[25] = _mm512_xor_si512(l[25], o0);
713            l[19] = _mm512_xor_si512(l[19], o1);
714            l[9] = _mm512_xor_si512(l[9], o2);
715            l[0] = _mm512_xor_si512(l[0], o3);
716        }
717
718        //s5 expand
719        e0 = _mm512_xor_si512(r[15], keys[SUBKEY_SCHEDULE[round][24]]);
720        e1 = _mm512_xor_si512(r[16], keys[SUBKEY_SCHEDULE[round][25]]);
721        e2 = _mm512_xor_si512(r[17], keys[SUBKEY_SCHEDULE[round][26]]);
722        e3 = _mm512_xor_si512(r[18], keys[SUBKEY_SCHEDULE[round][27]]);
723        e4 = _mm512_xor_si512(r[19], keys[SUBKEY_SCHEDULE[round][28]]);
724        e5 = _mm512_xor_si512(r[20], keys[SUBKEY_SCHEDULE[round][29]]);
725
726        //s6 expand
727        f0 = _mm512_xor_si512(r[19], keys[SUBKEY_SCHEDULE[round][30]]);
728        f1 = _mm512_xor_si512(r[20], keys[SUBKEY_SCHEDULE[round][31]]);
729        f2 = _mm512_xor_si512(r[21], keys[SUBKEY_SCHEDULE[round][32]]);
730        f3 = _mm512_xor_si512(r[22], keys[SUBKEY_SCHEDULE[round][33]]);
731        f4 = _mm512_xor_si512(r[23], keys[SUBKEY_SCHEDULE[round][34]]);
732        f5 = _mm512_xor_si512(r[24], keys[SUBKEY_SCHEDULE[round][35]]);
733
734        //s7 expand
735        g0 = _mm512_xor_si512(r[23], keys[SUBKEY_SCHEDULE[round][36]]);
736        g1 = _mm512_xor_si512(r[24], keys[SUBKEY_SCHEDULE[round][37]]);
737        g2 = _mm512_xor_si512(r[25], keys[SUBKEY_SCHEDULE[round][38]]);
738        g3 = _mm512_xor_si512(r[26], keys[SUBKEY_SCHEDULE[round][39]]);
739        g4 = _mm512_xor_si512(r[27], keys[SUBKEY_SCHEDULE[round][40]]);
740        g5 = _mm512_xor_si512(r[28], keys[SUBKEY_SCHEDULE[round][41]]);
741
742        //s8 expand
743        h0 = _mm512_xor_si512(r[27], keys[SUBKEY_SCHEDULE[round][42]]);
744        h1 = _mm512_xor_si512(r[28], keys[SUBKEY_SCHEDULE[round][43]]);
745        h2 = _mm512_xor_si512(r[29], keys[SUBKEY_SCHEDULE[round][44]]);
746        h3 = _mm512_xor_si512(r[30], keys[SUBKEY_SCHEDULE[round][45]]);
747        h4 = _mm512_xor_si512(r[31], keys[SUBKEY_SCHEDULE[round][46]]);
748        h5 = _mm512_xor_si512(r[0], keys[SUBKEY_SCHEDULE[round][47]]);
749
750        //s5 compute
751        {
752            let (o0, o1, o2, o3) = s5_avx(e0, e1, e2, e3, e4, e5);
753            l[7] = _mm512_xor_si512(l[7], o0);
754            l[13] = _mm512_xor_si512(l[13], o1);
755            l[24] = _mm512_xor_si512(l[24], o2);
756            l[2] = _mm512_xor_si512(l[2], o3);
757        }
758
759        //s6 compute
760        {
761            let (o0, o1, o2, o3) = s6_avx(f0, f1, f2, f3, f4, f5);
762            l[3] = _mm512_xor_si512(l[3], o0);
763            l[28] = _mm512_xor_si512(l[28], o1);
764            l[10] = _mm512_xor_si512(l[10], o2);
765            l[18] = _mm512_xor_si512(l[18], o3);
766        }
767
768        //s7 compute
769        {
770            let (o0, o1, o2, o3) = s7_avx(g0, g1, g2, g3, g4, g5);
771            l[31] = _mm512_xor_si512(l[31], o0);
772            l[11] = _mm512_xor_si512(l[11], o1);
773            l[21] = _mm512_xor_si512(l[21], o2);
774            l[6] = _mm512_xor_si512(l[6], o3);
775        }
776
777        //s8 compute
778        {
779            let (o0, o1, o2, o3) = s8_avx(h0, h1, h2, h3, h4, h5);
780            l[4] = _mm512_xor_si512(l[4], o0);
781            l[26] = _mm512_xor_si512(l[26], o1);
782            l[14] = _mm512_xor_si512(l[14], o2);
783            l[20] = _mm512_xor_si512(l[20], o3);
784        }
785    }
786}
787
788#[inline(always)]
789pub unsafe fn feistel_function_avx_(
790    l: &mut [__m512i; 32],
791    r: &mut [__m512i; 32],
792    keys: &[__m512i; 64],
793) {
794    unsafe {
795        // ---- S1 + S2 ---- reuse e0..e5 and f0..f5 ----
796        let mut e0 = _mm512_xor_si512(r[31], keys[13]);
797        let mut e1 = _mm512_xor_si512(r[0], keys[16]);
798        let mut e2 = _mm512_xor_si512(r[1], keys[10]);
799        let mut e3 = _mm512_xor_si512(r[2], keys[23]);
800        let mut e4 = _mm512_xor_si512(r[3], keys[0]);
801        let mut e5 = _mm512_xor_si512(r[4], keys[4]);
802
803        let mut f0 = _mm512_xor_si512(r[3], keys[2]);
804        let mut f1 = _mm512_xor_si512(r[4], keys[27]);
805        let mut f2 = _mm512_xor_si512(r[5], keys[14]);
806        let mut f3 = _mm512_xor_si512(r[6], keys[5]);
807        let mut f4 = _mm512_xor_si512(r[7], keys[20]);
808        let mut f5 = _mm512_xor_si512(r[8], keys[9]);
809
810        {
811            let (o0, o1, o2, o3) = s1_avx(e0, e1, e2, e3, e4, e5);
812            let (p0, p1, p2, p3) = s2_avx(f0, f1, f2, f3, f4, f5);
813
814            l[8] = _mm512_xor_si512(l[8], o0);
815            l[16] = _mm512_xor_si512(l[16], o1);
816            l[22] = _mm512_xor_si512(l[22], o2);
817            l[30] = _mm512_xor_si512(l[30], o3);
818
819            l[12] = _mm512_xor_si512(l[12], p0);
820            l[27] = _mm512_xor_si512(l[27], p1);
821            l[1] = _mm512_xor_si512(l[1], p2);
822            l[17] = _mm512_xor_si512(l[17], p3);
823        }
824
825        // ---- S3 + S4 ---- reuse e0..e5 and f0..f5 ----
826        e0 = _mm512_xor_si512(r[7], keys[22]);
827        e1 = _mm512_xor_si512(r[8], keys[18]);
828        e2 = _mm512_xor_si512(r[9], keys[11]);
829        e3 = _mm512_xor_si512(r[10], keys[3]);
830        e4 = _mm512_xor_si512(r[11], keys[25]);
831        e5 = _mm512_xor_si512(r[12], keys[7]);
832
833        f0 = _mm512_xor_si512(r[11], keys[15]);
834        f1 = _mm512_xor_si512(r[12], keys[6]);
835        f2 = _mm512_xor_si512(r[13], keys[26]);
836        f3 = _mm512_xor_si512(r[14], keys[19]);
837        f4 = _mm512_xor_si512(r[15], keys[12]);
838        f5 = _mm512_xor_si512(r[16], keys[1]);
839
840        {
841            let (o0, o1, o2, o3) = s3_avx(e0, e1, e2, e3, e4, e5);
842            let (p0, p1, p2, p3) = s4_avx(f0, f1, f2, f3, f4, f5);
843
844            l[23] = _mm512_xor_si512(l[23], o0);
845            l[15] = _mm512_xor_si512(l[15], o1);
846            l[29] = _mm512_xor_si512(l[29], o2);
847            l[5] = _mm512_xor_si512(l[5], o3);
848
849            l[25] = _mm512_xor_si512(l[25], p0);
850            l[19] = _mm512_xor_si512(l[19], p1);
851            l[9] = _mm512_xor_si512(l[9], p2);
852            l[0] = _mm512_xor_si512(l[0], p3);
853        }
854
855        // ---- S5 + S6 ---- reuse e0..e5 and f0..f5 ----
856        e0 = _mm512_xor_si512(r[15], keys[7]);
857        e1 = _mm512_xor_si512(r[16], keys[31]);
858        e2 = _mm512_xor_si512(r[17], keys[21]);
859        e3 = _mm512_xor_si512(r[18], keys[13]);
860        e4 = _mm512_xor_si512(r[19], keys[24]);
861        e5 = _mm512_xor_si512(r[20], keys[2]);
862
863        f0 = _mm512_xor_si512(r[19], keys[3]);
864        f1 = _mm512_xor_si512(r[20], keys[28]);
865        f2 = _mm512_xor_si512(r[21], keys[10]);
866        f3 = _mm512_xor_si512(r[22], keys[18]);
867        f4 = _mm512_xor_si512(r[23], keys[5]);
868        f5 = _mm512_xor_si512(r[24], keys[26]);
869
870        {
871            let (o0, o1, o2, o3) = s5_avx(e0, e1, e2, e3, e4, e5);
872            let (p0, p1, p2, p3) = s6_avx(f0, f1, f2, f3, f4, f5);
873
874            l[7] = _mm512_xor_si512(l[7], o0);
875            l[13] = _mm512_xor_si512(l[13], o1);
876            l[24] = _mm512_xor_si512(l[24], o2);
877            l[2] = _mm512_xor_si512(l[2], o3);
878
879            l[3] = _mm512_xor_si512(l[3], p0);
880            l[28] = _mm512_xor_si512(l[28], p1);
881            l[10] = _mm512_xor_si512(l[10], p2);
882            l[18] = _mm512_xor_si512(l[18], p3);
883        }
884
885        // ---- S7 + S8 ---- reuse e0..e5 and f0..f5 ----
886        e0 = _mm512_xor_si512(r[23], keys[14]);
887        e1 = _mm512_xor_si512(r[24], keys[20]);
888        e2 = _mm512_xor_si512(r[25], keys[6]);
889        e3 = _mm512_xor_si512(r[26], keys[11]);
890        e4 = _mm512_xor_si512(r[27], keys[0]);
891        e5 = _mm512_xor_si512(r[28], keys[22]);
892
893        f0 = _mm512_xor_si512(r[27], keys[8]);
894        f1 = _mm512_xor_si512(r[28], keys[17]);
895        f2 = _mm512_xor_si512(r[29], keys[4]);
896        f3 = _mm512_xor_si512(r[30], keys[19]);
897        f4 = _mm512_xor_si512(r[31], keys[9]);
898        f5 = _mm512_xor_si512(r[0], keys[1]);
899
900        {
901            let (o0, o1, o2, o3) = s7_avx(e0, e1, e2, e3, e4, e5);
902            let (p0, p1, p2, p3) = s8_avx(f0, f1, f2, f3, f4, f5);
903
904            l[31] = _mm512_xor_si512(l[31], o0);
905            l[11] = _mm512_xor_si512(l[11], o1);
906            l[21] = _mm512_xor_si512(l[21], o2);
907            l[6] = _mm512_xor_si512(l[6], o3);
908
909            l[4] = _mm512_xor_si512(l[4], p0);
910            l[26] = _mm512_xor_si512(l[26], p1);
911            l[14] = _mm512_xor_si512(l[14], p2);
912            l[20] = _mm512_xor_si512(l[20], p3);
913        }
914    }
915}
916
917fn permute_bits_pc(p_box: &[u64], input: u64, input_length: usize) -> u64 {
918    let p_box_length = p_box.len();
919    let mut output: u64 = 0;
920    for i in 0..p_box_length {
921        output |= permute_bits::<u64>(input, input_length, p_box[i] as usize, p_box_length, i + 1);
922    }
923    output
924}
925
926fn permute_bits<T>(
927    input: T,
928    input_length: usize,
929    input_index: usize,
930    output_length: usize,
931    output_index: usize,
932) -> T
933where
934    T: Copy
935        + Shl<usize, Output = T>
936        + Shr<usize, Output = T>
937        + BitAnd<Output = T>
938        + BitOr<Output = T>
939        + From<u64>,
940{
941    ((input >> (input_length - input_index)) & T::from(1)) << (output_length - output_index)
942}