Renaming, Documentation and Formatting
This commit is contained in:
parent
35ca1dcfb4
commit
cab45768d5
166
src/lib.rs
166
src/lib.rs
|
@ -10,6 +10,13 @@ use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::ops::{Add, Mul, Sub};
|
use std::ops::{Add, Mul, Sub};
|
||||||
|
|
||||||
|
/// A tag is a probabilistic cryptographic structure. When constructed for a given `FuzzyMetaPublicKey`
|
||||||
|
/// it will pass the `FuzzyMetaDetectionKey::test` 100% of the time. For other public keys
|
||||||
|
/// it will pass the test with probability `gamma` related to the security parameter of the system.
|
||||||
|
/// This system provides the following security properties:
|
||||||
|
/// - Correctness: Valid tags for a public key for a key pair always validate when tested against the secret key
|
||||||
|
/// - Fuzziness: Invalid matches should produce false positives with probability p related to the security property (γ)
|
||||||
|
/// - Security: An adversarial server with access to Test oracle (i.e. the detection key) is unable to distinguish false positives from true positives. (Detection Ambiguity)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FuzzyMetaTag {
|
pub struct FuzzyMetaTag {
|
||||||
u: RistrettoPoint,
|
u: RistrettoPoint,
|
||||||
|
@ -17,6 +24,82 @@ pub struct FuzzyMetaTag {
|
||||||
ciphertexts: BitVec,
|
ciphertexts: BitVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A collection of "secret" data that can be used to determine if a `FuzzyMetaTag` was intended for
|
||||||
|
/// the derived public key.
|
||||||
|
pub struct FuzzyMetaDetectionKey(Vec<Scalar>);
|
||||||
|
|
||||||
|
impl FuzzyMetaDetectionKey {
|
||||||
|
/// returns true if the tag was intended for this key
|
||||||
|
pub fn test(&self, tag: &FuzzyMetaTag) -> bool {
|
||||||
|
let m = FuzzyMetaTagKeyPair::g(tag.u, &tag.ciphertexts);
|
||||||
|
|
||||||
|
let g = RISTRETTO_BASEPOINT_POINT;
|
||||||
|
|
||||||
|
// Re-derive w = g^z from the public tag.
|
||||||
|
// y = (1/r * (z-m)
|
||||||
|
// u = g^r
|
||||||
|
// so w = g^m + u^y
|
||||||
|
// w = g^m + g^(r * 1/r * (z-m))
|
||||||
|
// w = g^m + g^(z-m)
|
||||||
|
// w = g^z
|
||||||
|
let w = g.mul(m).add(tag.u.mul(tag.y));
|
||||||
|
|
||||||
|
// for each secret key part...
|
||||||
|
for (i, x_i) in self.0.iter().enumerate() {
|
||||||
|
// re-derive the key from the tag
|
||||||
|
let k_i = FuzzyMetaTagKeyPair::h(tag.u, tag.u.mul(x_i), w);
|
||||||
|
|
||||||
|
// calculate the "original" plaintext
|
||||||
|
let c_i = match tag.ciphertexts.get(i).unwrap() {
|
||||||
|
true => 0x01,
|
||||||
|
false => 0x00,
|
||||||
|
};
|
||||||
|
let b_i = k_i ^ c_i;
|
||||||
|
// if these don't match then return false
|
||||||
|
if b_i != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A public identity that others can create tags for.
|
||||||
|
pub struct FuzzyMetaPublicKey(Vec<RistrettoPoint>);
|
||||||
|
|
||||||
|
impl FuzzyMetaPublicKey {
|
||||||
|
/// creates a new tag for this public key
|
||||||
|
pub fn flag(&self) -> FuzzyMetaTag {
|
||||||
|
let mut rng = OsRng::default();
|
||||||
|
let g = RISTRETTO_BASEPOINT_POINT;
|
||||||
|
|
||||||
|
// generate some random points...
|
||||||
|
let r = Scalar::random(&mut rng);
|
||||||
|
let u = g.mul(r);
|
||||||
|
let z = Scalar::random(&mut rng);
|
||||||
|
let w = g.mul(z);
|
||||||
|
|
||||||
|
// construct the ciphertext portion of the tag
|
||||||
|
let mut ciphertexts = BitVec::new();
|
||||||
|
for (_i, h_i) in self.0.iter().enumerate() {
|
||||||
|
let k_i = FuzzyMetaTagKeyPair::h(u, h_i.mul(r), w);
|
||||||
|
let c_i = k_i ^ 0x01;
|
||||||
|
ciphertexts.push(c_i == 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From the paper:
|
||||||
|
// "The value w corresponds to a chameleon hash [KR00] computed on the message (0,z), where z is chosen at random.
|
||||||
|
// Once the ciphertext has been computed, we use a master trapdoor for the chameleon hash (which is part of the scheme’s secret key) in order to compute a collision (y,m) where m
|
||||||
|
// is a hash of the remaining components of the ciphertext"
|
||||||
|
|
||||||
|
// finally calculate a `y` = 1/r * (z-m) which will be used to re-derive `w`
|
||||||
|
let m = FuzzyMetaTagKeyPair::g(u, &ciphertexts);
|
||||||
|
let y = r.invert().mul(z.sub(m));
|
||||||
|
|
||||||
|
return FuzzyMetaTag { u, y, ciphertexts };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for FuzzyMetaTag {
|
impl Display for FuzzyMetaTag {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
@ -29,14 +112,17 @@ impl Display for FuzzyMetaTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// An identity keypair for generating and validating fuzzy meta tags.
|
||||||
pub struct FuzzyMetaTagKey {
|
pub struct FuzzyMetaTagKeyPair {
|
||||||
s_keys: Vec<Scalar>,
|
pub detection_key: FuzzyMetaDetectionKey,
|
||||||
p_keys: Vec<RistrettoPoint>,
|
pub public_key: FuzzyMetaPublicKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuzzyMetaTagKey {
|
impl FuzzyMetaTagKeyPair {
|
||||||
pub fn generate(gamma: usize) -> FuzzyMetaTagKey {
|
/// Generate a new Key Pair given a security parameter `gamma`. Tags generated for a given
|
||||||
|
/// `FuzzyMetaPublicKey::flag` will pass the `FuzzyMetaDetectionKey::test` for other public
|
||||||
|
/// keys with probability $ 2 ^ -8 $
|
||||||
|
pub fn generate(gamma: usize) -> FuzzyMetaTagKeyPair {
|
||||||
let mut rng = OsRng::default();
|
let mut rng = OsRng::default();
|
||||||
let g = RISTRETTO_BASEPOINT_POINT;
|
let g = RISTRETTO_BASEPOINT_POINT;
|
||||||
let mut s_keys = vec![];
|
let mut s_keys = vec![];
|
||||||
|
@ -47,9 +133,13 @@ impl FuzzyMetaTagKey {
|
||||||
s_keys.push(sk_i);
|
s_keys.push(sk_i);
|
||||||
p_keys.push(pk_i);
|
p_keys.push(pk_i);
|
||||||
}
|
}
|
||||||
FuzzyMetaTagKey { s_keys, p_keys }
|
FuzzyMetaTagKeyPair {
|
||||||
|
detection_key: FuzzyMetaDetectionKey { 0: s_keys },
|
||||||
|
public_key: FuzzyMetaPublicKey { 0: p_keys },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// a hash function that takes 3 risretto points as a parameter and outputs 0 or 1.
|
||||||
fn h(u: RistrettoPoint, h: RistrettoPoint, w: RistrettoPoint) -> u8 {
|
fn h(u: RistrettoPoint, h: RistrettoPoint, w: RistrettoPoint) -> u8 {
|
||||||
let hash = sha3::Sha3_256::digest(
|
let hash = sha3::Sha3_256::digest(
|
||||||
format!(
|
format!(
|
||||||
|
@ -63,78 +153,40 @@ impl FuzzyMetaTagKey {
|
||||||
return hash.as_slice()[0] & 0x01;
|
return hash.as_slice()[0] & 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// a hash function which takes a ristretto point and a vector of ciphertexts and ouputs a
|
||||||
|
/// ristretto scalar.
|
||||||
fn g(u: RistrettoPoint, points: &BitVec) -> Scalar {
|
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())
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
extern crate test;
|
extern crate test;
|
||||||
use crate::FuzzyMetaTagKey;
|
use crate::FuzzyMetaTagKeyPair;
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn correctness() {
|
fn correctness() {
|
||||||
let number_of_messages = 100;
|
let number_of_messages = 100;
|
||||||
let key = FuzzyMetaTagKey::generate(3);
|
let key = FuzzyMetaTagKeyPair::generate(16);
|
||||||
for i in 0..number_of_messages {
|
for i in 0..number_of_messages {
|
||||||
let tag = key.flag();
|
let tag = key.public_key.flag();
|
||||||
println!("{}: {}", i, tag);
|
println!("{}: {}", i, tag);
|
||||||
assert_eq!(true, key.test(&tag));
|
assert!(key.detection_key.test(&tag));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn generate(b: &mut Bencher) {
|
fn generate(_b: &mut Bencher) {
|
||||||
let number_of_messages = 1000;
|
let number_of_messages = 1000;
|
||||||
let key = FuzzyMetaTagKey::generate(3);
|
let key = FuzzyMetaTagKeyPair::generate(3);
|
||||||
let mut false_positives = 0;
|
let mut false_positives = 0;
|
||||||
for _i in 0..number_of_messages {
|
for _i in 0..number_of_messages {
|
||||||
let key2 = FuzzyMetaTagKey::generate(3);
|
let key2 = FuzzyMetaTagKeyPair::generate(3);
|
||||||
let tag = key2.flag();
|
let tag = key2.public_key.flag();
|
||||||
assert!(key2.test(&tag));
|
assert!(key2.detection_key.test(&tag));
|
||||||
if key.test(&tag) == true {
|
if key.detection_key.test(&tag) == true {
|
||||||
false_positives += 1;
|
false_positives += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue