1use std::ops::*;
51
52#[inline]
64pub fn pseudo_encrypt<A>(a: A) -> A
65where
66 A: Shl<usize, Output = A>
67 + Shr<usize, Output = A>
68 + Add<Output = A>
69 + Mul<Output = A>
70 + Rem<Output = A>
71 + BitAnd<Output = A>
72 + BitXor<Output = A>
73 + PseudoEncryptable
74 + From<<A as PseudoEncryptable>::HalfBitType>,
75{
76 let left_select = (a >> <A as PseudoEncryptable>::HALF_BIT_SIZE)
77 & <A as PseudoEncryptable>::HALF_BIT_MAX.into();
78 let right_select = a & <A as PseudoEncryptable>::HALF_BIT_MAX.into();
79 let (l, r) = (0..3).fold((left_select, right_select), |(l1, r1), _| {
80 let l2 = r1;
81 let r2 = l1
82 ^ (<A as PseudoEncryptable>::cast_from_f32(
83 ((<A as PseudoEncryptable>::cast_to_f32(
84 (r1 * <A as PseudoEncryptable>::cast_from_i32(1366)
85 + <A as PseudoEncryptable>::cast_from_i32(150889))
86 % <A as PseudoEncryptable>::cast_from_i32(714025),
87 ) / 714025.0)
88 * 32767.0)
89 .round(),
90 ));
91 (l2, r2)
92 });
93 (r << <A as PseudoEncryptable>::HALF_BIT_SIZE) + l
94}
95
96pub trait PseudoEncryptable: Copy {
97 type HalfBitType: Copy;
98 const HALF_BIT_SIZE: usize;
99 const HALF_BIT_MAX: Self::HalfBitType;
100
101 fn cast_from_i32(f: i32) -> Self;
102
103 fn cast_from_f32(f: f32) -> Self;
104
105 fn cast_to_f32(f: Self) -> f32;
106}
107
108impl PseudoEncryptable for i32 {
109 type HalfBitType = u16;
110 const HALF_BIT_SIZE: usize = 16;
111 const HALF_BIT_MAX: Self::HalfBitType = u16::MAX;
112
113 #[inline]
114 fn cast_from_i32(f: i32) -> Self {
115 f
116 }
117
118 #[inline]
119 fn cast_from_f32(f: f32) -> Self {
120 f as Self
121 }
122
123 #[inline]
124 fn cast_to_f32(f: Self) -> f32 {
125 f as f32
126 }
127}
128
129impl PseudoEncryptable for i64 {
130 type HalfBitType = u32;
131 const HALF_BIT_SIZE: usize = 32;
132 const HALF_BIT_MAX: Self::HalfBitType = u32::MAX;
133
134 #[inline]
135 fn cast_from_i32(f: i32) -> Self {
136 f as Self
137 }
138
139 #[inline]
140 fn cast_from_f32(f: f32) -> Self {
141 f as Self
142 }
143
144 #[inline]
145 fn cast_to_f32(f: Self) -> f32 {
146 f as f32
147 }
148}
149
150impl PseudoEncryptable for i128 {
151 type HalfBitType = u64;
152 const HALF_BIT_SIZE: usize = 64;
153 const HALF_BIT_MAX: Self::HalfBitType = u64::MAX;
154
155 #[inline]
156 fn cast_from_i32(f: i32) -> Self {
157 f as Self
158 }
159
160 #[inline]
161 fn cast_from_f32(f: f32) -> Self {
162 f as Self
163 }
164
165 #[inline]
166 fn cast_to_f32(f: Self) -> f32 {
167 f as f32
168 }
169}
170
171impl PseudoEncryptable for u32 {
172 type HalfBitType = u16;
173 const HALF_BIT_SIZE: usize = 16;
174 const HALF_BIT_MAX: Self::HalfBitType = u16::MAX;
175
176 #[inline]
177 fn cast_from_i32(f: i32) -> Self {
178 f as Self
179 }
180
181 #[inline]
182 fn cast_from_f32(f: f32) -> Self {
183 f as Self
184 }
185 #[inline]
186 fn cast_to_f32(f: Self) -> f32 {
187 f as f32
188 }
189}
190
191impl PseudoEncryptable for u64 {
192 type HalfBitType = u32;
193 const HALF_BIT_SIZE: usize = 32;
194 const HALF_BIT_MAX: Self::HalfBitType = u32::MAX;
195
196 #[inline]
197 fn cast_from_i32(f: i32) -> Self {
198 f as Self
199 }
200
201 #[inline]
202 fn cast_from_f32(f: f32) -> Self {
203 f as Self
204 }
205
206 #[inline]
207 fn cast_to_f32(f: Self) -> f32 {
208 f as f32
209 }
210}
211
212impl PseudoEncryptable for u128 {
213 type HalfBitType = u64;
214 const HALF_BIT_SIZE: usize = 64;
215 const HALF_BIT_MAX: Self::HalfBitType = u64::MAX;
216
217 #[inline]
218 fn cast_from_i32(f: i32) -> Self {
219 f as Self
220 }
221
222 #[inline]
223 fn cast_from_f32(f: f32) -> Self {
224 f as Self
225 }
226
227 #[inline]
228 fn cast_to_f32(f: Self) -> f32 {
229 f as f32
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use crate::*;
236 use proptest::prelude::*;
237 use std::collections::{HashMap, HashSet};
238 use std::sync::Mutex;
239
240 const TEST_CASES: u32 = 1000000;
241
242 #[test]
243 fn test_test_pseudo_encrypt_values_u32() {
244 let input_expected = vec![
245 (0, 1777613459),
246 (1, 561465857),
247 (2, 436885871),
248 (3, 576481439),
249 (4, 483424269),
250 (5, 1905133426),
251 (6, 971249312),
252 (7, 1926833684),
253 (8, 735327624),
254 (9, 1731020007),
255 (10, 792482838),
256 ];
257 for (input, expected) in input_expected {
258 let r = pseudo_encrypt(input);
259 assert_eq!(expected, r);
260 }
261 }
262
263 #[test]
264 fn test_test_pseudo_encrypt_values_i32() {
265 let input_expected: Vec<(i32, i32)> = vec![
266 (-10, -1270576520),
267 (-9, -236348969),
268 (-8, -1184061109),
269 (-7, -25446276),
270 (-6, -1507538963),
271 (-5, -518858927),
272 (-4, -1458116927),
273 (-3, -532482573),
274 (-2, -157973154),
275 (-1, -1105881908),
276 (0, 1777613459),
277 (1, 561465857),
278 (2, 436885871),
279 (3, 576481439),
280 (4, 483424269),
281 (5, 1905133426),
282 (6, 971249312),
283 (7, 1926833684),
284 (8, 735327624),
285 (9, 1731020007),
286 (10, 792482838),
287 ];
288 for (input, expected) in input_expected {
289 let r = pseudo_encrypt(input);
290 assert_eq!(expected, r);
291 }
292 }
293
294 #[test]
295 fn test_test_pseudo_encrypt_no_collisions_u32() {
296 let seen_inputs_mutex = Mutex::new(HashSet::with_capacity(TEST_CASES as usize));
297 let seen_results_mutex = Mutex::new(HashMap::with_capacity(TEST_CASES as usize));
298 proptest!(ProptestConfig::with_cases(TEST_CASES), move |(u: u32)| {
299 let mut seen_inputs = seen_inputs_mutex.lock().unwrap();
300 prop_assume!(!seen_inputs.contains(&u));
301 seen_inputs.insert(u);
302
303 let mut seen_results = seen_results_mutex.lock().unwrap();
304 let r = pseudo_encrypt(u);
305
306 let previous_input_for_result = seen_results.get(&r);
307 prop_assert!(previous_input_for_result.is_none(), "Previous input [{:?}] yielded the same result [{}]", previous_input_for_result, r);
308 seen_results.insert(r, u);
309 });
310 }
311
312 #[test]
313 fn test_test_pseudo_encrypt_no_collisions_i32() {
314 let seen_inputs_mutex = Mutex::new(HashSet::with_capacity(TEST_CASES as usize));
315 let seen_results_mutex = Mutex::new(HashMap::with_capacity(TEST_CASES as usize));
316 proptest!(ProptestConfig::with_cases(TEST_CASES), move |(u: i32)| {
317 let mut seen_inputs = seen_inputs_mutex.lock().unwrap();
318 prop_assume!(!seen_inputs.contains(&u));
319
320 seen_inputs.insert(u);
321
322 let mut seen_results = seen_results_mutex.lock().unwrap();
323 let r = pseudo_encrypt(u);
324
325 let previous_input_for_result = seen_results.get(&r);
326 prop_assert!(previous_input_for_result.is_none(), "Previous input [{:?}] yielded the same result [{}]", previous_input_for_result, r);
327 seen_results.insert(r, u);
328 });
329 }
330
331 #[test]
332 fn test_test_pseudo_encrypt_no_collisions_i64() {
333 let seen_inputs_mutex = Mutex::new(HashSet::with_capacity(TEST_CASES as usize));
334 let seen_results_mutex = Mutex::new(HashMap::with_capacity(TEST_CASES as usize));
335 proptest!(ProptestConfig::with_cases(TEST_CASES), move |(u: i64)| {
336 let mut seen_inputs = seen_inputs_mutex.lock().unwrap();
337 prop_assume!(!seen_inputs.contains(&u));
338 seen_inputs.insert(u);
339
340 let mut seen_results = seen_results_mutex.lock().unwrap();
341 let r = pseudo_encrypt(u);
342
343 let previous_input_for_result = seen_results.get(&r);
344 prop_assert!(previous_input_for_result.is_none(), "Previous input [{:?}] yielded the same result [{}]", previous_input_for_result, r);
345 seen_results.insert(r, u);
346 });
347 }
348
349 #[test]
350 fn test_test_pseudo_encrypt_no_collisions_u64() {
351 let seen_inputs_mutex = Mutex::new(HashSet::with_capacity(TEST_CASES as usize));
352 let seen_results_mutex = Mutex::new(HashMap::with_capacity(TEST_CASES as usize));
353 proptest!(ProptestConfig::with_cases(TEST_CASES), move |(u: u64)| {
354 let mut seen_inputs = seen_inputs_mutex.lock().unwrap();
355 prop_assume!(!seen_inputs.contains(&u));
356 seen_inputs.insert(u);
357
358 let mut seen_results = seen_results_mutex.lock().unwrap();
359 let r = pseudo_encrypt(u);
360
361 let previous_input_for_result = seen_results.get(&r);
362 prop_assert!(previous_input_for_result.is_none(), "Previous input [{:?}] yielded the same result [{}]", previous_input_for_result, r);
363 seen_results.insert(r, u);
364 });
365 }
366
367 #[test]
368 fn test_test_pseudo_encrypt_no_collisions_i128() {
369 let seen_inputs_mutex = Mutex::new(HashSet::with_capacity(TEST_CASES as usize));
370 let seen_results_mutex = Mutex::new(HashMap::with_capacity(TEST_CASES as usize));
371 proptest!(ProptestConfig::with_cases(TEST_CASES), move |(u: i128)| {
372 let mut seen_inputs = seen_inputs_mutex.lock().unwrap();
373 prop_assume!(!seen_inputs.contains(&u));
374 seen_inputs.insert(u);
375
376 let mut seen_results = seen_results_mutex.lock().unwrap();
377 let r = pseudo_encrypt(u);
378
379 let previous_input_for_result = seen_results.get(&r);
380 prop_assert!(previous_input_for_result.is_none(), "Previous input [{:?}] yielded the same result [{}]", previous_input_for_result, r);
381 seen_results.insert(r, u);
382 });
383 }
384
385 #[test]
386 fn test_test_pseudo_encrypt_no_collisions_u128() {
387 let seen_inputs_mutex = Mutex::new(HashSet::with_capacity(TEST_CASES as usize));
388 let seen_results_mutex = Mutex::new(HashMap::with_capacity(TEST_CASES as usize));
389 proptest!(ProptestConfig::with_cases(TEST_CASES), move |(u: u128)| {
390 let mut seen_inputs = seen_inputs_mutex.lock().unwrap();
391 prop_assume!(!seen_inputs.contains(&u));
392 seen_inputs.insert(u);
393
394 let mut seen_results = seen_results_mutex.lock().unwrap();
395 let r = pseudo_encrypt(u);
396
397 let previous_input_for_result = seen_results.get(&r);
398 prop_assert!(previous_input_for_result.is_none(), "Previous input [{:?}] yielded the same result [{}]", previous_input_for_result, r);
399 seen_results.insert(r, u);
400 });
401 }
402}