diff --git a/pop-mpc/Cargo.toml b/pop-mpc/Cargo.toml index 7622d36d0..87d61d20b 100644 --- a/pop-mpc/Cargo.toml +++ b/pop-mpc/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] aes = { version="0.7.5", features=[]} +cipher = "0.3" rand = "0.7" rand_core = "0.5" rand_chacha = "0.2" diff --git a/pop-mpc/benches/half_gate.rs b/pop-mpc/benches/half_gate.rs index c561f084f..ae1b6a4b2 100644 --- a/pop-mpc/benches/half_gate.rs +++ b/pop-mpc/benches/half_gate.rs @@ -3,15 +3,18 @@ use pop_mpc::block::Block; use pop_mpc::circuit::Circuit; use pop_mpc::garble::{ evaluator::HalfGateEvaluator, generator::half_gate::*, generator::GarbledCircuitGenerator, - hash::aes::Aes, }; +use aes::cipher::{ + generic_array::GenericArray, NewBlockCipher, +}; +use aes::Aes128; use rand::SeedableRng; use rand_chacha::ChaCha12Rng; fn criterion_benchmark(c: &mut Criterion) { c.bench_function("half_gate_garble_and", move |bench| { let mut rng = ChaCha12Rng::from_entropy(); - let h = Aes::new(&[0u8; 16]); + let mut cipher = Aes128::new(GenericArray::from_slice(&[0u8; 16])); let gen = HalfGateGenerator; let mut delta = Block::random(&mut rng); @@ -23,14 +26,14 @@ fn criterion_benchmark(c: &mut Criterion) { let gid: usize = 1; bench.iter(|| { - let res = gen.and_gate(&h, x, y, delta, gid); + let res = gen.and_gate(&mut cipher, x, y, delta, gid); black_box(res); }); }); c.bench_function("half_gate_eval_and", move |bench| { let mut rng = ChaCha12Rng::from_entropy(); - let h = Aes::new(&[0u8; 16]); + let mut cipher = Aes128::new(GenericArray::from_slice(&[0u8; 16])); let gen = HalfGateGenerator; let ev = HalfGateEvaluator; @@ -42,21 +45,21 @@ fn criterion_benchmark(c: &mut Criterion) { let y = [y_0, y_0 ^ delta]; let gid: usize = 1; - let (_, table) = gen.and_gate(&h, x, y, delta, gid); + let (_, table) = gen.and_gate(&mut cipher, x, y, delta, gid); bench.iter(|| { - let res = ev.and_gate(&h, x[0], y[0], table, gid); + let res = ev.and_gate(&mut cipher, x[0], y[0], table, gid); black_box(res); }); }); c.bench_function("half_gate_aes", move |bench| { let mut rng = ChaCha12Rng::from_entropy(); - let h = Aes::new(&[0u8; 16]); + let mut cipher = Aes128::new(GenericArray::from_slice(&[0u8; 16])); let circ = Circuit::parse("circuits/aes_128_reverse.txt").unwrap(); let half_gate = HalfGateGenerator; bench.iter(|| { - let gb = half_gate.garble(&h, &mut rng, &circ).unwrap(); + let gb = half_gate.garble(&mut cipher, &mut rng, &circ).unwrap(); black_box(gb); }); }); diff --git a/pop-mpc/src/block.rs b/pop-mpc/src/block.rs index de8dc6254..1d7590bfb 100644 --- a/pop-mpc/src/block.rs +++ b/pop-mpc/src/block.rs @@ -1,6 +1,7 @@ use core::ops::{BitAnd, BitXor, BitXorAssign}; use rand::{CryptoRng, Rng, SeedableRng}; -use std::convert::From; +use std::convert::{From, TryInto}; +use cipher::{BlockCipher, BlockEncrypt, consts::U16, generic_array::GenericArray}; #[repr(transparent)] #[derive(Copy, Clone, Debug, PartialEq)] @@ -20,6 +21,28 @@ impl Block { Self::new(rng.gen()) } + pub fn hash_tweak + BlockEncrypt>(&self, c: &mut C, tweak: usize) -> Self { + let gid: [u8; 16] = (tweak as u128).to_be_bytes(); + let label: [u8; 16] = self.to_be_bytes(); + + let mut h1: GenericArray = GenericArray::from(label); + c.encrypt_block(&mut h1); + + let h2: GenericArray = GenericArray::clone_from_slice(h1.as_slice()); + let mut h2: GenericArray = h2.into_iter().zip(gid).map(|(a, b)| a ^ b).collect(); + c.encrypt_block(&mut h2); + + let h3: GenericArray = GenericArray::clone_from_slice(h2.as_slice()); + let h3: GenericArray = h3.into_iter().zip(h1).map(|(a, b)| a ^ b).collect(); + + let b: [u8; 16] = h3 + .as_slice() + .try_into() + .expect("Expected array to have length 16"); + let h: u128 = u128::from_be_bytes(b); + Self::new(h) + } + #[inline] pub fn zero() -> Self { Self(0) diff --git a/pop-mpc/src/garble/evaluator/half_gate.rs b/pop-mpc/src/garble/evaluator/half_gate.rs index cbaa7be33..82bc05fe6 100644 --- a/pop-mpc/src/garble/evaluator/half_gate.rs +++ b/pop-mpc/src/garble/evaluator/half_gate.rs @@ -3,16 +3,16 @@ use crate::block::{Block, SELECT_MASK}; use crate::circuit::Circuit; use crate::errors::EvaluatorError; use crate::garble::circuit::GarbledCircuit; -use crate::garble::hash::WireLabelHasher; +use cipher::{BlockCipher, BlockEncrypt, consts::U16, generic_array::GenericArray}; use crate::gate::Gate; pub struct HalfGateEvaluator; impl HalfGateEvaluator { #[inline] - pub fn and_gate( + pub fn and_gate + BlockEncrypt>( &self, - h: &H, + c: &mut C, x: Block, y: Block, table: [Block; 2], @@ -24,8 +24,8 @@ impl HalfGateEvaluator { let j = gid; let k = gid + 1; - let hx = h.hash(x, j); - let hy = h.hash(y, k); + let hx = x.hash_tweak(c, j); + let hy = y.hash_tweak(c, k); let w_g = hx ^ (table[0] & SELECT_MASK[s_a]); let w_e = hy ^ (SELECT_MASK[s_b] & (table[1] ^ x)); @@ -45,9 +45,9 @@ impl HalfGateEvaluator { } impl GarbledCircuitEvaluator for HalfGateEvaluator { - fn eval( + fn eval + BlockEncrypt>( &self, - h: &H, + c: &mut C, circ: &Circuit, gc: &GarbledCircuit, input_labels: Vec, @@ -86,7 +86,7 @@ impl GarbledCircuitEvaluator for HalfGateEvaluator { } => { let x = cache[xref].ok_or_else(|| EvaluatorError::UninitializedLabel(xref))?; let y = cache[yref].ok_or_else(|| EvaluatorError::UninitializedLabel(yref))?; - let z = self.and_gate(h, x, y, gc.table[gid - 1], gid); + let z = self.and_gate(c, x, y, gc.table[gid - 1], gid); cache[zref] = Some(z); gid += 1; } diff --git a/pop-mpc/src/garble/evaluator/mod.rs b/pop-mpc/src/garble/evaluator/mod.rs index 9755e4be3..674f0c7de 100644 --- a/pop-mpc/src/garble/evaluator/mod.rs +++ b/pop-mpc/src/garble/evaluator/mod.rs @@ -6,12 +6,12 @@ use crate::block::Block; use crate::circuit::Circuit; use crate::errors::EvaluatorError; use crate::garble::circuit::GarbledCircuit; -use crate::garble::hash::WireLabelHasher; +use cipher::{BlockCipher, BlockEncrypt, consts::U16, generic_array::GenericArray}; pub trait GarbledCircuitEvaluator { - fn eval( + fn eval + BlockEncrypt>( &self, - h: &H, + c: &mut C, circ: &Circuit, gc: &GarbledCircuit, input_labels: Vec, diff --git a/pop-mpc/src/garble/generator/half_gate.rs b/pop-mpc/src/garble/generator/half_gate.rs index 93a345e8a..1b4597dc5 100644 --- a/pop-mpc/src/garble/generator/half_gate.rs +++ b/pop-mpc/src/garble/generator/half_gate.rs @@ -3,7 +3,7 @@ use crate::block::{Block, SELECT_MASK}; use crate::circuit::Circuit; use crate::errors::GeneratorError; use crate::garble::circuit::GarbledCircuit; -use crate::garble::hash::WireLabelHasher; +use cipher::{BlockCipher, BlockEncrypt, consts::U16, generic_array::GenericArray}; use crate::gate::Gate; use rand::{CryptoRng, Rng, SeedableRng}; @@ -11,9 +11,9 @@ pub struct HalfGateGenerator; impl HalfGateGenerator { #[inline] - pub fn and_gate( + pub fn and_gate + BlockEncrypt>( &self, - h: &H, + c: &mut C, x: [Block; 2], y: [Block; 2], delta: Block, @@ -24,13 +24,13 @@ impl HalfGateGenerator { let j = gid; let k = gid + 1; - let hx_0 = h.hash(x[0], j); - let hy_0 = h.hash(y[0], k); + let hx_0 = x[0].hash_tweak(c, j); + let hy_0 = y[0].hash_tweak(c, k); - let t_g = hx_0 ^ h.hash(x[1], j) ^ (SELECT_MASK[p_b] & delta); + let t_g = hx_0 ^ x[1].hash_tweak(c, j) ^ (SELECT_MASK[p_b] & delta); let w_g = hx_0 ^ (SELECT_MASK[p_a] & t_g); - let t_e = hy_0 ^ h.hash(y[1], k) ^ x[0]; + let t_e = hy_0 ^ y[1].hash_tweak(c, k) ^ x[0]; let w_e = hy_0 ^ (SELECT_MASK[p_b] & (t_e ^ x[0])); let z_0 = w_g ^ w_e; @@ -53,9 +53,9 @@ impl HalfGateGenerator { } impl GarbledCircuitGenerator for HalfGateGenerator { - fn garble( + fn garble + BlockEncrypt>( &self, - h: &H, + c: &mut C, rng: &mut R, circ: &Circuit, ) -> Result { @@ -97,7 +97,7 @@ impl GarbledCircuitGenerator for HalfGateGenerator { } => { let x = cache[xref].ok_or_else(|| GeneratorError::UninitializedLabel(xref))?; let y = cache[yref].ok_or_else(|| GeneratorError::UninitializedLabel(yref))?; - let (z, t) = self.and_gate(h, x, y, delta, gid); + let (z, t) = self.and_gate(c, x, y, delta, gid); table.push(t); cache[zref] = Some(z); gid += 1; @@ -124,16 +124,19 @@ impl GarbledCircuitGenerator for HalfGateGenerator { #[cfg(test)] mod tests { use super::*; - use crate::garble::hash::aes::Aes; + use aes::cipher::{ + generic_array::GenericArray, NewBlockCipher, + }; + use aes::Aes128; use rand_chacha::ChaCha12Rng; #[test] fn test_encode_wire_labels() { + let mut cipher = Aes128::new(GenericArray::from_slice(&[0u8; 16])); let mut rng = ChaCha12Rng::from_entropy(); - let h = Aes::new(&[0u8; 16]); let circ = Circuit::parse("circuits/aes_128_reverse.txt").unwrap(); let half_gate = HalfGateGenerator; - let gc = half_gate.garble(&h, &mut rng, &circ); + let gc = half_gate.garble(&mut cipher, &mut rng, &circ); } } diff --git a/pop-mpc/src/garble/generator/mod.rs b/pop-mpc/src/garble/generator/mod.rs index 6a8076152..dceaccadf 100644 --- a/pop-mpc/src/garble/generator/mod.rs +++ b/pop-mpc/src/garble/generator/mod.rs @@ -5,13 +5,13 @@ pub use half_gate::*; use crate::circuit::Circuit; use crate::errors::GeneratorError; use crate::garble::circuit::GarbledCircuit; -use crate::garble::hash::WireLabelHasher; +use cipher::{BlockCipher, BlockEncrypt, consts::U16, generic_array::GenericArray}; use rand::{CryptoRng, Rng}; pub trait GarbledCircuitGenerator { - fn garble( + fn garble + BlockEncrypt>( &self, - h: &H, + c: &mut C, rng: &mut R, circ: &Circuit, ) -> Result; diff --git a/pop-mpc/src/garble/hash/aes.rs b/pop-mpc/src/garble/hash/aes.rs deleted file mode 100644 index af22316f2..000000000 --- a/pop-mpc/src/garble/hash/aes.rs +++ /dev/null @@ -1,95 +0,0 @@ -use super::WireLabelHasher; -use crate::block::Block; -use aes::cipher::{ - generic_array::GenericArray, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, -}; -use aes::{Aes128, Block as AesBlock, ParBlocks}; -use std::convert::TryInto; -use std::ops::BitXor; - -pub struct Aes { - cipher: Aes128, -} - -impl Aes { - pub fn new(key: &[u8; 16]) -> Self { - Aes { - cipher: Aes128::new(GenericArray::from_slice(key)), - } - } -} - -fn xor_blocks(a: AesBlock, b: AesBlock) -> AesBlock { - a.into_iter().zip(b).map(|(_a, _b)| _a ^ _b).collect() -} - -impl WireLabelHasher for Aes { - /// π(π(x) ⊕ i) ⊕ π(x) - fn hash(&self, label: Block, gid: usize) -> Block { - let gid: [u8; 16] = (gid as u128).to_be_bytes(); - let label: [u8; 16] = label.to_be_bytes(); - - let mut h1 = AesBlock::from(label); - self.cipher.encrypt_block(&mut h1); - - let h2 = AesBlock::clone_from_slice(h1.as_slice()); - let mut h2 = h2.into_iter().zip(gid).map(|(a, b)| a ^ b).collect(); - self.cipher.encrypt_block(&mut h2); - - let h3 = AesBlock::clone_from_slice(h2.as_slice()); - let h3: AesBlock = h3.into_iter().zip(h1).map(|(a, b)| a ^ b).collect(); - - let b: [u8; 16] = h3 - .as_slice() - .try_into() - .expect("Expected array to have length 16"); - let h: u128 = u128::from_be_bytes(b); - Block::new(h) - } - - // fn hash_many(&mut self, labels: Vec, gids: Vec) -> Vec { - // let gids: Vec = gids - // .into_iter() - // .map(|gid| AesBlock::clone_from_slice((gid as u128).to_ne_bytes().as_ref())) - // .collect(); - - // // π(x) - // let mut h1: ParBlocks = labels - // .into_iter() - // .map(|label| AesBlock::from(label)) - // .collect(); - // self.cipher.encrypt_par_blocks(&mut h1); - - // // π(π(x) ⊕ i) - // let h2: ParBlocks = h1.iter().map(|b| AesBlock::clone_from_slice(b)).collect(); - // let mut h2: ParBlocks = h2 - // .into_iter() - // .zip(gids) - // .map(|(h, gid)| xor_blocks(h, gid)) - // .collect(); - // self.cipher.encrypt_par_blocks(&mut h2); - - // // π(π(x) ⊕ i) ⊕ π(x) - // let h: Vec = h1 - // .into_iter() - // .zip(h2) - // .map(|(h1, h2)| { - // let h = xor_blocks(h1, h2); - // let bytes: [u8; 16] = h.try_into().expect("Expected array to be length 16"); - // Block::from(bytes) - // }) - // .collect(); - // h - // } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_aes() { - let key = [0u8; 16]; - let aes = Aes::new(&key); - } -} diff --git a/pop-mpc/src/garble/hash/mod.rs b/pop-mpc/src/garble/hash/mod.rs deleted file mode 100644 index 1fe16623d..000000000 --- a/pop-mpc/src/garble/hash/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod aes; - -use crate::block::Block; - -pub trait WireLabelHasher { - fn hash(&self, label: Block, gid: usize) -> Block; - - //fn hash_many(&mut self, labels: Vec, gids: Vec) -> Vec; -} diff --git a/pop-mpc/src/garble/mod.rs b/pop-mpc/src/garble/mod.rs index 57edc5e15..9eb18a402 100644 --- a/pop-mpc/src/garble/mod.rs +++ b/pop-mpc/src/garble/mod.rs @@ -1,4 +1,3 @@ pub mod circuit; pub mod evaluator; -pub mod generator; -pub mod hash; +pub mod generator; \ No newline at end of file diff --git a/pop-mpc/src/lib.rs b/pop-mpc/src/lib.rs index 514922716..4a1cf8205 100644 --- a/pop-mpc/src/lib.rs +++ b/pop-mpc/src/lib.rs @@ -8,4 +8,3 @@ pub mod element; pub mod errors; pub mod garble; mod gate; -pub mod ot; diff --git a/pop-mpc/tests/half_gate.rs b/pop-mpc/tests/half_gate.rs index 49a60a8f5..83973ec86 100644 --- a/pop-mpc/tests/half_gate.rs +++ b/pop-mpc/tests/half_gate.rs @@ -1,15 +1,19 @@ use pop_mpc::{ block::Block, circuit::Circuit, - garble::{evaluator::*, generator::*, hash::aes::Aes}, + garble::{evaluator::*, generator::*}, }; +use aes::cipher::{ + generic_array::GenericArray, NewBlockCipher, +}; +use aes::Aes128; use rand::SeedableRng; use rand_chacha::ChaCha12Rng; #[test] fn test_and_gate() { let mut rng = ChaCha12Rng::from_entropy(); - let h = Aes::new(&[0u8; 16]); + let mut cipher = Aes128::new(GenericArray::from_slice(&[0u8; 16])); let gen = HalfGateGenerator; let ev = HalfGateEvaluator; @@ -21,12 +25,12 @@ fn test_and_gate() { let y = [y_0, y_0 ^ delta]; let gid: usize = 1; - let (z, table) = gen.and_gate(&h, x, y, delta, gid); + let (z, table) = gen.and_gate(&mut cipher, x, y, delta, gid); - assert_eq!(ev.and_gate(&h, x[0], y[0], table, gid), z[0]); - assert_eq!(ev.and_gate(&h, x[0], y[1], table, gid), z[0]); - assert_eq!(ev.and_gate(&h, x[1], y[0], table, gid), z[0]); - assert_eq!(ev.and_gate(&h, x[1], y[1], table, gid), z[1]); + assert_eq!(ev.and_gate(&mut cipher, x[0], y[0], table, gid), z[0]); + assert_eq!(ev.and_gate(&mut cipher, x[0], y[1], table, gid), z[0]); + assert_eq!(ev.and_gate(&mut cipher, x[1], y[0], table, gid), z[0]); + assert_eq!(ev.and_gate(&mut cipher, x[1], y[1], table, gid), z[1]); } #[test] @@ -70,12 +74,12 @@ fn test_inv_gate() { #[test] fn test_aes_128() { let mut rng = ChaCha12Rng::from_entropy(); - let h = Aes::new(&[0u8; 16]); + let mut cipher = Aes128::new(GenericArray::from_slice(&[0u8; 16])); let circ = Circuit::parse("circuits/aes_128_reverse.txt").unwrap(); let gen = HalfGateGenerator; let ev = HalfGateEvaluator; - let gc = gen.garble(&h, &mut rng, &circ).unwrap(); + let gc = gen.garble(&mut cipher, &mut rng, &circ).unwrap(); let a: Vec = vec![1; 128]; @@ -89,7 +93,7 @@ fn test_aes_128() { .map(|(label, input)| label[input as usize]) .collect(); - let output_labels = ev.eval(&h, &circ, &gc, input_labels).unwrap(); + let output_labels = ev.eval(&mut cipher, &circ, &gc, input_labels).unwrap(); let mut outputs: Vec = Vec::with_capacity(circ.noutput_wires); for (i, label) in output_labels.iter().enumerate() { outputs.push((label.lsb() ^ gc.output_bits[i]) as u8);