Clean up benchmarks, move RNG to function parameters + optimize generation

This commit is contained in:
Sarah Jamie Lewis 2021-05-20 01:53:33 -07:00
parent 1124ffc1a6
commit 2d73a43d7f
4 changed files with 68 additions and 36 deletions

View File

@ -104,12 +104,14 @@ validate against a random public key with a maximum probability of _2^-gamma_.
Once in possession of a tagging key, a party in a metadata resistant app can use it to generate tags:
use fuzzytags::RootSecret;
use rand::rngs::OsRng;
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 = tagging_key.generate_tag();
let mut rng = OsRng::default();
let tag = tagging_key.generate_tag(&mut rng);
These tags can then be attached to a message in a metadata resistant system.
@ -120,6 +122,7 @@ 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::RootSecret;
use rand::rngs::OsRng;
let secret = RootSecret::<24>::generate();
let tagging_key = secret.tagging_key();
// extract a detection key
@ -127,7 +130,8 @@ This extracted key can then be given to an adversarial server. The server can th
// Give the tagging key to a another party...
// and then they can do...
let tag = tagging_key.generate_tag();
let mut rng = OsRng::default();
let tag = tagging_key.generate_tag(&mut rng);
// The server can now do this:
if detection_key.test_tag(&tag) {
@ -144,6 +148,8 @@ opens up applications like **multiple broadcast** and **deniable sending**.
use fuzzytags::{RootSecret, TaggingKey};
use rand::rngs::OsRng;
let mut rng = OsRng::default();
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
@ -151,7 +157,7 @@ opens up applications like **multiple broadcast** and **deniable sending**.
// Will validate for detection keys derived from both secret_1 and secret_2 up
// to n=8
#[cfg(feature = "entangled")]
let tag = TaggingKey::generate_entangled_tag(vec![tagging_key_1,tagging_key_2], 8);
let tag = TaggingKey::generate_entangled_tag(vec![tagging_key_1,tagging_key_2], &mut rng, 8);
## Serialization
@ -161,13 +167,15 @@ of different approaches e.g.:
use fuzzytags::RootSecret;
use fuzzytags::Tag;
use rand::rngs::OsRng;
let mut rng = OsRng::default();
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 = tagging_key.generate_tag();
let tag = tagging_key.generate_tag(&mut rng);
// An example using JSON serialization...see serde doc for other formats:
let serialized_tag = serde_json::to_string(&tag).unwrap();

View File

@ -4,8 +4,8 @@ use std::time::Duration;
fn benchmark_entangled(c: &mut Criterion) {
let mut group = c.benchmark_group("entangling");
group.measurement_time(Duration::new(10, 0));
group.sample_size(10);
group.measurement_time(Duration::new(5000, 0));
group.sample_size(50);
let secret_key_1 = RootSecret::<24>::generate();
let secret_key_2 = RootSecret::<24>::generate();
let public_key_1 = secret_key_1.tagging_key();

View File

@ -1,5 +1,6 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use fuzzytags::{RootSecret, TaggingKey};
use rand::rngs::OsRng;
use std::time::Duration;
fn benchmark_generate_tag(c: &mut Criterion) {
@ -7,10 +8,11 @@ fn benchmark_generate_tag(c: &mut Criterion) {
group.measurement_time(Duration::new(10, 0));
group.sample_size(1000);
let secret_key = RootSecret::<24>::generate();
let mut rng = OsRng::default();
let public_key = secret_key.tagging_key();
for p in [5, 10, 15].iter() {
let public_key = secret_key.tagging_key();
group.bench_with_input(BenchmarkId::from_parameter(p), p, |b, _gamma| {
b.iter(|| public_key.generate_tag())
b.iter(|| public_key.generate_tag(&mut rng))
});
}
}
@ -20,11 +22,12 @@ fn benchmark_test_tag(c: &mut Criterion) {
group.measurement_time(Duration::new(10, 0));
group.sample_size(1000);
let secret_key = RootSecret::<24>::generate();
let mut rng = OsRng::default();
for p in [5, 10, 15].iter() {
let tag = secret_key.tagging_key().generate_tag();
for p in [5, 10, 15, 24].iter() {
let detection_key = secret_key.extract_detection_key(*p);
group.bench_with_input(BenchmarkId::from_parameter(p), p, |b, _gamma| {
let tag = secret_key.tagging_key().generate_tag(&mut rng);
b.iter(|| detection_key.test_tag(&tag))
});
}

View File

@ -11,6 +11,7 @@ use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::MultiscalarMul;
use rand::rngs::OsRng;
use rand::{CryptoRng, RngCore};
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use sha3::{Sha3_256, Sha3_512};
use std::convert::TryFrom;
@ -107,6 +108,7 @@ impl<const GAMMA: u8> Tag<{ GAMMA }> {
/// 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 rand::rngs::OsRng;
/// use fuzzytags::RootSecret;
/// let secret = RootSecret::<24>::generate();
/// let tagging_key = secret.tagging_key();
@ -115,7 +117,8 @@ impl<const GAMMA: u8> Tag<{ GAMMA }> {
///
/// // Give tagging key to a another party...
/// // and then they can do...
/// let tag = tagging_key.generate_tag();
/// let mut rng = OsRng::default();
/// let tag = tagging_key.generate_tag(&mut rng);
/// let compressed_tag = tag.compress();
/// ```
pub fn compress(&self) -> Vec<u8> {
@ -137,7 +140,9 @@ impl<const GAMMA: u8> Tag<{ GAMMA }> {
///
/// // Give tagging key to a another party...
/// // and then they can do...
/// let tag = tagging_key.generate_tag();
/// use rand::rngs::OsRng;
/// let mut rng = OsRng::default();
/// let tag = tagging_key.generate_tag(&mut rng);
/// let compressed_tag = tag.compress();
/// let decompressed_tag = Tag::decompress(&compressed_tag).unwrap();
/// assert_eq!(tag, decompressed_tag);
@ -334,7 +339,9 @@ impl<const GAMMA: u8> DetectionKey<{ GAMMA }> {
///
/// // Give tagging key to a another party...
/// // and then they can do...
/// let tag = tagging_key.generate_tag();
/// use rand::rngs::OsRng;
/// let mut rng = OsRng::default();
/// let tag = tagging_key.generate_tag(&mut rng);
///
/// // The server can now do this:
/// if detection_key.test_tag(&tag) {
@ -399,7 +406,9 @@ impl<const GAMMA: u8> DetectionKey<{ GAMMA }> {
/// let secrets: Vec<RootSecret<24>> = (0..2).map(|_x| RootSecret::<24>::generate()).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
/// let entangled_tag = TaggingKey::generate_entangled_tag(tagging_keys, 16);
/// use rand::rngs::OsRng;
/// let mut rng = OsRng::default();
/// let entangled_tag = TaggingKey::generate_entangled_tag(tagging_keys, &mut rng, 16);
/// let detection_keys = secrets.iter().map(|x| x.extract_detection_key(16)).collect();
///
/// let results = DetectionKey::test_tag_bulk(&detection_keys, &entangled_tag);
@ -495,21 +504,25 @@ impl<const GAMMA: u8> TaggingKey<{ GAMMA }> {
/// 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();
/// use rand::rngs::OsRng;
/// let mut rng = OsRng::default();
/// let tag = tagging_key.generate_tag(&mut rng);
/// ```
pub fn generate_tag(&self) -> Tag<{ GAMMA }> {
let mut rng = OsRng::default();
let g = RISTRETTO_BASEPOINT_POINT;
pub fn generate_tag<R: RngCore + CryptoRng>(&self, rng: &mut R) -> Tag<{ GAMMA }> {
// generate some random points...
let r = Scalar::random(&mut rng);
let u = g.mul(r);
let z = Scalar::random(&mut rng);
let w = g.mul(z);
let r = Scalar::random(rng);
let u = RISTRETTO_BASEPOINT_POINT.mul(r);
let z = Scalar::random(rng);
let w = RISTRETTO_BASEPOINT_POINT.mul(z);
// precompute the first part of the `H` hash function
let pre_h = RootSecret::<GAMMA>::pre_h(u, w);
// construct the ciphertext portion of the tag
let mut ciphertexts = BitVec::new();
for (_i, h_i) in self.0.iter().enumerate() {
let mut ciphertexts = BitVec::with_capacity(GAMMA.into());
for h_i in self.0.iter() {
let k_i = RootSecret::<GAMMA>::post_h(pre_h.clone(), h_i.mul(r));
// encrypt a plaintext of all 1's
let c_i = k_i ^ 0x01;
@ -551,13 +564,14 @@ impl<const GAMMA: u8> TaggingKey<{ GAMMA }> {
/// // 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 = TaggingKey::generate_entangled_tag(vec![tagging_key_1,tagging_key_2], 8);
/// use rand::rngs::OsRng;
/// let mut rng = OsRng::default();
/// let tag = TaggingKey::generate_entangled_tag(vec![tagging_key_1,tagging_key_2], &mut rng, 8);
/// ```
pub fn generate_entangled_tag(tagging_keys: Vec<TaggingKey<{ GAMMA }>>, length: usize) -> Tag<{ GAMMA }> {
let mut rng = OsRng::default();
pub fn generate_entangled_tag<R: RngCore + CryptoRng>(tagging_keys: Vec<TaggingKey<{ GAMMA }>>, rng: &mut R, length: usize) -> Tag<{ GAMMA }> {
let g = RISTRETTO_BASEPOINT_POINT;
// generate some random points...
let r = Scalar::random(&mut rng);
let r = Scalar::random(rng);
let u = g.mul(r);
// Compute and cache some public points that we will be using over and over again
@ -621,7 +635,8 @@ mod tests {
// Give tagging key to a another party...
// and then they can do...
let tag = tagging_key.generate_tag();
let mut rng = OsRng::default();
let tag = tagging_key.generate_tag(&mut rng);
let compressed_tag = tag.compress();
let decompressed_tag = Tag::<24>::decompress(&compressed_tag).unwrap();
assert_eq!(tag, decompressed_tag);
@ -630,8 +645,10 @@ mod tests {
#[test]
fn test_serialization() {
// generate some new keys...
let secret = RootSecret::<15>::generate();
let tag = secret.tagging_key().generate_tag();
let mut rng = OsRng::default();
let tag = secret.tagging_key().generate_tag(&mut rng);
let detection_key = secret.extract_detection_key(10);
let serialized_tag = serde_json::to_string(&tag).unwrap();
println!("{}", serialized_tag);
@ -641,7 +658,7 @@ mod tests {
// generate some new keys...
let secret = RootSecret::<24>::generate();
let tag = secret.tagging_key().generate_tag();
let tag = secret.tagging_key().generate_tag(&mut rng);
let detection_key = secret.extract_detection_key(10);
let serialized_tag = serde_json::to_string(&tag).unwrap();
let deserialized_tag: Tag<24> = serde_json::from_str(&serialized_tag).unwrap();
@ -680,7 +697,8 @@ mod tests {
let secrets: Vec<RootSecret<24>> = (0..2).map(|_x| RootSecret::<24>::generate()).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
let entangled_tag = TaggingKey::generate_entangled_tag(tagging_keys, 16);
let mut rng = OsRng::default();
let entangled_tag = TaggingKey::generate_entangled_tag(tagging_keys, &mut rng, 16);
println!("{}", entangled_tag);
for secret in secrets.iter() {
let detection_key = secret.extract_detection_key(16);
@ -696,7 +714,8 @@ mod tests {
let secrets: Vec<RootSecret<24>> = (0..2).map(|_x| RootSecret::<24>::generate()).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
let entangled_tag = TaggingKey::generate_entangled_tag(tagging_keys, 16);
let mut rng = OsRng::default();
let entangled_tag = TaggingKey::generate_entangled_tag(tagging_keys, &mut rng, 16);
let detection_keys = secrets
.iter()
.map(|x| x.extract_detection_key(16))
@ -710,8 +729,9 @@ mod tests {
fn correctness() {
let number_of_messages = 100;
let secret = RootSecret::<16>::generate();
let mut rng = OsRng::default();
for i in 0..number_of_messages {
let tag = secret.tagging_key().generate_tag();
let tag = secret.tagging_key().generate_tag(&mut rng);
println!("{}: {}", i, tag);
assert!(secret.extract_detection_key(5).test_tag(&tag));
}
@ -769,9 +789,10 @@ mod tests {
let number_of_messages = 1000;
let secret = RootSecret::<24>::generate();
let mut false_positives = 0;
let mut rng = OsRng::default();
for _i in 0..number_of_messages {
let secret2 = RootSecret::<24>::generate();
let tag = secret2.tagging_key().generate_tag();
let tag = secret2.tagging_key().generate_tag(&mut rng);
assert!(secret2.extract_detection_key(3).test_tag(&tag));
if secret.extract_detection_key(3).test_tag(&tag) == true {
false_positives += 1;