Move entangled tag generation over to brute-force library

This commit is contained in:
Sarah Jamie Lewis 2021-02-03 20:15:09 -08:00
parent b6338e11e5
commit 1adfe996a6
2 changed files with 24 additions and 61 deletions

View File

@ -1,7 +1,7 @@
[package] [package]
name = "fuzzytags" name = "fuzzytags"
description = "a probabilistic cryptographic structure for metadata resistant tagging" description = "a probabilistic cryptographic structure for metadata resistant tagging"
version = "0.2.3" version = "0.3.0"
repository = "https://git.openprivacy.ca/openprivacy/fuzzytags" repository = "https://git.openprivacy.ca/openprivacy/fuzzytags"
authors = ["Sarah Jamie Lewis <sarah@openprivacy.ca>"] authors = ["Sarah Jamie Lewis <sarah@openprivacy.ca>"]
edition = "2018" edition = "2018"
@ -17,7 +17,7 @@ curve25519-dalek = {version="3.0.0", features=["serde"]}
sha3 = "0.9.1" sha3 = "0.9.1"
bit-vec = {version="0.6.3", features=["serde"]} bit-vec = {version="0.6.3", features=["serde"]}
serde = {version="1.0.123", features=["derive"]} 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] [dev-dependencies]
criterion = {version="0.3", features=["html_reports"]} criterion = {version="0.3", features=["html_reports"]}
@ -28,5 +28,5 @@ name = "fuzzy_tags_benches"
harness = false harness = false
[features] [features]
entangled = ["rayon"] entangled = ["brute-force"]

View File

@ -18,11 +18,9 @@ use std::fmt::{Display, Formatter};
use std::ops::{Mul, Sub}; use std::ops::{Mul, Sub};
#[cfg(feature = "entangled")] #[cfg(feature = "entangled")]
use rayon::iter::ParallelIterator; use brute_force::adaptors;
#[cfg(feature = "entangled")] #[cfg(feature = "entangled")]
use rayon::prelude::IntoParallelIterator; use brute_force::brute_force;
#[cfg(feature = "entangled")]
use std::sync::Arc;
/// 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 `FuzzyPublicKey`
/// it will pass the `FuzzyDetectionKey::test` 100% of the time. For other public keys /// 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); /// let tag = FuzzyPublicKey::generate_entangled_tag(vec![public_key_1,public_key_2], 8);
/// ``` /// ```
pub fn generate_entangled_tag(public_keys: Vec<FuzzyPublicKey>, length: usize) -> FuzzyTag { pub fn generate_entangled_tag(public_keys: Vec<FuzzyPublicKey>, length: usize) -> FuzzyTag {
let arc_public_keys = Arc::new(public_keys);
loop {
let results: Vec<FuzzyTag> = (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<Vec<FuzzyPublicKey>>, length: usize) -> Result<FuzzyTag, ()> {
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...
let r = Scalar::random(&mut rng); let r = Scalar::random(&mut rng);
let u = g.mul(r); 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 // Compute and cache some public points that we will be using over and over again
let mut public_key_precomputes = vec![]; let mut public_key_precomputes = vec![];
for public_key in public_keys.iter() { for public_key in public_keys.iter() {
@ -355,46 +327,37 @@ impl FuzzyPublicKey {
public_key_precomputes.push(precompute); public_key_precomputes.push(precompute);
} }
// Try a 1000 different options and hope maybe one of them is the magic number... let config = brute_force::Config::default();
while !entangled && attempts < 1000 { let f = |z: &Scalar| {
attempts += 1;
ciphertexts = BitVec::new();
z = Scalar::random(&mut rng);
let w = g.mul(z); let w = g.mul(z);
entangled = true; let mut key = vec![];
for (i, precompute) in public_key_precomputes[0].iter().enumerate() { for (i, precompute) in public_key_precomputes[0].iter().enumerate() {
let mut same = true;
let k_i = FuzzySecretKey::h(u, *precompute, w); let k_i = FuzzySecretKey::h(u, *precompute, w);
if i < length { if i < length {
for precompute in public_key_precomputes.iter().skip(1) { for precompute in public_key_precomputes.iter().skip(1) {
let n_k_i = FuzzySecretKey::h(u, precompute[i], w); let n_k_i = FuzzySecretKey::h(u, precompute[i], w);
if k_i != n_k_i { if k_i != n_k_i {
same = false; return None;
break;
} }
} }
if !same { key.push(k_i)
entangled = false;
break;
}
} }
}
// generate the tag
let mut ciphertexts = BitVec::new();
for k_i in key.iter() {
// 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);
} }
}
// If we are not entangled then at this point we return an error // This is the same as generate_tag, kept separate to avoid over-decomposition
if entangled == false { let m = FuzzySecretKey::g(u, &ciphertexts);
return Err(()); let y = r.invert().mul(z.sub(m));
} return Some(FuzzyTag { u, y, ciphertexts });
};
// This is the same as generate_tag, kept separate to avoid over-decomposition brute_force(config, adaptors::auto_advance(f))
let m = FuzzySecretKey::g(u, &ciphertexts);
let y = r.invert().mul(z.sub(m));
return Ok(FuzzyTag { u, y, ciphertexts });
} }
} }
@ -418,13 +381,13 @@ mod tests {
#[cfg(feature = "entangled")] #[cfg(feature = "entangled")]
fn test_multiple() { fn test_multiple() {
use crate::FuzzyPublicKey; use crate::FuzzyPublicKey;
let secret_keys: Vec<FuzzySecretKey> = (0..3).map(|_x| FuzzySecretKey::generate(24)).collect(); let secret_keys: Vec<FuzzySecretKey> = (0..2).map(|_x| FuzzySecretKey::generate(24)).collect();
let public_keys: Vec<FuzzyPublicKey> = secret_keys.iter().map(|x| x.public_key()).collect(); let public_keys: Vec<FuzzyPublicKey> = 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 // 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); println!("{}", entangled_tag);
for secret_key in secret_keys.iter() { 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)); assert!(detection_key.test_tag(&entangled_tag));
println!("{}", detection_key); println!("{}", detection_key);
} }