diff --git a/Cargo.toml b/Cargo.toml index eabf715..e5c7341 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "fuzzytags" description = "a probabilistic cryptographic structure for metadata resistant tagging" -version = "0.2.3" +version = "0.3.0" repository = "https://git.openprivacy.ca/openprivacy/fuzzytags" authors = ["Sarah Jamie Lewis "] edition = "2018" @@ -17,7 +17,7 @@ curve25519-dalek = {version="3.0.0", features=["serde"]} sha3 = "0.9.1" bit-vec = {version="0.6.3", features=["serde"]} serde = {version="1.0.123", features=["derive"]} -rayon = {version="1.5.0", optional = true} +brute-force = {version="0.1.0", features=["curve25519"], optional=true} [dev-dependencies] criterion = {version="0.3", features=["html_reports"]} @@ -28,5 +28,5 @@ name = "fuzzy_tags_benches" harness = false [features] -entangled = ["rayon"] +entangled = ["brute-force"] diff --git a/src/lib.rs b/src/lib.rs index 24fa70f..59571e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,11 +18,9 @@ use std::fmt::{Display, Formatter}; use std::ops::{Mul, Sub}; #[cfg(feature = "entangled")] -use rayon::iter::ParallelIterator; +use brute_force::adaptors; #[cfg(feature = "entangled")] -use rayon::prelude::IntoParallelIterator; -#[cfg(feature = "entangled")] -use std::sync::Arc; +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 @@ -313,38 +311,12 @@ impl FuzzyPublicKey { /// let tag = FuzzyPublicKey::generate_entangled_tag(vec![public_key_1,public_key_2], 8); /// ``` pub fn generate_entangled_tag(public_keys: Vec, length: usize) -> FuzzyTag { - let arc_public_keys = Arc::new(public_keys); - loop { - let results: Vec = (0..8) - .into_par_iter() - .map(|_x| FuzzyPublicKey::try_entangled_tag(arc_public_keys.clone(), length)) - .filter_map(|x| x.ok()) - .collect(); - if results.is_empty() == false { - return results[0].clone(); - } - } - } - - #[cfg(feature = "entangled")] - fn try_entangled_tag(public_keys: Arc>, length: usize) -> Result { let mut rng = OsRng::default(); let g = RISTRETTO_BASEPOINT_POINT; - // generate some random points... let r = Scalar::random(&mut rng); let u = g.mul(r); - // Set z to zero... - let mut z = Scalar::zero(); - - // construct the ciphertext portion of the tag - let mut ciphertexts = BitVec::new(); - - // Keep track of how many attempts and whether we have succeeded... - let mut attempts = 0; - let mut entangled = false; - // 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() { @@ -355,46 +327,37 @@ impl FuzzyPublicKey { public_key_precomputes.push(precompute); } - // Try a 1000 different options and hope maybe one of them is the magic number... - while !entangled && attempts < 1000 { - attempts += 1; - ciphertexts = BitVec::new(); - z = Scalar::random(&mut rng); + let config = brute_force::Config::default(); + let f = |z: &Scalar| { let w = g.mul(z); - entangled = true; + let mut key = vec![]; for (i, precompute) in public_key_precomputes[0].iter().enumerate() { - let mut same = true; let k_i = FuzzySecretKey::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); if k_i != n_k_i { - same = false; - break; + return None; } } - if !same { - entangled = false; - break; - } + key.push(k_i) } + } + + // generate the tag + let mut ciphertexts = BitVec::new(); + for k_i in key.iter() { // encrypt a plaintext of all 1's let c_i = k_i ^ 0x01; ciphertexts.push(c_i == 0x01); } - } - // If we are not entangled then at this point we return an error - if entangled == false { - return Err(()); - } - - // This is the same as generate_tag, kept separate to avoid over-decomposition - let m = FuzzySecretKey::g(u, &ciphertexts); - let y = r.invert().mul(z.sub(m)); - - return Ok(FuzzyTag { u, y, ciphertexts }); + // This is the same as generate_tag, kept separate to avoid over-decomposition + let m = FuzzySecretKey::g(u, &ciphertexts); + let y = r.invert().mul(z.sub(m)); + return Some(FuzzyTag { u, y, ciphertexts }); + }; + brute_force(config, adaptors::auto_advance(f)) } } @@ -418,13 +381,13 @@ mod tests { #[cfg(feature = "entangled")] fn test_multiple() { use crate::FuzzyPublicKey; - let secret_keys: Vec = (0..3).map(|_x| FuzzySecretKey::generate(24)).collect(); + let secret_keys: Vec = (0..2).map(|_x| FuzzySecretKey::generate(24)).collect(); let public_keys: Vec = secret_keys.iter().map(|x| x.public_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, 6); + let entangled_tag = FuzzyPublicKey::generate_entangled_tag(public_keys, 16); println!("{}", entangled_tag); for secret_key in secret_keys.iter() { - let detection_key = secret_key.extract(6); + let detection_key = secret_key.extract(16); assert!(detection_key.test_tag(&entangled_tag)); println!("{}", detection_key); }