Apply optimizations to tag generation + entangled tag generation

This commit is contained in:
Sarah Jamie Lewis 2021-05-20 01:11:07 -07:00
parent 788270a02a
commit 1124ffc1a6
4 changed files with 40 additions and 21 deletions

View File

@ -29,6 +29,10 @@ bincode = "1.3.1"
name = "fuzzy_tags_benches" name = "fuzzy_tags_benches"
harness = false harness = false
[[bench]]
name = "entangled"
harness = false
[features] [features]
entangled = ["brute-force"] entangled = ["brute-force"]
bulk_verify = ["rayon"] bulk_verify = ["rayon"]

21
benches/entangled.rs Normal file
View File

@ -0,0 +1,21 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use fuzzytags::{RootSecret, TaggingKey};
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);
let secret_key_1 = RootSecret::<24>::generate();
let secret_key_2 = RootSecret::<24>::generate();
let public_key_1 = secret_key_1.tagging_key();
let public_key_2 = secret_key_2.tagging_key();
for p in [4, 8, 16, 20, 24].iter() {
group.bench_with_input(BenchmarkId::from_parameter(p), p, |b, _gamma| {
b.iter(|| TaggingKey::generate_entangled_tag(vec![public_key_1.clone(), public_key_2.clone()], *p))
});
}
}
criterion_group!(benches, benchmark_entangled);
criterion_main!(benches);

View File

@ -1,5 +1,5 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use fuzzytags::RootSecret; use fuzzytags::{RootSecret, TaggingKey};
use std::time::Duration; use std::time::Duration;
fn benchmark_generate_tag(c: &mut Criterion) { fn benchmark_generate_tag(c: &mut Criterion) {

View File

@ -428,6 +428,7 @@ impl<const GAMMA: u8> DetectionKey<{ 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]);
let (tx, rx) = channel(); let (tx, rx) = channel();
let pre_h = RootSecret::<GAMMA>::pre_h(tag.u, w);
// for each secret part... // for each secret part...
let mut results: Vec<usize> = vec![]; let mut results: Vec<usize> = vec![];
@ -435,30 +436,21 @@ impl<const GAMMA: u8> DetectionKey<{ GAMMA }> {
.par_iter() .par_iter()
.enumerate() .enumerate()
.for_each_with(tx.clone(), |tx, (index, detection_key)| { .for_each_with(tx.clone(), |tx, (index, detection_key)| {
let mut result = true; let mut result = 0;
for (i, x_i) in detection_key.0.iter().enumerate() { for (x_i, c_i) in detection_key.0.iter().zip(&tag.ciphertexts) {
// re-derive the key from the tag // re-derive the key from the tag
let k_i = RootSecret::<GAMMA>::h(tag.u, tag.u.mul(x_i), w); let k_i = RootSecret::<GAMMA>::post_h(pre_h.clone(), tag.u.mul(x_i));
// calculate the "original" plaintext // calculate the "original" plaintext
let c_i = match tag.ciphertexts.get(i) { let b_i = k_i ^ (c_i as u8);
Some(true) => 0x01,
Some(false) => 0x00,
_ => 0x00,
// we've run out of ciphertext, it doesn't really matter what we put here, the rest of the test will fail
// since the security of k_i is modelled as a random oracle, (k_i ^ 0) should also be random
};
let b_i = k_i ^ c_i;
if b_i != 1 { if b_i != 1 {
result = false;
break; break;
} }
// assert that the plaintext is all 1's // assert that the plaintext is all 1's
result = result & (b_i == 1); result += 1;
} }
if result { if result == detection_key.0.len() {
match tx.send(index) { match tx.send(index) {
_ => { _ => {
// TODO...surface this error... // TODO...surface this error...
@ -514,11 +506,11 @@ impl<const GAMMA: u8> TaggingKey<{ GAMMA }> {
let u = g.mul(r); let u = g.mul(r);
let z = Scalar::random(&mut rng); let z = Scalar::random(&mut rng);
let w = g.mul(z); let w = g.mul(z);
let pre_h = RootSecret::<GAMMA>::pre_h(u, w);
// 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 = RootSecret::<GAMMA>::h(u, h_i.mul(r), w); let k_i = RootSecret::<GAMMA>::post_h(pre_h.clone(), h_i.mul(r));
// 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);
@ -579,14 +571,16 @@ impl<const GAMMA: u8> TaggingKey<{ GAMMA }> {
} }
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 pre_h = RootSecret::<GAMMA>::pre_h(u, w);
let mut key = vec![]; let mut key = vec![];
for (i, precompute) in tagging_key_precomputes[0].iter().enumerate() { for (i, precompute) in tagging_key_precomputes[0].iter().enumerate() {
let k_i = RootSecret::<GAMMA>::h(u, *precompute, w); let k_i = RootSecret::<GAMMA>::post_h(pre_h.clone(), *precompute);
if i < length { if i < length {
for precompute in tagging_key_precomputes.iter().skip(1) { for precompute in tagging_key_precomputes.iter().skip(1) {
let n_k_i = RootSecret::<GAMMA>::h(u, precompute[i], w); let n_k_i = RootSecret::<GAMMA>::post_h(pre_h.clone(), precompute[i]);
if k_i != n_k_i { if k_i != n_k_i {
return None; return None;
} }
@ -614,7 +608,7 @@ impl<const GAMMA: u8> TaggingKey<{ GAMMA }> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{RootSecret, Tag}; use crate::{DetectionKey, 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;