Skip to content

Commit

Permalink
Implement SerializableState for hashes (#574)
Browse files Browse the repository at this point in the history
This is a rebase of #385 on master.

RustCrypto/traits#1369 introduced a
`SerializableState` trait to serialize the hasher. This implements it
for each of the hashers we have.

Co-authored-by: Ruslan Piasetskyi <ruslan.piasetskyi@esrlabs.com>
  • Loading branch information
baloo and Ruslan Piasetskyi committed Mar 19, 2024
1 parent 1f79203 commit c30e701
Show file tree
Hide file tree
Showing 40 changed files with 1,709 additions and 59 deletions.
7 changes: 3 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Expand Up @@ -26,3 +26,7 @@ members = [

[profile.dev]
opt-level = 2

[patch.crates-io]
# https://github.com/RustCrypto/traits/pull/1537 - Unreleased
digest = { git = "https://github.com/RustCrypto/traits.git" }
2 changes: 1 addition & 1 deletion blake2/tests/mac.rs
Expand Up @@ -12,7 +12,7 @@ fn blake2b_new_test() {

fn run<T: Mac + KeyInit>(key: &[u8]) {
const DATA: &[u8] = &[42; 300];
let res1 = T::new(Array::from_slice(key))
let res1 = T::new(&Array::try_from(key).unwrap())
.chain_update(DATA)
.finalize()
.into_bytes();
Expand Down
10 changes: 8 additions & 2 deletions fsb/src/lib.rs
Expand Up @@ -12,7 +12,7 @@
#[macro_use]
mod macros;

use core::fmt;
use core::{fmt, ops::Add};
pub use digest::{self, Digest};

// Double check this contains all values in the reference implementation
Expand All @@ -24,7 +24,8 @@ use digest::{
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore,
OutputSizeUser, Reset, UpdateCore,
},
typenum::Unsigned,
crypto_common::hazmat::{DeserializeStateError, SerializableState, SerializedState},
typenum::{Unsigned, U8},
HashMarker, Output,
};

Expand All @@ -38,6 +39,7 @@ fsb_impl!(
160,
U60,
U20,
U80,
5 << 18,
80,
640,
Expand All @@ -54,6 +56,7 @@ fsb_impl!(
224,
U84,
U28,
U112,
7 << 18,
112,
896,
Expand All @@ -70,6 +73,7 @@ fsb_impl!(
256,
U96,
U32,
U128,
1 << 21,
128,
1024,
Expand All @@ -86,6 +90,7 @@ fsb_impl!(
384,
U115,
U48,
U184,
23 << 16,
184,
1472,
Expand All @@ -102,6 +107,7 @@ fsb_impl!(
512,
U155,
U64,
U248,
31 << 16,
248,
1984,
Expand Down
33 changes: 30 additions & 3 deletions fsb/src/macros.rs
@@ -1,9 +1,9 @@
macro_rules! fsb_impl {
(
$full_state:ident, $state:ident, $state_num:expr, $blocksize:ident, $outputsize:ident, $n:expr, $w:expr,
$r:expr, $p:expr, $s:expr, $full_doc:expr, $doc:expr,
$full_state:ident, $state:ident, $state_num:expr, $blocksize:ident, $outputsize:ident, $statesize:ident,
$n:expr, $w:expr, $r:expr, $p:expr, $s:expr, $full_doc:expr, $doc:expr,
) => {
use digest::consts::{$blocksize, $outputsize};
use digest::consts::{$blocksize, $outputsize, $statesize};

#[derive(Clone)]
#[doc=$doc]
Expand Down Expand Up @@ -95,6 +95,33 @@ macro_rules! fsb_impl {
#[cfg(feature = "zeroize")]
impl ZeroizeOnDrop for $state {}

impl SerializableState for $state {
type SerializedStateSize = <$statesize as Add<U8>>::Output;

fn serialize(&self) -> SerializedState<Self> {
let mut serialized_state = SerializedState::<Self>::default();

serialized_state[..self.state.len()].copy_from_slice(&self.state[..]);
serialized_state[self.state.len()..]
.copy_from_slice(&self.blocks_len.to_le_bytes());

serialized_state
}

fn deserialize(
serialized_state: &SerializedState<Self>,
) -> Result<Self, DeserializeStateError> {
let (serialized_state, serialized_block_len) =
serialized_state.split::<$statesize>();

let mut state = [0; $r / 8];
state.copy_from_slice(serialized_state.as_ref());

let blocks_len = u64::from_le_bytes(*serialized_block_len.as_ref());
Ok(Self { state, blocks_len })
}
}

impl $state {
const SIZE_OUTPUT_COMPRESS: usize = $r / 8;
const SIZE_INPUT_COMPRESS: usize = $s / 8;
Expand Down
129 changes: 127 additions & 2 deletions fsb/tests/mod.rs
@@ -1,5 +1,7 @@
use digest::dev::{feed_rand_16mib, fixed_reset_test};
use digest::new_test;
use digest::{
dev::{feed_rand_16mib, fixed_reset_test},
hash_serialization_test, new_test,
};
use fsb::{Digest, Fsb160, Fsb224, Fsb256, Fsb384, Fsb512};
use hex_literal::hex;

Expand All @@ -9,6 +11,129 @@ new_test!(fsb256_main, "fsb256", Fsb256, fixed_reset_test);
new_test!(fsb384_main, "fsb384", Fsb384, fixed_reset_test);
new_test!(fsb512_main, "fsb512", Fsb512, fixed_reset_test);

#[rustfmt::skip]
hash_serialization_test!(
fsb160_serialization,
Fsb160,
hex!("
e269a086505e9493fa92ed509f6cdce8
51dd58654160a8c8a499a953a479c169
d46c0576d8e7b262341087f58eb3dc9d
3002451f8f0d484cbdc8b342afef13e5
4f2fce12e400eca0a6bc0b8837f999c3
01000000000000000113000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
0000000000
")
);
#[rustfmt::skip]
hash_serialization_test!(
fsb224_serialization,
Fsb224,
hex!("
bfba3bbd79050b4428d239ec4eb25277
b228898bd26c04ccf11e052944e72b61
aae3f1a0a6cdb862d87fac21fefb1dc1
4074cfc45d8994087dc70d1d5308b6b1
f68f6eea5d886904dfcab198e62f6c97
67ae365fc648b1bb7d00f65ff276373a
7a1b4d80efdd7af5fce3b0e93371172a
01000000000000000113000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000
")
);

#[rustfmt::skip]
hash_serialization_test!(
fsb256_serialization,
Fsb256,
hex!("
6c4fef5401baa1825e74fe2a150dd746
55ba10d8fa2db4ee3e6925de2cf4a83a
5121e2ded528f92613ec858045c1bdd1
5a11ce8bd4df1a3f409dfc9d1025d333
360f30a342f417018fcf0ff1c5dddb04
2a18453d707d27721e57fd182d932945
89a1c3ef007e6bb3b59f2a361094e21d
6c72d213545a6612a2adc547968a03e9
01000000000000000113000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
000000000000000000
")
);

#[rustfmt::skip]
hash_serialization_test!(
fsb384_serialization,
Fsb384,
hex!("
41825b73ae6b5cdc91b8b70723dc1f92
97fec62f09c17c75a2326e3d7664efb5
df1104db5c711016d161187f3174ef77
f5e0545c917d01375537d15cf90c838d
2f5fd5a294c7012d80a0f6a6240f90f9
a6976812ec60fdd35bbc1a064287308e
1d916cb4d59c02b19ab2d20e1b9b2acb
e826c4d0022db322e3314fe0cf232cdd
75b61c653bf30569ca76dd11bd032d03
bc83a0e59964eb5dd77a22d0a459de63
ab5ff6ce1207a9daed690c36399f7306
43a1628e0f33650a0100000000000000
01130000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000
")
);

#[rustfmt::skip]
hash_serialization_test!(
fsb512_serialization,
Fsb512,
hex!("
4feff733b532b0767d0bbe8804f60ebc
bbf33aa6796e608d37e6e24dcf216636
31312286c6efa794b237f05df2838526
cb5120291a53566bb784ff32d2ea5464
693cd68fc52a37375160c0a4f4b8dae8
06703a98720180c4abaa2c195a6ede59
ed68fc5caae6172003ad9195d7ae7747
10d7a0c46772a7216e553a39dbeac282
fa2848e7038eec7c78f7da35db4cf8ea
d35f2f140ec49203f1d3afe24fe4100a
9d0cc5fdb1e964ed48fe786e2bfdabe4
70c148f65c67c21cc6794b8e1eb90e6a
39800334a2016e2081f5a458fcd348d8
778dc4090066f3906b835a1283c97569
4e1dc38fef18dd35d2d4f283d0bc1502
db72a91871a23bc40100000000000000
01130000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
000000000000000000000000
")
);

#[test]
fn fsb160_rand() {
let mut h = Fsb160::new();
Expand Down
48 changes: 47 additions & 1 deletion gost94/src/gost94_core.rs
@@ -1,12 +1,14 @@
#![allow(clippy::many_single_char_names)]
use core::fmt;
use digest::{
array::Array,
block_buffer::Eager,
core_api::{
AlgorithmName, Block as TBlock, BlockSizeUser, Buffer, BufferKindUser, FixedOutputCore,
OutputSizeUser, Reset, UpdateCore,
},
typenum::{Unsigned, U32},
crypto_common::hazmat::{DeserializeStateError, SerializableState, SerializedState},
typenum::{Unsigned, U32, U96},
HashMarker, Output,
};

Expand Down Expand Up @@ -290,3 +292,47 @@ impl<P: Gost94Params> Drop for Gost94Core<P> {

#[cfg(feature = "zeroize")]
impl<P: Gost94Params> ZeroizeOnDrop for Gost94Core<P> {}

impl<P: Gost94Params> SerializableState for Gost94Core<P> {
type SerializedStateSize = U96;

fn serialize(&self) -> SerializedState<Self> {
let serialized_h = Array::<_, U32>::from(self.h);

let mut serialized_n = Array::<_, U32>::default();
for (val, chunk) in self.n.iter().zip(serialized_n.chunks_exact_mut(8)) {
chunk.copy_from_slice(&val.to_le_bytes());
}

let mut serialized_sigma = Array::<_, U32>::default();
for (val, chunk) in self.sigma.iter().zip(serialized_sigma.chunks_exact_mut(8)) {
chunk.copy_from_slice(&val.to_le_bytes());
}

serialized_h.concat(serialized_n).concat(serialized_sigma)
}

fn deserialize(
serialized_state: &SerializedState<Self>,
) -> Result<Self, DeserializeStateError> {
let (serialized_h, remaining_buffer) = serialized_state.split::<U32>();

let (serialized_n, serialized_sigma) = remaining_buffer.split::<U32>();
let mut n = [0; 4];
for (val, chunk) in n.iter_mut().zip(serialized_n.chunks_exact(8)) {
*val = u64::from_le_bytes(chunk.try_into().unwrap());
}

let mut sigma = [0; 4];
for (val, chunk) in sigma.iter_mut().zip(serialized_sigma.chunks_exact(8)) {
*val = u64::from_le_bytes(chunk.try_into().unwrap());
}

Ok(Self {
h: serialized_h.into(),
n,
sigma,
_m: core::marker::PhantomData,
})
}
}

0 comments on commit c30e701

Please sign in to comment.