# Crate opendp[−][src]

## Expand description

A library for working with differential privacy.

This library implements the framework described in the paper, A Programming Framework for OpenDP. OpenDP (the library) is part of the larger OpenDP Project.

# Overview

OpenDP provides three main concepts:

- A flexible architecture for modeling privacy-preserving computations.
- Implementations of several common algorithms for statistical analysis and data manipulation, which can be used out-of-the-box to assemble DP applications.
- Facilities for extending OpenDP with new algorithms, privacy models, etc.

In addition, there’s a companion crate, opendp-ffi, which provides FFI wrappers for opendp functionality. This can be used to implement bindings in languages other than Rust.

# User Guide

OpenDP applications are created by using constructors and combinators to create private computation pipelines. These can be written directly in Rust, or by using a language binding that uses OpenDP through an FFI interface. Python is the first language binding available, but we made add others in the future.

## Rust Application Example

Here’s a simple example of using OpenDP from Rust to create a private sum:

```
use opendp::core;
use opendp::meas;
use opendp::trans;
use opendp::trans::{manipulation, sum, make_split_lines, make_cast_default, make_clamp, make_bounded_sum};
use opendp::dist::{SubstituteDistance, L1Distance};
use opendp::error::*;
use opendp::comb::{make_chain_tt, make_chain_mt};
use opendp::meas::make_base_laplace;
use opendp::dom::VectorDomain;
pub fn example() -> Fallible<()> {
let data = "56\n15\n97\n56\n6\n17\n2\n19\n16\n50".to_owned();
let bounds = (0.0, 100.0);
let epsilon = 1.0;
let sigma = (bounds.1 - bounds.0) / epsilon;
// Construct a Transformation to load the numbers.
let split_lines = make_split_lines()?;
let cast = make_cast_default::<String, f64>()?;
let load_numbers = make_chain_tt(&cast, &split_lines, None)?;
// Construct a Measurement to calculate a noisy sum.
let clamp = make_clamp(bounds)?;
let bounded_sum = make_bounded_sum(bounds)?;
let laplace = make_base_laplace(sigma)?;
let intermediate = make_chain_tt(&bounded_sum, &clamp, None)?;
let noisy_sum = make_chain_mt(&laplace, &intermediate, None)?;
// Put it all together.
let pipeline = make_chain_mt(&noisy_sum, &load_numbers, None)?;
let result = pipeline.function.eval(&data)?;
println!("result = {}", result);
Ok(())
}
example().unwrap_test();
```

# Contributor Guide

Contributions to OpenDP typically take the form of what we call “Components.” A Component is shorthand for
the collection of code that comprises a `Measurement`

or `Transformation`

.

## Adding Components

OpenDP components take the form of constructor functions that construct new instances of `Measurement`

and `Transformation`

. Measurement constructors go in the module `meas`

, and Transformation constructors
in the module `trans`

. (We’ll probably split these up as they grow.)

There are two steps to adding a constructor function: Writing the function itself, and adding the FFI wrapper.

### Writing Constructors

Constructors are functions that take configuration parameters and return an appropriately configured `Measurement`

or `Transformation`

.
They typically follow a common pattern:

- Choose the appropriate input and output
`Domain`

. - Write a closure that implements the
`Function`

. - Choose the appropriate input and output
`Metric`

/`Measure`

. - Write a closure that implements the
`PrivacyRelation`

/`StabilityRelation`

.

#### Example Transformation Constructor

```
pub fn make_i32_identity() -> Transformation<AllDomain<i32>, AllDomain<i32>, L1Distance<i32>, L1Distance<i32>> {
let input_domain = AllDomain::new();
let output_domain = AllDomain::new();
let function = Function::new(|arg: &i32| -> i32 { *arg });
let input_metric = L1Distance::default();
let output_metric = L1Distance::default();
let stability_relation = StabilityRelation::new_from_constant(1);
Transformation::new(input_domain, output_domain, function, input_metric, output_metric, stability_relation)
}
make_i32_identity();
```

#### Input and Output Types

The `Function`

created in a constructor is allowed to have any type for its input and output `Domain::Carrier`

.
There’s no need for special data carrying wrappers. The clue code in the FFI layer handles this transparently.
However, the most common are the Rust primitives (e.g., `i32`

, `f64`

, etc.), and collections of the primitives
(`Vec<i32>`

, `HashMap<String, f64>`

).

#### Handling Generics

`Measurement`

/`Transformation`

constructors are allowed to be generic! Typically, this means that the type parameter on the
constructor will determine type of the input or output `Domain::Carrier`

(or the generic type within, for instance the `i32`

of `Vec<i32>`

).

## Modules

Core concepts of OpenDP.

Framework for flexible abstract data type model for DataFrames.

Various implementations of Metric/Measure (and associated Distance).

Various implementations of Domain.

Various implementations of Measurement.

Various implementations of Transformations.