From 49134d643dc4f55708ed05ff79aad50fb7147dd0 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Fri, 5 Feb 2021 13:57:25 -0800 Subject: [PATCH] Renaming --- README.md | 75 ++++----- benches/fuzzy_tags_benches.rs | 12 +- src/lib.rs | 293 +++++++++++++++++----------------- 3 files changed, 192 insertions(+), 188 deletions(-) diff --git a/README.md b/README.md index 58ea865..d6cb1d5 100644 --- a/README.md +++ b/README.md @@ -45,20 +45,20 @@ Now, instead of each party adopting a download-everything approach to metadata p or other assumptions) we can leverage fuzzytags to reduce the number of messages downloaded from the server by each party while maintaining a formalized concept of metadata privacy. -Every party generates a `FuzzyTagKeyPair`, consisting of a `FuzzyTagSecretKey` and a `FuzzyTagPublicKey`. These keys will +Every party generates a `RootSecret`, from which they can derive a `DetectionKey` and a `TaggingKey`. These keys will be generated with a parameter _γ_ that relates to the minimum false-positive probability 2^-γ. When submitting messages to the server for an intended **recipient**, the **sender** will generate a new tag -from the **recipients** `FuzzyTagPublicKey`. +from the **recipients** `TaggingKey`. -All parties will `extract` a `FuzzyTagDetectionKey` from their key pair. This key will be of length `n` and provide +All parties will `extract` a `DetectionKey` from their key pair. This key will be of length `n` and provide a false positive detection probability of 0 <= 2^-n <= 2^-γ. This detection key can be given to an adversarial server. When fetching new messages from the adversarial server, the server first runs a `test` of the tag of the message against the parties' detection key. If the tag passes the test, the message (along with the tag) is provided to the **recipient**. Finally, the **recipient** runs their own `test` of the tag against an extracted detection key such that -`FuzzyTagSecretKey == FuzzyTagDetectionKey` i.e. the probability of a false positive will be 2^-n == 2^-γ. This will +the probability of a false positive will be 2^-n == 2^-γ. This will produce a subset of messages likely intended for the **recipient**, with a smaller probability of false positives. Alternatively the **recipient** can simply try and decrypt every message in the subset of messages that the server @@ -66,30 +66,31 @@ provided them (depending on the efficiency of the decryption method). ## Usage -Generate a key pair: +A party first needs to generate `RootSecret` - use fuzzytags::FuzzySecretKey; - let secret_key = FuzzySecretKey::<24>::generate(); + use fuzzytags::RootSecret; + let secret = RootSecret::<24>::generate(); -`key.public_key` can be given to parties who you want to be able to communicate with you over a specific anonymous -messaging service / privacy-preserving application. +From the secret detection key a party can derive a `DetectionKey` which can be given to adversarial server to +fuzzily detect tags on behalf of the party. -`key.detection_key` can be given to untrusted _adversarial_ servers. +From the secret detection key a party can also derive a `TaggingKey` that can be public and given to +other parties for the purpose of generating fuzzytags addressed to a given party. -`gamma` is security property (_γ_) in the system. For a given gamma, a tag generated for a specific public key will +The `24` in the above code is a security property (_γ_) in the system. For a given gamma, a tag generated for a specific public key will validate against a random public key with a maximum probability of _2^-gamma_. ## Generating Tags -Once in possession of a public key, a party in a metadata resistant app can use it to generate tags: +Once in possession of a tagging key, a party in a metadata resistant app can use it to generate tags: - 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(); // Give public key to a another party... // and then they can do... - let tag = public_key.generate_tag(); + let tag = tagging_key.generate_tag(); These tags can then be attached to a message in a metadata resistant system. @@ -99,15 +100,15 @@ First it is necessary to extract a detection key for a given false positive prob This extracted key can then be given to an adversarial server. The server can then test a given tag against the detection key e.g.: - 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 the 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) { @@ -118,20 +119,20 @@ This extracted key can then be given to an adversarial server. The server can th ## Entangled Tags -When enabled with the `entangled` feature the `FuzzyPublicKey::generate_entangled_tag` function is available. This -allows you to generate tags that will validate against **multiple** detection keys from **distinct public keys** and +When enabled with the `entangled` feature the `TaggingKey::generate_entangled_tag` function is available. This +allows you to generate tags that will validate against **multiple** detection keys from **distinct tagging keys** and opens up applications like **multiple broadcast** and **deniable sending**. - use fuzzytags::{FuzzySecretKey, FuzzyPublicKey}; - 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, TaggingKey}; + 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 #[cfg(feature = "entangled")] - 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); ## Serialization @@ -139,22 +140,22 @@ This crate relies on `serde` for serialization. FuzzyTags are first compressed i `γ` bits, padded to the end with zeros to the nearest byte. This representation can then be exchanged using a number of different approaches e.g.: - use fuzzytags::FuzzySecretKey; - use fuzzytags::FuzzyTag; + use fuzzytags::RootSecret; + use fuzzytags::Tag; - 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... // and then they can do... - let tag = public_key.generate_tag(); + let tag = tagging_key.generate_tag(); // An example using JSON serialization...see serde doc for other formats: let serialized_tag = serde_json::to_string(&tag).unwrap(); println!("Serialized: {}", serialized_tag); // We can then deserialize with: - let deserialized_tag: Result, serde_json::Error> = serde_json::from_str(&serialized_tag); + let deserialized_tag: Result, serde_json::Error> = serde_json::from_str(&serialized_tag); println!("Deserialized: {}", deserialized_tag.unwrap()); ## Benchmarks diff --git a/benches/fuzzy_tags_benches.rs b/benches/fuzzy_tags_benches.rs index 775af40..c61933d 100644 --- a/benches/fuzzy_tags_benches.rs +++ b/benches/fuzzy_tags_benches.rs @@ -1,14 +1,14 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; -use fuzzytags::FuzzySecretKey; +use fuzzytags::RootSecret; use std::time::Duration; fn benchmark_generate_tag(c: &mut Criterion) { let mut group = c.benchmark_group("generate_tags"); group.measurement_time(Duration::new(10, 0)); group.sample_size(1000); - let secret_key = FuzzySecretKey::<24>::generate(); + let secret_key = RootSecret::<24>::generate(); for p in [5, 10, 15].iter() { - let public_key = secret_key.public_key(); + let public_key = secret_key.tagging_key(); group.bench_with_input(BenchmarkId::from_parameter(p), p, |b, _gamma| b.iter(|| public_key.generate_tag())); } } @@ -17,11 +17,11 @@ fn benchmark_test_tag(c: &mut Criterion) { let mut group = c.benchmark_group("test_tags"); group.measurement_time(Duration::new(10, 0)); group.sample_size(1000); - let secret_key = FuzzySecretKey::<24>::generate(); + let secret_key = RootSecret::<24>::generate(); for p in [5, 10, 15].iter() { - let tag = secret_key.public_key().generate_tag(); - let detection_key = secret_key.extract(*p); + let tag = secret_key.tagging_key().generate_tag(); + let detection_key = secret_key.extract_detection_key(*p); group.bench_with_input(BenchmarkId::from_parameter(p), p, |b, _gamma| b.iter(|| detection_key.test_tag(&tag))); } } diff --git a/src/lib.rs b/src/lib.rs index ed09a65..9438dcd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 `FuzzyPublicKey` -/// 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 `TaggingKey` +/// 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 FuzzyTag { +pub struct Tag { u: RistrettoPoint, y: Scalar, ciphertexts: BitVec, } -impl Serialize for FuzzyTag<{ GAMMA }> { +impl Serialize for Tag<{ GAMMA }> { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -51,7 +51,7 @@ impl Serialize for FuzzyTag<{ GAMMA }> { } } -impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> { +impl<'de, const GAMMA: u8> Deserialize<'de> for Tag<{ GAMMA }> { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -59,13 +59,13 @@ impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> { struct FuzzyTagVisitor; impl<'de, const GAMMA: u8> Visitor<'de> for FuzzyTagVisitor<{ GAMMA }> { - type Value = FuzzyTag<{ 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(self, mut seq: A) -> Result, A::Error> + fn visit_seq(self, mut seq: A) -> Result, A::Error> where A: serde::de::SeqAccess<'de>, { @@ -79,7 +79,7 @@ impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> { _ => break, } } - FuzzyTag::::decompress(&bytes).ok_or(serde::de::Error::custom("invalid fuzzytag")) + Tag::::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 FuzzyTag<{ GAMMA }> { +impl 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 { @@ -116,20 +116,20 @@ impl 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, FuzzyTag}; - /// 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 = FuzzyTag::decompress(&compressed_tag).unwrap(); + /// let decompressed_tag = Tag::decompress(&compressed_tag).unwrap(); /// assert_eq!(tag, decompressed_tag); /// ``` - pub fn decompress(bytes: &[u8]) -> Option> { + pub fn decompress(bytes: &[u8]) -> Option> { 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 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(FuzzyTag { u, y, ciphertexts }), + (Some(u), Some(y)) => Some(Tag { u, y, ciphertexts }), _ => None, }; } @@ -156,7 +156,7 @@ impl FuzzyTag<{ GAMMA }> { } } -impl Display for FuzzyTag<{ GAMMA }> { +impl Display for Tag<{ GAMMA }> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, @@ -168,64 +168,67 @@ impl Display for FuzzyTag<{ GAMMA }> { } } -/// The complete secret key. Can't directly be used for testing. Instead you will need to generate -/// a FuzzyDetectionKey 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 { +pub struct RootSecret { /// 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, - /// the public key - this can be given to people who you want to contact you - public_key: FuzzyPublicKey<{ GAMMA }>, + secret: Vec, + /// the tagging key - this can be given to people who you want to contact you + tagging_key: TaggingKey<{ GAMMA }>, } -impl FuzzySecretKey<{ GAMMA }> { +impl 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:: { - secret_key, - public_key: FuzzyPublicKey { 0: p_keys }, + RootSecret:: { + secret, + tagging_key: TaggingKey { 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) -> FuzzyDetectionKey<{ GAMMA }> { - let parts = self.secret_key.iter().take(n).cloned().collect(); - FuzzyDetectionKey:: { 0: parts } + pub fn extract_detection_key(&self, n: usize) -> DetectionKey<{ GAMMA }> { + let parts = self.secret.iter().take(n).cloned().collect(); + DetectionKey:: { 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) -> FuzzyPublicKey<{ GAMMA }> { - self.public_key.clone() + pub fn tagging_key(&self) -> TaggingKey<{ 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 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 FuzzyDetectionKey(Vec); +pub struct DetectionKey(Vec); -impl FuzzyDetectionKey<{ GAMMA }> { +impl 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 FuzzyDetectionKey<{ GAMMA }> { } } -impl Display for FuzzyDetectionKey<{ GAMMA }> { +impl Display for DetectionKey<{ GAMMA }> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{}", self.id()) } } -impl FuzzyDetectionKey<{ GAMMA }> { +impl 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 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 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: &FuzzyTag<{ 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::::g(tag.u, &tag.ciphertexts); + let m = RootSecret::::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 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::::h(tag.u, tag.u.mul(x_i), w); + let k_i = RootSecret::::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 FuzzyDetectionKey<{ GAMMA }> { /// A public identity that others can create tags for. #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct FuzzyPublicKey(Vec); +pub struct TaggingKey(Vec); -impl FuzzyPublicKey<{ GAMMA }> { - /// a convenient id for a public key for internal accounting purposes +impl TaggingKey<{ 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 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) -> FuzzyTag<{ GAMMA }> { + pub fn generate_tag(&self) -> Tag<{ GAMMA }> { let mut rng = OsRng::default(); let g = RISTRETTO_BASEPOINT_POINT; @@ -388,7 +391,7 @@ impl 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::::h(u, h_i.mul(r), w); + let k_i = RootSecret::::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 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 key) 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 DetectionKey) 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 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::::g(u, &ciphertexts); + let m = RootSecret::::g(u, &ciphertexts); let y = r.invert().mul(z.sub(m)); - return FuzzyTag { 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, FuzzyPublicKey}; - /// 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, TaggingKey}; + /// 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>, length: usize) -> FuzzyTag<{ GAMMA }> { + pub fn generate_entangled_tag(tagging_keys: Vec>, length: usize) -> Tag<{ GAMMA }> { let mut rng = OsRng::default(); let g = RISTRETTO_BASEPOINT_POINT; // generate some random points... @@ -439,24 +442,24 @@ impl 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::::h(u, *precompute, w); + for (i, precompute) in tagging_key_precomputes[0].iter().enumerate() { + let k_i = RootSecret::::h(u, *precompute, w); if i < length { - for precompute in public_key_precomputes.iter().skip(1) { - let n_k_i = FuzzySecretKey::::h(u, precompute[i], w); + for precompute in tagging_key_precomputes.iter().skip(1) { + let n_k_i = RootSecret::::h(u, precompute[i], w); if k_i != n_k_i { return None; } @@ -474,9 +477,9 @@ impl FuzzyPublicKey<{ GAMMA }> { } // This is the same as generate_tag, kept separate to avoid over-decomposition - let m = FuzzySecretKey::::g(u, &ciphertexts); + let m = RootSecret::::g(u, &ciphertexts); let y = r.invert().mul(z.sub(m)); - return Some(FuzzyTag { u, y, ciphertexts }); + return Some(Tag { u, y, ciphertexts }); }; brute_force(config, adaptors::auto_advance(f)) } @@ -484,48 +487,48 @@ impl FuzzyPublicKey<{ GAMMA }> { #[cfg(test)] mod tests { - use crate::{FuzzySecretKey, FuzzyTag}; + 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 = FuzzyTag::<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: FuzzyTag<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: FuzzyTag<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: FuzzyTag<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::FuzzyPublicKey; - let secret_keys: Vec> = (0..2).map(|_x| FuzzySecretKey::<24>::generate()).collect(); - let public_keys: Vec> = secret_keys.iter().map(|x| x.public_key()).collect(); + use crate::TaggingKey; + let secrets: Vec> = (0..2).map(|_x| RootSecret::<24>::generate()).collect(); + let tagging_keys: Vec> = secrets.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_keys.iter() { - let detection_key = secret_key.extract(16); + for secret in secrets.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() -> FuzzyTag<24> { - let tag = FuzzyTag { + 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() -> FuzzyTag<24> { - let mut tag = FuzzyTag { + 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_key2.extract(3).test_tag(&tag)); - if secret_key.extract(3).test_tag(&tag) == true { + let secret2 = RootSecret::<24>::generate(); + let tag = secret2.tagging_key().generate_tag(); + assert!(secret2.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) ); }