Skip to content

Federated-DP Evidence

director_ai.core.federated_dp.evidence.FederatedDPEvidence

FederatedDPEvidence(calibration_round: FederatedCalibrationRound)

Produce formal-privacy and poisoning-resilience evidence for a round.

Parameters:

Name Type Description Default
calibration_round FederatedCalibrationRound

The :class:FederatedCalibrationRound whose parameters (clip norm, noise multiplier, learning rate) drive the evidence.

required

effective_noise_multiplier property

effective_noise_multiplier: float

The cohort-independent Gaussian noise multiplier z = m / 2.

epsilon_bound

epsilon_bound(*, delta: float, rounds: int | None = None) -> DPGuarantee

Formal (ε, δ)-DP bound for the applied (or requested) rounds.

Composes the per-round Gaussian mechanism at the effective noise multiplier with the Rényi-DP accountant and converts at δ. rounds defaults to the round's :attr:rounds_applied.

poisoning_bound

poisoning_bound(*, num_malicious: int, cohort_size: int, rounds: int | None = None) -> PoisoningBound

Certified worst-case parameter shift for num_malicious attackers.

evidence_packet

evidence_packet(*, delta: float, num_malicious: int, cohort_size: int, rounds: int | None = None) -> FederatedDPEvidencePacket

Combine the formal (ε, δ) bound and the poisoning bound.

simulate_poisoning

simulate_poisoning(*, num_malicious: int, cohort_size: int, honest_update: float, rounds: int, attacker_update: float | None = None, seed: int = 0) -> PoisoningSimulation

Run an attacked trajectory against an all-honest baseline.

num_malicious attackers submit attacker_update (default +clip_norm, the maximally adversarial value); the remaining tenants and the whole baseline cohort submit honest_update. Both trajectories share the noise seed, so the Gaussian noise cancels in the difference and the observed shift is purely the poisoning effect. The result is checked against the certified bound.

director_ai.core.federated_dp.evidence.FederatedDPEvidencePacket dataclass

FederatedDPEvidencePacket(rounds: int, noise_multiplier: float, effective_noise_multiplier: float, epsilon: float, delta: float, rdp_order: float, poisoning: PoisoningBound)

Combined formal-privacy and poisoning-resilience evidence for a round.

to_dict

to_dict() -> dict[str, object]

Tenant-safe view of the whole evidence packet.

director_ai.core.federated_dp.evidence.PoisoningBound dataclass

PoisoningBound(num_malicious: int, cohort_size: int, clip_norm: float, learning_rate: float, rounds: int, per_round_shift: float, total_shift: float)

The certified worst-case parameter shift a malicious coalition can induce.

fraction_malicious property

fraction_malicious: float

Fraction of the cohort controlled by the coalition.

to_dict

to_dict() -> dict[str, float | int]

Tenant-safe view of the certified bound.

director_ai.core.federated_dp.evidence.PoisoningSimulation dataclass

PoisoningSimulation(bound: PoisoningBound, observed_shift: float, baseline_value: float, attacked_value: float)

The observed vs certified poisoning shift from a simulated attack.

within_bound property

within_bound: bool

Whether the observed shift stayed within the certified bound.

to_dict

to_dict() -> dict[str, object]

Tenant-safe view of the simulation outcome.

Boundary

FederatedCalibrationRound aggregates clipped per-tenant updates under Gaussian noise. Before a regulated deployment trusts that cross-tenant calibration, it needs two pieces of evidence — this module produces both from the round's parameters.

Formal (ε, δ) bound

The clipped mean has L2 sensitivity 2·C / n to one tenant (C the clip norm, n the cohort); the noise added to the mean is N(0, (m·C / n)²) for noise multiplier m, so the effective noise multiplier is z = m / 2, independent of cohort size. Composing R rounds at z with the Rényi-DP accountant and converting at δ gives the formal bound — the tight composition, not the loose basic/advanced (ε, δ) sum.

Poisoning bound

Clipping is what makes the aggregate poisoning-resilient. A coalition of f malicious tenants out of n can move the clipped mean by at most 2·f·C / n per round (each can swing its clipped contribution across the full [-C, C] range), so the certified worst-case parameter shift is lr · 2·f·C / n per round and R times that over R rounds. Without clipping a single tenant could move the parameter without bound; the certificate is the resilience guarantee.

simulate_poisoning runs an attacked trajectory against an all-honest baseline with a shared noise seed (so the noise cancels and the residual is purely the poisoning effect) and confirms the observed shift stays within the certificate.

from director_ai.core.federated_dp import FederatedCalibrationRound, FederatedDPEvidence

round_ = FederatedCalibrationRound(0.6, clip_norm=0.1, noise_multiplier=1.0)
evidence = FederatedDPEvidence(round_)

packet = evidence.evidence_packet(delta=1e-5, num_malicious=2, cohort_size=10, rounds=10)
print(packet.epsilon, packet.poisoning.total_shift)

sim = evidence.simulate_poisoning(
    num_malicious=2, cohort_size=10, honest_update=0.0, rounds=10
)
assert sim.within_bound

ProductionGuard.federated_dp_evidence() builds one over a calibration round (the guard's default round, or one passed in).