Renaming
This commit is contained in:
parent
a9f10651cc
commit
49134d643d
75
README.md
75
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
|
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.
|
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^-γ.
|
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
|
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.
|
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
|
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**.
|
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
|
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.
|
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
|
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
|
## Usage
|
||||||
|
|
||||||
Generate a key pair:
|
A party first needs to generate `RootSecret`
|
||||||
|
|
||||||
use fuzzytags::FuzzySecretKey;
|
use fuzzytags::RootSecret;
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
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
|
From the secret detection key a party can derive a `DetectionKey` which can be given to adversarial server to
|
||||||
messaging service / privacy-preserving application.
|
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_.
|
validate against a random public key with a maximum probability of _2^-gamma_.
|
||||||
|
|
||||||
## Generating Tags
|
## 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;
|
use fuzzytags::RootSecret;
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret = RootSecret::<24>::generate();
|
||||||
let public_key = secret_key.public_key();
|
let tagging_key = secret.tagging_key();
|
||||||
|
|
||||||
// Give public key to a another party...
|
// Give public key to a another party...
|
||||||
// and then they can do...
|
// 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.
|
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.:
|
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;
|
use fuzzytags::RootSecret;
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret = RootSecret::<24>::generate();
|
||||||
let public_key = secret_key.public_key();
|
let tagging_key = secret.tagging_key();
|
||||||
// extract a detection 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...
|
// and then they can do...
|
||||||
let tag = public_key.generate_tag();
|
let tag = tagging_key.generate_tag();
|
||||||
|
|
||||||
// The server can now do this:
|
// The server can now do this:
|
||||||
if detection_key.test_tag(&tag) {
|
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
|
## Entangled Tags
|
||||||
|
|
||||||
When enabled with the `entangled` feature the `FuzzyPublicKey::generate_entangled_tag` function is available. This
|
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 public keys** and
|
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**.
|
opens up applications like **multiple broadcast** and **deniable sending**.
|
||||||
|
|
||||||
|
|
||||||
use fuzzytags::{FuzzySecretKey, FuzzyPublicKey};
|
use fuzzytags::{RootSecret, TaggingKey};
|
||||||
let secret_key_1 = FuzzySecretKey::<24>::generate();
|
let secret_1 = RootSecret::<24>::generate();
|
||||||
let secret_key_2 = FuzzySecretKey::<24>::generate();
|
let secret_2 = RootSecret::<24>::generate();
|
||||||
let public_key_1 = secret_key_1.public_key(); // give this to a sender
|
let tagging_key_1 = secret_1.tagging_key(); // give this to a sender
|
||||||
let public_key_2 = secret_key_2.public_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_key_1 and secret_key_2 up
|
// Will validate for detection keys derived from both secret_1 and secret_2 up
|
||||||
// to n=8
|
// to n=8
|
||||||
#[cfg(feature = "entangled")]
|
#[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
|
## 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
|
`γ` 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.:
|
of different approaches e.g.:
|
||||||
|
|
||||||
use fuzzytags::FuzzySecretKey;
|
use fuzzytags::RootSecret;
|
||||||
use fuzzytags::FuzzyTag;
|
use fuzzytags::Tag;
|
||||||
|
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret = RootSecret::<24>::generate();
|
||||||
let public_key = secret_key.public_key();
|
let tagging_key = secret.tagging_key();
|
||||||
|
|
||||||
// Give public key to a another party...
|
// Give public key to a another party...
|
||||||
// and then they can do...
|
// 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:
|
// An example using JSON serialization...see serde doc for other formats:
|
||||||
let serialized_tag = serde_json::to_string(&tag).unwrap();
|
let serialized_tag = serde_json::to_string(&tag).unwrap();
|
||||||
println!("Serialized: {}", serialized_tag);
|
println!("Serialized: {}", serialized_tag);
|
||||||
|
|
||||||
// We can then deserialize with:
|
// We can then deserialize with:
|
||||||
let deserialized_tag: Result<FuzzyTag<24>, serde_json::Error> = serde_json::from_str(&serialized_tag);
|
let deserialized_tag: Result<Tag<24>, serde_json::Error> = serde_json::from_str(&serialized_tag);
|
||||||
println!("Deserialized: {}", deserialized_tag.unwrap());
|
println!("Deserialized: {}", deserialized_tag.unwrap());
|
||||||
|
|
||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||||
use fuzzytags::FuzzySecretKey;
|
use fuzzytags::RootSecret;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
fn benchmark_generate_tag(c: &mut Criterion) {
|
fn benchmark_generate_tag(c: &mut Criterion) {
|
||||||
let mut group = c.benchmark_group("generate_tags");
|
let mut group = c.benchmark_group("generate_tags");
|
||||||
group.measurement_time(Duration::new(10, 0));
|
group.measurement_time(Duration::new(10, 0));
|
||||||
group.sample_size(1000);
|
group.sample_size(1000);
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret_key = RootSecret::<24>::generate();
|
||||||
for p in [5, 10, 15].iter() {
|
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()));
|
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");
|
let mut group = c.benchmark_group("test_tags");
|
||||||
group.measurement_time(Duration::new(10, 0));
|
group.measurement_time(Duration::new(10, 0));
|
||||||
group.sample_size(1000);
|
group.sample_size(1000);
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret_key = RootSecret::<24>::generate();
|
||||||
|
|
||||||
for p in [5, 10, 15].iter() {
|
for p in [5, 10, 15].iter() {
|
||||||
let tag = secret_key.public_key().generate_tag();
|
let tag = secret_key.tagging_key().generate_tag();
|
||||||
let detection_key = secret_key.extract(*p);
|
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)));
|
group.bench_with_input(BenchmarkId::from_parameter(p), p, |b, _gamma| b.iter(|| detection_key.test_tag(&tag)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
293
src/lib.rs
293
src/lib.rs
|
@ -22,21 +22,21 @@ use brute_force::adaptors;
|
||||||
#[cfg(feature = "entangled")]
|
#[cfg(feature = "entangled")]
|
||||||
use brute_force::brute_force;
|
use brute_force::brute_force;
|
||||||
|
|
||||||
/// A tag is a probabilistic cryptographic structure. When constructed for a given `FuzzyPublicKey`
|
/// A tag is a probabilistic cryptographic structure. When constructed for a given `TaggingKey`
|
||||||
/// it will pass the `FuzzyDetectionKey::test` 100% of the time. For other public keys
|
/// 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.
|
/// it will pass the test with probability `GAMMA` related to the security parameter of the system.
|
||||||
/// This system provides the following security properties:
|
/// 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 (_γ_)
|
/// * 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)
|
/// * 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)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct FuzzyTag<const GAMMA: u8> {
|
pub struct Tag<const GAMMA: u8> {
|
||||||
u: RistrettoPoint,
|
u: RistrettoPoint,
|
||||||
y: Scalar,
|
y: Scalar,
|
||||||
ciphertexts: BitVec,
|
ciphertexts: BitVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const GAMMA: u8> Serialize for FuzzyTag<{ GAMMA }> {
|
impl<const GAMMA: u8> Serialize for Tag<{ GAMMA }> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
|
@ -51,7 +51,7 @@ impl<const GAMMA: u8> 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<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
|
@ -59,13 +59,13 @@ impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> {
|
||||||
struct FuzzyTagVisitor<const GAMMA: u8>;
|
struct FuzzyTagVisitor<const GAMMA: u8>;
|
||||||
|
|
||||||
impl<'de, const GAMMA: u8> Visitor<'de> for FuzzyTagVisitor<{ GAMMA }> {
|
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 {
|
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
formatter.write_str("64 bytes + GAMMA+bits of data")
|
formatter.write_str("64 bytes + GAMMA+bits of data")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_seq<A>(self, mut seq: A) -> Result<FuzzyTag<{ GAMMA }>, A::Error>
|
fn visit_seq<A>(self, mut seq: A) -> Result<Tag<{ GAMMA }>, A::Error>
|
||||||
where
|
where
|
||||||
A: serde::de::SeqAccess<'de>,
|
A: serde::de::SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
|
@ -79,7 +79,7 @@ impl<'de, const GAMMA: u8> Deserialize<'de> for FuzzyTag<{ GAMMA }> {
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FuzzyTag::<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> FuzzyTag<{ GAMMA }> {
|
impl<const GAMMA: u8> Tag<{ GAMMA }> {
|
||||||
/// An optimal sized copy of the tag
|
/// An optimal sized copy of the tag
|
||||||
/// Compressed u || y || ciphertext
|
/// Compressed u || y || ciphertext
|
||||||
/// Ciphertext is right-padded with zeros to the nearest byte
|
/// 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)
|
/// You probably want to use one of the many serde `serialize` apis instead (see README)
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::FuzzySecretKey;
|
/// use fuzzytags::RootSecret;
|
||||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
/// let secret = RootSecret::<24>::generate();
|
||||||
/// let public_key = secret_key.public_key();
|
/// let tagging_key = secret.tagging_key();
|
||||||
/// // extract a detection 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...
|
/// // and then they can do...
|
||||||
/// let tag = public_key.generate_tag();
|
/// let tag = tagging_key.generate_tag();
|
||||||
/// let compressed_tag = tag.compress();
|
/// let compressed_tag = tag.compress();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn compress(&self) -> Vec<u8> {
|
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
|
/// 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)
|
/// You probably want to use one of the many serde `deserialize` apis instead (see README)
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::{FuzzySecretKey, FuzzyTag};
|
/// use fuzzytags::{RootSecret, Tag};
|
||||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
/// let secret = RootSecret::<24>::generate();
|
||||||
/// let public_key = secret_key.public_key();
|
/// let tagging_key = secret.tagging_key();
|
||||||
/// // extract a detection 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...
|
/// // and then they can do...
|
||||||
/// let tag = public_key.generate_tag();
|
/// let tag = tagging_key.generate_tag();
|
||||||
/// let compressed_tag = tag.compress();
|
/// 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);
|
/// assert_eq!(tag, decompressed_tag);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn decompress(bytes: &[u8]) -> Option<FuzzyTag<{ GAMMA }>> {
|
pub fn decompress(bytes: &[u8]) -> Option<Tag<{ GAMMA }>> {
|
||||||
if bytes.len() > 64 {
|
if bytes.len() > 64 {
|
||||||
let (u_bytes, rest) = bytes.split_at(32);
|
let (u_bytes, rest) = bytes.split_at(32);
|
||||||
let (y_bytes, ciphertext) = rest.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);
|
let mut ciphertexts = BitVec::from_bytes(ciphertext);
|
||||||
ciphertexts.truncate(GAMMA as usize);
|
ciphertexts.truncate(GAMMA as usize);
|
||||||
return match (CompressedRistretto::from_slice(u_bytes).decompress(), Scalar::from_canonical_bytes(y_bytes_fixed)) {
|
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,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ impl<const GAMMA: u8> FuzzyTag<{ GAMMA }> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const GAMMA: u8> Display for FuzzyTag<{ GAMMA }> {
|
impl<const GAMMA: u8> Display for Tag<{ GAMMA }> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
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
|
/// The complete secret. Can't directly be used for testing. Instead you will need to generate
|
||||||
/// a FuzzyDetectionKey using extract
|
/// a DetectionKey using `extract_detection_key`
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[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
|
/// 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)
|
/// filter messages (with a false-positive rate derived from γ and a 0% false negative rate)
|
||||||
secret_key: Vec<Scalar>,
|
secret: Vec<Scalar>,
|
||||||
/// the public key - this can be given to people who you want to contact you
|
/// the tagging key - this can be given to people who you want to contact you
|
||||||
public_key: FuzzyPublicKey<{ GAMMA }>,
|
tagging_key: TaggingKey<{ 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
|
/// 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 $
|
/// keys with probability $ 2 ^ -8 $
|
||||||
/// Example:
|
/// Example:
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::{FuzzySecretKey};
|
/// use fuzzytags::{RootSecret};
|
||||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
/// let secret = RootSecret::<24>::generate();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn generate() -> FuzzySecretKey<{ GAMMA }> {
|
pub fn generate() -> RootSecret<{ GAMMA }> {
|
||||||
let mut rng = OsRng::default();
|
let mut rng = OsRng::default();
|
||||||
let g = RISTRETTO_BASEPOINT_POINT;
|
let g = RISTRETTO_BASEPOINT_POINT;
|
||||||
let mut secret_key = vec![];
|
let mut secret = vec![];
|
||||||
let mut p_keys = vec![];
|
let mut p_keys = vec![];
|
||||||
for _i in 0..GAMMA {
|
for _i in 0..GAMMA {
|
||||||
let sk_i = Scalar::random(&mut rng);
|
let sk_i = Scalar::random(&mut rng);
|
||||||
let pk_i = g.mul(sk_i);
|
let pk_i = g.mul(sk_i);
|
||||||
secret_key.push(sk_i);
|
secret.push(sk_i);
|
||||||
p_keys.push(pk_i);
|
p_keys.push(pk_i);
|
||||||
}
|
}
|
||||||
FuzzySecretKey::<GAMMA> {
|
RootSecret::<GAMMA> {
|
||||||
secret_key,
|
secret,
|
||||||
public_key: FuzzyPublicKey { 0: p_keys },
|
tagging_key: TaggingKey { 0: p_keys },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// extract a detection key for a given false positive (p = 2^-n)
|
/// 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:
|
/// Example:
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::{FuzzySecretKey};
|
/// use fuzzytags::{RootSecret};
|
||||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
/// let secret = RootSecret::<24>::generate();
|
||||||
/// let detection_key = secret_key.extract(2);
|
/// let detection_key = secret.extract_detection_key(2);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn extract(&self, n: usize) -> FuzzyDetectionKey<{ GAMMA }> {
|
pub fn extract_detection_key(&self, n: usize) -> DetectionKey<{ GAMMA }> {
|
||||||
let parts = self.secret_key.iter().take(n).cloned().collect();
|
let parts = self.secret.iter().take(n).cloned().collect();
|
||||||
FuzzyDetectionKey::<GAMMA> { 0: parts }
|
DetectionKey::<GAMMA> { 0: parts }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// derive the public key for this key
|
/// derive the tagging key for this secret
|
||||||
/// Example:
|
/// Example:
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::FuzzySecretKey;
|
/// use fuzzytags::RootSecret;
|
||||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
/// let secret = RootSecret::<24>::generate();
|
||||||
/// let public_key = secret_key.public_key();
|
/// let tagging_key = secret.tagging_key();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn public_key(&self) -> FuzzyPublicKey<{ GAMMA }> {
|
pub fn tagging_key(&self) -> TaggingKey<{ GAMMA }> {
|
||||||
self.public_key.clone()
|
self.tagging_key.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// a hash function that takes 3 ristretto points as a parameter and outputs 0 or 1.
|
/// 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
|
/// 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)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct FuzzyDetectionKey<const GAMMA: u8>(Vec<Scalar>);
|
pub struct DetectionKey<const GAMMA: u8>(Vec<Scalar>);
|
||||||
|
|
||||||
impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
|
impl<const GAMMA: u8> DetectionKey<{ GAMMA }> {
|
||||||
/// a convenient id for a detection key for internal accounting purposes
|
/// a convenient id for a detection key for internal accounting purposes
|
||||||
/// do not expose this to applications
|
/// do not expose this to applications
|
||||||
pub fn id(&self) -> String {
|
pub fn id(&self) -> String {
|
||||||
|
@ -266,20 +269,20 @@ impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const GAMMA: u8> Display for FuzzyDetectionKey<{ GAMMA }> {
|
impl<const GAMMA: u8> Display for DetectionKey<{ GAMMA }> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.id())
|
write!(f, "{}", self.id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const GAMMA: u8> FuzzyDetectionKey<{ GAMMA }> {
|
impl<const GAMMA: u8> DetectionKey<{ GAMMA }> {
|
||||||
/// calculate the ideal false positive rate of this detection key
|
/// calculate the ideal false positive rate of this detection key
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::FuzzySecretKey;
|
/// use fuzzytags::RootSecret;
|
||||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
/// let secret = RootSecret::<24>::generate();
|
||||||
/// let public_key = secret_key.public_key();
|
/// let tagging_key = secret.tagging_key();
|
||||||
/// // extract a detection 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();
|
/// detection_key.false_positive_probability();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn false_positive_probability(&self) -> f64 {
|
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
|
/// returns true if the tag was intended for this key
|
||||||
/// Example:
|
/// Example:
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::FuzzySecretKey;
|
/// use fuzzytags::RootSecret;
|
||||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
/// let secret = RootSecret::<24>::generate();
|
||||||
/// let public_key = secret_key.public_key();
|
/// let tagging_key = secret.tagging_key();
|
||||||
/// // extract a detection 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...
|
/// // and then they can do...
|
||||||
/// let tag = public_key.generate_tag();
|
/// let tag = tagging_key.generate_tag();
|
||||||
///
|
///
|
||||||
/// // The server can now do this:
|
/// // The server can now do this:
|
||||||
/// if detection_key.test_tag(&tag) {
|
/// 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.
|
/// // 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.
|
// 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.
|
// That doesn't seem like a great idea, so we return false to be safe.
|
||||||
// Zero values should never appear in well generated tags.
|
// Zero values should never appear in well generated tags.
|
||||||
if tag.u.eq(&RistrettoPoint::default()) || tag.y.eq(&Scalar::zero()) {
|
if tag.u.eq(&RistrettoPoint::default()) || tag.y.eq(&Scalar::zero()) {
|
||||||
return false;
|
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;
|
let g = RISTRETTO_BASEPOINT_POINT;
|
||||||
|
|
||||||
// Re-derive w = g^z from the public tag.
|
// Re-derive w = g^z from the public tag.
|
||||||
// y = (1/r * (z-m)
|
// y = (1/r) * (z-m)
|
||||||
// u = g^r
|
// u = g^r
|
||||||
// so w = g^m + u^y
|
// so w = g^m + u^y
|
||||||
// w = g^m + g^(r * 1/r * (z-m))
|
// 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:
|
// See below for a full explanation as to the reason for this:
|
||||||
let w = RistrettoPoint::multiscalar_mul(&[m, tag.y], &[g, tag.u]);
|
let w = RistrettoPoint::multiscalar_mul(&[m, tag.y], &[g, tag.u]);
|
||||||
|
|
||||||
// for each secret key part...
|
// for each secret part...
|
||||||
let mut result = true;
|
let mut result = true;
|
||||||
for (i, x_i) in self.0.iter().enumerate() {
|
for (i, x_i) in self.0.iter().enumerate() {
|
||||||
// re-derive the key from the tag
|
// 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
|
// calculate the "original" plaintext
|
||||||
let c_i = match tag.ciphertexts.get(i) {
|
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.
|
/// A public identity that others can create tags for.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct FuzzyPublicKey<const GAMMA: u8>(Vec<RistrettoPoint>);
|
pub struct TaggingKey<const GAMMA: u8>(Vec<RistrettoPoint>);
|
||||||
|
|
||||||
impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
|
impl<const GAMMA: u8> TaggingKey<{ GAMMA }> {
|
||||||
/// a convenient id for a public key for internal accounting purposes
|
/// a convenient id for a tagging key for internal accounting purposes
|
||||||
/// do not expose this to applications
|
/// do not expose this to applications
|
||||||
pub fn id(&self) -> String {
|
pub fn id(&self) -> String {
|
||||||
let mut hash = sha3::Sha3_256::new();
|
let mut hash = sha3::Sha3_256::new();
|
||||||
|
@ -367,15 +370,15 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
|
||||||
format!("{}", hex::encode(hash.finalize().as_slice()),)
|
format!("{}", hex::encode(hash.finalize().as_slice()),)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generate a new tag for this public key
|
/// generate a new tag for this tagging key
|
||||||
/// Example:
|
/// Example:
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::{FuzzySecretKey};
|
/// use fuzzytags::{RootSecret};
|
||||||
/// let secret_key = FuzzySecretKey::<24>::generate();
|
/// let secret = RootSecret::<24>::generate();
|
||||||
/// let public_key = secret_key.public_key(); // give this to a sender
|
/// let tagging_key = secret.tagging_key(); // give this to a sender
|
||||||
/// let tag = public_key.generate_tag();
|
/// 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 mut rng = OsRng::default();
|
||||||
let g = RISTRETTO_BASEPOINT_POINT;
|
let g = RISTRETTO_BASEPOINT_POINT;
|
||||||
|
|
||||||
|
@ -388,7 +391,7 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
|
||||||
// construct the ciphertext portion of the tag
|
// construct the ciphertext portion of the tag
|
||||||
let mut ciphertexts = BitVec::new();
|
let mut ciphertexts = BitVec::new();
|
||||||
for (_i, h_i) in self.0.iter().enumerate() {
|
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
|
// encrypt a plaintext of all 1's
|
||||||
let c_i = k_i ^ 0x01;
|
let c_i = k_i ^ 0x01;
|
||||||
ciphertexts.push(c_i == 0x01);
|
ciphertexts.push(c_i == 0x01);
|
||||||
|
@ -401,7 +404,7 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
|
||||||
|
|
||||||
// From the paper:
|
// From the paper:
|
||||||
// "The value w corresponds to a chameleon hash [KR00] computed on the message (0,z), where z is chosen at random.
|
// "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"
|
// is a hash of the remaining components of the ciphertext"
|
||||||
|
|
||||||
// Translated m is a challenge over the random element u and the ordered ciphertexts
|
// 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.
|
// used to derive the key.
|
||||||
|
|
||||||
// finally calculate a `y` = 1/r * (z-m) which will be used to re-derive `w`
|
// 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));
|
let y = r.invert().mul(z.sub(m));
|
||||||
|
|
||||||
return FuzzyTag { u, y, ciphertexts };
|
return Tag { u, y, ciphertexts };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "entangled")]
|
#[cfg(feature = "entangled")]
|
||||||
/// WARNING: if you pass in a large length into this function it will take a long time!
|
/// 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
|
/// 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:
|
/// Example:
|
||||||
/// ```
|
/// ```
|
||||||
/// use fuzzytags::{FuzzySecretKey, FuzzyPublicKey};
|
/// use fuzzytags::{RootSecret, TaggingKey};
|
||||||
/// let secret_key_1 = FuzzySecretKey::<24>::generate();
|
/// let secret_1 = RootSecret::<24>::generate();
|
||||||
/// let secret_key_2 = FuzzySecretKey::<24>::generate();
|
/// let secret_2 = RootSecret::<24>::generate();
|
||||||
/// let public_key_1 = secret_key_1.public_key(); // give this to a sender
|
/// let tagging_key_1 = secret_1.tagging_key(); // give this to a sender
|
||||||
/// let public_key_2 = secret_key_2.public_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_key_1 and secret_key_2 up
|
/// // Will validate for detection keys derived from both secret_1 and secret_2 up
|
||||||
/// // to n=8
|
/// // to n=8
|
||||||
/// // Sender can now do...tag will validate on detection keys of length 8 or lower.
|
/// // 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<FuzzyPublicKey<{ GAMMA }>>, length: usize) -> FuzzyTag<{ GAMMA }> {
|
pub fn generate_entangled_tag(tagging_keys: Vec<TaggingKey<{ GAMMA }>>, length: usize) -> Tag<{ GAMMA }> {
|
||||||
let mut rng = OsRng::default();
|
let mut rng = OsRng::default();
|
||||||
let g = RISTRETTO_BASEPOINT_POINT;
|
let g = RISTRETTO_BASEPOINT_POINT;
|
||||||
// generate some random points...
|
// generate some random points...
|
||||||
|
@ -439,24 +442,24 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
|
||||||
let u = g.mul(r);
|
let u = g.mul(r);
|
||||||
|
|
||||||
// Compute and cache some public points that we will be using over and over again
|
// Compute and cache some public points that we will be using over and over again
|
||||||
let mut public_key_precomputes = vec![];
|
let mut tagging_key_precomputes = vec![];
|
||||||
for public_key in public_keys.iter() {
|
for tagging_key in tagging_keys.iter() {
|
||||||
let mut precompute = vec![];
|
let mut precompute = vec![];
|
||||||
for i in public_key.0.iter() {
|
for i in tagging_key.0.iter() {
|
||||||
precompute.push(i.mul(r));
|
precompute.push(i.mul(r));
|
||||||
}
|
}
|
||||||
public_key_precomputes.push(precompute);
|
tagging_key_precomputes.push(precompute);
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = brute_force::Config::default();
|
let config = brute_force::Config::default();
|
||||||
let f = |z: &Scalar| {
|
let f = |z: &Scalar| {
|
||||||
let w = g.mul(z);
|
let w = g.mul(z);
|
||||||
let mut key = vec![];
|
let mut key = vec![];
|
||||||
for (i, precompute) in public_key_precomputes[0].iter().enumerate() {
|
for (i, precompute) in tagging_key_precomputes[0].iter().enumerate() {
|
||||||
let k_i = FuzzySecretKey::<GAMMA>::h(u, *precompute, w);
|
let k_i = RootSecret::<GAMMA>::h(u, *precompute, w);
|
||||||
if i < length {
|
if i < length {
|
||||||
for precompute in public_key_precomputes.iter().skip(1) {
|
for precompute in tagging_key_precomputes.iter().skip(1) {
|
||||||
let n_k_i = FuzzySecretKey::<GAMMA>::h(u, precompute[i], w);
|
let n_k_i = RootSecret::<GAMMA>::h(u, precompute[i], w);
|
||||||
if k_i != n_k_i {
|
if k_i != n_k_i {
|
||||||
return None;
|
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
|
// 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));
|
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))
|
brute_force(config, adaptors::auto_advance(f))
|
||||||
}
|
}
|
||||||
|
@ -484,48 +487,48 @@ impl<const GAMMA: u8> FuzzyPublicKey<{ GAMMA }> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{FuzzySecretKey, FuzzyTag};
|
use crate::{RootSecret, Tag};
|
||||||
use bit_vec::BitVec;
|
use bit_vec::BitVec;
|
||||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_compression() {
|
fn test_compression() {
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret = RootSecret::<24>::generate();
|
||||||
let public_key = secret_key.public_key();
|
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...
|
// and then they can do...
|
||||||
let tag = public_key.generate_tag();
|
let tag = tagging_key.generate_tag();
|
||||||
let compressed_tag = tag.compress();
|
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);
|
assert_eq!(tag, decompressed_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialization() {
|
fn test_serialization() {
|
||||||
// generate some new keys...
|
// generate some new keys...
|
||||||
let secret_key = FuzzySecretKey::<15>::generate();
|
let secret = RootSecret::<15>::generate();
|
||||||
let tag = secret_key.public_key.generate_tag();
|
let tag = secret.tagging_key().generate_tag();
|
||||||
let detection_key = secret_key.extract(10);
|
let detection_key = secret.extract_detection_key(10);
|
||||||
let serialized_tag = serde_json::to_string(&tag).unwrap();
|
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!(tag.compress(), deserialized_tag.compress());
|
||||||
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
||||||
|
|
||||||
// generate some new keys...
|
// generate some new keys...
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret = RootSecret::<24>::generate();
|
||||||
let tag = secret_key.public_key.generate_tag();
|
let tag = secret.tagging_key().generate_tag();
|
||||||
let detection_key = secret_key.extract(10);
|
let detection_key = secret.extract_detection_key(10);
|
||||||
let serialized_tag = serde_json::to_string(&tag).unwrap();
|
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!(tag.compress(), deserialized_tag.compress());
|
||||||
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
||||||
|
|
||||||
// Test some bincode...
|
// Test some bincode...
|
||||||
let bincode_tag = bincode::serialize(&tag);
|
let bincode_tag = bincode::serialize(&tag);
|
||||||
// println!("Serialized: {:?}", bincode_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);
|
//println!("Deserialized: {}", deserialized_tag);
|
||||||
//assert_eq!(tag.compress(), deserialized_tag.compress());
|
//assert_eq!(tag.compress(), deserialized_tag.compress());
|
||||||
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
assert_eq!(true, detection_key.test_tag(&deserialized_tag));
|
||||||
|
@ -534,14 +537,14 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "entangled")]
|
#[cfg(feature = "entangled")]
|
||||||
fn test_multiple() {
|
fn test_multiple() {
|
||||||
use crate::FuzzyPublicKey;
|
use crate::TaggingKey;
|
||||||
let secret_keys: Vec<FuzzySecretKey<24>> = (0..2).map(|_x| FuzzySecretKey::<24>::generate()).collect();
|
let secrets: Vec<RootSecret<24>> = (0..2).map(|_x| RootSecret::<24>::generate()).collect();
|
||||||
let public_keys: Vec<FuzzyPublicKey<24>> = secret_keys.iter().map(|x| x.public_key()).collect();
|
let tagging_keys: Vec<TaggingKey<24>> = 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
|
// 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);
|
println!("{}", entangled_tag);
|
||||||
for secret_key in secret_keys.iter() {
|
for secret in secrets.iter() {
|
||||||
let detection_key = secret_key.extract(16);
|
let detection_key = secret.extract_detection_key(16);
|
||||||
assert!(detection_key.test_tag(&entangled_tag));
|
assert!(detection_key.test_tag(&entangled_tag));
|
||||||
println!("{}", detection_key);
|
println!("{}", detection_key);
|
||||||
}
|
}
|
||||||
|
@ -550,16 +553,16 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn correctness() {
|
fn correctness() {
|
||||||
let number_of_messages = 100;
|
let number_of_messages = 100;
|
||||||
let secret_key = FuzzySecretKey::<16>::generate();
|
let secret = RootSecret::<16>::generate();
|
||||||
for i in 0..number_of_messages {
|
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);
|
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> {
|
fn gen_zero_tag_zero() -> Tag<24> {
|
||||||
let tag = FuzzyTag {
|
let tag = Tag {
|
||||||
u: RistrettoPoint::default(),
|
u: RistrettoPoint::default(),
|
||||||
y: Scalar::default(),
|
y: Scalar::default(),
|
||||||
ciphertexts: BitVec::from_elem(24, false),
|
ciphertexts: BitVec::from_elem(24, false),
|
||||||
|
@ -567,8 +570,8 @@ mod tests {
|
||||||
tag
|
tag
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_zero_tag_one() -> FuzzyTag<24> {
|
fn gen_zero_tag_one() -> Tag<24> {
|
||||||
let mut tag = FuzzyTag {
|
let mut tag = Tag {
|
||||||
u: RistrettoPoint::default(),
|
u: RistrettoPoint::default(),
|
||||||
y: Scalar::default(),
|
y: Scalar::default(),
|
||||||
ciphertexts: BitVec::from_elem(24, false),
|
ciphertexts: BitVec::from_elem(24, false),
|
||||||
|
@ -579,33 +582,33 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// Thanks to Lee Bousfield who noticed an all zeros or all ones tag would
|
// 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...
|
// broadcast, which overall seems like a bad idea...
|
||||||
// Test to make sure that doesn't happen.
|
// Test to make sure that doesn't happen.
|
||||||
fn test_zero_tag() {
|
fn test_zero_tag() {
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret = RootSecret::<24>::generate();
|
||||||
let tag = gen_zero_tag_zero();
|
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();
|
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]
|
#[test]
|
||||||
fn false_positives() {
|
fn false_positives() {
|
||||||
let number_of_messages = 1000;
|
let number_of_messages = 1000;
|
||||||
let secret_key = FuzzySecretKey::<24>::generate();
|
let secret = RootSecret::<24>::generate();
|
||||||
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 secret_key2 = FuzzySecretKey::<24>::generate();
|
let secret2 = RootSecret::<24>::generate();
|
||||||
let tag = secret_key2.public_key().generate_tag();
|
let tag = secret2.tagging_key().generate_tag();
|
||||||
assert!(secret_key2.extract(3).test_tag(&tag));
|
assert!(secret2.extract_detection_key(3).test_tag(&tag));
|
||||||
if secret_key.extract(3).test_tag(&tag) == true {
|
if secret.extract_detection_key(3).test_tag(&tag) == true {
|
||||||
false_positives += 1;
|
false_positives += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!(
|
println!(
|
||||||
"Expected False Positive Rate: {}\nActual False Positive Rate: {}",
|
"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)
|
(false_positives as f64 / number_of_messages as f64)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue