• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::convert::*;
2 
3 /// This is a constant with a lot of special properties found by automated search.
4 /// See the unit tests below. (Below are alternative values)
5 #[cfg(all(target_feature = "ssse3", not(miri)))]
6 const SHUFFLE_MASK: u128 = 0x020a0700_0c01030e_050f0d08_06090b04_u128;
7 //const SHUFFLE_MASK: u128 = 0x000d0702_0a040301_05080f0c_0e0b0609_u128;
8 //const SHUFFLE_MASK: u128 = 0x040A0700_030E0106_0D050F08_020B0C09_u128;
9 
10 #[inline(always)]
folded_multiply(s: u64, by: u64) -> u6411 pub(crate) const fn folded_multiply(s: u64, by: u64) -> u64 {
12     let result = (s as u128).wrapping_mul(by as u128);
13     ((result & 0xffff_ffff_ffff_ffff) as u64) ^ ((result >> 64) as u64)
14 }
15 
16 
17 /// Given a small (less than 8 byte slice) returns the same data stored in two u32s.
18 /// (order of and non-duplication of bytes is NOT guaranteed)
19 #[inline(always)]
read_small(data: &[u8]) -> [u64; 2]20 pub(crate) fn read_small(data: &[u8]) -> [u64; 2] {
21     debug_assert!(data.len() <= 8);
22     if data.len() >= 2 {
23         if data.len() >= 4 {
24             //len 4-8
25             [data.read_u32().0 as u64, data.read_last_u32() as u64]
26         } else {
27             //len 2-3
28             [data.read_u16().0 as u64, data[data.len() - 1] as u64]
29         }
30     } else {
31         if data.len() > 0 {
32             [data[0] as u64, data[0] as u64]
33         } else {
34             [0, 0]
35         }
36     }
37 }
38 
39 #[inline(always)]
shuffle(a: u128) -> u12840 pub(crate) fn shuffle(a: u128) -> u128 {
41     #[cfg(all(target_feature = "ssse3", not(miri)))]
42     {
43         #[cfg(target_arch = "x86")]
44         use core::arch::x86::*;
45         #[cfg(target_arch = "x86_64")]
46         use core::arch::x86_64::*;
47         use core::mem::transmute;
48         unsafe { transmute(_mm_shuffle_epi8(transmute(a), transmute(SHUFFLE_MASK))) }
49     }
50     #[cfg(not(all(target_feature = "ssse3", not(miri))))]
51     {
52         a.swap_bytes()
53     }
54 }
55 
56 #[allow(unused)] //not used by fallback
57 #[inline(always)]
add_and_shuffle(a: u128, b: u128) -> u12858 pub(crate) fn add_and_shuffle(a: u128, b: u128) -> u128 {
59     let sum = add_by_64s(a.convert(), b.convert());
60     shuffle(sum.convert())
61 }
62 
63 #[allow(unused)] //not used by fallbac
64 #[inline(always)]
shuffle_and_add(base: u128, to_add: u128) -> u12865 pub(crate) fn shuffle_and_add(base: u128, to_add: u128) -> u128 {
66     let shuffled: [u64; 2] = shuffle(base).convert();
67     add_by_64s(shuffled, to_add.convert()).convert()
68 }
69 
70 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2", not(miri)))]
71 #[inline(always)]
add_by_64s(a: [u64; 2], b: [u64; 2]) -> [u64; 2]72 pub(crate) fn add_by_64s(a: [u64; 2], b: [u64; 2]) -> [u64; 2] {
73     use core::mem::transmute;
74     unsafe {
75         #[cfg(target_arch = "x86")]
76         use core::arch::x86::*;
77         #[cfg(target_arch = "x86_64")]
78         use core::arch::x86_64::*;
79         transmute(_mm_add_epi64(transmute(a), transmute(b)))
80     }
81 }
82 
83 #[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2", not(miri))))]
84 #[inline(always)]
add_by_64s(a: [u64; 2], b: [u64; 2]) -> [u64; 2]85 pub(crate) fn add_by_64s(a: [u64; 2], b: [u64; 2]) -> [u64; 2] {
86     [a[0].wrapping_add(b[0]), a[1].wrapping_add(b[1])]
87 }
88 
89 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
90 #[allow(unused)]
91 #[inline(always)]
aesenc(value: u128, xor: u128) -> u12892 pub(crate) fn aesenc(value: u128, xor: u128) -> u128 {
93     #[cfg(target_arch = "x86")]
94     use core::arch::x86::*;
95     #[cfg(target_arch = "x86_64")]
96     use core::arch::x86_64::*;
97     use core::mem::transmute;
98     unsafe {
99         let value = transmute(value);
100         transmute(_mm_aesenc_si128(value, transmute(xor)))
101     }
102 }
103 
104 #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd"))]
105 #[allow(unused)]
106 #[inline(always)]
aesenc(value: u128, xor: u128) -> u128107 pub(crate) fn aesenc(value: u128, xor: u128) -> u128 {
108     #[cfg(target_arch = "arm")]
109     use core::arch::arm::*;
110     #[cfg(target_arch = "aarch64")]
111     use core::arch::aarch64::*;
112     use core::mem::transmute;
113     unsafe {
114         let value = transmute(value);
115         transmute(vaesmcq_u8(vaeseq_u8(value, transmute(xor))))
116     }
117 }
118 
119 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
120 #[allow(unused)]
121 #[inline(always)]
aesdec(value: u128, xor: u128) -> u128122 pub(crate) fn aesdec(value: u128, xor: u128) -> u128 {
123     #[cfg(target_arch = "x86")]
124     use core::arch::x86::*;
125     #[cfg(target_arch = "x86_64")]
126     use core::arch::x86_64::*;
127     use core::mem::transmute;
128     unsafe {
129         let value = transmute(value);
130         transmute(_mm_aesdec_si128(value, transmute(xor)))
131     }
132 }
133 
134 #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd"))]
135 #[allow(unused)]
136 #[inline(always)]
aesdec(value: u128, xor: u128) -> u128137 pub(crate) fn aesdec(value: u128, xor: u128) -> u128 {
138     #[cfg(target_arch = "arm")]
139     use core::arch::arm::*;
140     #[cfg(target_arch = "aarch64")]
141     use core::arch::aarch64::*;
142     use core::mem::transmute;
143     unsafe {
144         let value = transmute(value);
145         transmute(vaesimcq_u8(vaesdq_u8(value, transmute(xor))))
146     }
147 }
148 
149 #[cfg(test)]
150 mod test {
151     use super::*;
152     use crate::convert::Convert;
153 
154     // This is code to search for the shuffle constant
155     //
156     //thread_local! { static MASK: Cell<u128> = Cell::new(0); }
157     //
158     // fn shuffle(a: u128) -> u128 {
159     //     use std::intrinsics::transmute;
160     //     #[cfg(target_arch = "x86")]
161     //     use core::arch::x86::*;
162     //     #[cfg(target_arch = "x86_64")]
163     //     use core::arch::x86_64::*;
164     //     MASK.with(|mask| {
165     //         unsafe { transmute(_mm_shuffle_epi8(transmute(a), transmute(mask.get()))) }
166     //     })
167     // }
168     //
169     // #[test]
170     // fn find_shuffle() {
171     //     use rand::prelude::*;
172     //     use SliceRandom;
173     //     use std::panic;
174     //     use std::io::Write;
175     //
176     //     let mut value: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ,13, 14, 15];
177     //     let mut rand = thread_rng();
178     //     let mut successful_list = HashMap::new();
179     //     for _attempt in 0..10000000 {
180     //         rand.shuffle(&mut value);
181     //         let test_val = value.convert();
182     //         MASK.with(|mask| {
183     //             mask.set(test_val);
184     //         });
185     //         if let Ok(successful) = panic::catch_unwind(|| {
186     //             test_shuffle_does_not_collide_with_aes();
187     //             test_shuffle_moves_high_bits();
188     //             test_shuffle_moves_every_value();
189     //             //test_shuffle_does_not_loop();
190     //             value
191     //         }) {
192     //             let successful: u128 = successful.convert();
193     //             successful_list.insert(successful, iters_before_loop());
194     //         }
195     //     }
196     //     let write_file = File::create("/tmp/output").unwrap();
197     //     let mut writer = BufWriter::new(&write_file);
198     //
199     //     for success in successful_list {
200     //         writeln!(writer, "Found successful: {:x?} - {:?}", success.0, success.1);
201     //     }
202     // }
203     //
204     // fn iters_before_loop() -> u32 {
205     //     let numbered = 0x00112233_44556677_8899AABB_CCDDEEFF;
206     //     let mut shuffled = shuffle(numbered);
207     //     let mut count = 0;
208     //     loop {
209     //         // println!("{:>16x}", shuffled);
210     //         if numbered == shuffled {
211     //             break;
212     //         }
213     //         count += 1;
214     //         shuffled = shuffle(shuffled);
215     //     }
216     //     count
217     // }
218 
219     #[cfg(all(
220         any(target_arch = "x86", target_arch = "x86_64"),
221         target_feature = "ssse3",
222         target_feature = "aes",
223         not(miri)
224     ))]
225     #[test]
test_shuffle_does_not_collide_with_aes()226     fn test_shuffle_does_not_collide_with_aes() {
227         let mut value: [u8; 16] = [0; 16];
228         let zero_mask_enc = aesenc(0, 0);
229         let zero_mask_dec = aesdec(0, 0);
230         for index in 0..16 {
231             value[index] = 1;
232             let excluded_positions_enc: [u8; 16] = aesenc(value.convert(), zero_mask_enc).convert();
233             let excluded_positions_dec: [u8; 16] = aesdec(value.convert(), zero_mask_dec).convert();
234             let actual_location: [u8; 16] = shuffle(value.convert()).convert();
235             for pos in 0..16 {
236                 if actual_location[pos] != 0 {
237                     assert_eq!(
238                         0, excluded_positions_enc[pos],
239                         "Forward Overlap between {:?} and {:?} at {}",
240                         excluded_positions_enc, actual_location, index
241                     );
242                     assert_eq!(
243                         0, excluded_positions_dec[pos],
244                         "Reverse Overlap between {:?} and {:?} at {}",
245                         excluded_positions_dec, actual_location, index
246                     );
247                 }
248             }
249             value[index] = 0;
250         }
251     }
252 
253     #[test]
test_shuffle_contains_each_value()254     fn test_shuffle_contains_each_value() {
255         let value: [u8; 16] = 0x00010203_04050607_08090A0B_0C0D0E0F_u128.convert();
256         let shuffled: [u8; 16] = shuffle(value.convert()).convert();
257         for index in 0..16_u8 {
258             assert!(shuffled.contains(&index), "Value is missing {}", index);
259         }
260     }
261 
262     #[test]
test_shuffle_moves_every_value()263     fn test_shuffle_moves_every_value() {
264         let mut value: [u8; 16] = [0; 16];
265         for index in 0..16 {
266             value[index] = 1;
267             let shuffled: [u8; 16] = shuffle(value.convert()).convert();
268             assert_eq!(0, shuffled[index], "Value is not moved {}", index);
269             value[index] = 0;
270         }
271     }
272 
273     #[test]
test_shuffle_moves_high_bits()274     fn test_shuffle_moves_high_bits() {
275         assert!(
276             shuffle(1) > (1_u128 << 80),
277             "Low bits must be moved to other half {:?} -> {:?}",
278             0,
279             shuffle(1)
280         );
281 
282         assert!(
283             shuffle(1_u128 << 58) >= (1_u128 << 64),
284             "High bits must be moved to other half {:?} -> {:?}",
285             7,
286             shuffle(1_u128 << 58)
287         );
288         assert!(
289             shuffle(1_u128 << 58) < (1_u128 << 112),
290             "High bits must not remain high {:?} -> {:?}",
291             7,
292             shuffle(1_u128 << 58)
293         );
294         assert!(
295             shuffle(1_u128 << 64) < (1_u128 << 64),
296             "Low bits must be moved to other half {:?} -> {:?}",
297             8,
298             shuffle(1_u128 << 64)
299         );
300         assert!(
301             shuffle(1_u128 << 64) >= (1_u128 << 16),
302             "Low bits must not remain low {:?} -> {:?}",
303             8,
304             shuffle(1_u128 << 64)
305         );
306 
307         assert!(
308             shuffle(1_u128 << 120) < (1_u128 << 50),
309             "High bits must be moved to low half {:?} -> {:?}",
310             15,
311             shuffle(1_u128 << 120)
312         );
313     }
314 
315     #[cfg(all(
316         any(target_arch = "x86", target_arch = "x86_64"),
317         target_feature = "ssse3",
318         not(miri)
319     ))]
320     #[test]
test_shuffle_does_not_loop()321     fn test_shuffle_does_not_loop() {
322         let numbered = 0x00112233_44556677_8899AABB_CCDDEEFF;
323         let mut shuffled = shuffle(numbered);
324         for count in 0..100 {
325             // println!("{:>16x}", shuffled);
326             assert_ne!(numbered, shuffled, "Equal after {} vs {:x}", count, shuffled);
327             shuffled = shuffle(shuffled);
328         }
329     }
330 }
331