1use bitsliced_op::{ALL_ONES, transpose_64x64};
2use core::arch::x86_64::__m512i;
3use std::{
4 arch::x86_64::{
5 _mm512_set_epi64, _mm512_set1_epi64, _mm512_setzero_si512, _mm512_storeu_si512,
6 },
7 mem::transmute,
8};
9use wide::u64x8;
10
11use crate::{
12 constants::IP_INVO,
13 des::{compute_pc1, create_subkeys, encrypt},
14 des_optimized::{
15 compute_pc1_optimized, create_subkeys_optimized, encrypt_optimized, encrypt_simd,
16 encrypt_simd_avx, feistel_function_avx,
17 },
18};
19
20pub mod benchmark;
21mod constants;
22pub mod des;
23pub mod des_optimized;
24pub mod sbox_optimized;
25pub mod sbox_simd;
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] {
38 let mut k_slice = transpose(keys);
39
40 encrypt_simd(plaintext, &mut k_slice);
41 let ciphertext = transpose_back(&k_slice);
42 ciphertext
43}
44
45pub fn bitsliced_des_inline_simd(plaintext: u64, keys: &mut [u64x8; 64]) {
47 encrypt_simd(plaintext, keys);
48}
49
50pub fn bitsliced_netntlmv1_simd(plaintext: u64, keys: &[[u64; 64]; 8]) -> [[u64; 64]; 8] {
52 let transposed = transpose(keys);
53 let mut keys = convert_to_key::<u64x8>(&transposed, ALL_ONES);
54 bitsliced_des_inline_simd(plaintext, &mut keys);
55 let ciphertext = transpose_back(&keys);
56 ciphertext
57}
58
59pub fn bitsliced_netntlmv1_inline_simd(plaintext: u64, keys: &mut [u64x8; 64]) {
61 *keys = convert_to_key::<u64x8>(&keys, ALL_ONES);
62 bitsliced_des_inline_simd(plaintext, keys);
63}
64
65#[target_feature(enable = "avx512f,avx512vl,avx512bw")]
66pub unsafe fn bitsliced_des_simd_avx(keys: &[[u64; 64]; 8]) -> [[u64; 64]; 8] {
67 unsafe {
68 let mut k_slice = transpose_avx(keys);
69 encrypt_simd_avx(&mut k_slice);
70 transpose_back_avx(&k_slice)
71 }
72}
73
74#[target_feature(enable = "avx512f,avx512vl,avx512bw")]
75pub unsafe fn bitsliced_des_inline_simd_avx(keys: &mut [__m512i; 64]) {
76 encrypt_simd_avx(keys);
77}
78
79#[target_feature(enable = "avx512f,avx512vl,avx512bw")]
80pub unsafe fn bitsliced_netntlmv1_inline_simd_avx(keys: &mut [__m512i; 64]) {
81 *keys = convert_to_key::<__m512i>(&keys, _mm512_set1_epi64(-1i64));
82 bitsliced_des_inline_simd_avx(keys);
83}
84
85#[target_feature(enable = "avx512f,avx512vl,avx512bw")]
86pub unsafe fn bitsliced_netntlmv1_simd_avx(keys: &[[u64; 64]; 8]) -> [[u64; 64]; 8] {
87 unsafe {
88 let k_slice = transpose_avx(keys);
89 let mut converted = convert_to_key::<__m512i>(&k_slice, _mm512_set1_epi64(-1i64));
90 encrypt_simd_avx(&mut converted);
91 transpose_back_avx(&converted)
92 }
93}
94
95const DES_KEY_PERM: [i8; 64] = [
96 0, 1, 2, 3, 4, 5, 6, -1, 7, 8, 9, 10, 11, 12, 13, -1, 14, 15, 16, 17, 18, 19, 20, -1, 21, 22,
97 23, 24, 25, 26, 27, -1, 28, 29, 30, 31, 32, 33, 34, -1, 35, 36, 37, 38, 39, 40, 41, -1, 42, 43,
98 44, 45, 46, 47, 48, -1, 49, 50, 51, 52, 53, 54, 55, -1,
99];
100
101fn convert_to_key<T: Copy>(plaintexts: &[T; 64], all_ones: T) -> [T; 64] {
103 [
104 plaintexts[8],
105 plaintexts[9],
106 plaintexts[10],
107 plaintexts[11],
108 plaintexts[12],
109 plaintexts[13],
110 plaintexts[14],
111 all_ones,
112 plaintexts[15],
113 plaintexts[16],
114 plaintexts[17],
115 plaintexts[18],
116 plaintexts[19],
117 plaintexts[20],
118 plaintexts[21],
119 all_ones,
120 plaintexts[22],
121 plaintexts[23],
122 plaintexts[24],
123 plaintexts[25],
124 plaintexts[26],
125 plaintexts[27],
126 plaintexts[28],
127 all_ones,
128 plaintexts[29],
129 plaintexts[30],
130 plaintexts[31],
131 plaintexts[32],
132 plaintexts[33],
133 plaintexts[34],
134 plaintexts[35],
135 all_ones,
136 plaintexts[36],
137 plaintexts[37],
138 plaintexts[38],
139 plaintexts[39],
140 plaintexts[40],
141 plaintexts[41],
142 plaintexts[42],
143 all_ones,
144 plaintexts[43],
145 plaintexts[44],
146 plaintexts[45],
147 plaintexts[46],
148 plaintexts[47],
149 plaintexts[48],
150 plaintexts[49],
151 all_ones,
152 plaintexts[50],
153 plaintexts[51],
154 plaintexts[52],
155 plaintexts[53],
156 plaintexts[54],
157 plaintexts[55],
158 plaintexts[56],
159 all_ones,
160 plaintexts[57],
161 plaintexts[58],
162 plaintexts[59],
163 plaintexts[60],
164 plaintexts[61],
165 plaintexts[62],
166 plaintexts[63],
167 all_ones,
168 ]
169}
170
171unsafe fn transpose_avx(blocks: &[[u64; 64]; 8]) -> [__m512i; 64] {
173 let mut outputs = [_mm512_setzero_si512(); 64];
174 let mut blocks_transposed = [[0u64; 64]; 8];
175
176 for b in 0..8 {
178 blocks_transposed[b] = bitsliced_op::transpose_64x64(&blocks[b]);
179 }
180 for bit_idx in 0..64 {
181 outputs[bit_idx] = _mm512_set_epi64(
182 blocks_transposed[7][bit_idx] as i64,
183 blocks_transposed[6][bit_idx] as i64,
184 blocks_transposed[5][bit_idx] as i64,
185 blocks_transposed[4][bit_idx] as i64,
186 blocks_transposed[3][bit_idx] as i64,
187 blocks_transposed[2][bit_idx] as i64,
188 blocks_transposed[1][bit_idx] as i64,
189 blocks_transposed[0][bit_idx] as i64,
190 );
191 }
192
193 outputs
194}
195
196unsafe fn transpose_back_avx(outputs_simd: &[__m512i; 64]) -> [[u64; 64]; 8] {
197 let mut blocks_transposed = [[0u64; 64]; 8];
198 let mut final_blocks = [[0u64; 64]; 8];
199
200 for bit_idx in 0..64 {
203 let reg = outputs_simd[bit_idx];
204
205 let mut lanes = [0u64; 8];
207 _mm512_storeu_si512(lanes.as_mut_ptr() as *mut _, reg);
208
209 for b in 0..8 {
212 blocks_transposed[b][bit_idx] = lanes[b];
213 }
214 }
215
216 for b in 0..8 {
218 final_blocks[b] = bitsliced_op::transpose_64x64(&blocks_transposed[b]);
219 }
220
221 final_blocks
222}
223
224fn transpose(input: &[[u64; 64]; 8]) -> [u64x8; 64] {
225 let mut out: [u64x8; 64] = [u64x8::ZERO; 64];
226 for k in 0..8 {
227 let tmp = input[k];
228 let tmp = transpose_64x64(&tmp);
229
230 for r in 0..64 {
231 out[r].as_mut_array()[k] = tmp[r];
232 }
233 }
234 out
235}
236
237fn transpose_back(input: &[u64x8; 64]) -> [[u64; 64]; 8] {
238 let mut out = [[0u64; 64]; 8];
239
240 for j in 0..64 {
241 let tmp = input[j].as_array();
242 out[0][j] = tmp[0];
243 out[1][j] = tmp[1];
244 out[2][j] = tmp[2];
245 out[3][j] = tmp[3];
246 out[4][j] = tmp[4];
247 out[5][j] = tmp[5];
248 out[6][j] = tmp[6];
249 out[7][j] = tmp[7];
250 }
251 for k in 0..8 {
252 let tmp = out[k];
253 out[k] = transpose_64x64(&tmp);
254 }
255
256 out
257}
258
259#[cfg(test)]
260mod tests {
261
262 use std::arch::x86_64::{_mm512_set1_epi64, _mm512_setzero_si512};
263
264 use super::*;
266
267 #[test]
268 fn test_encrypt_works_correctly() {
269 let ciphertext = des(0x0123456789ABCDEF, 0x133457799BBCDFF1);
271 assert_eq!(ciphertext, 0x85E813540F0AB405);
272 }
273
274 #[test]
275 fn test_encrypt_optimized_works_correctly() {
276 let k = 0x133457799BBCDFF1u64;
278 let mut keys = [[k; 64]; 8];
279 let ciphertexts = bitsliced_des_simd(0x0123456789ABCDEF, &mut keys);
280 assert_eq!(ciphertexts[0][0], 0x85E813540F0AB405);
281 assert_eq!(ciphertexts[0][63], 0x85E813540F0AB405);
282 }
283
284 #[test]
285 fn test_encrypt_optimized_inline_works_correctly() {
286 let k = 0x133457799BBCDFF1u64;
288 let mut keys = [[k; 64]; 8];
289 let mut transposed = transpose(&keys);
290 bitsliced_des_inline_simd(0x0123456789ABCDEF, &mut transposed);
291 let ciphertexts = transpose_back(&transposed);
292 assert_eq!(ciphertexts[0][0], 0x85E813540F0AB405);
293 assert_eq!(ciphertexts[0][63], 0x85E813540F0AB405);
294 }
295
296 #[test]
297 fn test_encrypt_optimized_inline_avx_works_correctly() {
298 unsafe {
299 let k = 0x8923BDFDAF753F63u64;
300 let keys = [k; 64];
301 let transposed = transpose_64x64(&keys);
302 let mut keys = [_mm512_setzero_si512(); 64];
303 for (i, t) in transposed.iter().enumerate() {
304 if *t != 0 {
305 keys[i] = _mm512_set1_epi64(-1);
306 }
307 }
308 bitsliced_des_inline_simd_avx(&mut keys);
309 let mut output = Box::new([0u64; 64]);
310 for (i, k) in keys.iter().enumerate() {
311 let lanes: [u64; 8] = transmute(*k);
312 let first = lanes[0];
313 output[i] = first;
314 }
315 let ciphertexts = transpose_64x64(&output);
316 assert_eq!(ciphertexts[0], 0x727B4E35F947129E);
317 assert_eq!(ciphertexts[0], 0x727B4E35F947129E);
318 }
319 }
320
321 #[test]
322 fn test_encrypt_optimized_avx_works_correctly() {
323 unsafe {
324 let k = 0x8923BDFDAF753F63u64;
325 let keys = [[k; 64]; 8];
326
327 let output = bitsliced_des_simd_avx(&keys);
328 assert_eq!(output[0][0], 0x727B4E35F947129E);
329 assert_eq!(output[7][63], 0x727B4E35F947129E);
330 }
331 }
332
333 #[test]
334 fn test_netntlmv1_encrypt_works_correctly() {
335 let k = 0x8846F7EAEE8FB1u64;
336 let keys = [[k; 64]; 8];
337 let ciphertexts = bitsliced_netntlmv1_simd(0x1122334455667788, &keys);
338 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
339 assert_eq!(ciphertexts[0][63], 0x727B4E35F947129E);
340 }
341
342 #[test]
343 fn test_netntlmv1_inline_encrypt_works_correctly() {
344 let k = 0x8846F7EAEE8FB1u64;
345 let keys = [[k; 64]; 8];
346 let mut transposed = transpose(&keys);
347 bitsliced_netntlmv1_inline_simd(0x1122334455667788, &mut transposed);
348 let ciphertexts = transpose_back(&transposed);
349 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
350 assert_eq!(ciphertexts[0][63], 0x727B4E35F947129E);
351 }
352
353 #[test]
354 fn test_netntlmv1_encrypt_avx_works_correctly() {
355 unsafe {
356 let k = 0x8846F7EAEE8FB1u64;
357 let keys = [[k; 64]; 8];
358 let ciphertexts = bitsliced_netntlmv1_simd_avx(&keys);
359 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
360 assert_eq!(ciphertexts[0][63], 0x727B4E35F947129E);
361 }
362 }
363
364 #[test]
365 fn test_netntlmv1_inline_encrypt_avx_works_correctly() {
366 unsafe {
367 let k = 0x8846F7EAEE8FB1u64;
368 let keys = [[k; 64]; 8];
369 let mut transposed = transpose_avx(&keys);
370 bitsliced_netntlmv1_inline_simd_avx(&mut transposed);
371 let ciphertexts = transpose_back_avx(&transposed);
372 assert_eq!(ciphertexts[0][0], 0x727B4E35F947129E);
373 assert_eq!(ciphertexts[7][63], 0x727B4E35F947129E);
374 }
375 }
376}