Skip to content

Commit

Permalink
Apply input validation to serde as well
Browse files Browse the repository at this point in the history
  • Loading branch information
divergentdave committed Jul 12, 2024
1 parent ef95daa commit 30bfbe4
Showing 1 changed file with 40 additions and 1 deletion.
41 changes: 40 additions & 1 deletion src/dp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl ZCdpBudget {
impl DifferentialPrivacyBudget for ZCdpBudget {}

/// Pure differential privacy budget. (ε-DP or (ε, 0)-DP)
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Ord, PartialOrd)]
pub struct PureDpBudget {
epsilon: Ratio<BigUint>,
}
Expand All @@ -125,6 +125,31 @@ impl PureDpBudget {

impl DifferentialPrivacyBudget for PureDpBudget {}

/// This module encapsulates a deserialization helper struct. It is needed so we can wrap its
/// derived `Deserialize` implementation in a customized `Deserialize` implementation, which makes
/// use of the budget's constructor to enforce input validation invariants.
mod budget_serde {
use num_bigint::BigUint;
use num_rational::Ratio;
use serde::{de, Deserialize};

#[derive(Deserialize)]
pub struct PureDpBudget {
epsilon: Ratio<BigUint>,
}

impl<'de> Deserialize<'de> for super::PureDpBudget {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let helper = PureDpBudget::deserialize(deserializer)?;
super::PureDpBudget::new(super::Rational(helper.epsilon))
.map_err(|_| de::Error::custom("epsilon cannot be zero"))
}
}
}

/// Strategy to make aggregate results differentially private, e.g. by adding noise from a specific
/// type of distribution instantiated with a given DP budget.
pub trait DifferentialPrivacyStrategy {
Expand All @@ -149,3 +174,17 @@ pub trait DifferentialPrivacyStrategy {
}

pub mod distributions;

#[cfg(test)]
mod tests {
use serde_json::json;

use super::PureDpBudget;

#[test]
fn budget_deserialization() {
serde_json::from_value::<PureDpBudget>(json!({"epsilon": [[1], [1]]})).unwrap();
serde_json::from_value::<PureDpBudget>(json!({"epsilon": [[0], [1]]})).unwrap_err();
serde_json::from_value::<PureDpBudget>(json!({"epsilon": [[1], [0]]})).unwrap_err();
}
}

0 comments on commit 30bfbe4

Please sign in to comment.