Skip to main content

Compute f-DP trade-off curves and calibrate differentially private algorithms to operational privacy risk measures

Project description

riskcal

pypi docs CI arXiv arXiv


⚠️ This is a research prototype. Avoid or be extra careful when using in production.


The library provides tools for computing f-DP trade-off curves for differentially private algorithms, and calibrating their noise scale to operational privacy risk measures (attack advantage, or attack TPR and FPR). The library enables reducing noise scale while maintaining the same level of targeted attack risk.

Background

Privacy risk and f-DP

Differential privacy (DP) protects against information leakage from machine learning models, datasets, and statistical releases by adding controlled random noise. Traditional DP uses epsilon-delta parameters that are difficult to interpret. In practice, we want to understand privacy in terms of concrete attack risks membership inference, re-identification, and attribute reconstruction.

f-Differential privacy (f-DP) directly quantifies these attack risks using:

  • Trade-off curve: False positive rate (FPR, alpha) vs. false negative rate (FNR, beta) for the worst-case attacker. Note that true positive rate (TPR) is 1 - beta.
  • Advantage: Maximum value of TPR - FPR = 1 - beta - alpha, achieved at the optimal threshold. This bound is also known as total variation (TV) privacy.

The f-DP trade-off curve and advantage correspond directly to operational attack metrics:

Measure Membership Inference Singling out / Reconstruction / Attribute Inference
Trade-off curve (beta/alpha) Min FNR at FPR Max success probability bounded by TPR at baseline alpha
Advantage Max TPR - FPR Max probability increase over baseline

See Kulynych & Gomez et al. (2024)[^1] for membership inference and Kulynych et al. (2025)[^2] for the unified framework connecting re-identification, attribute inference, and reconstruction.

Methods

The library implements methods described by Kulynych & Gomez et al., 2024[^1].

  • The direct method for computing the trade-off curve based on privacy loss random variables is described in Algorithm 1.
  • The mapping between f-DP and operational privacy risk, and the idea of direct noise calibration to risk instead of the standard calibration to a given (epsilon, delta) is described in Sections 2 and 3.

References

[^1]: Attack-Aware Noise Calibration for Differential Privacy. NeurIPS 2024. [^2]: Unifying Re-Identification, Attribute Inference, and Data Reconstruction Risks in Differential Privacy. NeurIPS 2025.

If you make use of the library or methods, please cite:

@article{kulynych2024attack,
  title={Attack-Aware Noise Calibration for Differential Privacy},
  author={Kulynych, Bogdan and Gomez, Juan Felipe and Kaissis, Georgios and du Pin Calmon, Flavio and Troncoso, Carmela},
  journal={Advances in Neural Information Processing Systems},
  volume={37},
  year={2024}
}

@article{kulynych2025unifying,
  title={Unifying Re-Identification, Attribute Inference, and Data Reconstruction Risks in Differential Privacy},
  author = {Kulynych, Bogdan and Gomez, Juan Felipe and Kaissis, Georgios and Hayes, Jamie and Balle, Borja and du Pin Calmon, Flavio and Raisaro, Jean Louis},
  journal={Advances in Neural Information Processing Systems},
  volume={38},
  year={2025}
}

Installation

Install with pip:

pip install riskcal

For local development, clone the repository and run:

uv sync --dev

Quickstart

Analysis and Conversions

The library supports computing privacy risk metrics from different privacy representations:

Source Privacy Notion Trade-off (f-DP) Advantage (TV) Bayes Risk
PLD (Privacy Loss Distribution)
GDP (Gaussian DP)
ADP (Approximate DP) ✓* ✓*
RDP (Renyi DP)
zCDP (Zero-Concentrated DP)
  • The conversion from a single pair of (epsilon, delta)-ADP guarantees is very lossy for most mechanisms[^1]. For meaningful risk bounds, use other available representations.

Minimal Example. Here's a complete example showing how to evaluate privacy risk for a simple mechanism:

from riskcal import analysis
from dp_accounting.pld.privacy_loss_distribution import from_gaussian_mechanism

# Create a Gaussian mechanism with noise scale 1.0
pld = from_gaussian_mechanism(1.0)

# What's the worst-case attack advantage?
advantage = analysis.get_advantage_from_pld(pld)
print(f"Maximum attack advantage: {advantage:.3f}")

# What's the maximum attack TPR at 1% FPR?
beta = analysis.get_beta_from_pld(pld, alpha=0.01)
tpr_bound = 1 - beta
print(f"Max TPR at 1% FPR: {tpr_bound:.3f}")

Computing Trade-Off Curves. The trade-off curve shows the relationship between false positive rate (FPR, alpha) and false negative rate (FNR, beta) for the worst-case attacker. For DP-SGD:

from riskcal.analysis import get_beta_from_pld
from dp_accounting.pld import privacy_loss_distribution as pld_module
import numpy as np

# DP-SGD parameters
noise_multiplier = 0.5
sample_rate = 0.002
num_steps = 10000

# Create PLD for DP-SGD using composition
pld = pld_module.from_gaussian_mechanism(
    standard_deviation=noise_multiplier,
    sampling_prob=sample_rate,
    use_connect_dots=True,
).self_compose(num_steps)

# Compute FNR (beta) at various FPR (alpha) values
alpha = np.array([0.01, 0.05, 0.1])
beta = get_beta_from_pld(pld, alpha=alpha)
print(f"Trade-off curve: {list(zip(alpha, beta))}")

You can also use the Opacus-compatible accountant for easier integration with DP-SGD training:

from riskcal.accountants import CTDAccountant
import numpy as np

# Track privacy over training
acct = CTDAccountant()
noise_multiplier = 0.5
sample_rate = 0.002
num_steps = 100
for _ in range(num_steps):
    acct.step(noise_multiplier=noise_multiplier, sample_rate=sample_rate)

# Get the trade-off curve
alpha = np.array([0.01, 0.05, 0.1])
beta = acct.get_beta(alpha=alpha)

# Get the maximum advantage
advantage = acct.get_advantage()
print(f"Maximum attack advantage: {advantage:.3f}")

The library works with any DP mechanism supported supported by dp_accounting library, e.g., arbitrary adaptive compositions of (Subsampled) Gaussian, Discrete Gaussian, Laplace mechanisms:

from riskcal.analysis import get_beta_from_pld, get_advantage_from_pld
from dp_accounting.pld.privacy_loss_distribution import from_gaussian_mechanism, from_laplace_mechanism

# Compose multiple mechanisms
pld = from_gaussian_mechanism(1.0).compose(from_laplace_mechanism(0.5))

# Analyze the composed mechanism
advantage = get_advantage_from_pld(pld)
beta = get_beta_from_pld(pld, alpha=0.1)
print(f"Advantage: {advantage:.3f}, Beta at alpha=0.1: {beta:.3f}")

Gaussian Differential Privacy (GDP). Gaussian differential privacy tightly characterizes many DP mechanisms based on the Gaussian mechanism or its composition. For a given GDP parameter mu, get the advantage and the trade-off curve:

from riskcal.analysis import get_advantage_from_gdp, get_beta_from_gdp
import numpy as np

mu = 2.0  # GDP parameter

# Get advantage directly from mu
advantage = get_advantage_from_gdp(mu)

# Get trade-off curve
alpha = np.linspace(0, 1, 100)
beta = get_beta_from_gdp(mu, alpha)

This is faster than PLD-based computation.See also a dedicated library for privacy accounting of DP mechanisms in terms of GDP, gdpnum.

Zero-Concentrated Differential Privacy (zCDP) and Renyi DP (RDP). Zero-Concentrated Differential Privacy (zCDP) is characterized by a single parameter rho. Renyi DP is parameterized by an epsilon value at a specific divergence order.

Get the trade-off curve from zCDP:

from riskcal.analysis import get_advantage_from_zcdp, get_beta_from_zcdp
import numpy as np

rho = 0.5  # zCDP parameter

# Get advantage directly from rho
advantage = get_advantage_from_zcdp(rho)
print(f"Maximum attack advantage: {advantage:.3f}")

# Get trade-off curve for various FPR values
alpha = np.linspace(0.01, 0.1, 10)
beta = get_beta_from_zcdp(rho, alpha)
print(f"Trade-off curve: {list(zip(alpha, beta))}")

Get the trade-off curve from RDP:

from riskcal.analysis import get_beta_from_rdp
import numpy as np

epsilon = 1.0  # Renyi divergence parameter
order = 2.0    # Renyi divergence order (alpha in Renyi DP literature)

# Get FNR at specific FPR
beta = get_beta_from_rdp(epsilon=epsilon, alpha=0.1, order=order)
print(f"Beta (FNR) at alpha=0.1: {beta:.3f}")

Computing Bayes Risk. Bayes risk measures the maximum accuracy of attacks under a binary prior. This is useful for attribute inference (assuming a record has one of two attributes) or membership inference (with a prior probability of membership):

from riskcal.analysis import get_bayes_risk_from_pld
from dp_accounting.pld.privacy_loss_distribution import from_laplace_mechanism
import numpy as np

pld = from_laplace_mechanism(1.0)

# Compute attack accuracy for different prior probabilities
prior = np.array([0.5, 0.8, 0.95])
risk = get_bayes_risk_from_pld(pld, prior=prior)
print(f"Bayes risk at priors {prior}: {risk}")

Calibration

You can directly calibrate noise to bound attack success rates.

Calibrating Noise for DP-SGD. Calibrate to maximum attack advantage:

from riskcal.calibration.dpsgd import find_noise_multiplier_for_advantage

sample_rate = 0.002
num_steps = 10000

# Find noise multiplier that bounds advantage at 10%
noise_multiplier = find_noise_multiplier_for_advantage(
    advantage=0.1,
    sample_rate=sample_rate,
    num_steps=num_steps,
)
print(f"Required noise multiplier: {noise_multiplier:.3f}")

Calibrate to bound attack TPR at a specific FPR:

from riskcal.calibration.dpsgd import find_noise_multiplier_for_err_rates

# Bound attack to max 5% TPR at 1% FPR
noise_multiplier = find_noise_multiplier_for_err_rates(
    beta=0.95,  # FNR = 1 - TPR = 1 - 0.05
    alpha=0.01,  # FPR
    sample_rate=0.002,
    num_steps=10000,
    grid_step=1e-2,  # Lower resolution for the sake of running the example faster.
)
print(f"Required noise multiplier: {noise_multiplier:.3f}")

Calibrating Generic Mechanisms. For custom mechanisms beyond DP-SGD, use the generic calibration framework. You provide an evaluator function that computes privacy metrics for a given parameter value:

from riskcal.calibration.core import (
    calibrate_parameter,
    PrivacyEvaluator,
    PrivacyMetrics,
    CalibrationTarget,
    CalibrationConfig,
)
from riskcal.analysis import get_advantage_from_pld, get_beta_from_pld
from dp_accounting.pld.privacy_loss_distribution import from_laplace_mechanism

# Define evaluator for Laplace mechanism
def evaluate_laplace(scale: float) -> PrivacyMetrics:
    """Compute privacy metrics for Laplace mechanism with given scale."""
    pld = from_laplace_mechanism(sensitivity=1.0, parameter=scale)
    advantage = get_advantage_from_pld(pld)
    beta = get_beta_from_pld(pld, alpha=0.01)  # For FPR=1%
    return PrivacyMetrics(advantage=advantage, alpha=0.01, beta=beta)

# Calibrate to advantage target
target = CalibrationTarget(kind="advantage", advantage=0.1)
config = CalibrationConfig(param_min=0.1, param_max=30.0, increasing=False)
result = calibrate_parameter(
    evaluator=evaluate_laplace,
    target=target,
    config=config,
    parameter_name="scale"
)
print(f"Required Laplace scale: {result.parameter_value:.3f}")
print(f"Achieved advantage: {result.achieved_advantage:.3f}")

This approach works with any mechanism where you can compute privacy metrics as a function of a tunable parameter (noise scale, sampling rate, etc.).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

riskcal-1.5.0.tar.gz (211.7 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

riskcal-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (739.4 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

riskcal-1.5.0-cp313-cp313-macosx_11_0_arm64.whl (295.9 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

riskcal-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl (298.4 kB view details)

Uploaded CPython 3.13macOS 10.13+ x86-64

riskcal-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (744.6 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

riskcal-1.5.0-cp312-cp312-macosx_11_0_arm64.whl (296.6 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

riskcal-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl (298.9 kB view details)

Uploaded CPython 3.12macOS 10.13+ x86-64

File details

Details for the file riskcal-1.5.0.tar.gz.

File metadata

  • Download URL: riskcal-1.5.0.tar.gz
  • Upload date:
  • Size: 211.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for riskcal-1.5.0.tar.gz
Algorithm Hash digest
SHA256 f8343eb75c7422f1d7c4bec589734e655d73d8e6b331dcbe66484ab15eeed70c
MD5 8fc6ff4207817ff83757db525334bcf9
BLAKE2b-256 8fb21255ec6ad921a3d7bd3d03e27f456dabba9c59db0b249d8b5e847190b418

See more details on using hashes here.

File details

Details for the file riskcal-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

  • Download URL: riskcal-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  • Upload date:
  • Size: 739.4 kB
  • Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for riskcal-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 eff959ff85ff02aad5592ce9a9f4e6994c701213f74563d2361e91a6fa8e823d
MD5 59bbba3e7b2c706d988419d0ad7a2255
BLAKE2b-256 6ceb1f7892820831d593b0e4e762c80a7b46909370a5b0c7fb64a8d253d73932

See more details on using hashes here.

File details

Details for the file riskcal-1.5.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

  • Download URL: riskcal-1.5.0-cp313-cp313-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 295.9 kB
  • Tags: CPython 3.13, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for riskcal-1.5.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4cc2642e99c7c50fe9f22a4b478254ae5335c25cc903503808de5852cadff796
MD5 7cac08eff149b07f34ea5882e6ec200e
BLAKE2b-256 14a833d0909fb826d3a2c080fa4b30a3f520089df49de9b2f3a69d9de6bd3f0d

See more details on using hashes here.

File details

Details for the file riskcal-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl.

File metadata

  • Download URL: riskcal-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl
  • Upload date:
  • Size: 298.4 kB
  • Tags: CPython 3.13, macOS 10.13+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for riskcal-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 01e36610d9c9cd04192c34cb2dcc8196dee517def8edf2b57f4b5ff293688a8f
MD5 012c8eea18da42167b188655f4de06cc
BLAKE2b-256 06529996d8db758c326281c2c6924750c186212f4c7e9bc794ec659b768b0f60

See more details on using hashes here.

File details

Details for the file riskcal-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

  • Download URL: riskcal-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  • Upload date:
  • Size: 744.6 kB
  • Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for riskcal-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f22c862c6b427a058ae5f2f9cd23430c52528f84972ed984862f7985925b0f55
MD5 43b2077c236b92180a679d2bd4357b5c
BLAKE2b-256 87eddc7c0447ccca90986a63d52e883a61a36901f89a3a824f16f30d2480d766

See more details on using hashes here.

File details

Details for the file riskcal-1.5.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

  • Download URL: riskcal-1.5.0-cp312-cp312-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 296.6 kB
  • Tags: CPython 3.12, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for riskcal-1.5.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4baf89c9b48feb76ad66400582d59feb71d0392474d763e657cfa2180f9ed594
MD5 cd42b434022d845be8adb80168756245
BLAKE2b-256 163952200ee39048bef328636c8eeac1a39ec9ba0d17563b39a6f628f067ea81

See more details on using hashes here.

File details

Details for the file riskcal-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl.

File metadata

  • Download URL: riskcal-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl
  • Upload date:
  • Size: 298.9 kB
  • Tags: CPython 3.12, macOS 10.13+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for riskcal-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 768e9e77bf0dcec5133f99bc88efd972820173040133bcdab628937394f93a41
MD5 704d79eebfca0399d14e4affb2bd1071
BLAKE2b-256 cbe9a56526fb637b6ca418a03a2d9e3c89b8a25c27a57cd18a8f156721386070

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page