2021-01-29 21:52:34 +00:00
|
|
|
#![feature(test)]
|
2021-01-29 23:47:40 +00:00
|
|
|
use bit_vec::BitVec;
|
|
|
|
use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
|
|
|
|
use curve25519_dalek::digest::Digest;
|
2021-01-29 21:52:34 +00:00
|
|
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
2021-01-29 23:47:40 +00:00
|
|
|
use curve25519_dalek::scalar::Scalar;
|
2021-01-29 21:52:34 +00:00
|
|
|
use rand::rngs::OsRng;
|
2021-01-29 23:47:40 +00:00
|
|
|
use sha3::Sha3_512;
|
2021-01-29 21:52:34 +00:00
|
|
|
use std::fmt;
|
2021-01-29 23:47:40 +00:00
|
|
|
use std::fmt::{Display, Formatter};
|
|
|
|
use std::ops::{Add, Mul, Sub};
|
2021-01-29 21:52:34 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct FuzzyMetaTag {
|
|
|
|
u: RistrettoPoint,
|
|
|
|
y: Scalar,
|
2021-01-29 23:47:40 +00:00
|
|
|
ciphertexts: BitVec,
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for FuzzyMetaTag {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
2021-01-29 23:47:40 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{} {} {}",
|
|
|
|
hex::encode(self.u.compress().as_bytes()),
|
|
|
|
hex::encode(self.y.as_bytes()),
|
|
|
|
hex::encode(self.ciphertexts.to_bytes())
|
|
|
|
)
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct FuzzyMetaTagKey {
|
|
|
|
s_keys: Vec<Scalar>,
|
2021-01-29 23:47:40 +00:00
|
|
|
p_keys: Vec<RistrettoPoint>,
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2021-01-29 23:47:40 +00:00
|
|
|
FuzzyMetaTagKey { s_keys, p_keys }
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 23:47:40 +00:00
|
|
|
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;
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2021-01-29 23:47:40 +00:00
|
|
|
let r = Scalar::random(&mut rng);
|
2021-01-29 21:52:34 +00:00
|
|
|
let u = g.mul(r);
|
2021-01-29 23:47:40 +00:00
|
|
|
let z = Scalar::random(&mut rng);
|
2021-01-29 21:52:34 +00:00
|
|
|
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));
|
|
|
|
|
2021-01-29 23:47:40 +00:00
|
|
|
return FuzzyMetaTag { u, y, ciphertexts };
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
2021-01-29 23:47:40 +00:00
|
|
|
for (i, x_i) in self.s_keys.iter().enumerate() {
|
2021-01-29 21:52:34 +00:00
|
|
|
let k_i = FuzzyMetaTagKey::h(tag.u, tag.u.mul(x_i), w);
|
|
|
|
let c_i = match tag.ciphertexts.get(i).unwrap() {
|
|
|
|
true => 0x01,
|
2021-01-29 23:47:40 +00:00
|
|
|
false => 0x00,
|
2021-01-29 21:52:34 +00:00
|
|
|
};
|
|
|
|
let b_i = k_i ^ c_i;
|
|
|
|
if b_i != 1 {
|
2021-01-29 23:47:40 +00:00
|
|
|
return false;
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-29 23:47:40 +00:00
|
|
|
return true;
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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) {
|
2021-01-29 23:47:40 +00:00
|
|
|
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)
|
|
|
|
);
|
2021-01-29 21:52:34 +00:00
|
|
|
}
|
2021-01-29 23:47:40 +00:00
|
|
|
}
|