Skip to content

Commit 7bbc010

Browse files
authored
digest: improve implementations of the SerializableState trait (#1953)
Previously we were using block size + 1 byte to serialize eager block buffers while block size is sufficient. It resulted in odd serialization state sizes. The `SerializableState` impl also a bit convoluted. The new implementation results in more efficient serialization and more straightforward code. The main drawback is that it inevitably involves a breaking change in the serialization format.
1 parent 75413c9 commit 7bbc010

File tree

10 files changed

+60
-131
lines changed

10 files changed

+60
-131
lines changed

Cargo.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ signature = { path = "signature" }
2020
# https://github.com/RustCrypto/utils/pull/1187
2121
blobby = { git = "https://github.com/RustCrypto/utils" }
2222
# https://github.com/RustCrypto/utils/pull/1192
23+
# https://github.com/RustCrypto/utils/pull/1200
2324
block-buffer = { git = "https://github.com/RustCrypto/utils" }

digest/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
- Edition changed to 2024 and MSRV bumped to 1.85 ([#1759])
1717
- `CtVariableCoreWrapper` renamed to `CtOutWrapper` ([#1799])
1818
- Removed the OID type parameter from `CtOutWrapper` ([#1799])
19+
- Implementations of the `SerializableState` trait ([#1953])
1920

2021
### Removed
2122
- `Mac::new`, `Mac::new_from_slice`, and `Mac::generate_key` methods ([#1173])
@@ -29,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2930
[#1799]: https://github.com/RustCrypto/traits/pull/1799
3031
[#1809]: https://github.com/RustCrypto/traits/pull/1809
3132
[#1820]: https://github.com/RustCrypto/traits/pull/1820
33+
[#1953]: https://github.com/RustCrypto/traits/pull/1953
3234

3335
## 0.10.7 (2023-05-19)
3436
### Changed

digest/src/block_api/ct_variable.rs

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,12 @@ use super::{
55
#[cfg(feature = "mac")]
66
use crate::MacMarker;
77
use crate::{CollisionResistance, CustomizedInit, HashMarker, VarOutputCustomized};
8-
use core::{
9-
fmt,
10-
marker::PhantomData,
11-
ops::{Add, Sub},
12-
};
8+
use core::{fmt, marker::PhantomData};
139
use crypto_common::{
1410
Block, BlockSizeUser, OutputSizeUser,
1511
array::{Array, ArraySize},
16-
hazmat::{DeserializeStateError, SerializableState, SerializedState, SubSerializedStateSize},
17-
typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, True, U1, U256},
12+
hazmat::{DeserializeStateError, SerializableState, SerializedState},
13+
typenum::{IsLessOrEqual, True},
1814
};
1915

2016
/// Wrapper around [`VariableOutputCore`] which selects output size at compile time.
@@ -177,41 +173,21 @@ where
177173
}
178174
}
179175

180-
type CtVariableCoreWrapperSerializedStateSize<T> =
181-
Sum<<T as SerializableState>::SerializedStateSize, U1>;
182-
183176
impl<T, OutSize> SerializableState for CtOutWrapper<T, OutSize>
184177
where
185178
T: VariableOutputCore + SerializableState,
186179
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
187-
T::BlockSize: IsLess<U256>,
188-
Le<T::BlockSize, U256>: NonZero,
189-
T::SerializedStateSize: Add<U1>,
190-
CtVariableCoreWrapperSerializedStateSize<T>: Sub<T::SerializedStateSize> + ArraySize,
191-
SubSerializedStateSize<CtVariableCoreWrapperSerializedStateSize<T>, T>: ArraySize,
192180
{
193-
type SerializedStateSize = CtVariableCoreWrapperSerializedStateSize<T>;
181+
type SerializedStateSize = <T as SerializableState>::SerializedStateSize;
194182

195183
fn serialize(&self) -> SerializedState<Self> {
196-
let serialized_inner = self.inner.serialize();
197-
let serialized_outsize = Array([OutSize::U8]);
198-
199-
serialized_inner.concat(serialized_outsize)
184+
self.inner.serialize()
200185
}
201186

202187
fn deserialize(
203188
serialized_state: &SerializedState<Self>,
204189
) -> Result<Self, DeserializeStateError> {
205-
let (serialized_inner, serialized_outsize) =
206-
serialized_state.split_ref::<T::SerializedStateSize>();
207-
208-
if serialized_outsize[0] != OutSize::U8 {
209-
return Err(DeserializeStateError);
210-
}
211-
212-
Ok(Self {
213-
inner: T::deserialize(serialized_inner)?,
214-
_out: PhantomData,
215-
})
190+
let _out = PhantomData;
191+
T::deserialize(serialized_state).map(|inner| Self { inner, _out })
216192
}
217193
}

digest/src/buffer_macros/fixed.rs

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -429,49 +429,33 @@ macro_rules! buffer_fixed {
429429
impl$(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::crypto_common::hazmat::SerializableState for $name$(< $( $lt ),+ >)? {
430430
type SerializedStateSize = $crate::typenum::Sum<
431431
<$core_ty as $crate::crypto_common::hazmat::SerializableState>::SerializedStateSize,
432-
$crate::typenum::Add1<
433-
<$core_ty as $crate::block_api::BlockSizeUser>::BlockSize
432+
$crate::block_buffer::SerializedBufferSize<
433+
<$core_ty as $crate::block_api::BlockSizeUser>::BlockSize,
434+
<$core_ty as $crate::block_api::BufferKindUser>::BufferKind,
434435
>
435436
>;
436437

437438
#[inline]
438439
fn serialize(&self) -> $crate::crypto_common::hazmat::SerializedState<Self> {
439-
use $crate::{
440-
array::Array,
441-
consts::U1,
442-
block_buffer::BlockBuffer,
443-
crypto_common::hazmat::SerializableState,
444-
};
445-
446440
let serialized_core = self.core.serialize();
447-
let pos = u8::try_from(self.buffer.get_pos()).unwrap();
448-
let serialized_pos: Array<u8, U1> = Array([pos]);
449-
let serialized_data = self.buffer.clone().pad_with_zeros();
450-
451-
serialized_core
452-
.concat(serialized_pos)
453-
.concat(serialized_data)
441+
let serialized_buf = self.buffer.serialize();
442+
serialized_core.concat(serialized_buf)
454443
}
455444

456445
#[inline]
457446
fn deserialize(
458447
serialized_state: &$crate::crypto_common::hazmat::SerializedState<Self>,
459448
) -> Result<Self, $crate::crypto_common::hazmat::DeserializeStateError> {
460-
use $crate::{
461-
block_buffer::BlockBuffer,
462-
consts::U1,
463-
crypto_common::hazmat::{SerializableState, DeserializeStateError},
464-
};
449+
use $crate::crypto_common::hazmat::{SerializableState, DeserializeStateError};
465450

466-
let (serialized_core, remaining_buffer) = serialized_state
451+
let (serialized_core, serialized_buf) = serialized_state
467452
.split_ref::<<$core_ty as SerializableState>::SerializedStateSize>();
468-
let (serialized_pos, serialized_data) = remaining_buffer.split_ref::<U1>();
469453

470-
Ok(Self {
471-
core: <$core_ty as SerializableState>::deserialize(serialized_core)?,
472-
buffer: BlockBuffer::try_new(&serialized_data[..serialized_pos[0].into()])
473-
.map_err(|_| DeserializeStateError)?,
474-
})
454+
let core = SerializableState::deserialize(serialized_core)?;
455+
let buffer = $crate::block_buffer::BlockBuffer::deserialize(serialized_buf)
456+
.map_err(|_| DeserializeStateError)?;
457+
458+
Ok(Self { core, buffer })
475459
}
476460
}
477461

digest/src/buffer_macros/variable_ct.rs

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -176,54 +176,32 @@ macro_rules! buffer_ct_variable {
176176
where
177177
$out_size: $crate::array::ArraySize + $crate::typenum::IsLessOrEqual<$max_size, Output = $crate::typenum::True>,
178178
{
179-
type SerializedStateSize = $crate::typenum::Add1<$crate::typenum::Sum<
180-
<
181-
$crate::block_api::CtOutWrapper<$core_ty, $out_size>
182-
as $crate::crypto_common::hazmat::SerializableState
183-
>::SerializedStateSize,
184-
<$core_ty as $crate::block_api::BlockSizeUser>::BlockSize,
185-
>>;
179+
type SerializedStateSize = $crate::typenum::Sum<
180+
<$core_ty as $crate::crypto_common::hazmat::SerializableState>::SerializedStateSize,
181+
$crate::block_buffer::SerializedBufferSize<
182+
<$core_ty as $crate::block_api::BlockSizeUser>::BlockSize,
183+
<$core_ty as $crate::block_api::BufferKindUser>::BufferKind,
184+
>
185+
>;
186186

187187
#[inline]
188188
fn serialize(&self) -> $crate::crypto_common::hazmat::SerializedState<Self> {
189-
use $crate::{
190-
array::Array,
191-
consts::U1,
192-
block_buffer::BlockBuffer,
193-
crypto_common::hazmat::SerializableState,
194-
};
195-
196189
let serialized_core = self.core.serialize();
197-
let pos = u8::try_from(self.buffer.get_pos()).unwrap();
198-
let serialized_pos: Array<u8, U1> = Array([pos]);
199-
let serialized_data = self.buffer.clone().pad_with_zeros();
200-
201-
serialized_core
202-
.concat(serialized_pos)
203-
.concat(serialized_data)
190+
let serialized_buf = self.buffer.serialize();
191+
serialized_core.concat(serialized_buf)
204192
}
205193

206194
#[inline]
207195
fn deserialize(
208196
serialized_state: &$crate::crypto_common::hazmat::SerializedState<Self>,
209197
) -> Result<Self, $crate::crypto_common::hazmat::DeserializeStateError> {
210-
use $crate::{
211-
block_buffer::BlockBuffer,
212-
consts::U1,
213-
block_api::CtOutWrapper,
214-
crypto_common::hazmat::{SerializableState, DeserializeStateError},
215-
};
216-
217-
let (serialized_core, remaining_buffer) = serialized_state
218-
.split_ref::<<
219-
CtOutWrapper<$core_ty, $out_size>
220-
as SerializableState
221-
>::SerializedStateSize>();
222-
let (serialized_pos, serialized_data) = remaining_buffer.split_ref::<U1>();
198+
use $crate::crypto_common::hazmat::{SerializableState, DeserializeStateError};
199+
200+
let (serialized_core, serialized_buf) = serialized_state
201+
.split_ref::<<$core_ty as SerializableState>::SerializedStateSize>();
223202

224203
let core = SerializableState::deserialize(serialized_core)?;
225-
let pos = usize::from(serialized_pos[0]);
226-
let buffer = BlockBuffer::try_new(&serialized_data[..pos])
204+
let buffer = $crate::block_buffer::BlockBuffer::deserialize(serialized_buf)
227205
.map_err(|_| DeserializeStateError)?;
228206

229207
Ok(Self { core, buffer })

digest/src/buffer_macros/xof.rs

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -284,49 +284,33 @@ macro_rules! buffer_xof {
284284
impl $crate::crypto_common::hazmat::SerializableState for $name {
285285
type SerializedStateSize = $crate::typenum::Sum<
286286
<$core_ty as $crate::crypto_common::hazmat::SerializableState>::SerializedStateSize,
287-
$crate::typenum::Add1<
288-
<$core_ty as $crate::block_api::BlockSizeUser>::BlockSize
287+
$crate::block_buffer::SerializedBufferSize<
288+
<$core_ty as $crate::block_api::BlockSizeUser>::BlockSize,
289+
<$core_ty as $crate::block_api::BufferKindUser>::BufferKind,
289290
>
290291
>;
291292

292293
#[inline]
293294
fn serialize(&self) -> $crate::crypto_common::hazmat::SerializedState<Self> {
294-
use $crate::{
295-
array::Array,
296-
consts::U1,
297-
block_buffer::BlockBuffer,
298-
crypto_common::hazmat::SerializableState,
299-
};
300-
301295
let serialized_core = self.core.serialize();
302-
let pos = u8::try_from(self.buffer.get_pos()).unwrap();
303-
let serialized_pos: Array<u8, U1> = Array([pos]);
304-
let serialized_data = self.buffer.clone().pad_with_zeros();
305-
306-
serialized_core
307-
.concat(serialized_pos)
308-
.concat(serialized_data)
296+
let serialized_buf = self.buffer.serialize();
297+
serialized_core.concat(serialized_buf)
309298
}
310299

311300
#[inline]
312301
fn deserialize(
313302
serialized_state: &$crate::crypto_common::hazmat::SerializedState<Self>,
314303
) -> Result<Self, $crate::crypto_common::hazmat::DeserializeStateError> {
315-
use $crate::{
316-
block_buffer::BlockBuffer,
317-
consts::U1,
318-
crypto_common::hazmat::{SerializableState, DeserializeStateError},
319-
};
304+
use $crate::crypto_common::hazmat::{SerializableState, DeserializeStateError};
320305

321-
let (serialized_core, remaining_buffer) = serialized_state
306+
let (serialized_core, serialized_buf) = serialized_state
322307
.split_ref::<<$core_ty as SerializableState>::SerializedStateSize>();
323-
let (serialized_pos, serialized_data) = remaining_buffer.split_ref::<U1>();
324308

325-
Ok(Self {
326-
core: <$core_ty as SerializableState>::deserialize(serialized_core)?,
327-
buffer: BlockBuffer::try_new(&serialized_data[..serialized_pos[0].into()])
328-
.map_err(|_| DeserializeStateError)?,
329-
})
309+
let core = SerializableState::deserialize(serialized_core)?;
310+
let buffer = $crate::block_buffer::BlockBuffer::deserialize(serialized_buf)
311+
.map_err(|_| DeserializeStateError)?;
312+
313+
Ok(Self { core, buffer })
330314
}
331315
}
332316

digest/src/dev.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ macro_rules! new_test {
5454
/// Define hash function serialization test
5555
#[macro_export]
5656
macro_rules! hash_serialization_test {
57-
($name:ident, $hasher:ty, $expected_serialized_state:expr) => {
57+
($name:ident, $hasher:ty $(,)?) => {
5858
#[test]
5959
fn $name() {
6060
use digest::{
@@ -68,7 +68,8 @@ macro_rules! hash_serialization_test {
6868
h.update(&[0x13; <$hasher as BlockSizeUser>::BlockSize::USIZE + 1]);
6969

7070
let serialized_state = h.serialize();
71-
assert_eq!(serialized_state.as_slice(), $expected_serialized_state);
71+
let expected = include_bytes!(concat!("data/", stringify!($name), ".bin"));
72+
assert_eq!(serialized_state.as_slice(), expected);
7273

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

16 Bytes
Binary file not shown.

digest/tests/dummy_fixed.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ digest::buffer_fixed!(
111111
impl: FixedHashTraits;
112112
);
113113

114+
#[cfg(feature = "dev")]
115+
digest::hash_serialization_test!(fixed_hash_serialization, FixedHashWithSer,);
116+
114117
#[cfg(feature = "zeroize")]
115118
/// check for `ZeroizeOnDrop` implementations
116119
const _: () = {

0 commit comments

Comments
 (0)