#差分隐私 #隐私保护 #框架 #发布者 #流式处理 #k-匿名性 #多样性

bin+lib diff-priv

k-匿名性、(c,l)-多样性和 ε-差分隐私框架

1 个不稳定版本

0.1.0 2022 年 8 月 18 日

#3 in #隐私保护

MIT 许可证

8.5MB
3.5K SLoC

包含 (JAR 文件, 7.5MB) moa-ppsm.jar

DiffPriv

DiffPriv 是用 Rust 编写的实时数据流差分隐私框架。支持 k-匿名性、(c,l)-多样性和 ε-差分隐私。该框架基于“Preserving Differential Privacy and Utility of Non-stationary Data Streams”论文,并实现了各种改进。

该项目是我的硕士论文“大规模数据流的差分隐私”的结果。它是在STRM Privacy实习期间开发的。

如何使用

建议首先使用以下命令构建应用程序,因为它将显著加快算法的速度

cargo build --release

根目录中需要存在一个 application.conf 文件。这将构建一个可以以下命令运行的二进制文件

RUST_LOG="debug" ./target/release/diff-priv

这将使用来自 datasets 文件夹的数据集,支持的数据集可以在 test/tests.rsRUST_LOG 部分查看。根据用户的喜好,可以删除 RUST_LOG。这将删除算法运行时的调试日志。

数据导出到哪里

当运行 main.rs 时,处理后的数据集可以在 exports 目录中看到。

应用程序参数

application.conf 中,可以编辑所有不同的隐私参数以符合用户的需求。目前对于 buffer_size,我们使用 3*k,而对于 k_max,我们使用 4*k。这可以在 environment.rstests.rs 文件中编辑。可以通过在 config.rs 文件中添加它作为结构属性并将其添加到 application.conf 中轻松添加额外的参数。

文档

DiffPriv

DiffPriv 是用 Rust 编写的实时数据流差分隐私框架。支持 k-匿名性、(c,l)-多样性和 ε-差分隐私。该框架基于“Preserving Differential Privacy and Utility of Non-stationary Data Streams”论文,并实现了各种改进。

该库是我的硕士论文“大规模数据流的差分隐私”的结果。它是在STRM Privacy实习期间开发的。

使用匿名化器

以下是一个使用匿名化器的示例

use csv::Reader;
use diff_priv::anonymization::microagg_anonymizer::MicroaggAnonymizer;
use diff_priv::noise::laplace::laplace_noiser::LaplaceNoiser;
use diff_priv::test::adult::Adult;
use diff_priv::test::dummy_publisher::DummyPublisher;

// we initialize our noiser that implements the `Noiser` trait
let noiser = LaplaceNoiser::new(0.1, 3, 0.1);
// we initialize a publisher that implements the `Publisher` trait
let publisher = DummyPublisher::default();
// we create the anonymizer with the desired parameters
// k: 2 | k_max: 10 | c: 2 | l: 7 | diff_thres: 0.1 | delta: 10 | buff_size: 5
let mut anonymizer: MicroaggAnonymizer<LaplaceNoiser, Adult, DummyPublisher> =
    MicroaggAnonymizer::new(2, 10, 2, 7, 0.1, 10, 5, publisher, noiser);

// load CSV file representing an Adult
let mut file = Reader::from_path("datasets/Adult_1_numeric_only_class_50K.csv").unwrap();
for line in file.deserialize() {
    let row_result = line;
    // when we call for `anonymizer()` the anonymizer will
    // automatically publish to the given backend when the given
    // privacy parameter conditions are met
    match row_result {
        Ok(row) => anonymizer.anonymize(row),
        Err(e) => panic!("{}", e)
    }
 }

// publish remaining data tuples to the given publisher
// in this case a `DummyPublisher`
anonymizer
    .cluster_set
    .into_iter()
    .for_each(|(_, mut cluster)| {
        cluster.publish_all(&mut anonymizer.publisher, &mut anonymizer.analysers)
});

实现 Anonymizable 特性以匿名化新数据

通过在任何数据结构类型上实现 Anonymizable 特性,DiffPriv 将知道如何对其进行匿名化。以下 QIs 类型已实现

 /// value, min_value, max_value, weight of attribute
pub type IntervalType = (
    QuasiIdentifierType,
    QuasiIdentifierType,
    QuasiIdentifierType,
    usize,
);

/// rank, max_rank, weight of attribute
pub type OrdinalType = (i32, i32, usize);

/// value, max value, weight of attribute
pub type NominalType = (i32, i32, usize);

以下是一个 Anonymizable 特性的示例实现

use std::time::{SystemTime, UNIX_EPOCH};
use serde::{Serialize, Deserialize};
use bimap::BiMap;
use lazy_static::lazy_static;
use uuid::Uuid;

use diff_priv::data_manipulation::anonymizable::{
    Anonymizable, QuasiIdentifierType, QuasiIdentifierTypes, SensitiveAttribute,
};

lazy_static! {
    static ref CLASS_BIMAP: BiMap<&'static str, i32> =
        BiMap::from_iter(vec![("<=50K", 0), (">50K", 1),]);
}

// This is the datastructure that we are going to anonymize
#[derive(Debug, Serialize, Clone, Deserialize)]
pub struct Adult {
    timestamp: i32,
    age: i32,
    capital_gain: i32,
    capital_loss: i32,
    class: String,
    #[serde(skip_deserializing, default = "default_time")]
    time_generated: SystemTime,
}

fn default_time() -> SystemTime {
    SystemTime::now()
}

impl Default for Adult {
    fn default() -> Self {
        Self {
            timestamp: 0,
            age: 0,
            capital_gain: 0,
            capital_loss: 0,
            class: "".to_string(),
            time_generated: SystemTime::now(),
        }
    }
}

impl Adult {
    // here we extract an Interval QI from the `age` attribute
    fn get_age_qi(&self) -> QuasiIdentifierTypes {
        QuasiIdentifierTypes::Interval((
            QuasiIdentifierType::Integer(self.age),
            QuasiIdentifierType::Integer(1),
            QuasiIdentifierType::Integer(100),
            1,
        ))
    }

    // here we extract an Interval QI from the `capital_gain` attribute
    fn get_capital_gain_qi(&self) -> QuasiIdentifierTypes {
        QuasiIdentifierTypes::Interval((
            QuasiIdentifierType::Integer(self.capital_gain),
            QuasiIdentifierType::Integer(0),
            QuasiIdentifierType::Integer(100000),
            1,
        ))
    }

    // here we extract an Interval QI from the `capital_loss` attribute
    fn get_capital_loss_qi(&self) -> QuasiIdentifierTypes {
        QuasiIdentifierTypes::Interval((
            QuasiIdentifierType::Integer(self.capital_loss),
            QuasiIdentifierType::Integer(0),
            QuasiIdentifierType::Integer(5000),
            1,
        ))
    }

}

// Here we implement the `Anonymizable` trait
impl Anonymizable for Adult {
    // We extract the QIs from the datastructure and return a `vec` of QIs
    fn quasi_identifiers(&self) -> Vec<QuasiIdentifierTypes> {
        let age = self.get_age_qi();
        let capital_gain = self.get_capital_gain_qi();
        let capital_loss = self.get_capital_loss_qi();

        vec![
            age,
            capital_gain,
            capital_loss,
        ]
    }

    // We update the datastructures QIs with a `vec` of QIs. The `vec` needs to be
    // popped in the same order that the QIs are extracted with the `quasi_identifiers`
    // function
    fn update_quasi_identifiers(&self, mut qi: Vec<QuasiIdentifierTypes>) -> Self {
        if let (
            QuasiIdentifierType::Integer(capital_loss),
            QuasiIdentifierType::Integer(capital_gain),
            QuasiIdentifierType::Integer(age),
        ) = (
            qi.pop().unwrap().extract_value(),
            qi.pop().unwrap().extract_value(),
            qi.pop().unwrap().extract_value(),
        ) {
            Self {
                timestamp: self.timestamp,
                age,
                capital_gain,
                capital_loss,
                class: self.class.to_owned(),
                time_generated: self.time_generated,
            }
        } else {
            panic!("Couldn't Adult with QI's")
        }
    }

    // We extract the sensative attribute from the datastructure
    fn sensitive_value(&self) -> SensitiveAttribute {
        SensitiveAttribute::String(self.class.to_owned())
    }

    // We return a vector of strings containing the String version of the QIs
    // Used for printing to CSVs
    fn extract_string_values(&self, uuid: Uuid, dr: f64) -> Vec<String> {
        vec![
            uuid.to_string(),
            dr.to_string(),
            self.timestamp.to_string(),
            self.age.to_string(),
            self.capital_gain.to_string(),
            self.capital_loss.to_string(),
            self.class.to_owned(),
        ]
    }

    fn get_timestamp(&self) -> SystemTime {
        self.time_generated
    }
}

Publisher 特性

要将匿名化的结构体发布到目标后端,我们使用 Publisher 特性。DiffPriv 还支持导出到 Apache Kafka 主题。这可以在 publishing 目录中看到。这里有一个 CSV 的示例发布者:CsvPublisher。要实现自定义发布后端,可以使用 Publisher 特性。

Noiser 特性

DiffPriv 支持 Laplace noise 用于 ε-差分隐私。噪声生成器支持两种不同类型的噪声:一种用于 数值,另一种用于 分类。要实现 ε-差分隐私噪声的自定义实现,可以使用 Noiser 特性。

架构

以下展示了 DiffPriv 框架的架构 替代文本

仓库中的论文相关内容

在我的论文中描述了使用 knn-test.sh 的测试。要运行此测试,您需要 Java 8。

许可证

MIT 许可证

版权所有 (c) 2022 Maciek Mika

在此特此授予任何获得本软件及其相关文档副本(“软件”)的人免费使用该软件的权利,不受任何限制,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本的权利,并允许向获得软件的人提供软件副本,前提是遵守以下条件

上述版权声明和本许可声明应包含在软件的所有副本或实质性部分中。

本软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、适用于特定目的和不受侵犯的保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任承担责任,无论是在合同、侵权或其他行为中,源于、因之或与此软件或其使用或其它交易有关。

依赖项

~21–36MB
~563K SLoC