Renaming, Documentation and Formatting

This commit is contained in:
Sarah Jamie Lewis 2021-01-29 18:18:08 -08:00
parent 35ca1dcfb4
commit cab45768d5
1 changed files with 109 additions and 57 deletions

View File

@ -10,6 +10,13 @@ use std::fmt;
use std::fmt::{Display, Formatter};
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)]
pub struct FuzzyMetaTag {
u: RistrettoPoint,
@ -17,6 +24,82 @@ pub struct FuzzyMetaTag {
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 schemes 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 {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
@ -29,14 +112,17 @@ impl Display for FuzzyMetaTag {
}
}
#[derive(Debug)]
pub struct FuzzyMetaTagKey {
s_keys: Vec<Scalar>,
p_keys: Vec<RistrettoPoint>,
/// An identity keypair for generating and validating fuzzy meta tags.
pub struct FuzzyMetaTagKeyPair {
pub detection_key: FuzzyMetaDetectionKey,
pub public_key: FuzzyMetaPublicKey,
}
impl FuzzyMetaTagKey {
pub fn generate(gamma: usize) -> FuzzyMetaTagKey {
impl FuzzyMetaTagKeyPair {
/// 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 g = RISTRETTO_BASEPOINT_POINT;
let mut s_keys = vec![];
@ -47,9 +133,13 @@ impl FuzzyMetaTagKey {
s_keys.push(sk_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 {
let hash = sha3::Sha3_256::digest(
format!(
@ -63,78 +153,40 @@ impl FuzzyMetaTagKey {
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 {
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 crate::FuzzyMetaTagKeyPair;
use test::Bencher;
#[test]
fn correctness() {
let number_of_messages = 100;
let key = FuzzyMetaTagKey::generate(3);
let key = FuzzyMetaTagKeyPair::generate(16);
for i in 0..number_of_messages {
let tag = key.flag();
let tag = key.public_key.flag();
println!("{}: {}", i, tag);
assert_eq!(true, key.test(&tag));
assert!(key.detection_key.test(&tag));
}
}
#[bench]
fn generate(b: &mut Bencher) {
fn generate(_b: &mut Bencher) {
let number_of_messages = 1000;
let key = FuzzyMetaTagKey::generate(3);
let key = FuzzyMetaTagKeyPair::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 {
let key2 = FuzzyMetaTagKeyPair::generate(3);
let tag = key2.public_key.flag();
assert!(key2.detection_key.test(&tag));
if key.detection_key.test(&tag) == true {
false_positives += 1;
}
}