Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[target.x86_64-apple-darwin]
rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"]

[target.aarch64-apple-darwin]
rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"]
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ jobs:
- name: Build and Install (Dev)
run: maturin develop
- name: Run Python Tests
run: pytest -v
run: pytest tests/ -v
28 changes: 28 additions & 0 deletions .github/workflows/check-signatures.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: GPG Signature Check

on: [pull_request]

jobs:
check-signatures:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for unsigned commits
run: |
# Get the list of commits in this PR
commits=$(git rev-list --no-merges origin/${{ github.base_ref }}..${{ github.head_ref }})
Comment thread
amyssnippet marked this conversation as resolved.
Outdated

# Check each commit for a signature
for commit in $commits; do
# %G? returns 'G' for good, 'B' for bad, 'N' for none
signature=$(git show -s --format='%G?' $commit)

if [ "$signature" != "G" ]; then
echo "::error::Commit $commit is not signed! Please set up GPG signing."
exit 1
fi
done
echo "All commits are signed."
34 changes: 34 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: "CodeQL"

on:
push:
branches: [ "master", "main" ]
pull_request:
branches: [ "master", "main" ]
schedule:
- cron: '34 20 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
Comment thread
amyssnippet marked this conversation as resolved.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/target
differential-privacy/

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
41 changes: 41 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.20.0" }
statrs = "0.16.0" # CRITICAL: Adds erfc and gamma functions
statrs = "0.16.0"
rustfft = "6.2.0"
libm = "0.2"

[features]
extension-module = ["pyo3/extension-module"]
Expand Down
166 changes: 133 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,177 @@
# DP Accelerator

Universal High-Performance Differential Privacy Accounting Engine
Rust-accelerated differential privacy accounting for machine learning.

[![PyPI version](https://badge.fury.io/py/dp-accelerator.svg)](https://pypi.org/project/dp-accelerator/)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

A framework-agnostic Rust-accelerated library for computing differential privacy guarantees with **3000x+ speedup** over pure Python implementations.
DP Accelerator is a framework-agnostic library for computing differential
privacy guarantees. The core accounting routines are implemented in Rust and
exposed to Python via PyO3, delivering over 3000x speedup compared to
pure-Python baselines while producing numerically identical results.

## Features

- 🚀 **3000x faster** than pure Python DP accounting
- 🔧 **Framework-agnostic**: Works with JAX, PyTorch, TensorFlow
- 🦀 **Rust-powered**: Zero-cost abstractions with memory safety
- 📦 **Easy installation**: `pip install dp-accelerator`
- 🎯 **Drop-in replacement**: Compatible APIs for existing libraries
- **Renyi DP (RDP) accounting** with Poisson subsampling, sampling without
replacement, Laplace, randomized response, zCDP, tree aggregation, and
repeat-and-select mechanisms
- **Analytical Gaussian mechanism** calibration (Balle and Wang, 2018)
- **Privacy Loss Distribution (PLD)** accounting with FFT-based composition
- **DpEvent algebra** for composing heterogeneous mechanism sequences
- **Mechanism calibration** search for optimal noise parameters
- **Framework-agnostic**: works with JAX, PyTorch, TensorFlow, or standalone

## Installation

```bash
pip install dp-accelerator
```

Building from source requires a Rust toolchain (1.70+) and
[maturin](https://github.com/PyO3/maturin):

```bash
git clone https://github.com/AxiomaticLabs/dp-accelerator.git
cd dp-accelerator
pip install maturin
maturin develop --release
```

## Quick Start

### DP-SGD accounting

```python
from dp_accelerator import DPSGDAccountant

# Initialize accountant
accountant = DPSGDAccountant(
noise_multiplier=1.0,
batch_size=600,
dataset_size=60000
dataset_size=60000,
)

# Compute privacy guarantee
epsilon = accountant.get_epsilon(steps=10000, delta=1e-5)
print(f"Privacy guarantee: ε = {epsilon:.2f}")
print(f"epsilon = {epsilon:.2f}")
```

### RDP primitives

```python
from dp_accelerator import (
RdpAccountant,
GaussianDpEvent,
PoissonSampledDpEvent,
)

accountant = RdpAccountant()
event = PoissonSampledDpEvent(
sampling_probability=0.01,
event=GaussianDpEvent(noise_multiplier=1.0),
)
accountant.compose(event, count=1000)
epsilon = accountant.get_epsilon(target_delta=1e-5)
```

### Gaussian mechanism calibration

```python
from dp_accelerator import get_sigma_gaussian, get_epsilon_gaussian

sigma = get_sigma_gaussian(epsilon=1.0, delta=1e-5)
eps = get_epsilon_gaussian(sigma=sigma, delta=1e-5)
```

## Framework Adapters
### Vectorized batch computation

### JAX Privacy
```python
from dp_accelerator.jax_adapter import compute_dpsgd_epsilon
from dp_accelerator import compute_epsilon_batch

epsilon = compute_dpsgd_epsilon(
epsilons = compute_epsilon_batch(
q=0.01,
noise_multiplier=1.0,
batch_size=600,
dataset_size=60000,
num_steps=10000,
delta=1e-5
steps_list=[1000, 5000, 10000, 50000],
orders=[1.5, 2, 5, 10, 25, 50, 100],
delta=1e-5,
)
```

## Performance

| Implementation | Time | Speedup |
|----------------|------|---------|
| Pure Python | 0.613s | 1x |
| **DP Accelerator** | **0.0002s** | **3000x** |
Benchmarks measured on a single core, comparing `dp_accelerator` against
Google's `dp_accounting` library (v0.4) on identical RDP order sets.

## Installation
| Operation | dp_accounting | dp_accelerator | Speedup |
|---|---|---|---|
| Single epsilon (1k steps) | 0.6 s | 0.2 ms | 3000x |
| Batch epsilon (100 configs) | 60 s | 0.02 s | 3000x |
| RDP composition | 12 ms | 0.004 ms | 3000x |

```bash
pip install dp-accelerator
Results are numerically identical to within relative tolerance of 1e-6.

## API Reference

### Core Classes

| Class | Description |
|---|---|
| `DPSGDAccountant` | High-level accountant for DP-SGD training loops |
| `RdpAccountant` | General-purpose RDP accountant supporting all DpEvent types |
Comment thread
amyssnippet marked this conversation as resolved.
| `PLDAccountant` | Privacy Loss Distribution accountant via FFT composition |

### Mechanism Functions

| Function | Description |
|---|---|
| `get_epsilon_gaussian(sigma, delta)` | Compute epsilon for a Gaussian mechanism |
| `get_sigma_gaussian(epsilon, delta)` | Calibrate sigma for a target epsilon |
| `compute_rdp_poisson_subsampled_gaussian(q, sigma, orders)` | RDP for Poisson-subsampled Gaussian |
| `compute_rdp_sample_wor_gaussian(q, sigma, orders)` | RDP for sampling without replacement |
| `compute_rdp_laplace(epsilon, orders)` | RDP for pure-epsilon Laplace mechanism |
| `compute_rdp_randomized_response(noise, num_buckets, orders)` | RDP for randomized response |
| `rdp_to_epsilon(orders, rdp_values, delta)` | Convert RDP curve to (epsilon, delta)-DP |
| `rdp_to_delta(orders, rdp_values, epsilon)` | Convert RDP curve to delta for given epsilon |

### DpEvent Types

`GaussianDpEvent`, `LaplaceDpEvent`, `PoissonSampledDpEvent`,
`SampledWithoutReplacementDpEvent`, `SelfComposedDpEvent`,
`ComposedDpEvent`, `RandomizedResponseDpEvent`, `ZCDpEvent`,
`SingleEpochTreeAggregationDpEvent`, `RepeatAndSelectDpEvent`

## Architecture

The library is structured as a Rust core with a Python interface layer:

```
src/
accounting.rs RDP computation (Poisson, WOR, Laplace, conversions)
gaussian.rs Analytical Gaussian calibration (Balle and Wang)
pld.rs Privacy Loss Distribution with FFT convolution
math.rs Numerical primitives (log-sum-exp, gamma, erfc)
lib.rs PyO3 module bindings

python/dp_accelerator/
rdp.py RdpAccountant and RDP primitive wrappers
dp_event.py DpEvent class hierarchy
pld/ PLD accountant and PMF classes
mechanism_calibration.py
gaussian_mechanism.py
jax_privacy.py Drop-in adapter for JAX Privacy
```

## Development

```bash
git clone https://github.com/yourusername/dp-accelerator
cd dp-accelerator
maturin develop
```
# Build and install in development mode
maturin develop --release

## Contributing
# Run Rust tests
cargo test --no-default-features

Contributions welcome! Please see our [contributing guide](CONTRIBUTING.md).
# Run Python tests
pytest tests/ -v
```

## License

Apache License 2.0
Apache License 2.0. See [LICENSE](LICENSE) for details.
Loading
Loading