apfsds_obfuscation/
timing.rs1use std::time::Duration;
4
5pub const DEFAULT_JITTER_MS: u64 = 50;
7
8pub const DEFAULT_INTER_FRAME_DELAY_US: (u64, u64) = (100, 5000);
10
11#[derive(Debug, Clone)]
13pub enum JitterStrategy {
14 Fixed { max_ms: u64 },
16 Normal { mean_ms: f64, std_dev_ms: f64 },
18 Exponential { lambda: f64 },
20 Adaptive { base_ms: u64, factor: f64 },
22}
23
24impl Default for JitterStrategy {
25 fn default() -> Self {
26 Self::Fixed {
27 max_ms: DEFAULT_JITTER_MS,
28 }
29 }
30}
31
32#[derive(Debug, Clone)]
34pub struct TimingConfig {
35 pub jitter_strategy: JitterStrategy,
37
38 pub inter_frame_delay: (u64, u64),
40
41 pub reconnect_interval: (u64, u64),
43
44 pub noise_interval: (u64, u64),
46}
47
48impl Default for TimingConfig {
49 fn default() -> Self {
50 Self {
51 jitter_strategy: JitterStrategy::default(),
52 inter_frame_delay: DEFAULT_INTER_FRAME_DELAY_US,
53 reconnect_interval: (60, 180),
54 noise_interval: (10, 30),
55 }
56 }
57}
58
59impl TimingConfig {
60 pub fn random_jitter(&self) -> Duration {
62 let jitter_ms = match &self.jitter_strategy {
63 JitterStrategy::Fixed { max_ms } => {
64 fastrand::u64(0..=*max_ms)
66 }
67 JitterStrategy::Normal {
68 mean_ms,
69 std_dev_ms,
70 } => {
71 let u1 = fastrand::f64();
73 let u2 = fastrand::f64();
74 let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos();
75 let jitter = mean_ms + z * std_dev_ms;
76 jitter.max(0.0) as u64
77 }
78 JitterStrategy::Exponential { lambda } => {
79 let u = fastrand::f64();
81 let jitter = -(1.0 / lambda) * u.ln();
82 (jitter * 1000.0).max(0.0) as u64
83 }
84 JitterStrategy::Adaptive { base_ms, factor } => {
85 let adaptive_max = (*base_ms as f64 * factor) as u64;
88 fastrand::u64(0..=adaptive_max)
89 }
90 };
91
92 Duration::from_millis(jitter_ms)
93 }
94
95 pub fn random_inter_frame_delay(&self) -> Duration {
97 let (min, max) = self.inter_frame_delay;
98 Duration::from_micros(fastrand::u64(min..=max))
99 }
100
101 pub fn random_reconnect_interval(&self) -> Duration {
103 let (min, max) = self.reconnect_interval;
104 Duration::from_secs(fastrand::u64(min..=max))
105 }
106
107 pub fn random_noise_interval(&self) -> Duration {
109 let (min, max) = self.noise_interval;
110 Duration::from_secs(fastrand::u64(min..=max))
111 }
112}
113
114pub async fn sleep_with_jitter(base: Duration, max_jitter_ms: u64) {
116 let jitter = Duration::from_millis(fastrand::u64(0..=max_jitter_ms));
117 tokio::time::sleep(base + jitter).await;
118}
119
120pub fn calculate_adaptive_delay(
122 last_packet_time_ms: u64,
123 current_time_ms: u64,
124 target_rate_bps: u64,
125) -> Duration {
126 let expected_interval_ms = 1000 / (target_rate_bps / 8 / 1500).max(1);
129
130 let elapsed = current_time_ms.saturating_sub(last_packet_time_ms);
131
132 if elapsed >= expected_interval_ms {
133 Duration::from_millis(fastrand::u64(0..10))
135 } else {
136 let delay = expected_interval_ms - elapsed;
138 Duration::from_millis(delay + fastrand::u64(0..10))
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_default_config() {
148 let config = TimingConfig::default();
149
150 assert_eq!(config.max_jitter_ms, 50);
151 assert_eq!(config.reconnect_interval, (60, 180));
152 }
153
154 #[test]
155 fn test_random_jitter() {
156 let config = TimingConfig::default();
157
158 for _ in 0..100 {
159 let jitter = config.random_jitter();
160 assert!(jitter <= Duration::from_millis(50));
161 }
162 }
163
164 #[test]
165 fn test_random_reconnect() {
166 let config = TimingConfig::default();
167
168 for _ in 0..100 {
169 let interval = config.random_reconnect_interval();
170 assert!(interval >= Duration::from_secs(60));
171 assert!(interval <= Duration::from_secs(180));
172 }
173 }
174
175 #[test]
176 fn test_adaptive_delay() {
177 let delay = calculate_adaptive_delay(0, 1000, 1_000_000);
179 assert!(delay < Duration::from_millis(100));
180
181 let delay = calculate_adaptive_delay(995, 1000, 1_000_000);
183 }
185}