use serde::{Deserialize, Serialize};
use crate::federated_learning_v2_backup::types::*;
use trustformers_core::{Result, Tensor};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedPrivacyConfig {
pub epsilon: f64,
pub delta: f64,
pub mechanism: PrivacyMechanism,
pub privacy_model: PrivacyModel,
pub composition_method: CompositionMethod,
pub adaptive_budgeting: bool,
pub amplification_config: PrivacyAmplificationConfig,
pub noise_config: NoiseDistributionConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrivacyAmplificationConfig {
pub subsampling_ratio: f64,
pub shuffling_enabled: bool,
pub secure_aggregation_amplification: bool,
pub sampling_method: SamplingMethod,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NoiseDistributionConfig {
pub noise_multiplier: f64,
pub clipping_norm: f64,
pub adaptive_clipping: bool,
pub per_layer_scaling: bool,
pub correlated_noise: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrivacyAccountingConfig {
pub accounting_method: PrivacyAccountingMethod,
pub target_epsilon: f64,
pub target_delta: f64,
pub max_rounds: u32,
pub privacy_loss_tracking: bool,
pub composition_analysis: bool,
}
#[derive(Debug, Clone)]
pub struct PrivacyAccountant {
privacy_config: AdvancedPrivacyConfig,
accounting_config: PrivacyAccountingConfig,
total_epsilon: f64,
total_delta: f64,
round_privacy_consumption: Vec<(f64, f64)>, }
impl PrivacyAccountant {
pub fn new(
privacy_config: &AdvancedPrivacyConfig,
accounting_config: &PrivacyAccountingConfig,
) -> Result<Self> {
Ok(Self {
privacy_config: privacy_config.clone(),
accounting_config: accounting_config.clone(),
total_epsilon: 0.0,
total_delta: 0.0,
round_privacy_consumption: Vec::new(),
})
}
pub fn account_round(&mut self, epsilon: f64, delta: f64) -> Result<()> {
let (composed_epsilon, composed_delta) = match self.privacy_config.composition_method {
CompositionMethod::Basic => {
(self.total_epsilon + epsilon, self.total_delta + delta)
}
CompositionMethod::Advanced => {
let k = self.round_privacy_consumption.len() as f64 + 1.0;
let composed_eps = epsilon * (2.0 * k * (k * epsilon).ln()).sqrt();
(self.total_epsilon + composed_eps, self.total_delta + k * delta)
}
CompositionMethod::Optimal => {
let k = self.round_privacy_consumption.len() as f64 + 1.0;
let composed_eps = epsilon * (k * (k * epsilon).ln()).sqrt();
(self.total_epsilon + composed_eps, self.total_delta + k * delta)
}
CompositionMethod::RenyiComposition => {
(self.total_epsilon + epsilon, self.total_delta + delta)
}
CompositionMethod::ZCDPComposition => {
(self.total_epsilon + epsilon, self.total_delta + delta)
}
CompositionMethod::PLDTracking => {
(self.total_epsilon + epsilon, self.total_delta + delta)
}
};
self.total_epsilon = composed_epsilon;
self.total_delta = composed_delta;
self.round_privacy_consumption.push((epsilon, delta));
Ok(())
}
pub fn get_privacy_budget(&self) -> (f64, f64) {
(self.total_epsilon, self.total_delta)
}
pub fn is_budget_exhausted(&self) -> bool {
self.total_epsilon >= self.accounting_config.target_epsilon
|| self.total_delta >= self.accounting_config.target_delta
}
pub fn get_remaining_budget(&self) -> (f64, f64) {
(
(self.accounting_config.target_epsilon - self.total_epsilon).max(0.0),
(self.accounting_config.target_delta - self.total_delta).max(0.0),
)
}
pub fn optimize_privacy_parameters(&self, remaining_rounds: u32) -> (f64, f64) {
let (remaining_epsilon, remaining_delta) = self.get_remaining_budget();
let epsilon_per_round = remaining_epsilon / remaining_rounds as f64;
let delta_per_round = remaining_delta / remaining_rounds as f64;
(epsilon_per_round, delta_per_round)
}
}
pub struct DifferentialPrivacyMechanism {
config: AdvancedPrivacyConfig,
}
impl DifferentialPrivacyMechanism {
pub fn new(config: AdvancedPrivacyConfig) -> Self {
Self { config }
}
pub fn apply_privacy(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
match self.config.mechanism {
PrivacyMechanism::Gaussian => self.apply_gaussian_mechanism(tensor, sensitivity),
PrivacyMechanism::Laplace => self.apply_laplace_mechanism(tensor, sensitivity),
PrivacyMechanism::Exponential => self.apply_exponential_mechanism(tensor, sensitivity),
PrivacyMechanism::AboveThreshold => self.apply_above_threshold_mechanism(tensor, sensitivity),
PrivacyMechanism::SparseVector => self.apply_sparse_vector_technique(tensor, sensitivity),
PrivacyMechanism::PATE => self.apply_pate_mechanism(tensor, sensitivity),
PrivacyMechanism::RenyiDP => self.apply_renyi_dp_mechanism(tensor, sensitivity),
PrivacyMechanism::ZCDP => self.apply_zcdp_mechanism(tensor, sensitivity),
}
}
fn apply_gaussian_mechanism(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
let sigma = sensitivity * self.config.noise_config.noise_multiplier;
let data = tensor.data()?;
let mut noisy_data = Vec::with_capacity(data.len());
for &value in data.iter() {
let noise = self.generate_gaussian_noise(0.0, sigma);
noisy_data.push(value + noise);
}
Tensor::from_vec(noisy_data, tensor.shape())
}
fn apply_laplace_mechanism(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
let scale = sensitivity / self.config.epsilon;
let data = tensor.data()?;
let mut noisy_data = Vec::with_capacity(data.len());
for &value in data.iter() {
let noise = self.generate_laplace_noise(0.0, scale);
noisy_data.push(value + noise);
}
Tensor::from_vec(noisy_data, tensor.shape())
}
fn apply_exponential_mechanism(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
self.apply_laplace_mechanism(tensor, sensitivity)
}
fn apply_above_threshold_mechanism(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
self.apply_laplace_mechanism(tensor, sensitivity)
}
fn apply_sparse_vector_technique(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
self.apply_laplace_mechanism(tensor, sensitivity)
}
fn apply_pate_mechanism(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
self.apply_gaussian_mechanism(tensor, sensitivity)
}
fn apply_renyi_dp_mechanism(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
self.apply_gaussian_mechanism(tensor, sensitivity)
}
fn apply_zcdp_mechanism(&self, tensor: &Tensor, sensitivity: f64) -> Result<Tensor> {
self.apply_gaussian_mechanism(tensor, sensitivity)
}
fn generate_gaussian_noise(&self, mean: f64, std_dev: f64) -> f32 {
use std::f64::consts::PI;
static mut U1: Option<f64> = None;
static mut U2: Option<f64> = None;
unsafe {
if U1.is_none() {
let u1 = 0.5; let u2 = 0.5;
let z0 = (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).cos();
let z1 = (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).sin();
U1 = Some(z0);
U2 = Some(z1);
}
let noise = U1.expect("U1 was just set") * std_dev + mean;
U1 = U2;
U2 = None;
noise as f32
}
}
fn generate_laplace_noise(&self, location: f64, scale: f64) -> f32 {
let u = 0.5; let noise = if u < 0.0 {
location + scale * (2.0 * (u + 0.5)).ln()
} else {
location - scale * (2.0 * (0.5 - u)).ln()
};
noise as f32
}
pub fn clip_gradients(&self, gradients: &[f32], clipping_bound: f64) -> Vec<f32> {
let norm: f64 = gradients.iter().map(|&x| (x as f64).powi(2)).sum::<f64>().sqrt();
if norm <= clipping_bound {
gradients.to_vec()
} else {
let scaling_factor = clipping_bound / norm;
gradients.iter().map(|&x| (x as f64 * scaling_factor) as f32).collect()
}
}
pub fn compute_sensitivity(&self, _gradient_norms: &[f64]) -> f64 {
self.config.noise_config.clipping_norm
}
}
impl Default for AdvancedPrivacyConfig {
fn default() -> Self {
Self {
epsilon: 1.0,
delta: 1e-5,
mechanism: PrivacyMechanism::default(),
privacy_model: PrivacyModel::default(),
composition_method: CompositionMethod::default(),
adaptive_budgeting: true,
amplification_config: PrivacyAmplificationConfig::default(),
noise_config: NoiseDistributionConfig::default(),
}
}
}
impl Default for PrivacyAmplificationConfig {
fn default() -> Self {
Self {
subsampling_ratio: 0.1,
shuffling_enabled: true,
secure_aggregation_amplification: true,
sampling_method: SamplingMethod::default(),
}
}
}
impl Default for NoiseDistributionConfig {
fn default() -> Self {
Self {
noise_multiplier: 1.0,
clipping_norm: 1.0,
adaptive_clipping: true,
per_layer_scaling: false,
correlated_noise: false,
}
}
}
impl Default for PrivacyAccountingConfig {
fn default() -> Self {
Self {
accounting_method: PrivacyAccountingMethod::default(),
target_epsilon: 10.0,
target_delta: 1e-5,
max_rounds: 100,
privacy_loss_tracking: true,
composition_analysis: true,
}
}
}