Skip to content

Commit

Permalink
Add Matyas-Meyer-Oseas. Only use it for DPF bench.
Browse files Browse the repository at this point in the history
  • Loading branch information
myl7 committed Jan 28, 2024
1 parent 4f8fd29 commit 85362eb
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 18 deletions.
1 change: 1 addition & 0 deletions bench.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set -euo pipefail
# See https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options
# for the reason why the script is created.

ulimit -s 16384 # For bench dpf_large_lambda after changing to use Matyas-Meyer-Oseas
bench_dirs=(benches)
bench_args=($(find $bench_dirs -type f -exec basename -s .rs {} \; | sed 's/^/--bench /'))
cargo bench $bench_args $@
12 changes: 6 additions & 6 deletions benches/dpf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
use criterion::{criterion_group, criterion_main, Criterion};
use rand::prelude::*;

use fss_rs::dpf::prg::Aes256HirosePrg;
use fss_rs::dpf::prg::Aes128MatyasMeyerOseasPrg;
use fss_rs::dpf::{Dpf, DpfImpl, PointFn};
use fss_rs::group::byte::ByteGroup;
use fss_rs::group::Group;

pub fn bench_gen(c: &mut Criterion) {
let keys: [[u8; 32]; 2] = thread_rng().gen();
let prg = Aes256HirosePrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let keys: [[u8; 16]; 2] = thread_rng().gen();
let prg = Aes128MatyasMeyerOseasPrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let dpf = DpfImpl::<16, 16, _>::new(prg);
let s0s: [[u8; 16]; 2] = thread_rng().gen();
let f = PointFn {
Expand All @@ -27,8 +27,8 @@ pub fn bench_gen(c: &mut Criterion) {
}

pub fn bench_eval(c: &mut Criterion) {
let keys: [[u8; 32]; 2] = thread_rng().gen();
let prg = Aes256HirosePrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let keys: [[u8; 16]; 2] = thread_rng().gen();
let prg = Aes128MatyasMeyerOseasPrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let dpf = DpfImpl::<16, 16, _>::new(prg);
let s0s: [[u8; 16]; 2] = thread_rng().gen();
let f = PointFn {
Expand All @@ -37,7 +37,7 @@ pub fn bench_eval(c: &mut Criterion) {
};

let k = dpf.gen(&f, [&s0s[0], &s0s[1]]);
let prg = Aes256HirosePrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let prg = Aes128MatyasMeyerOseasPrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let dpf = DpfImpl::<16, 16, _>::new(prg);
let x: [u8; 16] = thread_rng().gen();
let mut y = ByteGroup::zero();
Expand Down
8 changes: 4 additions & 4 deletions benches/dpf_batch_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
use criterion::{criterion_group, criterion_main, Criterion};
use rand::prelude::*;

use fss_rs::dpf::prg::Aes256HirosePrg;
use fss_rs::dpf::prg::Aes128MatyasMeyerOseasPrg;
use fss_rs::dpf::{Dpf, DpfImpl, PointFn};
use fss_rs::group::byte::ByteGroup;
use fss_rs::group::Group;

pub fn bench(c: &mut Criterion) {
let keys: [[u8; 32]; 2] = thread_rng().gen();
let prg = Aes256HirosePrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let keys: [[u8; 16]; 2] = thread_rng().gen();
let prg = Aes128MatyasMeyerOseasPrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let dpf = DpfImpl::<16, 16, _>::new(prg);
let s0s: [[u8; 16]; 2] = thread_rng().gen();
let f = PointFn {
alpha: thread_rng().gen(),
beta: ByteGroup(thread_rng().gen()),
};
let k = dpf.gen(&f, [&s0s[0], &s0s[1]]);
let prg = Aes256HirosePrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let prg = Aes128MatyasMeyerOseasPrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
let dpf = DpfImpl::<16, 16, _>::new(prg);
const N: usize = 100_000;
let mut xs = vec![[0; 16]; N];
Expand Down
9 changes: 5 additions & 4 deletions benches/dpf_large_lambda.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
use criterion::{criterion_group, criterion_main, Criterion};
use rand::prelude::*;

use fss_rs::dpf::prg::Aes256HirosePrg;
use fss_rs::dpf::prg::Aes128MatyasMeyerOseasPrg;
use fss_rs::dpf::{Dpf, DpfImpl, PointFn};
use fss_rs::group::byte::ByteGroup;
use fss_rs::group::Group;

pub fn bench(c: &mut Criterion) {
let mut keys = vec![[0; 32]; 2048];
let mut keys = vec![[0; 16]; 2048];
keys.iter_mut().for_each(|key| thread_rng().fill_bytes(key));
let prg = Aes256HirosePrg::<16384, 2048>::new(std::array::from_fn(|i| &keys[i]));
let prg = Aes128MatyasMeyerOseasPrg::<16384, 2048>::new(std::array::from_fn(|i| &keys[i]));
let dpf = DpfImpl::<16, 16384, _>::new(prg);
let mut s0s = vec![[0; 16384]; 2];
thread_rng().fill_bytes(&mut s0s[0]);
Expand All @@ -28,7 +28,8 @@ pub fn bench(c: &mut Criterion) {

c.bench_function("dpf eval 10k xs with lambda 16384", |b| {
b.iter(|| {
let prg = Aes256HirosePrg::<16384, 2048>::new(std::array::from_fn(|i| &keys[i]));
let prg =
Aes128MatyasMeyerOseasPrg::<16384, 2048>::new(std::array::from_fn(|i| &keys[i]));
let dpf = DpfImpl::<16, 16384, _>::new(prg);
let mut ys = vec![ByteGroup::zero(); N];
dpf.eval(
Expand Down
56 changes: 55 additions & 1 deletion src/dcf/prg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use aes::cipher::generic_array::GenericArray;
use aes::cipher::{BlockEncrypt, KeyInit};
use aes::Aes256;
use aes::{Aes128, Aes256};
use bitvec::prelude::*;

use super::Prg;
Expand Down Expand Up @@ -74,6 +74,60 @@ impl<const LAMBDA: usize, const N: usize> Prg<LAMBDA> for Aes256HirosePrg<LAMBDA
}
}

/// Matyas-Meyer-Oseas single-block-length one-way compression function with AES128 and precreated keys.
/// Integrated impl of [`Prg`].
///
/// To avoid `#![feature(generic_const_exprs)]`, it is **your responsibility**
/// to ensure `LAMBDA % 16 = 0` and `N = 4 * (LAMBDA / 16)`.
///
/// It actually works for LAMBDA * 8 - 1 bits other than LAMBDA bytes.
/// The last bit of the output `[u8; LAMBDA]` is always set to 0.
pub struct Aes128MatyasMeyerOseasPrg<const LAMBDA: usize, const N: usize> {
ciphers: [Aes128; N],
}

impl<const LAMBDA: usize, const N: usize> Aes128MatyasMeyerOseasPrg<LAMBDA, N> {
pub fn new(keys: [&[u8; 16]; N]) -> Self {
let ciphers = std::array::from_fn(|i| {
let key_block = GenericArray::from_slice(keys[i]);
Aes128::new(key_block)
});
Self { ciphers }
}
}

impl<const LAMBDA: usize, const N: usize> Prg<LAMBDA> for Aes128MatyasMeyerOseasPrg<LAMBDA, N> {
fn gen(&self, seed: &[u8; LAMBDA]) -> [([u8; LAMBDA], [u8; LAMBDA], bool); 2] {
let mut result_buf0 = [[0; LAMBDA]; 2];
let mut result_buf1 = [[0; LAMBDA]; 2];
let mut out_block = GenericArray::default();
(0..LAMBDA / 16).for_each(|j| {
let in_block = GenericArray::from_slice(&seed[j * 16..(j + 1) * 16]);
self.ciphers[j].encrypt_block_b2b(in_block, &mut out_block);
result_buf0[0][j * 16..(j + 1) * 16].copy_from_slice(out_block.as_ref());
self.ciphers[j + LAMBDA / 16].encrypt_block_b2b(in_block, &mut out_block);
result_buf0[1][j * 16..(j + 1) * 16].copy_from_slice(out_block.as_ref());
self.ciphers[j + LAMBDA / 16 * 2].encrypt_block_b2b(in_block, &mut out_block);
result_buf1[0][j * 16..(j + 1) * 16].copy_from_slice(out_block.as_ref());
self.ciphers[j + LAMBDA / 16 * 3].encrypt_block_b2b(in_block, &mut out_block);
result_buf1[1][j * 16..(j + 1) * 16].copy_from_slice(out_block.as_ref());
});
xor_inplace(&mut result_buf0[0], &[seed]);
xor_inplace(&mut result_buf0[1], &[seed]);
xor_inplace(&mut result_buf1[0], &[seed]);
xor_inplace(&mut result_buf1[1], &[seed]);
let bit0 = result_buf0[0].view_bits::<Lsb0>()[0];
let bit1 = result_buf0[1].view_bits::<Lsb0>()[0];
result_buf0
.iter_mut()
.for_each(|buf| buf[LAMBDA - 1].view_bits_mut::<Lsb0>().set(0, false));
[
(result_buf0[0], result_buf1[0], bit0),
(result_buf0[1], result_buf1[1], bit1),
]
}
}

impl<const LAMBDA: usize, P> Prg<LAMBDA> for P
where
P: PrgBytes,
Expand Down
49 changes: 46 additions & 3 deletions src/dpf/prg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,21 @@

use aes::cipher::generic_array::GenericArray;
use aes::cipher::{BlockEncrypt, KeyInit};
use aes::Aes256;
use aes::{Aes128, Aes256};
use bitvec::prelude::*;

use super::Prg;
use crate::utils::{xor, xor_inplace};
use crate::PrgBytes;

/// Hirose double-block-length one-way compression function with AES256 and precreated keys as an imp of [`Prg`].
/// Hirose double-block-length one-way compression function with AES256 and precreated keys.
/// Integrated impl of [`Prg`] with a good performance.
///
/// To avoid `#![feature(generic_const_exprs)]`, it is **your responsibility**
/// to ensure `LAMBDA % 16 = 0` and `N = LAMBDA / 16`.
///
/// It actually works for LAMBDA * 4 - 1 bits other than LAMBDA bytes.
/// The last bit of the output `[u8; LAMBDA]` is always set to 0.
/// The second (`v`) outputs are always `[0; LAMBDA]`.
pub struct Aes256HirosePrg<const LAMBDA: usize, const N: usize> {
ciphers: [Aes256; N],
}
Expand Down Expand Up @@ -66,6 +65,50 @@ impl<const LAMBDA: usize, const N: usize> Prg<LAMBDA> for Aes256HirosePrg<LAMBDA
}
}

/// Matyas-Meyer-Oseas single-block-length one-way compression function with AES128 and precreated keys.
/// Integrated impl of [`Prg`].
///
/// To avoid `#![feature(generic_const_exprs)]`, it is **your responsibility**
/// to ensure `LAMBDA % 16 = 0` and `N = 2 * (LAMBDA / 16)`.
///
/// It actually works for LAMBDA * 4 - 1 bits other than LAMBDA bytes.
/// The last bit of the output `[u8; LAMBDA]` is always set to 0.
pub struct Aes128MatyasMeyerOseasPrg<const LAMBDA: usize, const N: usize> {
ciphers: [Aes128; N],
}

impl<const LAMBDA: usize, const N: usize> Aes128MatyasMeyerOseasPrg<LAMBDA, N> {
pub fn new(keys: [&[u8; 16]; N]) -> Self {
let ciphers = std::array::from_fn(|i| {
let key_block = GenericArray::from_slice(keys[i]);
Aes128::new(key_block)
});
Self { ciphers }
}
}

impl<const LAMBDA: usize, const N: usize> Prg<LAMBDA> for Aes128MatyasMeyerOseasPrg<LAMBDA, N> {
fn gen(&self, seed: &[u8; LAMBDA]) -> [([u8; LAMBDA], bool); 2] {
let mut result_buf = [[0; LAMBDA]; 2];
let mut out_block = GenericArray::default();
(0..LAMBDA / 16).for_each(|j| {
let in_block = GenericArray::from_slice(&seed[j * 16..(j + 1) * 16]);
self.ciphers[j].encrypt_block_b2b(in_block, &mut out_block);
result_buf[0][j * 16..(j + 1) * 16].copy_from_slice(out_block.as_ref());
self.ciphers[j + LAMBDA / 16].encrypt_block_b2b(in_block, &mut out_block);
result_buf[1][j * 16..(j + 1) * 16].copy_from_slice(out_block.as_ref());
});
xor_inplace(&mut result_buf[0], &[seed]);
xor_inplace(&mut result_buf[1], &[seed]);
let bit0 = result_buf[0].view_bits::<Lsb0>()[0];
let bit1 = result_buf[1].view_bits::<Lsb0>()[0];
result_buf
.iter_mut()
.for_each(|buf| buf[LAMBDA - 1].view_bits_mut::<Lsb0>().set(0, false));
[(result_buf[0], bit0), (result_buf[1], bit1)]
}
}

impl<const LAMBDA: usize, P> Prg<LAMBDA> for P
where
P: PrgBytes,
Expand Down

0 comments on commit 85362eb

Please sign in to comment.