Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions blake2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ use digest::{
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, OutputSizeUser, TruncSide,
UpdateCore, VariableOutputCore, VariableOutputCoreCustomized,
},
block_buffer::{Lazy, LazyBuffer},
common::{InvalidLength, Key, KeyInit, KeySizeUser},
consts::{U4, U16, U32, U64, U128},
typenum::{IsLessOrEqual, True, Unsigned},
block_buffer::{Lazy, LazyBuffer, SerializedBufferSize},
common::{
InvalidLength, Key, KeyInit, KeySizeUser,
hazmat::{DeserializeStateError, SerializableState, SerializedState},
},
consts::{U4, U8, U16, U32, U64, U128},
typenum::{IsLessOrEqual, Sum, True, Unsigned},
};
#[cfg(feature = "reset")]
use digest::{FixedOutputReset, Reset};
Expand Down Expand Up @@ -56,7 +59,6 @@ blake2_impl!(
digest::buffer_ct_variable!(
/// BLAKE2b generic over output size.
pub struct Blake2b<OutSize>(Blake2bVarCore);
exclude: SerializableState;
max_size: U64;
);

Expand Down Expand Up @@ -104,7 +106,6 @@ blake2_impl!(
digest::buffer_ct_variable!(
/// BLAKE2s generic over output size.
pub struct Blake2s<OutSize>(Blake2sVarCore);
exclude: SerializableState;
max_size: U32;
);

Expand Down
157 changes: 157 additions & 0 deletions blake2/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,68 @@ macro_rules! blake2_impl {

#[cfg(feature = "zeroize")]
impl ZeroizeOnDrop for $name {}

impl SerializableState for $name {
// Note: using `$bytes` here instead of
// `Prod<<$vec as SerializableState>::SerializedStateSize, U2>` because the latter
// would require $vec to be a public type (but e.g. u64x4 is crate-private).
#[cfg(not(feature = "reset"))]
type SerializedStateSize = Sum<$bytes, U8>;
#[cfg(feature = "reset")]
type SerializedStateSize = Sum<Sum<$bytes, U8>, $bytes>;

fn serialize(&self) -> SerializedState<Self> {
let mut serialized_state = SerializedState::<Self>::default();
let vecsz = <$vec as SerializableState>::SerializedStateSize::USIZE;
let tsz = U8::USIZE;
serialized_state[..vecsz].copy_from_slice(&self.h[0].serialize());
serialized_state[vecsz..(2 * vecsz)].copy_from_slice(&self.h[1].serialize());
serialized_state[(2 * vecsz)..(2 * vecsz + tsz)]
.copy_from_slice(&self.t.serialize());
#[cfg(feature = "reset")]
serialized_state[(2 * vecsz + tsz)..(3 * vecsz + tsz)]
.copy_from_slice(&self.h0[0].serialize());
#[cfg(feature = "reset")]
serialized_state[(3 * vecsz + tsz)..(4 * vecsz + tsz)]
.copy_from_slice(&self.h0[1].serialize());
serialized_state
}

fn deserialize(
serialized_state: &SerializedState<Self>,
) -> Result<Self, DeserializeStateError> {
let vecsz = <$vec as SerializableState>::SerializedStateSize::USIZE;
let tsz = U8::USIZE;
let h_0 =
SerializableState::deserialize(&serialized_state[..vecsz].try_into().unwrap())?;
let h_1 = SerializableState::deserialize(
&serialized_state[vecsz..(2 * vecsz)].try_into().unwrap(),
)?;
let t = SerializableState::deserialize(
&serialized_state[(2 * vecsz)..(2 * vecsz + tsz)]
.try_into()
.unwrap(),
)?;
#[cfg(feature = "reset")]
let h0_0 = SerializableState::deserialize(
&serialized_state[(2 * vecsz + tsz)..(3 * vecsz + tsz)]
.try_into()
.unwrap(),
)?;
#[cfg(feature = "reset")]
let h0_1 = SerializableState::deserialize(
&serialized_state[(3 * vecsz + tsz)..(4 * vecsz + tsz)]
.try_into()
.unwrap(),
)?;
Ok(Self {
h: [h_0, h_1],
t,
#[cfg(feature = "reset")]
h0: [h0_0, h0_1],
})
}
}
};
}

Expand Down Expand Up @@ -471,5 +533,100 @@ macro_rules! blake2_mac_impl {
OutSize: ArraySize + IsLessOrEqual<$max_size, Output = True>
{
}

impl<OutSize> SerializableState for $name<OutSize>
where
OutSize: ArraySize + IsLessOrEqual<$max_size, Output = True>,
{
#[cfg(not(feature = "reset"))]
type SerializedStateSize = Sum<
<$hash as SerializableState>::SerializedStateSize,
SerializedBufferSize<<$hash as BlockSizeUser>::BlockSize, Lazy>,
>;
#[cfg(feature = "reset")]
type SerializedStateSize = Sum<
Sum<
<$hash as SerializableState>::SerializedStateSize,
SerializedBufferSize<<$hash as BlockSizeUser>::BlockSize, Lazy>,
>,
Sum<<Self as KeySizeUser>::KeySize, digest::consts::U1>,
>;

fn serialize(&self) -> SerializedState<Self> {
let mut serialized_state = SerializedState::<Self>::default();
let coresz = <$hash as SerializableState>::SerializedStateSize::USIZE;
let buffersz =
<SerializedBufferSize<<$hash as BlockSizeUser>::BlockSize, Lazy>>::USIZE;

serialized_state[..coresz].copy_from_slice(&self.core.serialize());
serialized_state[coresz..(coresz + buffersz)]
.copy_from_slice(&self.buffer.serialize());

#[cfg(feature = "reset")]
{
let boolsz = digest::consts::U1::USIZE;
let keyblocksz = <Self as KeySizeUser>::KeySize::USIZE;
if let Some(key_block) = self.key_block {
serialized_state[(coresz + buffersz)..(coresz + buffersz + boolsz)]
.copy_from_slice(&1u8.serialize());
serialized_state[(coresz + buffersz + boolsz)
..(coresz + buffersz + boolsz + keyblocksz)]
.copy_from_slice(&key_block);
} else {
serialized_state[(coresz + buffersz)..(coresz + buffersz + boolsz)]
.copy_from_slice(&0u8.serialize());
}
}

serialized_state
}

fn deserialize(
serialized_state: &SerializedState<Self>,
) -> Result<Self, DeserializeStateError> {
let coresz = <$hash as SerializableState>::SerializedStateSize::USIZE;
let buffersz =
<SerializedBufferSize<<$hash as BlockSizeUser>::BlockSize, Lazy>>::USIZE;

let core = SerializableState::deserialize(
&serialized_state[..coresz].try_into().unwrap(),
)?;
let buffer = LazyBuffer::<<$hash as BlockSizeUser>::BlockSize>::deserialize(
&serialized_state[coresz..(coresz + buffersz)]
.try_into()
.unwrap(),
)
.map_err(|_| DeserializeStateError)?;

#[cfg(feature = "reset")]
let key_block = {
let boolsz = digest::consts::U1::USIZE;
let keyblocksz = <Self as KeySizeUser>::KeySize::USIZE;
let present: u8 = SerializableState::deserialize(
&serialized_state[(coresz + buffersz)..(coresz + buffersz + boolsz)]
.try_into()
.unwrap(),
)?;
if present != 0 {
Some(
serialized_state[(coresz + buffersz + boolsz)
..(coresz + buffersz + boolsz + keyblocksz)]
.try_into()
.unwrap(),
)
} else {
None
}
};

Ok(Self {
core,
buffer,
#[cfg(feature = "reset")]
key_block,
_out: Default::default(),
})
}
}
};
}
23 changes: 23 additions & 0 deletions blake2/src/simd.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use core::ops::{Add, BitXor, Shl, Shr};

use digest::common::hazmat::{DeserializeStateError, SerializableState, SerializedState};

#[cfg(feature = "zeroize")]
use digest::zeroize::Zeroize;

Expand Down Expand Up @@ -181,6 +183,27 @@ macro_rules! impl_vector4 {
self.3.zeroize();
}
}

impl SerializableState for $vec {
type SerializedStateSize = <[$word; 4] as SerializableState>::SerializedStateSize;

fn serialize(&self) -> SerializedState<Self> {
[self.0, self.1, self.2, self.3].serialize()
}

fn deserialize(
serialized_state: &SerializedState<Self>,
) -> Result<Self, DeserializeStateError> {
let deserialized: [$word; 4] =
<[$word; 4] as SerializableState>::deserialize(serialized_state)?;
Ok($vec(
deserialized[0],
deserialized[1],
deserialized[2],
deserialized[3],
))
}
}
};
}

Expand Down
Binary file not shown.
Binary file added blake2/tests/data/blake2b_128_serialization.bin
Binary file not shown.
Binary file not shown.
Binary file added blake2/tests/data/blake2b_256_serialization.bin
Binary file not shown.
Binary file not shown.
Binary file added blake2/tests/data/blake2b_512_serialization.bin
Binary file not shown.
Binary file not shown.
Binary file added blake2/tests/data/blake2b_mac_512_serialization.bin
Binary file not shown.
Binary file not shown.
Binary file added blake2/tests/data/blake2s_128_serialization.bin
Binary file not shown.
Binary file not shown.
Binary file added blake2/tests/data/blake2s_256_serialization.bin
Binary file not shown.
Binary file not shown.
Binary file added blake2/tests/data/blake2s_mac_256_serialization.bin
Binary file not shown.
150 changes: 150 additions & 0 deletions blake2/tests/serializable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#[cfg(not(feature = "reset"))]
mod serialization_tests {
use crate::hash_mac_serialization_test;
use digest::hash_serialization_test;

hash_serialization_test!(blake2b_128_serialization, blake2::Blake2b128);
hash_serialization_test!(blake2b_256_serialization, blake2::Blake2b256);
hash_serialization_test!(blake2b_512_serialization, blake2::Blake2b512);
hash_mac_serialization_test!(blake2b_mac_512_serialization, blake2::Blake2bMac512, 64);
hash_serialization_test!(blake2s_128_serialization, blake2::Blake2s128);
hash_serialization_test!(blake2s_256_serialization, blake2::Blake2s256);
hash_mac_serialization_test!(blake2s_mac_256_serialization, blake2::Blake2sMac256, 32);
}

#[cfg(feature = "reset")]
mod serialization_tests {
use crate::hash_mac_serialization_test;
use digest::hash_serialization_test;

hash_serialization_test!(blake2b_128_reset_serialization, blake2::Blake2b128);
hash_serialization_test!(blake2b_256_reset_serialization, blake2::Blake2b256);
hash_serialization_test!(blake2b_512_reset_serialization, blake2::Blake2b512);
hash_mac_serialization_test!(
blake2b_mac_512_reset_serialization,
blake2::Blake2bMac512,
64
);
hash_serialization_test!(blake2s_128_reset_serialization, blake2::Blake2s128);
hash_serialization_test!(blake2s_256_reset_serialization, blake2::Blake2s256);
hash_mac_serialization_test!(
blake2s_mac_256_reset_serialization,
blake2::Blake2sMac256,
32
);
}

#[macro_export]
macro_rules! hash_mac_serialization_test {
($name:ident, $hasher:ty, $keysize:literal $(,)?) => {
#[test]
fn $name() {
use blake2::digest::KeyInit;
use digest::{Mac, array::Array, common::hazmat::SerializableState, typenum::Unsigned};

let mut h = <$hasher>::new(&Array::try_from(&[0x42u8; $keysize] as &[u8]).unwrap());

// in absence of other sizes we can use as reference (BlockSizeUser can't be accessed
// for blake2 Mac hashers), use the state size
digest::Update::update(
&mut h,
&[0x13; <$hasher as SerializableState>::SerializedStateSize::USIZE + 1],
);

let serialized_state = h.serialize();
let expected = include_bytes!(concat!("data/", stringify!($name), ".bin"));
assert_eq!(serialized_state.as_slice(), expected);

let mut h = <$hasher>::deserialize(&serialized_state).unwrap();

digest::Update::update(
&mut h,
&[0x13; <$hasher as SerializableState>::SerializedStateSize::USIZE + 1],
);
let output1 = h.finalize();

let mut h = <$hasher>::new(&Array::try_from(&[0x42u8; $keysize] as &[u8]).unwrap());
digest::Update::update(
&mut h,
&[0x13; 2 * (<$hasher as SerializableState>::SerializedStateSize::USIZE + 1)],
);
let output2 = h.finalize();

assert_eq!(output1, output2);
}
};
}

macro_rules! gen_test_file {
($name:ident) => {{
use blake2::digest::typenum::Unsigned;
use digest::Digest;
use digest::common::{BlockSizeUser, hazmat::SerializableState};

let mut a = blake2::$name::new();
digest::Update::update(
&mut a,
&[0x13; <blake2::$name as BlockSizeUser>::BlockSize::USIZE + 1],
);
let serialized = a.serialize();
let name = stringify!($name);
std::fs::write(
format!(
"./tests/data/blake2{}_{}{}_serialization.bin",
&name[6..7],
&name[(name.len() - 3)..],
(if cfg!(feature = "reset") {
"_reset"
} else {
""
})
),
serialized,
)
.unwrap();
}};
}

macro_rules! gen_test_file_mac {
($name:ident, $keysize:literal) => {{
use blake2::digest::{KeyInit, typenum::Unsigned};
use digest::array::Array;
use digest::common::hazmat::SerializableState;

let mut a = blake2::$name::new(&Array::try_from(&[0x42u8; $keysize] as &[u8]).unwrap());
digest::Update::update(
&mut a,
&[0x13; <blake2::$name as SerializableState>::SerializedStateSize::USIZE + 1],
);
let serialized = a.serialize();
let name = stringify!($name);
std::fs::write(
format!(
"./tests/data/blake2{}_mac_{}{}_serialization.bin",
&name[6..7],
&name[(name.len() - 3)..],
(if cfg!(feature = "reset") {
"_reset"
} else {
""
})
),
serialized,
)
.unwrap();
}};
}

/// Generates the data files used in the tests above. Remove #[ignore] to regenerate the data.
/// Needs to be executed twice, with feature="reset" enabled and disabled.
#[test]
#[ignore]
fn gen_test_files() {
gen_test_file!(Blake2b128);
gen_test_file!(Blake2b256);
gen_test_file!(Blake2b512);
gen_test_file_mac!(Blake2bMac512, 64);
gen_test_file!(Blake2s128);
gen_test_file!(Blake2s256);
gen_test_file_mac!(Blake2sMac256, 32);
}
Loading