@ -22,21 +22,21 @@ use brute_force::adaptors;
#[ cfg(feature = " entangled " ) ]
use brute_force ::brute_force ;
/// A tag is a probabilistic cryptographic structure. When constructed for a given ` FuzzyPublic Key`
/// it will pass the ` FuzzyDetectionKey::test` 100% of the time. For other public keys
/// A tag is a probabilistic cryptographic structure. When constructed for a given ` Tagging Key`
/// it will pass the ` DetectionKey::test_tag` 100% of the time. For other tagging 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 constructed for a specific public key will always validate when tested using the detection key
/// * Correctness: Valid tags constructed for a specific tagging key will always validate when tested using the detection key
/// * Fuzziness: Invalid tags will produce false positives with probability _p_ related to the security property (_γ _)
/// * Security: An adversarial server with access to the detection key is unable to distinguish false positives from true positives. (Detection Ambiguity)
#[ derive(Clone, Debug, Eq, PartialEq) ]
pub struct Fuzzy Tag< const GAMMA : u8 > {
pub struct Tag< const GAMMA : u8 > {
u : RistrettoPoint ,
y : Scalar ,
ciphertexts : BitVec ,
}
impl < const GAMMA : u8 > Serialize for Fuzzy Tag< { GAMMA } > {
impl < const GAMMA : u8 > Serialize for Tag< { GAMMA } > {
fn serialize < S > ( & self , serializer : S ) -> Result < S ::Ok , S ::Error >
where
S : Serializer ,
@ -51,7 +51,7 @@ impl<const GAMMA: u8> Serialize for FuzzyTag<{ GAMMA }> {
}
}
impl < ' de , const GAMMA : u8 > Deserialize < ' de > for Fuzzy Tag< { GAMMA } > {
impl < ' de , const GAMMA : u8 > Deserialize < ' de > for Tag< { GAMMA } > {
fn deserialize < D > ( deserializer : D ) -> Result < Self , D ::Error >
where
D : Deserializer < ' de > ,
@ -59,13 +59,13 @@ impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> {
struct FuzzyTagVisitor < const GAMMA : u8 > ;
impl < ' de , const GAMMA : u8 > Visitor < ' de > for FuzzyTagVisitor < { GAMMA } > {
type Value = Fuzzy Tag< { GAMMA } > ;
type Value = Tag< { GAMMA } > ;
fn expecting ( & self , formatter : & mut ::core ::fmt ::Formatter ) -> ::core ::fmt ::Result {
formatter . write_str ( "64 bytes + GAMMA+bits of data" )
}
fn visit_seq < A > ( self , mut seq : A ) -> Result < Fuzzy Tag< { GAMMA } > , A ::Error >
fn visit_seq < A > ( self , mut seq : A ) -> Result < Tag< { GAMMA } > , A ::Error >
where
A : serde ::de ::SeqAccess < ' de > ,
{
@ -79,7 +79,7 @@ impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> {
_ = > break ,
}
}
Fuzzy Tag::< GAMMA > ::decompress ( & bytes ) . ok_or ( serde ::de ::Error ::custom ( "invalid fuzzytag" ) )
Tag::< GAMMA > ::decompress ( & bytes ) . ok_or ( serde ::de ::Error ::custom ( "invalid fuzzytag" ) )
}
}
@ -88,21 +88,21 @@ impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> {
}
}
impl < const GAMMA : u8 > Fuzzy Tag< { GAMMA } > {
impl < const GAMMA : u8 > Tag< { GAMMA } > {
/// An optimal sized copy of the tag
/// Compressed u || y || ciphertext
/// Ciphertext is right-padded with zeros to the nearest byte
/// You probably want to use one of the many serde `serialize` apis instead (see README)
/// ```
/// use fuzzytags:: FuzzySecretKey ;
/// let secret _key = FuzzySecretKey ::<24>::generate();
/// let public_key = secret_key.public _key();
/// use fuzzytags:: RootSecret ;
/// let secret = RootSecret ::<24>::generate();
/// let tagging_key = secret.tagging _key();
/// // extract a detection key
/// let detection_key = secret _key .extract(5);
/// let detection_key = secret .extract_detection_key (5);
///
/// // Give public key to a another party...
/// // Give tagging key to a another party...
/// // and then they can do...
/// let tag = public _key.generate_tag();
/// let tag = tagging _key.generate_tag();
/// let compressed_tag = tag.compress();
/// ```
pub fn compress ( & self ) -> Vec < u8 > {
@ -116,20 +116,20 @@ impl<const GAMMA: u8> FuzzyTag<{ GAMMA }> {
/// decompress an optimally encoded fuzzytag byte array, returns None if invalid
/// You probably want to use one of the many serde `deserialize` apis instead (see README)
/// ```
/// use fuzzytags::{ FuzzySecretKey, Fuzzy Tag};
/// let secret _key = FuzzySecretKey ::<24>::generate();
/// let public_key = secret_key.public _key();
/// use fuzzytags::{ RootSecret, Tag};
/// let secret = RootSecret ::<24>::generate();
/// let tagging_key = secret.tagging _key();
/// // extract a detection key
/// let detection_key = secret _key .extract(5);
/// let detection_key = secret .extract_detection_key (5);
///
/// // Give public key to a another party...
/// // Give tagging key to a another party...
/// // and then they can do...
/// let tag = public _key.generate_tag();
/// let tag = tagging _key.generate_tag();
/// let compressed_tag = tag.compress();
/// let decompressed_tag = Fuzzy Tag::decompress(&compressed_tag).unwrap();
/// let decompressed_tag = Tag::decompress(&compressed_tag).unwrap();
/// assert_eq!(tag, decompressed_tag);
/// ```
pub fn decompress ( bytes : & [ u8 ] ) -> Option < Fuzzy Tag< { GAMMA } > > {
pub fn decompress ( bytes : & [ u8 ] ) -> Option < Tag< { GAMMA } > > {
if bytes . len ( ) > 64 {
let ( u_bytes , rest ) = bytes . split_at ( 32 ) ;
let ( y_bytes , ciphertext ) = rest . split_at ( 32 ) ;
@ -148,7 +148,7 @@ impl<const GAMMA: u8> FuzzyTag<{ GAMMA }> {
let mut ciphertexts = BitVec ::from_bytes ( ciphertext ) ;
ciphertexts . truncate ( GAMMA as usize ) ;
return match ( CompressedRistretto ::from_slice ( u_bytes ) . decompress ( ) , Scalar ::from_canonical_bytes ( y_bytes_fixed ) ) {
( Some ( u ) , Some ( y ) ) = > Some ( Fuzzy Tag { u , y , ciphertexts } ) ,
( Some ( u ) , Some ( y ) ) = > Some ( Tag { u , y , ciphertexts } ) ,
_ = > None ,
} ;
}
@ -156,7 +156,7 @@ impl<const GAMMA: u8> FuzzyTag<{ GAMMA }> {
}
}
impl < const GAMMA : u8 > Display for Fuzzy Tag< { GAMMA } > {
impl < const GAMMA : u8 > Display for Tag< { GAMMA } > {
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt ::Result {
write! (
f ,
@ -168,64 +168,67 @@ impl<const GAMMA: u8> Display for FuzzyTag<{ GAMMA }> {
}
}
/// The complete secret key . Can't directly be used for testing. Instead you will need to generate
/// a Fuzzy DetectionKey using extract
/// The complete secret . Can't directly be used for testing. Instead you will need to generate
/// a DetectionKey using ` extract_detection_key`
#[ derive(Debug, Serialize, Deserialize) ]
pub struct FuzzySecretKey < const GAMMA : u8 > {
pub struct RootSecret < const GAMMA : u8 > {
/// the detection key - this can be given to adversarial servers to help probabilistically
/// filter messages (with a false-positive rate derived from γ and a 0% false negative rate)
secret _key : Vec < Scalar > ,
/// the public key - this can be given to people who you want to contact you
public_key: FuzzyPublic Key< { GAMMA } > ,
secret : Vec < Scalar > ,
/// the tagging key - this can be given to people who you want to contact you
tagging_key: Tagging Key< { GAMMA } > ,
}
impl < const GAMMA : u8 > FuzzySecretKey < { GAMMA } > {
impl < const GAMMA : u8 > RootSecret < { GAMMA } > {
/// Generate a new Key Pair given a security parameter `GAMMA`. Tags generated for a given
/// ` FuzzyPublicKey::flag` will pass the `FuzzyDetectionKey::test` for other public
/// ` TaggingKey::generate_tag` will pass the `DetectionKey::test_tag` for other tagging
/// keys with probability $ 2 ^ -8 $
/// Example:
/// ```
/// use fuzzytags::{ FuzzySecretKey };
/// let secret _key = FuzzySecretKey ::<24>::generate();
/// use fuzzytags::{ RootSecret };
/// let secret = RootSecret ::<24>::generate();
/// ```
pub fn generate ( ) -> FuzzySecretKey < { GAMMA } > {
pub fn generate ( ) -> RootSecret < { GAMMA } > {
let mut rng = OsRng ::default ( ) ;
let g = RISTRETTO_BASEPOINT_POINT ;
let mut secret _key = vec! [ ] ;
let mut secret = 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 ) ;
secret _key . push ( sk_i ) ;
secret . push ( sk_i ) ;
p_keys . push ( pk_i ) ;
}
FuzzySecretKey ::< GAMMA > {
secret _key ,
public_key: FuzzyPublic Key { 0 : p_keys } ,
RootSecret ::< GAMMA > {
secret ,
tagging_key: Tagging Key { 0 : p_keys } ,
}
}
/// extract a detection key for a given false positive (p = 2^-n)
/// This is the key that can be given to adversarail servers so that they can
/// detected messages that *may* be tagged for a given detection key with an
/// ideal false positive rate 2^{-n}
/// Example:
/// ```
/// use fuzzytags::{FuzzySecretKey};
/// let secret _key = FuzzySecretKey ::<24>::generate();
/// let detection_key = secret _key .extract(2);
/// use fuzzytags::{ RootSecret };
/// let secret = RootSecret ::<24>::generate();
/// let detection_key = secret .extract_detection_key (2);
/// ```
pub fn extract ( & self , n : usize ) -> Fuzzy DetectionKey< { GAMMA } > {
let parts = self . secret _key . iter ( ) . take ( n ) . cloned ( ) . collect ( ) ;
Fuzzy DetectionKey::< GAMMA > { 0 : parts }
pub fn extract _detection_key ( & self , n : usize ) -> DetectionKey< { GAMMA } > {
let parts = self . secret . iter ( ) . take ( n ) . cloned ( ) . collect ( ) ;
DetectionKey::< GAMMA > { 0 : parts }
}
/// derive the public key for this key
/// derive the tagging key for this secret
/// Example:
/// ```
/// use fuzzytags:: FuzzySecretKey ;
/// let secret _key = FuzzySecretKey ::<24>::generate();
/// let public_key = secret_key.public _key();
/// use fuzzytags:: RootSecret ;
/// let secret = RootSecret ::<24>::generate();
/// let tagging_key = secret.tagging _key();
/// ```
pub fn public_key( & self ) -> FuzzyPublic Key< { GAMMA } > {
self . public _key. clone ( )
pub fn tagging_key( & self ) -> Tagging Key< { GAMMA } > {
self . tagging _key. clone ( )
}
/// a hash function that takes 3 ristretto points as a parameter and outputs 0 or 1.
@ -250,11 +253,11 @@ impl<const GAMMA: u8> FuzzySecretKey<{ GAMMA }> {
}
/// A collection of "secret" data that can be used to determine if a `FuzzyTag` was intended for
/// the derived public key with probability p
/// the derived tagging key with probability p
#[ derive(Clone, Debug, Serialize, Deserialize) ]
pub struct Fuzzy DetectionKey< const GAMMA : u8 > ( Vec < Scalar > ) ;
pub struct DetectionKey< const GAMMA : u8 > ( Vec < Scalar > ) ;
impl < const GAMMA : u8 > Fuzzy DetectionKey< { GAMMA } > {
impl < const GAMMA : u8 > DetectionKey< { GAMMA } > {
/// a convenient id for a detection key for internal accounting purposes
/// do not expose this to applications
pub fn id ( & self ) -> String {
@ -266,20 +269,20 @@ impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
}
}
impl < const GAMMA : u8 > Display for Fuzzy DetectionKey< { GAMMA } > {
impl < const GAMMA : u8 > Display for DetectionKey< { GAMMA } > {
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt ::Result {
write! ( f , "{}" , self . id ( ) )
}
}
impl < const GAMMA : u8 > Fuzzy DetectionKey< { GAMMA } > {
impl < const GAMMA : u8 > DetectionKey< { GAMMA } > {
/// calculate the ideal false positive rate of this detection key
/// ```
/// use fuzzytags:: FuzzySecretKey ;
/// let secret _key = FuzzySecretKey ::<24>::generate();
/// let public_key = secret_key.public _key();
/// use fuzzytags:: RootSecret ;
/// let secret = RootSecret ::<24>::generate();
/// let tagging_key = secret.tagging _key();
/// // extract a detection key
/// let detection_key = secret _key .extract(5);
/// let detection_key = secret .extract_detection_key (5);
/// detection_key.false_positive_probability();
/// ```
pub fn false_positive_probability ( & self ) -> f64 {
@ -289,15 +292,15 @@ impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
/// returns true if the tag was intended for this key
/// Example:
/// ```
/// use fuzzytags:: FuzzySecretKey ;
/// let secret _key = FuzzySecretKey ::<24>::generate();
/// let public_key = secret_key.public _key();
/// use fuzzytags:: RootSecret ;
/// let secret = RootSecret ::<24>::generate();
/// let tagging_key = secret.tagging _key();
/// // extract a detection key
/// let detection_key = secret _key .extract(5);
/// let detection_key = secret .extract_detection_key (5);
///
/// // Give public key to a another party...
/// // Give tagging key to a another party...
/// // and then they can do...
/// let tag = public _key.generate_tag();
/// let tag = tagging _key.generate_tag();
///
/// // The server can now do this:
/// if detection_key.test_tag(&tag) {
@ -306,20 +309,20 @@ impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
/// // the message attached to this tag is definitely *not* for the party associated with the detection key.
/// }
/// ```
pub fn test_tag ( & self , tag : & Fuzzy Tag< { GAMMA } > ) -> bool {
pub fn test_tag ( & self , tag : & Tag< { GAMMA } > ) -> bool {
// A few checks to make sure the tag is well formed.
// All zeros in u or y can lead to a tag that validates against *all* public keys
// All zeros in u or y can lead to a tag that validates against *all* tagging keys
// That doesn't seem like a great idea, so we return false to be safe.
// Zero values should never appear in well generated tags.
if tag . u . eq ( & RistrettoPoint ::default ( ) ) | | tag . y . eq ( & Scalar ::zero ( ) ) {
return false ;
}
let m = FuzzySecretKey ::< GAMMA > ::g ( tag . u , & tag . ciphertexts ) ;
let m = RootSecret ::< GAMMA > ::g ( tag . u , & tag . ciphertexts ) ;
let g = RISTRETTO_BASEPOINT_POINT ;
// Re-derive w = g^z from the public tag.
// y = (1/r * (z-m)
// y = (1/r ) * (z-m)
// u = g^r
// so w = g^m + u^y
// w = g^m + g^(r * 1/r * (z-m))
@ -328,11 +331,11 @@ impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
// See below for a full explanation as to the reason for this:
let w = RistrettoPoint ::multiscalar_mul ( & [ m , tag . y ] , & [ g , tag . u ] ) ;
// for each secret key part...
// for each secret part...
let mut result = true ;
for ( i , x_i ) in self . 0. iter ( ) . enumerate ( ) {
// re-derive the key from the tag
let k_i = FuzzySecretKey ::< GAMMA > ::h ( tag . u , tag . u . mul ( x_i ) , w ) ;
let k_i = RootSecret ::< GAMMA > ::h ( tag . u , tag . u . mul ( x_i ) , w ) ;
// calculate the "original" plaintext
let c_i = match tag . ciphertexts . get ( i ) {
@ -354,10 +357,10 @@ impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
/// A public identity that others can create tags for.
#[ derive(Clone, Debug, Serialize, Deserialize) ]
pub struct FuzzyPublic Key< const GAMMA : u8 > ( Vec < RistrettoPoint > ) ;
pub struct Tagging Key< const GAMMA : u8 > ( Vec < RistrettoPoint > ) ;
impl < const GAMMA : u8 > FuzzyPublic Key< { GAMMA } > {
/// a convenient id for a public key for internal accounting purposes
impl < const GAMMA : u8 > Tagging Key< { GAMMA } > {
/// a convenient id for a tagging key for internal accounting purposes
/// do not expose this to applications
pub fn id ( & self ) -> String {
let mut hash = sha3 ::Sha3_256 ::new ( ) ;
@ -367,15 +370,15 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
format! ( "{}" , hex ::encode ( hash . finalize ( ) . as_slice ( ) ) , )
}
/// generate a new tag for this public key
/// generate a new tag for this tagging key
/// Example:
/// ```
/// use fuzzytags::{ FuzzySecretKey };
/// let secret _key = FuzzySecretKey ::<24>::generate();
/// let public_key = secret_key.public _key(); // give this to a sender
/// let tag = public _key.generate_tag();
/// use fuzzytags::{ RootSecret };
/// let secret = RootSecret ::<24>::generate();
/// let tagging_key = secret.tagging _key(); // give this to a sender
/// let tag = tagging _key.generate_tag();
/// ```
pub fn generate_tag ( & self ) -> Fuzzy Tag< { GAMMA } > {
pub fn generate_tag ( & self ) -> Tag< { GAMMA } > {
let mut rng = OsRng ::default ( ) ;
let g = RISTRETTO_BASEPOINT_POINT ;
@ -388,7 +391,7 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
// construct the ciphertext portion of the tag
let mut ciphertexts = BitVec ::new ( ) ;
for ( _i , h_i ) in self . 0. iter ( ) . enumerate ( ) {
let k_i = FuzzySecretKey ::< GAMMA > ::h ( u , h_i . mul ( r ) , w ) ;
let k_i = RootSecret ::< GAMMA > ::h ( u , h_i . mul ( r ) , w ) ;
// encrypt a plaintext of all 1's
let c_i = k_i ^ 0x01 ;
ciphertexts . push ( c_i = = 0x01 ) ;
@ -401,7 +404,7 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
// 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 k ey) in order to compute a collision (y,m) where m
// Once the ciphertext has been computed, we use a master trapdoor for the chameleon hash (which is part of the scheme’ s DetectionK ey) in order to compute a collision (y,m) where m
// is a hash of the remaining components of the ciphertext"
// Translated m is a challenge over the random element u and the ordered ciphertexts
@ -409,29 +412,29 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
// used to derive the key.
// finally calculate a `y` = 1/r * (z-m) which will be used to re-derive `w`
let m = FuzzySecretKey ::< GAMMA > ::g ( u , & ciphertexts ) ;
let m = RootSecret ::< GAMMA > ::g ( u , & ciphertexts ) ;
let y = r . invert ( ) . mul ( z . sub ( m ) ) ;
return Fuzzy Tag { u , y , ciphertexts } ;
return Tag { u , y , ciphertexts } ;
}
#[ cfg(feature = " entangled " ) ]
/// WARNING: if you pass in a large length into this function it will take a long time!
/// This begins a very slow, but parallel, search for a tag that will validate of the given
/// public keys up to a given false positive rate 2^-l
/// tagging keys up to a given false positive rate 2^-l
/// Example:
/// ```
/// use fuzzytags::{ FuzzySecretKey, FuzzyPublic Key};
/// let secret_ key_1 = FuzzySecretKey ::<24>::generate();
/// let secret_ key_2 = FuzzySecretKey ::<24>::generate();
/// let public_key_1 = secret_key_1.public _key(); // give this to a sender
/// let public_key_2 = secret_key_2.public _key(); // give this to a sender
/// // Will validate for detection keys derived from both secret_ key_ 1 and secret_key _2 up
/// use fuzzytags::{ RootSecret, Tagging Key};
/// let secret_ 1 = RootSecret ::<24>::generate();
/// let secret_ 2 = RootSecret ::<24>::generate();
/// let tagging_key_1 = secret_1.tagging _key(); // give this to a sender
/// let tagging_key_2 = secret_2.tagging _key(); // give this to a sender
/// // Will validate for detection keys derived from both secret_ 1 and secret_2 up
/// // to n=8
/// // Sender can now do...tag will validate on detection keys of length 8 or lower.
/// let tag = FuzzyPublicKey::generate_entangled_tag(vec![public_key_1,public _key_2], 8);
/// let tag = TaggingKey::generate_entangled_tag(vec![tagging_key_1,tagging _key_2], 8);
/// ```
pub fn generate_entangled_tag ( public_keys: Vec < FuzzyPublic Key< { GAMMA } > > , length : usize ) -> Fuzzy Tag< { GAMMA } > {
pub fn generate_entangled_tag ( tagging_keys: Vec < Tagging Key< { GAMMA } > > , length : usize ) -> Tag< { GAMMA } > {
let mut rng = OsRng ::default ( ) ;
let g = RISTRETTO_BASEPOINT_POINT ;
// generate some random points...
@ -439,24 +442,24 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
let u = g . mul ( r ) ;
// Compute and cache some public points that we will be using over and over again
let mut public _key_precomputes = vec! [ ] ;
for public_key in public _keys. iter ( ) {
let mut tagging _key_precomputes = vec! [ ] ;
for tagging_key in tagging _keys. iter ( ) {
let mut precompute = vec! [ ] ;
for i in public _key. 0. iter ( ) {
for i in tagging _key. 0. iter ( ) {
precompute . push ( i . mul ( r ) ) ;
}
public _key_precomputes. push ( precompute ) ;
tagging _key_precomputes. push ( precompute ) ;
}
let config = brute_force ::Config ::default ( ) ;
let f = | z : & Scalar | {
let w = g . mul ( z ) ;
let mut key = vec! [ ] ;
for ( i , precompute ) in public _key_precomputes[ 0 ] . iter ( ) . enumerate ( ) {
let k_i = FuzzySecretKey ::< GAMMA > ::h ( u , * precompute , w ) ;
for ( i , precompute ) in tagging _key_precomputes[ 0 ] . iter ( ) . enumerate ( ) {
let k_i = RootSecret ::< GAMMA > ::h ( u , * precompute , w ) ;
if i < length {
for precompute in public _key_precomputes. iter ( ) . skip ( 1 ) {
let n_k_i = FuzzySecretKey ::< GAMMA > ::h ( u , precompute [ i ] , w ) ;
for precompute in tagging _key_precomputes. iter ( ) . skip ( 1 ) {
let n_k_i = RootSecret ::< GAMMA > ::h ( u , precompute [ i ] , w ) ;
if k_i ! = n_k_i {
return None ;
}
@ -474,9 +477,9 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
}
// This is the same as generate_tag, kept separate to avoid over-decomposition
let m = FuzzySecretKey ::< GAMMA > ::g ( u , & ciphertexts ) ;
let m = RootSecret ::< GAMMA > ::g ( u , & ciphertexts ) ;
let y = r . invert ( ) . mul ( z . sub ( m ) ) ;
return Some ( Fuzzy Tag { u , y , ciphertexts } ) ;
return Some ( Tag { u , y , ciphertexts } ) ;
} ;
brute_force ( config , adaptors ::auto_advance ( f ) )
}
@ -484,48 +487,48 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
#[ cfg(test) ]
mod tests {
use crate ::{ FuzzySecretKey, Fuzzy Tag} ;
use crate ::{ RootSecret, Tag} ;
use bit_vec ::BitVec ;
use curve25519_dalek ::ristretto ::RistrettoPoint ;
use curve25519_dalek ::scalar ::Scalar ;
#[ test ]
fn test_compression ( ) {
let secret _key = FuzzySecretKey ::< 24 > ::generate ( ) ;
let public_key = secret_key . public _key( ) ;
let secret = RootSecret ::< 24 > ::generate ( ) ;
let tagging_key = secret . tagging _key( ) ;
// Give public key to a another party...
// Give tagging key to a another party...
// and then they can do...
let tag = public _key. generate_tag ( ) ;
let tag = tagging _key. generate_tag ( ) ;
let compressed_tag = tag . compress ( ) ;
let decompressed_tag = Fuzzy Tag::< 24 > ::decompress ( & compressed_tag ) . unwrap ( ) ;
let decompressed_tag = Tag::< 24 > ::decompress ( & compressed_tag ) . unwrap ( ) ;
assert_eq! ( tag , decompressed_tag ) ;
}
#[ test ]
fn test_serialization ( ) {
// generate some new keys...
let secret _key = FuzzySecretKey ::< 15 > ::generate ( ) ;
let tag = secret _key. public_key . generate_tag ( ) ;
let detection_key = secret _key . extract ( 10 ) ;
let secret = RootSecret ::< 15 > ::generate ( ) ;
let tag = secret . tagging_key ( ) . generate_tag ( ) ;
let detection_key = secret . extract _detection_key ( 10 ) ;
let serialized_tag = serde_json ::to_string ( & tag ) . unwrap ( ) ;
let deserialized_tag : Fuzzy Tag< 15 > = serde_json ::from_str ( & serialized_tag ) . unwrap ( ) ;
let deserialized_tag : Tag< 15 > = serde_json ::from_str ( & serialized_tag ) . unwrap ( ) ;
assert_eq! ( tag . compress ( ) , deserialized_tag . compress ( ) ) ;
assert_eq! ( true , detection_key . test_tag ( & deserialized_tag ) ) ;
// generate some new keys...
let secret _key = FuzzySecretKey ::< 24 > ::generate ( ) ;
let tag = secret _key. public_key . generate_tag ( ) ;
let detection_key = secret _key . extract ( 10 ) ;
let secret = RootSecret ::< 24 > ::generate ( ) ;
let tag = secret . tagging_key ( ) . generate_tag ( ) ;
let detection_key = secret . extract _detection_key ( 10 ) ;
let serialized_tag = serde_json ::to_string ( & tag ) . unwrap ( ) ;
let deserialized_tag : Fuzzy Tag< 24 > = serde_json ::from_str ( & serialized_tag ) . unwrap ( ) ;
let deserialized_tag : Tag< 24 > = serde_json ::from_str ( & serialized_tag ) . unwrap ( ) ;
assert_eq! ( tag . compress ( ) , deserialized_tag . compress ( ) ) ;
assert_eq! ( true , detection_key . test_tag ( & deserialized_tag ) ) ;
// Test some bincode...
let bincode_tag = bincode ::serialize ( & tag ) ;
// println!("Serialized: {:?}", bincode_tag);
let deserialized_tag : Fuzzy Tag< 24 > = bincode ::deserialize ( & bincode_tag . unwrap ( ) ) . unwrap ( ) ;
let deserialized_tag : Tag< 24 > = bincode ::deserialize ( & bincode_tag . unwrap ( ) ) . unwrap ( ) ;
//println!("Deserialized: {}", deserialized_tag);
//assert_eq!(tag.compress(), deserialized_tag.compress());
assert_eq! ( true , detection_key . test_tag ( & deserialized_tag ) ) ;
@ -534,14 +537,14 @@ mod tests {
#[ test ]
#[ cfg(feature = " entangled " ) ]
fn test_multiple ( ) {
use crate ::FuzzyPublic Key;
let secret _keys: Vec < FuzzySecretKey < 24 > > = ( 0 .. 2 ) . map ( | _x | FuzzySecretKey ::< 24 > ::generate ( ) ) . collect ( ) ;
let public_keys: Vec < FuzzyPublic Key< 24 > > = secret _key s. iter ( ) . map ( | x | x . public _key( ) ) . collect ( ) ;
use crate ::Tagging Key;
let secret s: Vec < RootSecret < 24 > > = ( 0 .. 2 ) . map ( | _x | RootSecret ::< 24 > ::generate ( ) ) . collect ( ) ;
let tagging_keys: Vec < Tagging Key< 24 > > = secret s. iter ( ) . map ( | x | x . tagging _key( ) ) . collect ( ) ;
// it takes ~15 minutes on a standard desktop to find a length=24 match for 2 parties, so for testing let's keep things light
let entangled_tag = FuzzyPublicKey::generate_entangled_tag ( public _keys, 16 ) ;
let entangled_tag = TaggingKey::generate_entangled_tag ( tagging _keys, 16 ) ;
println! ( "{}" , entangled_tag ) ;
for secret _key in secret _key s. iter ( ) {
let detection_key = secret _key . extract ( 16 ) ;
for secret in secret s. iter ( ) {
let detection_key = secret . extract _detection_key ( 16 ) ;
assert! ( detection_key . test_tag ( & entangled_tag ) ) ;
println! ( "{}" , detection_key ) ;
}
@ -550,16 +553,16 @@ mod tests {
#[ test ]
fn correctness ( ) {
let number_of_messages = 100 ;
let secret _key = FuzzySecretKey ::< 16 > ::generate ( ) ;
let secret = RootSecret ::< 16 > ::generate ( ) ;
for i in 0 .. number_of_messages {
let tag = secret _key. public _key( ) . generate_tag ( ) ;
let tag = secret . tagging _key( ) . generate_tag ( ) ;
println! ( "{}: {}" , i , tag ) ;
assert! ( secret _key . extract ( 5 ) . test_tag ( & tag ) ) ;
assert! ( secret . extract _detection_key ( 5 ) . test_tag ( & tag ) ) ;
}
}
fn gen_zero_tag_zero ( ) -> Fuzzy Tag< 24 > {
let tag = Fuzzy Tag {
fn gen_zero_tag_zero ( ) -> Tag< 24 > {
let tag = Tag {
u : RistrettoPoint ::default ( ) ,
y : Scalar ::default ( ) ,
ciphertexts : BitVec ::from_elem ( 24 , false ) ,
@ -567,8 +570,8 @@ mod tests {
tag
}
fn gen_zero_tag_one ( ) -> Fuzzy Tag< 24 > {
let mut tag = Fuzzy Tag {
fn gen_zero_tag_one ( ) -> Tag< 24 > {
let mut tag = Tag {
u : RistrettoPoint ::default ( ) ,
y : Scalar ::default ( ) ,
ciphertexts : BitVec ::from_elem ( 24 , false ) ,
@ -579,33 +582,33 @@ mod tests {
#[ test ]
// Thanks to Lee Bousfield who noticed an all zeros or all ones tag would
// validate against a public key with 50% probability, allowing universal
// validate against a tagging key with 50% probability, allowing universal
// broadcast, which overall seems like a bad idea...
// Test to make sure that doesn't happen.
fn test_zero_tag ( ) {
let secret _key = FuzzySecretKey ::< 24 > ::generate ( ) ;
let secret = RootSecret ::< 24 > ::generate ( ) ;
let tag = gen_zero_tag_zero ( ) ;
assert_eq! ( false , secret _key . extract ( 6 ) . test_tag ( & tag ) ) ;
assert_eq! ( false , secret . extract _detection_key ( 6 ) . test_tag ( & tag ) ) ;
let tag = gen_zero_tag_one ( ) ;
assert_eq! ( false , secret _key . extract ( 6 ) . test_tag ( & tag ) ) ;
assert_eq! ( false , secret . extract _detection_key ( 6 ) . test_tag ( & tag ) ) ;
}
#[ test ]
fn false_positives ( ) {
let number_of_messages = 1000 ;
let secret _key = FuzzySecretKey ::< 24 > ::generate ( ) ;
let secret = RootSecret ::< 24 > ::generate ( ) ;
let mut false_positives = 0 ;
for _i in 0 .. number_of_messages {
let secret _key2 = FuzzySecretKey ::< 24 > ::generate ( ) ;
let tag = secret _key2. public _key( ) . generate_tag ( ) ;
assert! ( secret _key 2. extract ( 3 ) . test_tag ( & tag ) ) ;
if secret _key . extract ( 3 ) . test_tag ( & tag ) = = true {
let secret 2 = RootSecret ::< 24 > ::generate ( ) ;
let tag = secret 2. tagging _key( ) . generate_tag ( ) ;
assert! ( secret 2. extract _detection_key ( 3 ) . test_tag ( & tag ) ) ;
if secret . extract _detection_key ( 3 ) . test_tag ( & tag ) = = true {
false_positives + = 1 ;
}
}
println! (
"Expected False Positive Rate: {}\nActual False Positive Rate: {}" ,
secret _key . extract ( 3 ) . false_positive_probability ( ) ,
secret . extract _detection_key ( 3 ) . false_positive_probability ( ) ,
( false_positives as f64 / number_of_messages as f64 )
) ;
}