1use rand::Rng;
8
9pub struct DifferentialPrivacyEngine;
11
12impl DifferentialPrivacyEngine {
13 pub fn laplace_sample(scale: f64) -> f64 {
15 let mut rng = rand::thread_rng();
16 let u: f64 = rng.gen_range(-0.4999..0.4999);
17 let sgn: f64 = if u < 0.0 { -1.0 } else { 1.0 };
18 let abs_u: f64 = u.abs();
19 let term: f64 = (1.0 - 2.0 * abs_u).max(1e-10);
20 -scale * sgn * term.ln()
21 }
22
23 pub fn sanitize_metric(value: f64, epsilon: f64, sensitivity: f64) -> f64 {
25 if epsilon <= 0.0 {
26 return value;
27 }
28 let scale = sensitivity / epsilon;
29 let noise = Self::laplace_sample(scale);
30 (value + noise).max(0.0)
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn test_differential_privacy_engine() {
40 let original_val = 100.0;
41 let epsilon = 1.0;
42 let sensitivity = 1.0;
43
44 let sanitized = DifferentialPrivacyEngine::sanitize_metric(original_val, epsilon, sensitivity);
45 assert!(sanitized >= 0.0);
46 assert!((sanitized - original_val).abs() < 25.0);
48 }
49}