Skip to main content

ferrox_logger/
dp.rs

1//! # Differential Privacy Engine (`ferrox-logger::dp`)
2//!
3//! Provides Laplace Noise mechanism for exporting metric telemetry and security benchmarks
4//! under $(\epsilon, \delta)$-Differential Privacy guarantees.
5//! Reference: *Machine Learning and Security* (Ch. 8 - Privacy-Preserving Machine Learning).
6
7use rand::Rng;
8
9/// Differential Privacy Engine using Laplace distribution noise sampling
10pub struct DifferentialPrivacyEngine;
11
12impl DifferentialPrivacyEngine {
13    /// Generates a noise sample from a Laplace distribution with scale $b = \Delta f / \epsilon$
14    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    /// Adds Laplace noise to a numerical telemetry metric to preserve $(\epsilon, \delta)$-privacy
24    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        // Sanitized value should be close to original value with bounded noise
47        assert!((sanitized - original_val).abs() < 25.0);
48    }
49}