From f50ebb382386c8b6749799fc6a196f083d461a9e Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Sun, 20 Jan 2019 14:57:36 -0800 Subject: [PATCH 1/5] factor out compressor to reuse for blake2bp/sp --- blake2/src/blake2.rs | 309 +++++++++++++++++++++++++------------ blake2/src/blake2b.rs | 5 +- blake2/src/blake2s.rs | 5 +- blake2/src/compressor_b.rs | 4 + blake2/src/compressor_s.rs | 4 + blake2/src/lib.rs | 2 + 6 files changed, 227 insertions(+), 102 deletions(-) create mode 100644 blake2/src/compressor_b.rs create mode 100644 blake2/src/compressor_s.rs diff --git a/blake2/src/blake2.rs b/blake2/src/blake2.rs index 47e85bd82..a484ac5cd 100644 --- a/blake2/src/blake2.rs +++ b/blake2/src/blake2.rs @@ -1,34 +1,95 @@ -macro_rules! blake2_impl { +macro_rules! blake2_compressor_impl { ( - $state:ident, $fix_state:ident, $word:ident, $vec:ident, $bytes:ident, + $compressor:ident, $builder:ident, $word:ident, $vec:ident, $bytes:ident, $R1:expr, $R2:expr, $R3:expr, $R4:expr, $IV:expr, - $vardoc:expr, $doc:expr, + $XofLen:ident, $reserved_len:expr, $salt_len:expr, ) => { use $crate::as_bytes::AsBytes; use $crate::simd::{Vector4, $vec}; - use digest::{Input, BlockInput, FixedOutput, VariableOutput, Reset}; - use digest::InvalidOutputSize; + use byte_tools::copy; + use core::{mem, u8, u32}; use digest::generic_array::GenericArray; use digest::generic_array::typenum::Unsigned; - use core::cmp; - use byte_tools::{copy, zero}; - use crypto_mac::{Mac, MacResult, InvalidKeyLength}; - type Output = GenericArray; + #[derive(Clone, Copy)] + #[repr(packed)] + #[allow(unused)] + pub struct $builder { + digest_len: u8, + key_len: u8, + fanout: u8, + depth: u8, + leaf_len: u32, + node_offs: u32, + xof_len: $XofLen, + node_depth: u8, + inner_len: u8, + reserved: [u8; $reserved_len], + salt: [u8; $salt_len], + personal: [u8; $salt_len], + } - #[derive(Clone)] - #[doc=$vardoc] - pub struct $state { - m: [$word; 16], - h: [$vec; 2], - t: u64, - n: usize, + impl $builder { + pub fn new() -> Self { + Self { + digest_len: 0, + key_len: 0, + fanout: 1, + depth: 1, + leaf_len: 0, + node_offs: 0, + xof_len: 0, + node_depth: 0, + inner_len: 0, + reserved: Default::default(), + salt: Default::default(), + personal: Default::default(), + } + } - h0: [$vec; 2], - m0: [$word; 16], - t0: u64, + pub fn out(&mut self, out: usize) { + assert!(out <= usize::from(u8::MAX)); + self.digest_len = out as u8; + } + + pub fn key(&mut self, kk: usize) { + assert!(kk as usize <= $bytes::to_usize()); + self.key_len = kk as u8; + } + + pub fn fanout(&mut self, fanout: u8) { + self.fanout = fanout; + } + + pub fn depth(&mut self, depth: u8) { + self.depth = depth; + } + + pub fn node_depth(&mut self, node_depth: u8) { + self.node_depth = node_depth; + } + + pub fn node_offset(&mut self, node_offs: usize) { + assert!(node_offs <= u32::MAX as usize); + assert!(node_offs as u32 <= u32::MAX); + self.node_offs = u32::to_le(node_offs as u32); + } + + pub fn inner_length(&mut self, inner_len: u8) { + self.inner_len = inner_len; + } + + pub fn build(&self) -> $compressor { + assert!(self.digest_len > 0); + // All fields of both types are Copy. + // Field endianness is handled at field-setting time. + let h0: [$vec; 2] = unsafe { mem::transmute(*self) }; + $compressor { + h: [iv0() ^ h0[0].to_le(), iv1() ^ h0[1].to_le()], + } + } } #[inline(always)] @@ -36,6 +97,19 @@ macro_rules! blake2_impl { #[inline(always)] fn iv1() -> $vec { $vec::new($IV[4], $IV[5], $IV[6], $IV[7]) } + #[derive(Clone)] + pub struct $compressor { + h: [$vec; 2], + } + + impl Default for $compressor { + fn default() -> Self { + Self { + h: [$vec::new(0, 0, 0, 0), $vec::new(0, 0, 0, 0)] + } + } + } + #[inline(always)] fn quarter_round(v: &mut [$vec; 4], rd: u32, rb: u32, m: $vec) { v[0] = v[0].wrapping_add(v[1]).wrapping_add(m.from_le()); @@ -73,6 +147,104 @@ macro_rules! blake2_impl { unshuffle(v); } + impl $compressor { + pub fn with_parameter_block(p: &[$word; 8]) -> Self { + let h0 = [ + iv0() ^ $vec::new(p[0], p[1], p[2], p[3]), + iv1() ^ $vec::new(p[4], p[5], p[6], p[7]), + ]; + Self { + h: h0, + } + } + + pub fn compress(&mut self, m: &[$word; 16], f0: $word, f1: $word, t: u64) { + use $crate::consts::SIGMA; + + let h = &mut self.h; + + let t0 = t as $word; + let t1 = match $bytes::to_u8() { + 64 => 0, + 32 => (t >> 32) as $word, + _ => unreachable!(), + }; + + let mut v = [ + h[0], + h[1], + iv0(), + iv1() ^ $vec::new(t0, t1, f0, f1), + ]; + + round(&mut v, m, &SIGMA[0]); + round(&mut v, m, &SIGMA[1]); + round(&mut v, m, &SIGMA[2]); + round(&mut v, m, &SIGMA[3]); + round(&mut v, m, &SIGMA[4]); + round(&mut v, m, &SIGMA[5]); + round(&mut v, m, &SIGMA[6]); + round(&mut v, m, &SIGMA[7]); + round(&mut v, m, &SIGMA[8]); + round(&mut v, m, &SIGMA[9]); + if $bytes::to_u8() == 64 { + round(&mut v, m, &SIGMA[0]); + round(&mut v, m, &SIGMA[1]); + } + + h[0] = h[0] ^ (v[0] ^ v[2]); + h[1] = h[1] ^ (v[1] ^ v[3]); + } + + pub fn finalize(&mut self, out: &mut GenericArray, m: &[$word; 16], f1: $word, t: u64) { + self.compress(m, !0, f1, t); + let buf = [self.h[0].to_le(), self.h[1].to_le()]; + copy(buf.as_bytes(), out); + } + + pub fn finalize_into_slice(&mut self, out: &mut [u8], m: &[$word; 16], f1: $word, t: u64) { + self.compress(m, !0, f1, t); + let buf = [self.h[0].to_le(), self.h[1].to_le()]; + out.copy_from_slice(buf.as_bytes()); + } + + pub fn builder() -> $builder { + $builder::new() + } + } + } +} + +macro_rules! blake2_impl { + ( + $state:ident, $fix_state:ident, $compressor:ident, $word:ident, $bytes:ident, + $vardoc:expr, $doc:expr, + ) => { + + use $crate::as_bytes::AsBytes; + + use digest::{Input, BlockInput, FixedOutput, VariableOutput, Reset}; + use digest::InvalidOutputSize; + use digest::generic_array::GenericArray; + use digest::generic_array::typenum::Unsigned; + use core::cmp; + use byte_tools::{copy, zero}; + use crypto_mac::{Mac, MacResult, InvalidKeyLength}; + + type Output = GenericArray; + + #[derive(Clone)] + #[doc=$vardoc] + pub struct $state { + n: usize, + h: $compressor, + m: [$word; 16], + h0: $compressor, + m0: [$word; 16], + t: u64, + t0: u64, + } + impl $state { /// Creates a new hashing context with a key. /// @@ -80,32 +252,26 @@ macro_rules! blake2_impl { /// make sure to compare codes in constant time! It can be done /// for example by using `subtle` crate. pub fn new_keyed(key: &[u8], output_size: usize) -> Self { - let kk = key.len(); - assert!(kk <= $bytes::to_usize()); - assert!(output_size <= $bytes::to_usize()); - - let p0 = 0x0101_0000 ^ ((kk as $word) << 8) ^ - (output_size as $word); - let h0 = [iv0() ^ $vec::new(p0, 0, 0, 0), iv1()]; - let mut state = $state { - m: [0; 16], - h: h0, - t: 0, + let mut h0 = $compressor::builder(); + h0.key(key.len()); + h0.out(output_size); + let h0 = h0.build(); + let mut m = [0; 16]; + let mut t = 0; + if !key.is_empty() { + copy(key, m.as_mut_bytes()); + t = 2 * $bytes::to_u64(); + } + $state { + m, + h: h0.clone(), + t, n: output_size, - t0: 0, - m0: [0; 16], + t0: t, + m0: m, h0: h0, - }; - - if kk > 0 { - copy(key, state.m.as_mut_bytes()); - state.t = 2 * $bytes::to_u64(); } - - state.t0 = state.t; - state.m0 = state.m; - state } #[doc(hidden)] @@ -114,15 +280,10 @@ macro_rules! blake2_impl { let kk = (p[0] >> 8) as u8 as usize; assert!(nn >= 1 && nn <= $bytes::to_usize()); assert!(kk <= $bytes::to_usize()); - - let h0 = [ - iv0() ^ $vec::new(p[0], p[1], p[2], p[3]), - iv1() ^ $vec::new(p[4], p[5], p[6], p[7]), - ]; - + let h0 = $compressor::with_parameter_block(p); $state { m: [0; 16], - h: h0, + h: h0.clone(), t: 0, n: nn, @@ -151,7 +312,7 @@ macro_rules! blake2_impl { } while rest.len() >= block { - self.compress(0, 0); + self.h.compress(&self.m, 0, 0, self.t); let part = &rest[..block]; rest = &rest[part.len()..]; @@ -163,7 +324,7 @@ macro_rules! blake2_impl { let n = rest.len(); if n > 0 { - self.compress(0, 0); + self.h.compress(&self.m, 0, 0, self.t); copy(rest, &mut self.m.as_mut_bytes()); self.t = self.t.checked_add(rest.len() as u64) @@ -182,54 +343,10 @@ macro_rules! blake2_impl { if off != 0 { zero(&mut self.m.as_mut_bytes()[off..]); } - - self.compress(!0, f1); - - let buf = [self.h[0].to_le(), self.h[1].to_le()]; - let mut out = GenericArray::default(); - copy(buf.as_bytes(), &mut out); + self.h.finalize(&mut out, &self.m, f1, self.t); out } - - fn compress(&mut self, f0: $word, f1: $word) { - use $crate::consts::SIGMA; - - let m = &self.m; - let h = &mut self.h; - - let t0 = self.t as $word; - let t1 = match $bytes::to_u8() { - 64 => 0, - 32 => (self.t >> 32) as $word, - _ => unreachable!(), - }; - - let mut v = [ - h[0], - h[1], - iv0(), - iv1() ^ $vec::new(t0, t1, f0, f1), - ]; - - round(&mut v, m, &SIGMA[0]); - round(&mut v, m, &SIGMA[1]); - round(&mut v, m, &SIGMA[2]); - round(&mut v, m, &SIGMA[3]); - round(&mut v, m, &SIGMA[4]); - round(&mut v, m, &SIGMA[5]); - round(&mut v, m, &SIGMA[6]); - round(&mut v, m, &SIGMA[7]); - round(&mut v, m, &SIGMA[8]); - round(&mut v, m, &SIGMA[9]); - if $bytes::to_u8() == 64 { - round(&mut v, m, &SIGMA[0]); - round(&mut v, m, &SIGMA[1]); - } - - h[0] = h[0] ^ (v[0] ^ v[2]); - h[1] = h[1] ^ (v[1] ^ v[3]); - } } impl Default for $state { @@ -269,7 +386,7 @@ macro_rules! blake2_impl { fn reset(&mut self) { self.t = self.t0; self.m = self.m0; - self.h = self.h0; + self.h = self.h0.clone(); } } diff --git a/blake2/src/blake2b.rs b/blake2/src/blake2b.rs index 3a2a7a312..cc1913ad4 100644 --- a/blake2/src/blake2b.rs +++ b/blake2/src/blake2b.rs @@ -1,8 +1,7 @@ use digest::generic_array::typenum::U64; -use consts::BLAKE2B_IV; +use compressor_b::CompressorB; -blake2_impl!(VarBlake2b, Blake2b, u64, u64x4, U64, - 32, 24, 16, 63, BLAKE2B_IV, +blake2_impl!(VarBlake2b, Blake2b, CompressorB, u64, U64, "Blake2b instance with a variable output.", "Blake2b instance with a fixed output.", ); diff --git a/blake2/src/blake2s.rs b/blake2/src/blake2s.rs index b6c7ae41c..071cfe649 100644 --- a/blake2/src/blake2s.rs +++ b/blake2/src/blake2s.rs @@ -1,8 +1,7 @@ use digest::generic_array::typenum::U32; -use consts::BLAKE2S_IV; +use compressor_s::CompressorS; -blake2_impl!(VarBlake2s, Blake2s, u32, u32x4, U32, - 16, 12, 8, 7, BLAKE2S_IV, +blake2_impl!(VarBlake2s, Blake2s, CompressorS, u32, U32, "Blake2s instance with a variable output.", "Blake2s instance with a fixed output.", ); diff --git a/blake2/src/compressor_b.rs b/blake2/src/compressor_b.rs new file mode 100644 index 000000000..bfea35a6d --- /dev/null +++ b/blake2/src/compressor_b.rs @@ -0,0 +1,4 @@ +use digest::generic_array::typenum::U64; +use consts::BLAKE2B_IV; + +blake2_compressor_impl!(CompressorB, CompressorBBuilder, u64, u64x4, U64, 32, 24, 16, 63, BLAKE2B_IV, u32, 14, 16, ); diff --git a/blake2/src/compressor_s.rs b/blake2/src/compressor_s.rs new file mode 100644 index 000000000..748e0b183 --- /dev/null +++ b/blake2/src/compressor_s.rs @@ -0,0 +1,4 @@ +use digest::generic_array::typenum::U32; +use consts::BLAKE2S_IV; + +blake2_compressor_impl!(CompressorS, CompressorSBuilder, u32, u32x4, U32, 16, 12, 8, 7, BLAKE2S_IV, u16, 0, 8, ); diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index 6d645d688..d900b89e3 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -108,6 +108,8 @@ mod simd; #[macro_use] mod blake2; +mod compressor_b; +mod compressor_s; mod blake2b; mod blake2s; From 718f57edda47302aeb0f36d905e96c06bbea8f36 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 23 Jan 2019 08:51:54 -0800 Subject: [PATCH 2/5] blake2bp/blake2sp --- blake2/Cargo.toml | 2 +- blake2/benches/blake2bp.rs | 7 + blake2/benches/blake2sp.rs | 7 + blake2/src/as_bytes.rs | 2 + blake2/src/blake2.rs | 248 +++++++++++++++++++++++++++++++++ blake2/src/blake2bp.rs | 7 + blake2/src/blake2sp.rs | 7 + blake2/src/lib.rs | 4 + blake2/tests/data/blake2bp.blb | Bin 0 -> 51148 bytes blake2/tests/data/blake2sp.blb | Bin 0 -> 41351 bytes blake2/tests/lib.rs | 3 + 11 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 blake2/benches/blake2bp.rs create mode 100644 blake2/benches/blake2sp.rs create mode 100644 blake2/src/blake2bp.rs create mode 100644 blake2/src/blake2sp.rs create mode 100644 blake2/tests/data/blake2bp.blb create mode 100644 blake2/tests/data/blake2sp.blb diff --git a/blake2/Cargo.toml b/blake2/Cargo.toml index b7bcc7ad1..5bcf08c11 100644 --- a/blake2/Cargo.toml +++ b/blake2/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blake2" -version = "0.8.0" +version = "0.8.1" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" description = "BLAKE2 hash functions" diff --git a/blake2/benches/blake2bp.rs b/blake2/benches/blake2bp.rs new file mode 100644 index 000000000..cd92a8854 --- /dev/null +++ b/blake2/benches/blake2bp.rs @@ -0,0 +1,7 @@ +#![no_std] +#![feature(test)] +#[macro_use] +extern crate digest; +extern crate blake2; + +bench!(blake2::Blake2bp); diff --git a/blake2/benches/blake2sp.rs b/blake2/benches/blake2sp.rs new file mode 100644 index 000000000..ab1eb153d --- /dev/null +++ b/blake2/benches/blake2sp.rs @@ -0,0 +1,7 @@ +#![no_std] +#![feature(test)] +#[macro_use] +extern crate digest; +extern crate blake2; + +bench!(blake2::Blake2sp); diff --git a/blake2/src/as_bytes.rs b/blake2/src/as_bytes.rs index ae1fcfcef..7a1284e3e 100644 --- a/blake2/src/as_bytes.rs +++ b/blake2/src/as_bytes.rs @@ -41,3 +41,5 @@ unsafe impl Safe for i8 {} unsafe impl Safe for i16 {} unsafe impl Safe for i32 {} unsafe impl Safe for i64 {} +unsafe impl Safe for [T; 8] {} +unsafe impl Safe for [T; 16] {} diff --git a/blake2/src/blake2.rs b/blake2/src/blake2.rs index a484ac5cd..ea7331993 100644 --- a/blake2/src/blake2.rs +++ b/blake2/src/blake2.rs @@ -464,3 +464,251 @@ macro_rules! blake2_impl { impl_write!($fix_state); } } + +macro_rules! blake2_p_impl { + ( + $state:ident, $fix_state:ident, $compressor:ident, $builder:ident, $word:ident, $bytes:ident, $fanout:expr, + $vardoc:expr, $doc:expr, + ) => { + + use $crate::as_bytes::AsBytes; + + use digest::{Input, BlockInput, FixedOutput, VariableOutput, Reset}; + use digest::InvalidOutputSize; + use digest::generic_array::GenericArray; + use digest::generic_array::typenum::Unsigned; + use core::cmp; + use byte_tools::{copy, zero}; + use crypto_mac::{Mac, MacResult, InvalidKeyLength}; + + type Output = GenericArray; + + #[derive(Clone)] + #[doc=$vardoc] + pub struct $state { + n: usize, + m0: [$word; 16], + t0: u64, + h0: $builder, + h: [$compressor; $fanout], + m: [[$word; 16]; $fanout], + t: u64, + } + + impl $state { + /// Creates a new hashing context with a key. + /// + /// **WARNING!** If you plan to use it for variable output MAC, then + /// make sure to compare codes in constant time! It can be done + /// for example by using `subtle` crate. + pub fn new_keyed(key: &[u8], output_size: usize) -> Self { + let mut h0 = $builder::new(); + h0.key(key.len()); + h0.out(output_size); + h0.fanout($fanout); + h0.depth(2); + h0.inner_length($bytes::to_u8()); + let mut m0 = [0; 16]; + let mut t0 = 0; + if !key.is_empty() { + copy(key, m0.as_mut_bytes()); + t0 = 2 * $bytes::to_u64() * $fanout; + } + let mut state = $state { + n: output_size, + h0, + t0, + m0, + // everything else set up by reset() + h: Default::default(), + m: Default::default(), + t: Default::default(), + }; + state.reset(); + state + } + + /// Updates the hashing context with more data. + fn update(&mut self, mut data: &[u8]) { + const BLOCK: usize = 2 * $bytes::USIZE; + const RING: usize = BLOCK * $fanout; + + if self.t < RING as u64 { + // initial ring fill + let (d0, d1) = data.split_at(cmp::min(data.len(), RING - self.t as usize)); + self.m.as_mut_bytes()[self.t as usize..self.t as usize + d0.len()].copy_from_slice(d0); + self.t += d0.len() as u64; + data = d1; + } else if self.t as usize % BLOCK != 0 { + // complete partial block + let (d0, d1) = data.split_at(cmp::min(data.len(), BLOCK - self.t as usize % BLOCK)); + let ri = self.t as usize % RING; + self.m.as_mut_bytes()[ri..ri + d0.len()].copy_from_slice(d0); + self.t += d0.len() as u64; + data = d1; + } + + // if there's data remaining, the ring is full of whole blocks + for b in data.chunks(BLOCK) { + let i = self.t as usize / BLOCK % $fanout; + self.h[i].compress(&mut self.m[i], 0, 0, self.t / RING as u64 * BLOCK as u64); + self.m[i].as_mut_bytes()[..b.len()].copy_from_slice(b); + self.t += b.len() as u64; + } + } + + fn finalize(mut self) -> Output { + const BLOCK: usize = 2 * $bytes::USIZE; + const RING: usize = BLOCK * $fanout; + + self.h0.node_offset(0); + self.h0.node_depth(1); + let mut root = self.h0.build(); + + let mut ri = self.t as usize % RING; + let trb = self.t / RING as u64 * BLOCK as u64; + if ri % BLOCK != 0 { + let ni = ((self.t as usize & !(BLOCK - 1)) + BLOCK) % RING; + zero(&mut self.m.as_mut_bytes()[ri..ni]); + } + let mut inter = [0; 16]; + for i in 0..$fanout { + if i != 0 && i & 1 == 0 { + root.compress(&inter, 0, 0, i as u64 * $bytes::to_u64()); + } + let len = cmp::min(ri, BLOCK); + ri -= len; + let f1 = if i == $fanout - 1 { !0 } else { 0 }; + let ix0 = (i & 1) * $bytes::to_usize(); + let ix1 = ((i & 1) + 1) * $bytes::to_usize(); + self.h[i].finalize_into_slice(&mut inter.as_mut_bytes()[ix0..ix1], &self.m[i], f1, trb + len as u64); + } + let mut out = GenericArray::default(); + root.finalize(&mut out, &inter, !0, $fanout * $bytes::to_u64()); + out + } + } + + impl Default for $state { + fn default() -> Self { Self::new_keyed(&[], $bytes::to_usize()) } + } + + impl BlockInput for $state { + type BlockSize = $bytes; + } + + impl Input for $state { + fn input>(&mut self, data: B) { + self.update(data.as_ref()); + } + } + + impl VariableOutput for $state { + fn new(output_size: usize) -> Result { + if output_size == 0 || output_size > $bytes::to_usize() { + return Err(InvalidOutputSize); + } + Ok(Self::new_keyed(&[], output_size)) + } + + fn output_size(&self) -> usize { + self.n + } + + fn variable_result(self, f: F) { + let n = self.n; + let res = self.finalize(); + f(&res[..n]); + } + } + + impl Reset for $state { + fn reset(&mut self) { + self.h0.node_depth(0); + for (i, h) in self.h.iter_mut().enumerate() { + self.h0.node_offset(i); + *h = self.h0.build(); + } + + for m in self.m.iter_mut() { + m.copy_from_slice(&self.m0); + } + + self.t = self.t0; + } + } + + impl_opaque_debug!($state); + impl_write!($state); + + + #[derive(Clone)] + #[doc=$doc] + pub struct $fix_state { + state: $state, + } + + impl Default for $fix_state { + fn default() -> Self { + let state = $state::new_keyed(&[], $bytes::to_usize()); + Self { state } + } + } + + impl BlockInput for $fix_state { + type BlockSize = $bytes; + } + + impl Input for $fix_state { + fn input>(&mut self, data: B) { + self.state.update(data.as_ref()); + } + } + + impl FixedOutput for $fix_state { + type OutputSize = $bytes; + + fn fixed_result(self) -> Output { + self.state.finalize() + } + } + + impl Reset for $fix_state { + fn reset(&mut self) { + self.state.reset() + } + } + + impl Mac for $fix_state { + type OutputSize = $bytes; + type KeySize = $bytes; + + fn new(key: &GenericArray) -> Self { + let state = $state::new_keyed(key, $bytes::to_usize()); + Self { state } + } + + fn new_varkey(key: &[u8]) -> Result { + if key.len() > $bytes::to_usize() { + Err(InvalidKeyLength) + } else { + let state = $state::new_keyed(key, $bytes::to_usize()); + Ok(Self { state }) + } + } + + fn input(&mut self, data: &[u8]) { self.state.update(data); } + + fn reset(&mut self) { + ::reset(self) + } + + fn result(self) -> MacResult { + MacResult::new(self.state.finalize()) + } + } + + impl_opaque_debug!($fix_state); + impl_write!($fix_state); + } +} diff --git a/blake2/src/blake2bp.rs b/blake2/src/blake2bp.rs new file mode 100644 index 000000000..d5678c17e --- /dev/null +++ b/blake2/src/blake2bp.rs @@ -0,0 +1,7 @@ +use digest::generic_array::typenum::U64; +use compressor_b::{CompressorB, CompressorBBuilder}; + +blake2_p_impl!(VarBlake2bp, Blake2bp, CompressorB, CompressorBBuilder, u64, U64, 4, + "Blake2bp instance with a variable output.", + "Blake2bp instance with a fixed output.", +); diff --git a/blake2/src/blake2sp.rs b/blake2/src/blake2sp.rs new file mode 100644 index 000000000..aa7dd8a15 --- /dev/null +++ b/blake2/src/blake2sp.rs @@ -0,0 +1,7 @@ +use digest::generic_array::typenum::U32; +use compressor_s::{CompressorS, CompressorSBuilder}; + +blake2_p_impl!(VarBlake2sp, Blake2sp, CompressorS, CompressorSBuilder, u32, U32, 8, + "Blake2sp instance with a variable output.", + "Blake2sp instance with a fixed output.", +); diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index d900b89e3..4d0967ec6 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -112,7 +112,11 @@ mod compressor_b; mod compressor_s; mod blake2b; mod blake2s; +mod blake2bp; +mod blake2sp; pub use digest::Digest; pub use blake2b::{Blake2b, VarBlake2b}; pub use blake2s::{Blake2s, VarBlake2s}; +pub use blake2bp::{Blake2bp, VarBlake2bp}; +pub use blake2sp::{Blake2sp, VarBlake2sp}; diff --git a/blake2/tests/data/blake2bp.blb b/blake2/tests/data/blake2bp.blb new file mode 100644 index 0000000000000000000000000000000000000000..1b0ba9fec6ea50cbaedf50ba3139fa673dc5c7d9 GIT binary patch literal 51148 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 Xs-ZOrf6cOW2PhW7H{$CLW}5y7Higd` literal 0 HcmV?d00001 diff --git a/blake2/tests/data/blake2sp.blb b/blake2/tests/data/blake2sp.blb new file mode 100644 index 0000000000000000000000000000000000000000..bcc4cd9d4f9418d6cf8eba91c861e3b8ac281886 GIT binary patch literal 41351 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 literal 0 HcmV?d00001 diff --git a/blake2/tests/lib.rs b/blake2/tests/lib.rs index 452c618f7..2f15886e7 100644 --- a/blake2/tests/lib.rs +++ b/blake2/tests/lib.rs @@ -2,9 +2,12 @@ #[macro_use] extern crate digest; extern crate blake2; +extern crate hex_literal; use digest::dev::{digest_test, variable_test}; new_test!(blake2b_fixed, "blake2b/fixed", blake2::Blake2b, digest_test); new_test!(blake2b_variable, "blake2b/variable", blake2::VarBlake2b, variable_test); new_test!(blake2s_variable, "blake2s/variable", blake2::VarBlake2s, variable_test); +new_test!(blake2bp, "blake2bp", blake2::Blake2bp, digest_test); +new_test!(blake2sp, "blake2sp", blake2::Blake2sp, digest_test); From c5df7a5552fbb2f57b4b5b28500203fffc6c1ecd Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 23 Jan 2019 11:58:43 -0800 Subject: [PATCH 3/5] blake2b/s: simplify update --- blake2/src/blake2.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/blake2/src/blake2.rs b/blake2/src/blake2.rs index ea7331993..dbe4d9996 100644 --- a/blake2/src/blake2.rs +++ b/blake2/src/blake2.rs @@ -311,25 +311,13 @@ macro_rules! blake2_impl { .expect("hash data length overflow"); } - while rest.len() >= block { + for part in rest.chunks(block) { self.h.compress(&self.m, 0, 0, self.t); - let part = &rest[..block]; - rest = &rest[part.len()..]; - copy(part, &mut self.m.as_mut_bytes()); self.t = self.t.checked_add(part.len() as u64) .expect("hash data length overflow"); } - - let n = rest.len(); - if n > 0 { - self.h.compress(&self.m, 0, 0, self.t); - - copy(rest, &mut self.m.as_mut_bytes()); - self.t = self.t.checked_add(rest.len() as u64) - .expect("hash data length overflow"); - } } #[doc(hidden)] From efed3231d8673d9011c2f701ae8e5083c6fd6848 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Thu, 24 Jan 2019 10:55:14 -0800 Subject: [PATCH 4/5] x86 coresimd Replacement for simd + simd_opt. Builds on stable rustc 1.27+ The coresimd feature overrides all other simd flags. Build with coresimd will fail for unsupported target platforms, e.g. non-x86. Benched on a Xeon X5650: sse2 only: faster than simd_opt ssse3: slightly faster than simd_opt Benched on a Haswell: avx2: same speed as simd_opt --- blake2/Cargo.toml | 3 +- blake2/src/blake2.rs | 7 +- blake2/src/coresimd/mod.rs | 246 +++++++++++++++++++++++++++++++++++++ blake2/src/lib.rs | 9 +- blake2/src/simd/mod.rs | 23 +--- 5 files changed, 260 insertions(+), 28 deletions(-) create mode 100644 blake2/src/coresimd/mod.rs diff --git a/blake2/Cargo.toml b/blake2/Cargo.toml index 5bcf08c11..86df95367 100644 --- a/blake2/Cargo.toml +++ b/blake2/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blake2" -version = "0.8.1" +version = "0.8.2" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" description = "BLAKE2 hash functions" @@ -26,6 +26,7 @@ std = ["digest/std", "crypto-mac/std"] simd = [] simd_opt = ["simd"] simd_asm = ["simd_opt"] +coresimd = [] [badges] travis-ci = { repository = "RustCrypto/hashes" } diff --git a/blake2/src/blake2.rs b/blake2/src/blake2.rs index dbe4d9996..9b57b9edb 100644 --- a/blake2/src/blake2.rs +++ b/blake2/src/blake2.rs @@ -6,6 +6,7 @@ macro_rules! blake2_compressor_impl { ) => { use $crate::as_bytes::AsBytes; + #[allow(unused_imports)] use $crate::simd::{Vector4, $vec}; use byte_tools::copy; @@ -127,9 +128,9 @@ macro_rules! blake2_compressor_impl { #[inline(always)] fn unshuffle(v: &mut [$vec; 4]) { - v[1] = v[1].shuffle_right_1(); - v[2] = v[2].shuffle_right_2(); - v[3] = v[3].shuffle_right_3(); + v[1] = v[1].shuffle_left_3(); + v[2] = v[2].shuffle_left_2(); + v[3] = v[3].shuffle_left_1(); } #[inline(always)] diff --git a/blake2/src/coresimd/mod.rs b/blake2/src/coresimd/mod.rs new file mode 100644 index 000000000..3b44911c7 --- /dev/null +++ b/blake2/src/coresimd/mod.rs @@ -0,0 +1,246 @@ +use as_bytes::Safe; + +pub trait Vector4 {} + +#[cfg(target_feature = "sse2")] +mod sse2 { + use core::ops::BitXor; + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + + #[cfg(not(target_feature = "avx2"))] + use core::mem; + + #[cfg(not(target_feature = "avx2"))] + #[allow(non_camel_case_types)] + #[repr(C)] + #[derive(Copy, Clone)] + pub struct u64x4(__m128i, __m128i); + + #[cfg(not(target_feature = "avx2"))] + impl u64x4 { + #[inline(always)] + pub fn new(a: u64, b: u64, c: u64, d: u64) -> Self { + unsafe { u64x4(_mm_set_epi64x(b as i64, a as i64), _mm_set_epi64x(d as i64, c as i64)) } + } + + #[inline(always)] + pub fn gather(src: &[u64], i0: usize, i1: usize, i2: usize, i3: usize) -> Self { + Self::new(src[i0], src[i1], src[i2], src[i3]) + } + + #[inline(always)] + pub fn shuffle_left_1(mut self) -> Self { + unsafe { + let epi: &mut [u64; 4] = mem::transmute(&mut self); + let tmp = epi[0]; + epi[0] = epi[1]; + epi[1] = epi[2]; + epi[2] = epi[3]; + epi[3] = tmp; + self + } + } + + #[inline(always)] + pub fn shuffle_left_2(self) -> Self { u64x4(self.1, self.0) } + + #[inline(always)] + pub fn shuffle_left_3(mut self) -> Self { + unsafe { + let epi: &mut [u64; 4] = mem::transmute(&mut self); + let tmp = epi[3]; + epi[3] = epi[2]; + epi[2] = epi[1]; + epi[1] = epi[0]; + epi[0] = tmp; + self + } + } + + #[cfg(not(target_feature = "ssse3"))] + #[inline(always)] + pub fn rotate_right_const(self, i: u32) -> Self { + unsafe { + match i { + 16 => u64x4( + _mm_or_si128(_mm_slli_epi64(self.0, 48), _mm_srli_epi64(self.0, 16)), + _mm_or_si128(_mm_slli_epi64(self.1, 48), _mm_srli_epi64(self.1, 16)), + ), + 24 => u64x4( + _mm_or_si128(_mm_slli_epi64(self.0, 40), _mm_srli_epi64(self.0, 24)), + _mm_or_si128(_mm_slli_epi64(self.1, 40), _mm_srli_epi64(self.1, 24)), + ), + 32 => u64x4(_mm_shuffle_epi32(self.0, 0b10110001), _mm_shuffle_epi32(self.1, 0b10110001)), + 63 => u64x4( + _mm_or_si128(_mm_slli_epi64(self.0, 1), _mm_srli_epi64(self.0, 63)), + _mm_or_si128(_mm_slli_epi64(self.1, 1), _mm_srli_epi64(self.1, 63)), + ), + _ => unreachable!(), + } + } + } + + #[cfg(target_feature = "ssse3")] + #[inline(always)] + pub fn rotate_right_const(self, i: u32) -> Self { + unsafe { + let b16 = _mm_set_epi64x(0x09080f0e_0d0c0b0a, 0x01000706_05040302); + let b24 = _mm_set_epi64x(0x0a09080f_0e0d0c0b, 0x02010007_06050403); + match i { + 16 => u64x4(_mm_shuffle_epi8(self.0, b16), _mm_shuffle_epi8(self.1, b16)), + 24 => u64x4(_mm_shuffle_epi8(self.0, b24), _mm_shuffle_epi8(self.1, b24)), + 32 => u64x4(_mm_shuffle_epi32(self.0, 0b10110001), _mm_shuffle_epi32(self.1, 0b10110001)), + 63 => u64x4( + _mm_or_si128(_mm_slli_epi64(self.0, 1), _mm_srli_epi64(self.0, 63)), + _mm_or_si128(_mm_slli_epi64(self.1, 1), _mm_srli_epi64(self.1, 63)), + ), + _ => unreachable!(), + } + } + } + + #[inline(always)] pub fn wrapping_add(self, rhs: Self) -> Self { + unsafe { u64x4(_mm_add_epi64(self.0, rhs.0), _mm_add_epi64(self.1, rhs.1)) } + } + + #[inline(always)] pub fn to_le(self) -> Self { self } + #[inline(always)] pub fn from_le(self) -> Self { self } + } + + #[cfg(not(target_feature = "avx2"))] + impl BitXor for u64x4 { + type Output = Self; + #[inline(always)] + fn bitxor(self, rhs: Self) -> Self::Output { + unsafe { u64x4(_mm_xor_si128(self.0, rhs.0), _mm_xor_si128(self.1, rhs.1)) } + } + } + + #[allow(non_camel_case_types)] + #[repr(C)] + #[derive(Copy, Clone)] + pub struct u32x4(__m128i); + + impl u32x4 { + #[inline(always)] + pub fn new(a: u32, b: u32, c: u32, d: u32) -> Self { + unsafe { u32x4(_mm_set_epi32(d as i32, c as i32, b as i32, a as i32)) } + } + + #[inline(always)] + pub fn gather(src: &[u32], i0: usize, i1: usize, i2: usize, i3: usize) -> Self { + Self::new(src[i0], src[i1], src[i2], src[i3]) + } + + #[inline(always)] pub fn shuffle_left_1(self) -> Self { unsafe { u32x4(_mm_shuffle_epi32(self.0, 0b00111001)) } } + #[inline(always)] pub fn shuffle_left_2(self) -> Self { unsafe { u32x4(_mm_shuffle_epi32(self.0, 0b01001110)) } } + #[inline(always)] pub fn shuffle_left_3(self) -> Self { unsafe { u32x4(_mm_shuffle_epi32(self.0, 0b10010011)) } } + + #[cfg(not(target_feature = "ssse3"))] + #[inline(always)] + pub fn rotate_right_const(self, i: u32) -> Self { + unsafe { + match i { + 7 => u32x4(_mm_or_si128(_mm_slli_epi32(self.0, 25), _mm_srli_epi32(self.0, 7))), + 8 => u32x4(_mm_or_si128(_mm_slli_epi32(self.0, 24), _mm_srli_epi32(self.0, 8))), + 12 => u32x4(_mm_or_si128(_mm_slli_epi32(self.0, 20), _mm_srli_epi32(self.0, 12))), + 16 => u32x4(_mm_or_si128(_mm_slli_epi32(self.0, 16), _mm_srli_epi32(self.0, 16))), + _ => unreachable!(), + } + } + } + + #[cfg(target_feature = "ssse3")] + #[inline(always)] + pub fn rotate_right_const(self, i: u32) -> Self { + unsafe { + match i { + 7 => u32x4(_mm_or_si128(_mm_slli_epi32(self.0, 32 - 7), _mm_srli_epi32(self.0, 7))), + 8 => u32x4(_mm_shuffle_epi8(self.0, _mm_set_epi64x(0x0c0f0e0d_080b0a09, 0x04070605_00030201))), + 12 => u32x4(_mm_or_si128(_mm_slli_epi32(self.0, 32 - 12), _mm_srli_epi32(self.0, 12))), + 16 => u32x4(_mm_shuffle_epi8(self.0, _mm_set_epi64x(0x0d0c0f0e_09080b0a, 0x05040706_01000302))), + _ => unreachable!(), + } + } + } + + #[inline(always)] pub fn wrapping_add(self, rhs: Self) -> Self { unsafe { u32x4(_mm_add_epi32(self.0, rhs.0)) } } + + #[inline(always)] pub fn to_le(self) -> Self { self } + #[inline(always)] pub fn from_le(self) -> Self { self } + } + + impl BitXor for u32x4 { + type Output = Self; + #[inline(always)] fn bitxor(self, rhs: Self) -> Self::Output { unsafe { u32x4(_mm_xor_si128(self.0, rhs.0)) } } + } +} + +#[cfg(target_feature = "avx2")] +mod avx2 { + use core::ops::BitXor; + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + + #[allow(non_camel_case_types)] + #[repr(C)] + #[derive(Copy, Clone)] + pub struct u64x4(__m256i); + + impl u64x4 { + #[inline(always)] + pub fn new(a: u64, b: u64, c: u64, d: u64) -> Self { + unsafe { u64x4(_mm256_set_epi64x(d as i64, c as i64, b as i64, a as i64),) } + } + + #[inline(always)] + pub fn gather(src: &[u64], i0: usize, i1: usize, i2: usize, i3: usize) -> Self { + Self::new(src[i0], src[i1], src[i2], src[i3]) + } + + #[inline(always)] pub fn shuffle_left_1(self) -> Self { u64x4(unsafe { _mm256_permute4x64_epi64(self.0, 0b00111001) }) } + #[inline(always)] pub fn shuffle_left_2(self) -> Self { u64x4(unsafe { _mm256_permute4x64_epi64(self.0, 0b01001110) }) } + #[inline(always)] pub fn shuffle_left_3(self) -> Self { u64x4(unsafe { _mm256_permute4x64_epi64(self.0, 0b10010011) }) } + + #[inline(always)] + pub fn rotate_right_const(self, i: u32) -> Self { + unsafe { + let b16 = _mm256_set_epi64x(0x09080f0e0d0c0b0a, 0x0100070605040302, 0x09080f0e0d0c0b0a, 0x0100070605040302); + let b24 = _mm256_set_epi64x(0x0a09080f0e0d0c0b, 0x0201000706050403, 0x0a09080f0e0d0c0b, 0x0201000706050403); + match i { + 16 => u64x4(_mm256_shuffle_epi8(self.0, b16)), + 24 => u64x4(_mm256_shuffle_epi8(self.0, b24)), + 32 => u64x4(_mm256_shuffle_epi32(self.0, 0b10110001)), + 63 => u64x4(_mm256_or_si256(_mm256_slli_epi64(self.0, 1), _mm256_srli_epi64(self.0, 63))), + _ => unreachable!(), + } + } + } + + #[inline(always)] pub fn wrapping_add(self, rhs: Self) -> Self { unsafe { u64x4(_mm256_add_epi64(self.0, rhs.0)) } } + + #[inline(always)] pub fn to_le(self) -> Self { self } + #[inline(always)] pub fn from_le(self) -> Self { self } + } + + impl BitXor for u64x4 { + type Output = Self; + #[inline(always)] fn bitxor(self, rhs: Self) -> Self::Output { u64x4(unsafe { _mm256_xor_si256(self.0, rhs.0) }) } + } +} + +#[cfg(all(target_feature = "sse2", not(target_feature = "avx2")))] +pub use self::sse2::u64x4; +#[cfg(target_feature = "avx2")] +pub use self::avx2::u64x4; + +#[cfg(target_feature = "sse2")] +pub use self::sse2::u32x4; + +unsafe impl Safe for u64x4 {} +unsafe impl Safe for u32x4 {} diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index 4d0967ec6..e4cc6abbf 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -88,8 +88,8 @@ "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] #![warn(missing_docs)] -#![cfg_attr(feature = "simd", feature(platform_intrinsics, repr_simd))] -#![cfg_attr(feature = "simd_asm", feature(asm))] +#![cfg_attr(all(feature = "simd", not(feature = "coresimd")), feature(platform_intrinsics, repr_simd))] +#![cfg_attr(all(feature = "simd_asm", not(feature = "coresimd")), feature(asm))] #[macro_use] extern crate opaque_debug; #[macro_use] pub extern crate digest; @@ -102,6 +102,11 @@ extern crate std; mod consts; mod as_bytes; +#[cfg(feature = "coresimd")] +mod coresimd; +#[cfg(feature = "coresimd")] +mod simd { pub use coresimd::*; } +#[cfg(not(feature = "coresimd"))] mod simd; diff --git a/blake2/src/simd/mod.rs b/blake2/src/simd/mod.rs index bb999c223..661e93e68 100644 --- a/blake2/src/simd/mod.rs +++ b/blake2/src/simd/mod.rs @@ -18,7 +18,6 @@ pub trait Vector4: Copy { fn gather(src: &[T], i0: usize, i1: usize, i2: usize, i3: usize) -> Self; fn from_le(self) -> Self; - fn to_le(self) -> Self; fn wrapping_add(self, rhs: Self) -> Self; @@ -28,9 +27,7 @@ pub trait Vector4: Copy { fn shuffle_left_2(self) -> Self; fn shuffle_left_3(self) -> Self; - #[inline(always)] fn shuffle_right_1(self) -> Self { self.shuffle_left_3() } - #[inline(always)] fn shuffle_right_2(self) -> Self { self.shuffle_left_2() } - #[inline(always)] fn shuffle_right_3(self) -> Self { self.shuffle_left_1() } + #[inline(always)] fn to_le(self) -> Self { self.from_le() } } macro_rules! impl_vector4 { @@ -42,11 +39,6 @@ macro_rules! impl_vector4 { $vec::new(src[i0], src[i1], src[i2], src[i3]) } - #[cfg(target_endian = "little")] - #[inline(always)] - fn from_le(self) -> Self { self } - - #[cfg(not(target_endian = "little"))] #[inline(always)] fn from_le(self) -> Self { $vec::new($word::from_le(self.0), @@ -55,19 +47,6 @@ macro_rules! impl_vector4 { $word::from_le(self.3)) } - #[cfg(target_endian = "little")] - #[inline(always)] - fn to_le(self) -> Self { self } - - #[cfg(not(target_endian = "little"))] - #[inline(always)] - fn to_le(self) -> Self { - $vec::new(self.0.to_le(), - self.1.to_le(), - self.2.to_le(), - self.3.to_le()) - } - #[inline(always)] fn wrapping_add(self, rhs: Self) -> Self { self + rhs } From 5b4ea99bb4fcaf89c1903fdb6c9115143401f39d Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 29 Jan 2019 10:49:37 -0800 Subject: [PATCH 5/5] test coresimd on travis This will test the sse2 and probably ssse3 coresimd implementations. If the buildbox happens to support avx2, it will also test the avx2 implementations. --- test_features.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test_features.sh b/test_features.sh index 03747f87b..650fce517 100755 --- a/test_features.sh +++ b/test_features.sh @@ -3,4 +3,7 @@ cd sha1 && cargo test --features asm && cd .. && cd whirlpool && cargo test --features asm && cd .. && cd blake2 && cargo test --features simd && cargo test --features simd_opt && - cargo test --features simd_asm + cargo test --features simd_asm && + RUSTFLAGS="-Ctarget-cpu=native" cargo test --features coresimd && + RUSTFLAGS="-Ctarget-cpu=native -Ctarget-feature=-ssse3" cargo test --features coresimd && + RUSTFLAGS="-Ctarget-cpu=native -Ctarget-feature=-avx2" cargo test --features coresimd