Privacy-Preserving AI Fundamentals

Understanding the mathematical and conceptual foundations of privacy-preserving AI is essential for building compliant, secure, and effective machine learning systems. This guide covers the core principles that enable AI development without compromising individual privacy.

🎯 The Privacy Challenge in AI

Why Traditional Approaches Fail

# Traditional ML approach - Privacy risks
traditional_model = train_model(raw_sensitive_data)
# Problems:
# 1. Model memorizes training examples
# 2. Vulnerable to membership inference attacks  
# 3. Cannot share model without sharing data insights
# 4. Regulatory compliance impossible
 
# Privacy-preserving approach
private_model = train_with_differential_privacy(
    data=raw_sensitive_data,
    epsilon=1.0,  # Privacy budget
    delta=1e-5    # Failure probability
)
# Benefits:
# 1. Mathematical privacy guarantees
# 2. Safe to share and deploy
# 3. Compliant with regulations
# 4. Quantifiable privacy loss

🔐 Core Privacy Concepts

1. Differential Privacy

The gold standard for privacy protection with mathematical guarantees:

# Differential Privacy Definition
# A mechanism M is (ε, δ)-differentially private if:
# P[M(D) ∈ S] ≤ e^ε × P[M(D') ∈ S] + δ
# for all neighboring datasets D and D' (differ by one record)
 
class DifferentialPrivacy:
    def __init__(self, epsilon: float, delta: float):
        self.epsilon = epsilon  # Privacy loss parameter
        self.delta = delta      # Failure probability
        
    def add_noise(self, value: float, sensitivity: float) -> float:
        """Add calibrated noise for privacy"""
        # Laplace mechanism for pure DP
        scale = sensitivity / self.epsilon
        noise = np.random.laplace(0, scale)
        return value + noise
    
    def privacy_budget_consumed(self, queries: int) -> float:
        """Track cumulative privacy loss"""
        # Sequential composition
        return queries * self.epsilon

2. Synthetic Data Generation

Creating artificial data that preserves statistical properties:

# Three main approaches to synthetic data
 
# 1. Statistical Methods
class StatisticalSynthesizer:
    def fit(self, real_data):
        # Learn marginal distributions
        self.marginals = compute_marginals(real_data)
        # Learn correlations
        self.correlations = compute_correlations(real_data)
    
    def sample(self, n_samples):
        # Generate from learned distributions
        return sample_from_copula(self.marginals, self.correlations, n_samples)
 
# 2. Deep Learning Methods (GANs)
class CTGANSynthesizer:
    def __init__(self):
        self.generator = Generator()
        self.discriminator = Discriminator()
    
    def train(self, real_data):
        # Adversarial training
        for epoch in range(epochs):
            # Train discriminator
            d_loss = discriminator_step(real_data)
            # Train generator
            g_loss = generator_step()
 
# 3. Language Model Methods
class LLMSynthesizer:
    def generate(self, schema, n_samples):
        prompt = f"Generate {n_samples} rows matching: {schema}"
        return parse_llm_output(llm.generate(prompt))

3. Federated Learning

Training models without centralizing data:

# Federated Learning Architecture
class FederatedLearning:
    def __init__(self, clients, aggregator):
        self.clients = clients
        self.aggregator = aggregator
    
    def train_round(self, global_model):
        # Step 1: Distribute model
        for client in self.clients:
            client.receive_model(global_model)
        
        # Step 2: Local training
        client_updates = []
        for client in self.clients:
            local_update = client.train_locally()
            # Add privacy protection
            private_update = add_dp_noise(local_update)
            client_updates.append(private_update)
        
        # Step 3: Secure aggregation
        global_update = self.aggregator.aggregate(client_updates)
        return global_model + global_update

📊 Privacy Metrics and Guarantees

Measuring Privacy Loss

class PrivacyAccountant:
    def __init__(self):
        self.epsilon_total = 0
        self.delta_total = 0
    
    def compose_gaussian(self, sigma: float, num_steps: int) -> tuple:
        """Compute privacy loss for Gaussian mechanism"""
        # Using Rényi Differential Privacy
        orders = np.arange(2, 100)
        rdp = compute_rdp(sigma, num_steps, orders)
        eps, delta = get_privacy_spent(orders, rdp, target_delta=1e-5)
        return eps, delta
    
    def validate_privacy_budget(self, epsilon_limit: float):
        """Ensure we stay within privacy budget"""
        if self.epsilon_total > epsilon_limit:
            raise PrivacyBudgetExceeded(
                f"Used {self.epsilon_total:.2f} > limit {epsilon_limit}"
            )

Utility vs Privacy Trade-off

# Optimizing the privacy-utility trade-off
def optimize_privacy_utility(
    task_accuracy_requirement: float,
    privacy_budget: float
) -> dict:
    
    configs = []
    for epsilon in np.logspace(-2, 1, 20):
        for clip_norm in [0.1, 0.5, 1.0, 2.0]:
            accuracy = estimate_accuracy(epsilon, clip_norm)
            if accuracy >= task_accuracy_requirement:
                configs.append({
                    'epsilon': epsilon,
                    'clip_norm': clip_norm,
                    'accuracy': accuracy,
                    'privacy_score': 1.0 / epsilon
                })
    
    # Return config with best privacy for required accuracy
    return max(configs, key=lambda x: x['privacy_score'])

🧮 Mathematical Foundations

Key Concepts

1. Sensitivity

The maximum change in output when changing one record:

def compute_sensitivity(function, dataset):
    """Global sensitivity for differential privacy"""
    max_difference = 0
    
    for i in range(len(dataset)):
        # Dataset with record i
        output_with = function(dataset)
        
        # Dataset without record i  
        dataset_without = dataset.drop(i)
        output_without = function(dataset_without)
        
        difference = abs(output_with - output_without)
        max_difference = max(max_difference, difference)
    
    return max_difference

2. Privacy Amplification

Boosting privacy through sampling:

def privacy_amplification_by_sampling(
    population_size: int,
    sample_size: int,
    base_epsilon: float
) -> float:
    """Compute amplified epsilon for random sampling"""
    sampling_rate = sample_size / population_size
    
    # For small sampling rates
    if sampling_rate < 0.01:
        return 2 * sampling_rate * base_epsilon
    else:
        # General formula
        return np.log(1 + sampling_rate * (np.exp(base_epsilon) - 1))

3. Composition Theorems

Privacy loss accumulates over multiple accesses:

class CompositionTheorems:
    @staticmethod
    def basic_composition(epsilons: list) -> float:
        """Basic composition: ε_total = Σε_i"""
        return sum(epsilons)
    
    @staticmethod
    def advanced_composition(epsilon: float, delta: float, k: int) -> tuple:
        """Advanced composition for k mechanisms"""
        epsilon_total = epsilon * np.sqrt(2 * k * np.log(1/delta)) + k * epsilon * (np.exp(epsilon) - 1)
        delta_total = k * delta
        return epsilon_total, delta_total

🛡️ Privacy-Preserving Techniques

1. Secure Multi-Party Computation (SMPC)

# Secret sharing for secure computation
class SecretSharing:
    def __init__(self, num_parties: int, threshold: int):
        self.num_parties = num_parties
        self.threshold = threshold
    
    def share_secret(self, secret: int) -> list:
        """Split secret into shares"""
        # Shamir's secret sharing
        coefficients = [secret] + [
            random.randint(0, PRIME) 
            for _ in range(self.threshold - 1)
        ]
        
        shares = []
        for i in range(1, self.num_parties + 1):
            share = sum(
                coef * (i ** power) % PRIME
                for power, coef in enumerate(coefficients)
            ) % PRIME
            shares.append((i, share))
        
        return shares

2. Homomorphic Encryption

# Computing on encrypted data
import tenseal as ts
 
# Create context with encryption parameters
context = ts.context(
    ts.SCHEME_TYPE.CKKS,
    poly_modulus_degree=8192,
    coeff_mod_bit_sizes=[60, 40, 40, 60]
)
 
# Encrypt data
plain_vector = [1.5, 2.3, 3.7, 4.1]
encrypted_vector = ts.ckks_vector(context, plain_vector)
 
# Compute on encrypted data
result = encrypted_vector * 2 + 1  # Operations on ciphertext
 
# Decrypt result (only with secret key)
decrypted_result = result.decrypt()

3. Private Set Intersection

class PrivateSetIntersection:
    def __init__(self):
        self.hash_functions = generate_hash_functions(k=3)
    
    def compute_intersection(self, set_a: set, set_b: set) -> int:
        """Compute size of intersection without revealing elements"""
        # Using bloom filters for privacy
        bloom_a = BloomFilter(set_a, self.hash_functions)
        bloom_b = BloomFilter(set_b, self.hash_functions)
        
        # Secure computation of intersection
        intersection_size = secure_and(bloom_a, bloom_b).count_ones()
        
        # Add differential privacy noise
        noisy_size = add_laplace_noise(intersection_size, sensitivity=1)
        
        return max(0, int(noisy_size))

🚀 Implementation Best Practices

1. Start with Threat Modeling

@dataclass
class PrivacyThreatModel:
    adversary_capabilities: List[str]
    protected_attributes: List[str]
    acceptable_risk_level: float
    compliance_requirements: List[str]
    
    def select_techniques(self) -> List[str]:
        techniques = []
        
        if "membership_inference" in self.adversary_capabilities:
            techniques.append("differential_privacy")
        
        if "data_reconstruction" in self.adversary_capabilities:
            techniques.append("synthetic_data")
        
        if "model_inversion" in self.adversary_capabilities:
            techniques.append("homomorphic_encryption")
        
        return techniques

2. Privacy-First Architecture

class PrivacyFirstPipeline:
    def __init__(self, privacy_budget: float):
        self.privacy_accountant = PrivacyAccountant()
        self.privacy_budget = privacy_budget
    
    def preprocess_with_privacy(self, data):
        # Remove direct identifiers
        data = remove_pii(data)
        
        # Generalize quasi-identifiers
        data = generalize_attributes(data, k=5)
        
        # Add noise to sensitive attributes
        data = add_differential_privacy_noise(data, epsilon=0.1)
        
        return data
    
    def train_private_model(self, data):
        # Use DP-SGD for training
        model = create_model()
        optimizer = DPOptimizer(
            base_optimizer=tf.optimizers.Adam(),
            noise_multiplier=1.1,
            l2_norm_clip=1.0
        )
        
        return train_with_privacy(model, data, optimizer)

3. Continuous Privacy Monitoring

class PrivacyMonitor:
    def __init__(self):
        self.metrics = defaultdict(list)
    
    def log_privacy_event(self, event_type: str, epsilon_spent: float):
        self.metrics['epsilon_consumed'].append(epsilon_spent)
        self.metrics['total_epsilon'] = sum(self.metrics['epsilon_consumed'])
        
        # Alert if approaching budget
        if self.metrics['total_epsilon'] > 0.8 * PRIVACY_BUDGET:
            send_alert("Approaching privacy budget limit!")
    
    def generate_privacy_report(self) -> dict:
        return {
            'total_epsilon_spent': self.metrics['total_epsilon'],
            'queries_processed': len(self.metrics['epsilon_consumed']),
            'average_epsilon_per_query': np.mean(self.metrics['epsilon_consumed']),
            'privacy_guarantee': f"({self.metrics['total_epsilon']:.2f}, 1e-5)-DP"
        }

🔗 Next Steps

📖 References

  • Dwork & Roth, “The Algorithmic Foundations of Differential Privacy” (2014)
  • Abadi et al., “Deep Learning with Differential Privacy” (2016)
  • Li et al., “Federated Learning: Challenges, Methods, and Future Directions” (2020)
  • Google’s Differential Privacy Library

← Back to Synthetic Data & Privacy | Differential Privacy →