1use bitsliced_op::{ALL_ONES, transpose_64x64};
2use core::arch::x86_64::__m512i;
3use std::{
4 arch::x86_64::{
5 __m256i, _mm256_set_epi64x, _mm256_set1_epi64x, _mm256_storeu_si256, _mm512_set_epi64,
6 _mm512_set1_epi64, _mm512_setzero_si512, _mm512_storeu_si512,
7 },
8 mem::transmute,
9};
10use wide::u64x8;
11
12use crate::{
13 constants::IP_INVO,
14 des::{compute_pc1, create_subkeys, encrypt},
15 des_optimized::{
16 compute_pc1_optimized, create_subkeys_optimized, encrypt_avx_2, encrypt_avx_512,
17 encrypt_optimized, encrypt_simd, feistel_avx_512,
18 },
19};
20
21pub mod benchmark;
22mod constants;
23pub mod des;
24pub mod des_optimized;
25pub mod sboxes;
26mod utils;
27
28pub const ZERO: u64x8 = u64x8::ZERO;
29
30pub fn des(plaintext: u64, key: u64) -> u64 {
31 let (c0, d0) = compute_pc1(key);
32 let subkeys = create_subkeys(c0, d0);
33 let encrypted = encrypt(plaintext, subkeys);
34 encrypted
35}
36
37pub fn bitsliced_des_simd(plaintext: u64, keys: &[[u64; 64]; 8]) -> [[u64; 64]; 8] {
39 let mut k_slice = transpose(keys);
40
41 encrypt_simd(plaintext, &mut k_slice);
42 let ciphertext = transpose_back(&k_slice);
43 ciphertext
44}
45
46pub fn bitsliced_des_inline_simd(plaintext: u64, keys: &mut [u64x8; 64]) {
48 encrypt_simd(plaintext, keys);
49}
50
51pub fn bitsliced_netntlmv1_simd(plaintext: u64, keys: &[[u64; 64]; 8]) -> [[u64; 64]; 8] {
53 let transposed = transpose(keys);
54 let mut keys = convert_to_key::<u64x8>(&transposed, ALL_ONES);
55 bitsliced_des_inline_simd(plaintext, &mut keys);
56 let ciphertext = transpose_back(&keys);
57 ciphertext
58}
59
60pub fn bitsliced_netntlmv1_inline_simd(plaintext: u64, keys: &mut [u64x8; 64]) {
62 *keys = convert_to_key::<u64x8>(&keys, ALL_ONES);
63 bitsliced_des_inline_simd(plaintext, keys);
64}
65
66#[target_feature(enable = "avx512f,avx512vl,avx512bw")]
68pub unsafe fn bitsliced_des_simd_avx_512(keys: &[[u64; 64]; 8]) -> [[u64; 64]; 8] {
69 unsafe {
70 let mut k_slice = transpose_avx_512(keys);
71 encrypt_avx_512(&mut k_slice);
72 transpose_back_avx_512(&k_slice)
73 }
74}
75
76#[target_feature(enable = "avx512f,avx512vl,avx512bw")]
77pub unsafe fn bitsliced_des_inline_simd_avx_512(keys: &mut [__m512i; 64]) {
78 encrypt_avx_512(keys);
79}
80
81#[target_feature(enable = "avx512f,avx512vl,avx512bw")]
82pub unsafe fn bitsliced_netntlmv1_inline_simd_avx_512(keys: &mut [__m512i; 64]) {
83 *keys = convert_to_key::<__m512i>(&keys, _mm512_set1_epi64(-1i64));
84 bitsliced_des_inline_simd_avx_512(keys);
85}
86
87#[target_feature(enable = "avx512f,avx512vl,avx512bw")]
88pub unsafe fn bitsliced_netntlmv1_simd_avx_512(keys: &[[u64; 64]; 8]) -> [[u64; 64]; 8] {
89 unsafe {
90 let k_slice = transpose_avx_512(keys);
91 let mut converted = convert_to_key::<__m512i>(&k_slice, _mm512_set1_epi64(-1i64));
92 encrypt_avx_512(&mut converted);
93 transpose_back_avx_512(&converted)
94 }
95}
96
97#[target_feature(enable = "avx2")]
99pub unsafe fn bitsliced_des_simd_avx_2(keys: &[[u64; 64]; 4]) -> [[u64; 64]; 4] {
100 unsafe {
101 let mut k_slice = transpose_avx_2(keys);
102 encrypt_avx_2(&mut k_slice);
103 transpose_back_avx_2(&k_slice)
104 }
105}
106
107#[target_feature(enable = "avx2")]
108pub unsafe fn bitsliced_des_inline_simd_avx_2(keys: &mut [__m256i; 64]) {
109 encrypt_avx_2(keys);
110}
111
112#[target_feature(enable = "avx2")]
113pub unsafe fn bitsliced_netntlmv1_simd_avx_2(keys: &[[u64; 64]; 4]) -> [[u64; 64]; 4] {
114 unsafe {
115 let k_slice = transpose_avx_2(keys);
116 let mut converted = convert_to_key::<__m256i>(&k_slice, _mm256_set1_epi64x(-1i64));
117 encrypt_avx_2(&mut converted);
118 transpose_back_avx_2(&converted)
119 }
120}
121
122#[target_feature(enable = "avx2")]
123pub unsafe fn bitsliced_netntlmv1_inline_simd_avx_2(keys: &mut [__m256i; 64]) {
124 *keys = convert_to_key::<__m256i>(&keys, _mm256_set1_epi64x(-1i64));
125 bitsliced_des_inline_simd_avx_2(keys);
126}
127
128fn convert_to_key<T: Copy>(plaintexts: &[T; 64], all_ones: T) -> [T; 64] {
130 [
131 plaintexts[8],
132 plaintexts[9],
133 plaintexts[10],
134 plaintexts[11],
135 plaintexts[12],
136 plaintexts[13],
137 plaintexts[14],
138 all_ones,
139 plaintexts[15],
140 plaintexts[16],
141 plaintexts[17],
142 plaintexts[18],
143 plaintexts[19],
144 plaintexts[20],
145 plaintexts[21],
146 all_ones,
147 plaintexts[22],
148 plaintexts[23],
149 plaintexts[24],
150 plaintexts[25],
151 plaintexts[26],
152 plaintexts[27],
153 plaintexts[28],
154 all_ones,
155 plaintexts[29],
156 plaintexts[30],
157 plaintexts[31],
158 plaintexts[32],
159 plaintexts[33],
160 plaintexts[34],
161 plaintexts[35],
162 all_ones,
163 plaintexts[36],
164 plaintexts[37],
165 plaintexts[38],
166 plaintexts[39],
167 plaintexts[40],
168 plaintexts[41],
169 plaintexts[42],
170 all_ones,
171 plaintexts[43],
172 plaintexts[44],
173 plaintexts[45],
174 plaintexts[46],
175 plaintexts[47],
176 plaintexts[48],
177 plaintexts[49],
178 all_ones,
179 plaintexts[50],
180 plaintexts[51],
181 plaintexts[52],
182 plaintexts[53],
183 plaintexts[54],
184 plaintexts[55],
185 plaintexts[56],
186 all_ones,
187 plaintexts[57],
188 plaintexts[58],
189 plaintexts[59],
190 plaintexts[60],
191 plaintexts[61],
192 plaintexts[62],
193 plaintexts[63],
194 all_ones,
195 ]
196}
197
198unsafe fn transpose_avx_512(blocks: &[[u64; 64]; 8]) -> [__m512i; 64] {
200 let mut outputs = [transmute([0u64; 8]); 64];
201 let mut blocks_transposed = [[0u64; 64]; 8];
202
203 for b in 0..8 {
205 blocks_transposed[b] = bitsliced_op::transpose_64x64(&blocks[b]);
206 }
207 for bit_idx in 0..64 {
208 outputs[bit_idx] = _mm512_set_epi64(
209 blocks_transposed[7][bit_idx] as i64,
210 blocks_transposed[6][bit_idx] as i64,
211 blocks_transposed[5][bit_idx] as i64,
212 blocks_transposed[4][bit_idx] as i64,
213 blocks_transposed[3][bit_idx] as i64,
214 blocks_transposed[2][bit_idx] as i64,
215 blocks_transposed[1][bit_idx] as i64,
216 blocks_transposed[0][bit_idx] as i64,
217 );
218 }
219
220 outputs
221}
222
223unsafe fn transpose_back_avx_512(outputs_simd: &[__m512i; 64]) -> [[u64; 64]; 8] {
224 let mut blocks_transposed = [[0u64; 64]; 8];
225 let mut final_blocks = [[0u64; 64]; 8];
226
227 for bit_idx in 0..64 {
230 let reg = outputs_simd[bit_idx];
231
232 let mut lanes = [0u64; 8];
234 _mm512_storeu_si512(lanes.as_mut_ptr() as *mut _, reg);
235
236 for b in 0..8 {
239 blocks_transposed[b][bit_idx] = lanes[b];
240 }
241 }
242
243 for b in 0..8 {
245 final_blocks[b] = bitsliced_op::transpose_64x64(&blocks_transposed[b]);
246 }
247
248 final_blocks
249}
250
251unsafe fn transpose_avx_2(blocks: &[[u64; 64]; 4]) -> [__m256i; 64] {
253 let mut outputs = [transmute([0u64; 4]); 64];
254 let mut blocks_transposed = [[0u64; 64]; 4];
255
256 for b in 0..4 {
258 blocks_transposed[b] = bitsliced_op::transpose_64x64(&blocks[b]);
259 }
260 for bit_idx in 0..64 {
261 outputs[bit_idx] = _mm256_set_epi64x(
262 blocks_transposed[3][bit_idx] as i64,
263 blocks_transposed[2][bit_idx] as i64,
264 blocks_transposed[1][bit_idx] as i64,
265 blocks_transposed[0][bit_idx] as i64,
266 );
267 }
268
269 outputs
270}
271
272unsafe fn transpose_back_avx_2(outputs_simd: &[__m256i; 64]) -> [[u64; 64]; 4] {
273 let mut blocks_transposed = [[0u64; 64]; 4];
274 let mut final_blocks = [[0u64; 64]; 4];
275
276 for bit_idx in 0..64 {
279 let reg = outputs_simd[bit_idx];
280
281 let mut lanes = [0u64; 4];
283 _mm256_storeu_si256(lanes.as_mut_ptr() as *mut _, reg);
284
285 for b in 0..4 {
288 blocks_transposed[b][bit_idx] = lanes[b];
289 }
290 }
291
292 for b in 0..4 {
294 final_blocks[b] = bitsliced_op::transpose_64x64(&blocks_transposed[b]);
295 }
296
297 final_blocks
298}
299
300fn transpose(input: &[[u64; 64]; 8]) -> [u64x8; 64] {
301 let mut out: [u64x8; 64] = [u64x8::ZERO; 64];
302 for k in 0..8 {
303 let tmp = input[k];
304 let tmp = transpose_64x64(&tmp);
305
306 for r in 0..64 {
307 out[r].as_mut_array()[k] = tmp[r];
308 }
309 }
310 out
311}
312
313fn transpose_back(input: &[u64x8; 64]) -> [[u64; 64]; 8] {
314 let mut out = [[0u64; 64]; 8];
315
316 for j in 0..64 {
317 let tmp = input[j].as_array();
318 out[0][j] = tmp[0];
319 out[1][j] = tmp[1];
320 out[2][j] = tmp[2];
321 out[3][j] = tmp[3];
322 out[4][j] = tmp[4];
323 out[5][j] = tmp[5];
324 out[6][j] = tmp[6];
325 out[7][j] = tmp[7];
326 }
327 for k in 0..8 {
328 let tmp = out[k];
329 out[k] = transpose_64x64(&tmp);
330 }
331
332 out
333}
334
335#[cfg(test)]
336mod tests {
337
338 use std::arch::x86_64::{_mm512_set1_epi64, _mm512_setzero_si512};
339
340 use super::*;
342
343 #[test]
344 fn test_encrypt_works_correctly() {
345 let ciphertext = des(0x0123456789ABCDEF, 0x133457799BBCDFF1);
347 assert_eq!(ciphertext, 0x85E813540F0AB405);
348 }
349
350 #[test]
351 fn test_encrypt_optimized_works_correctly() {
352 let k = 0x133457799BBCDFF1u64;
354 let mut keys = [[k; 64]; 8];
355 let ciphertexts = bitsliced_des_simd(0x0123456789ABCDEF, &mut keys);
356 assert_eq!(ciphertexts[0][0], 0x85E813540F0AB405);
357 assert_eq!(ciphertexts[0][63], 0x85E813540F0AB405);
358 }
359
360 #[test]
361 fn test_encrypt_optimized_inline_works_correctly() {
362 let k = 0x133457799BBCDFF1u64;
364 let mut keys = [[k; 64]; 8];
365 let mut transposed = transpose(&keys);
366 bitsliced_des_inline_simd(0x0123456789ABCDEF, &mut transposed);
367 let ciphertexts = transpose_back(&transposed);
368 assert_eq!(ciphertexts[0][0], 0x85E813540F0AB405);
369 assert_eq!(ciphertexts[0][63], 0x85E813540F0AB405);
370 }
371
372 #[test]
373 fn test_encrypt_optimized_inline_avx_512_works_correctly() {
374 unsafe {
375 let k = 0x8923BDFDAF753F63u64;
376 let keys = [k; 64];
377 let transposed = transpose_64x64(&keys);
378 let mut keys = [_mm512_setzero_si512(); 64];
379 for (i, t) in transposed.iter().enumerate() {
380 if *t != 0 {
381 keys[i] = _mm512_set1_epi64(-1);
382 }
383 }
384 bitsliced_des_inline_simd_avx_512(&mut keys);
385 let mut output = Box::new([0u64; 64]);
386 for (i, k) in keys.iter().enumerate() {
387 let lanes: [u64; 8] = transmute(*k);
388 let first = lanes[0];
389 output[i] = first;
390 }
391 let ciphertexts = transpose_64x64(&output);
392 assert_eq!(ciphertexts[0], 0x727B4E35F947129E);
393 assert_eq!(ciphertexts[0], 0x727B4E35F947129E);
394 }
395 }
396
397 #[test]
398 fn test_encrypt_optimized_avx_512_works_correctly() {
399 unsafe {
400 let k = 0x8923BDFDAF753F63u64;
401 let keys = [[k; 64]; 8];
402
403 let output = bitsliced_des_simd_avx_512(&keys);
404 assert_eq!(output[0][0], 0x727B4E35F947129E);
405 assert_eq!(output[7][63], 0x727B4E35F947129E);
406 }
407 }
408
409 #[test]
410 fn test_netntlmv1_encrypt_works_correctly() {
411 let k = 0x8846F7EAEE8FB1u64;
412 let keys = [[k; 64]; 8];
413 let ciphertexts = bitsliced_netntlmv1_simd(0x1122334455667788, &keys);
414 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
415 assert_eq!(ciphertexts[0][63], 0x727B4E35F947129E);
416 }
417
418 #[test]
419 fn test_netntlmv1_inline_encrypt_works_correctly() {
420 let k = 0x8846F7EAEE8FB1u64;
421 let keys = [[k; 64]; 8];
422 let mut transposed = transpose(&keys);
423 bitsliced_netntlmv1_inline_simd(0x1122334455667788, &mut transposed);
424 let ciphertexts = transpose_back(&transposed);
425 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
426 assert_eq!(ciphertexts[0][63], 0x727B4E35F947129E);
427 }
428
429 #[test]
430 fn test_netntlmv1_encrypt_avx_512_works_correctly() {
431 unsafe {
432 let k = 0x8846F7EAEE8FB1u64;
433 let keys = [[k; 64]; 8];
434 let ciphertexts = bitsliced_netntlmv1_simd_avx_512(&keys);
435 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
436 assert_eq!(ciphertexts[0][63], 0x727B4E35F947129E);
437 }
438 }
439
440 #[test]
441 fn test_netntlmv1_inline_encrypt_avx_512_works_correctly() {
442 unsafe {
443 let k = 0x8846F7EAEE8FB1u64;
444 let keys = [[k; 64]; 8];
445 let mut transposed = transpose_avx_512(&keys);
446 bitsliced_netntlmv1_inline_simd_avx_512(&mut transposed);
447 let ciphertexts = transpose_back_avx_512(&transposed);
448 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
449 assert_eq!(ciphertexts[7][63], 0x727B4E35F947129E);
450 }
451 }
452
453 #[test]
454 fn test_netntlmv1_inline_encrypt_avx_2_works_correctly() {
455 unsafe {
456 let k = 0x8846F7EAEE8FB1u64;
457 let keys = [[k; 64]; 4];
458 let mut transposed = transpose_avx_2(&keys);
459 bitsliced_netntlmv1_inline_simd_avx_2(&mut transposed);
460 let ciphertexts = transpose_back_avx_2(&transposed);
461 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
462 assert_eq!(ciphertexts[3][63], 0x727B4E35F947129E);
463 }
464 }
465}