1pub mod rng;
2pub mod hash;
3pub mod string;
4pub mod flow;
5pub mod encoding;
6pub mod pointer;
7pub mod wide;
8
9pub use rng::{xxhash_mix, siphash_seed, gen_entropy, GLOBAL_SEED};
10pub use hash::{xxhash32, sdbm_hash};
11
12pub fn opaque_true() -> bool {
13 let t = std::time::SystemTime::now()
14 .duration_since(std::time::UNIX_EPOCH)
15 .unwrap()
16 .as_nanos();
17 (t | 1) != 0
18}
19
20pub fn opaque_identity<T>(val: T) -> T {
21 if opaque_true() { val } else { unreachable!() }
22}
23
24pub fn stack_trash() {
25 let mut buf = [0u8; 512];
26 for i in 0..512 {
27 buf[i] = ((i * 73) ^ 0xaa) as u8;
28 }
29 std::hint::black_box(&buf);
30}
31
32#[macro_export]
33macro_rules! hidden_call {
34 ($expr:expr) => {{
35 if $crate::opaque_true() {
36 $crate::stack_trash();
37 $expr
38 } else {
39 unreachable!()
40 }
41 }};
42}
43
44pub fn noise_loop(count: usize) -> u64 {
45 let mut acc = 0u64;
46 for i in 0..count {
47 acc = acc.wrapping_add(i as u64);
48 acc ^= 0xdeadbeef;
49 acc = acc.rotate_left(7);
50 }
51 acc
52}
53
54pub fn fake_compute(input: u64) -> u64 {
55 let mut val = input;
56 val ^= 0xa5a5a5a5a5a5a5a5;
57 val = val.wrapping_mul(0x517cc1b727220a95);
58 val = val.rotate_left(23);
59 val ^= val >> 17;
60 val
61}
62
63#[macro_export]
64macro_rules! obf_if {
65 ($cond:expr, $then:block, $else:block) => {{
66 let c = $cond;
67 $crate::stack_trash();
68 if c { $then } else { $else }
69 }};
70 ($cond:expr, $then:block) => {{
71 let c = $cond;
72 $crate::stack_trash();
73 if c { $then }
74 }};
75}
76
77pub fn xor_stream(data: &mut [u8], key: &[u8]) {
78 for (i, byte) in data.iter_mut().enumerate() {
79 *byte ^= key[i % key.len()];
80 }
81}
82
83pub fn cascade_encrypt(data: &[u8], rounds: usize) -> Vec<u8> {
84 let mut result = data.to_vec();
85 for round in 0..rounds {
86 let mut key = (0xb7u8).wrapping_add(round as u8);
87 for byte in result.iter_mut() {
88 *byte = byte.wrapping_add(key);
89 *byte ^= key;
90 key = key.wrapping_mul(17).wrapping_add(83);
91 }
92 }
93 result
94}
95
96pub fn cascade_decrypt(data: &[u8], rounds: usize) -> Vec<u8> {
97 let mut result = data.to_vec();
98 for round in (0..rounds).rev() {
99 let mut key = (0xb7u8).wrapping_add(round as u8);
100 for byte in result.iter_mut() {
101 *byte ^= key;
102 *byte = byte.wrapping_sub(key);
103 key = key.wrapping_mul(17).wrapping_add(83);
104 }
105 }
106 result
107}
108
109pub struct ObfuscatedValue<T> {
110 data: Vec<u8>,
111 key: u64,
112 _marker: std::marker::PhantomData<T>,
113}
114
115impl<T: Sized> ObfuscatedValue<T> {
116 pub fn new(val: T) -> Self {
117 let bytes = unsafe {
118 std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::<T>())
119 };
120 let key = noise_loop(100);
121 let data = bytes.iter().enumerate()
122 .map(|(i, &b)| b ^ ((key >> (i % 8 * 8)) as u8))
123 .collect();
124 std::mem::forget(val);
125 Self { data, key, _marker: std::marker::PhantomData }
126 }
127
128 pub fn get(&self) -> T {
129 let mut bytes = vec![0u8; self.data.len()];
130 for (i, &b) in self.data.iter().enumerate() {
131 bytes[i] = b ^ ((self.key >> (i % 8 * 8)) as u8);
132 }
133 unsafe { std::ptr::read(bytes.as_ptr() as *const T) }
134 }
135}
136
137pub fn tamper_check(expected: u32) -> bool {
138 let actual = ct_xxhash!(b"tamper_check");
139 actual == expected
140}
141
142pub fn anti_debug() -> bool {
143 #[cfg(target_os = "windows")]
144 {
145 unsafe {
146 extern "system" {
147 fn IsDebuggerPresent() -> i32;
148 }
149 IsDebuggerPresent() == 0
150 }
151 }
152 #[cfg(not(target_os = "windows"))]
153 {
154 true
155 }
156}
157
158#[macro_export]
159macro_rules! debug_trap {
160 () => {
161 if !$crate::anti_debug() {
162 panic!("debugger detected");
163 }
164 };
165}