Skip to content

Rényi-DP Accountant

director_ai.core.federated_privacy.rdp_accountant.RenyiAccountant

RenyiAccountant(*, orders: Sequence[float] | None = None)

Accumulate RDP across mechanisms and convert to (ε, δ)-DP.

The accountant holds one running RDP value per order in its grid. Each composed mechanism adds its per-order RDP; :meth:epsilon then converts the accumulated curve to the tightest (ε, δ)-DP bound over the grid.

Parameters:

Name Type Description Default
orders Sequence[float] | None

The Rényi orders to track. Defaults to the standard grid. All orders must be strictly greater than one.

None

orders property

orders: tuple[float, ...]

The Rényi orders tracked by this accountant.

rdp_curve

rdp_curve() -> tuple[float, ...]

The accumulated RDP value at each tracked order.

rdp_at

rdp_at(order: float) -> float

The accumulated RDP at a specific tracked order.

compose_gaussian

compose_gaussian(*, noise_multiplier: float, steps: int = 1) -> RenyiAccountant

Compose steps applications of the Gaussian mechanism.

Adds steps · α / (2 z²) to the running RDP at every order α. Returns self so compositions can be chained.

compose_rdp

compose_rdp(rdp_per_order: Sequence[float]) -> RenyiAccountant

Compose a mechanism given its RDP at each tracked order.

rdp_per_order must align with :attr:orders. Use this for any mechanism whose per-order RDP is known (additive composition).

epsilon

epsilon(*, delta: float) -> DPGuarantee

Convert the accumulated RDP to the tightest (ε, δ)-DP bound.

For each order α the Mironov (2017, Prop. 3) bound is ε_RDP(α) + ln(1/δ) / (α − 1); the reported guarantee is the minimum over the grid (and the order achieving it).

An accountant with no composed mechanism (an all-zero RDP curve) is trivially (0, δ)-DP — nothing was released — so ε = 0 is reported directly rather than the spurious positive ln(1/δ) / (α − 1) residual the conversion formula would give at zero RDP mass.

total_rdp_mass

total_rdp_mass() -> float

Sum of the RDP curve — a scalar progress signal for budget displays.

Not a privacy quantity on its own (RDP is per-order); exposed only so a dashboard can show monotone budget consumption without leaking the curve.

director_ai.core.federated_privacy.rdp_accountant.gaussian_rdp

gaussian_rdp(order: float, noise_multiplier: float) -> float

RDP of the Gaussian mechanism at a single order.

Parameters:

Name Type Description Default
order float

The Rényi order α; must be strictly greater than one.

required
noise_multiplier float

z = σ / Δ — the Gaussian noise standard deviation in units of the query's L2 sensitivity. z = 0 (no noise) has unbounded RDP, returned as math.inf.

required

Returns:

Type Description
float

α / (2 z²) — the Gaussian-mechanism RDP at order α.

director_ai.core.federated_privacy.rdp_accountant.DPGuarantee dataclass

DPGuarantee(epsilon: float, delta: float, order: float)

The (ε, δ)-DP guarantee converted from the accumulated RDP.

to_dict

to_dict() -> dict[str, float]

Tenant-safe view of the converted guarantee.

Boundary

RenyiAccountant tracks Rényi differential privacy (RDP) at a grid of orders and converts to an (ε, δ)-DP guarantee at release time. It is the tight route for composing many applications of the Gaussian mechanism — DP decoding and DP score release — where the (ε, δ) PrivacyAccountant's basic (linear) and advanced (Dwork-Rothblum-Vadhan) composition are loose.

Use PrivacyAccountant for pure-ε Laplace queries (such as DP retrieval ranking) and RenyiAccountant for Gaussian-mechanism pipelines that compose over many rounds.

from director_ai.core.federated_privacy import RenyiAccountant

accountant = RenyiAccountant()
# 50 rounds of the Gaussian mechanism at noise multiplier z = σ/Δ = 4.0.
accountant.compose_gaussian(noise_multiplier=4.0, steps=50)

guarantee = accountant.epsilon(delta=1e-5)
print(guarantee.epsilon, guarantee.order)

Mathematics

All formulae are the published RDP results (Mironov, Rényi Differential Privacy, CSF 2017); no constants are fabricated.

Step Result
Gaussian RDP A query with L2-sensitivity Δ perturbed by N(0, σ²) is (α, α·Δ²/(2σ²))-RDP for every α > 1. With noise multiplier z = σ/Δ this is α/(2z²).
Composition RDP is additive at a fixed order: (α, ε₁) ∘ (α, ε₂) = (α, ε₁ + ε₂)-RDP.
Conversion An (α, ε_RDP)-RDP mechanism is (ε_RDP + ln(1/δ)/(α − 1), δ)-DP. The reported ε is the minimum of that bound over the order grid.

The default order grid is the de-facto standard: fractional orders 1.1 … 10.9 plus integer orders 11 … 63. total_rdp_mass() exposes a monotone scalar for budget displays; it is not itself a privacy quantity (RDP is per-order) and leaks no curve detail.