Initial Commit

This commit is contained in:
Sarah Jamie Lewis 2021-01-29 13:52:34 -08:00
parent 99879eb844
commit 9ae5b58a57
4 changed files with 159 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
Cargo.lock

15
Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "fuzzymetatag"
version = "0.1.0"
authors = ["Sarah Jamie Lewis <sarah@openprivacy.ca>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hex = "0.4.2"
rand = "0.7.3"
curve25519-dalek = {version="3.0.0", features=["serde"]}
sha3 = "0.9.1"
serde = { version = "1", default_features = false, features = ["derive"], optional = true }
bit-vec = "0.6.3"

View File

@ -1,2 +1,6 @@
# fuzzymetatag
Experimental Rust implementation of https://eprint.iacr.org/2021/089 using Ristretto.

138
src/lib.rs Normal file
View File

@ -0,0 +1,138 @@
#![feature(test)]
use std::ops::{Mul, Sub, Add};
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::ristretto::RistrettoPoint;
use rand::rngs::OsRng;
use curve25519_dalek::digest::Digest;
use sha3::{Sha3_512};
use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
use std::fmt::{Display, Formatter};
use bit_vec::BitVec;
use std::fmt;
#[derive(Debug)]
pub struct FuzzyMetaTag {
u: RistrettoPoint,
y: Scalar,
ciphertexts: BitVec
}
impl Display for FuzzyMetaTag {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{} {} {}", hex::encode(self.u.compress().as_bytes()), hex::encode(self.y.as_bytes()), hex::encode(self.ciphertexts.to_bytes()))
}
}
#[derive(Debug)]
pub struct FuzzyMetaTagKey {
s_keys: Vec<Scalar>,
p_keys: Vec<RistrettoPoint>
}
impl FuzzyMetaTagKey {
pub fn generate(gamma: usize) -> FuzzyMetaTagKey {
let mut rng = OsRng::default();
let g = RISTRETTO_BASEPOINT_POINT;
let mut s_keys = vec![];
let mut p_keys = vec![];
for _i in 0..gamma {
let sk_i = Scalar::random(&mut rng);
let pk_i = g.mul(sk_i);
s_keys.push(sk_i);
p_keys.push(pk_i);
}
FuzzyMetaTagKey {
s_keys,
p_keys
}
}
fn h(u: RistrettoPoint, h :RistrettoPoint, w: RistrettoPoint) -> u8 {
let hash = sha3::Sha3_256::digest(format!("{}{}{}", hex::encode(u.compress().as_bytes()), hex::encode(h.compress().as_bytes()), hex::encode(w.compress().as_bytes())).as_bytes());
return hash.as_slice()[0] & 0x01
}
fn g(u: RistrettoPoint, points: &BitVec) -> Scalar {
Scalar::hash_from_bytes::<Sha3_512>(format!("{}{}", hex::encode(u.compress().as_bytes()), hex::encode(points.to_bytes())).as_bytes())
}
pub fn flag(&self) -> FuzzyMetaTag {
let mut rng = OsRng::default();
let g = RISTRETTO_BASEPOINT_POINT;
let r = Scalar::random(&mut rng);
let u = g.mul(r);
let z = Scalar::random(&mut rng);
let w = g.mul(z);
let mut ciphertexts = BitVec::new();
for (_i, h_i) in self.p_keys.iter().enumerate() {
let k_i = FuzzyMetaTagKey::h(u, h_i.mul(r), w);
let c_i = k_i ^ 0x01;
ciphertexts.push(c_i == 0x01);
}
let m = FuzzyMetaTagKey::g(u, &ciphertexts);
let y = r.invert().mul(z.sub(m));
return FuzzyMetaTag {
u,
y,
ciphertexts
}
}
pub fn test(&self, tag: &FuzzyMetaTag) -> bool {
let m = FuzzyMetaTagKey::g(tag.u, &tag.ciphertexts);
let g = RISTRETTO_BASEPOINT_POINT;
let w = g.mul(m).add(tag.u.mul(tag.y));
for (i,x_i) in self.s_keys.iter().enumerate() {
let k_i = FuzzyMetaTagKey::h(tag.u, tag.u.mul(x_i), w);
let c_i = match tag.ciphertexts.get(i).unwrap() {
true => 0x01,
false => 0x00,
};
let b_i = k_i ^ c_i;
if b_i != 1 {
return false
}
}
return true
}
}
#[cfg(test)]
mod tests {
extern crate test;
use crate::FuzzyMetaTagKey;
use test::Bencher;
#[test]
fn correctness() {
let number_of_messages = 100;
let key = FuzzyMetaTagKey::generate(3);
for i in 0..number_of_messages {
let tag = key.flag();
println!("{}: {}", i, tag);
assert_eq!(true, key.test(&tag));
}
}
#[bench]
fn generate(b: &mut Bencher) {
let number_of_messages = 1000;
let key = FuzzyMetaTagKey::generate(3);
let mut false_positives = 0;
for _i in 0..number_of_messages {
let key2 = FuzzyMetaTagKey::generate(3);
let tag = key2.flag();
assert!(key2.test(&tag));
if key.test(&tag) == true {
false_positives += 1;
}
}
println!("Expected False Positive Rate: {}\nActual False Positive Rate: {}", (2.0_f64).powi(-3), (false_positives as f64 / number_of_messages as f64));
}
}