Skip to content

Commit

Permalink
digest: add HashCoreSerializableState trait
Browse files Browse the repository at this point in the history
This trait is used for saving internal state of the hash core and
restoring it later.
  • Loading branch information
rpiasetskyi authored and Ruslan Piasetskyi committed Aug 19, 2022
1 parent 08c248f commit 45e5ef5
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 12 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/digest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: digest

on:
pull_request:
paths:
- "digest/**"
- "Cargo.*"
paths:
- "digest/**"
- "Cargo.*"
push:
branches: master

Expand All @@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
rust:
- 1.41.0 # MSRV
- 1.52 # MSRV
- stable
target:
- thumbv7em-none-eabi
Expand All @@ -43,14 +43,14 @@ jobs:
minimal-versions:
uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
with:
working-directory: ${{ github.workflow }}
working-directory: ${{ github.workflow }}

test:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- 1.41.0 # MSRV
- 1.52 # MSRV
- stable
steps:
- uses: actions/checkout@v2
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Collection of traits which describe functionality of cryptographic primitives.
| [`async‑signature`] | [Digital signature] | [![crates.io](https://img.shields.io/crates/v/async-signature.svg)](https://crates.io/crates/async-signature) | [![Documentation](https://docs.rs/async-signature/badge.svg)](https://docs.rs/async-signature) | ![MSRV 1.56][msrv-1.56] |
| [`cipher`] | [Block] and [stream cipher] | [![crates.io](https://img.shields.io/crates/v/cipher.svg)](https://crates.io/crates/cipher) | [![Documentation](https://docs.rs/cipher/badge.svg)](https://docs.rs/cipher) | ![MSRV 1.56][msrv-1.56] |
| [`crypto‑common`] | Common cryptographic traits | [![crates.io](https://img.shields.io/crates/v/crypto-common.svg)](https://crates.io/crates/crypto-common) | [![Documentation](https://docs.rs/crypto-common/badge.svg)](https://docs.rs/crypto-common) | ![MSRV 1.41][msrv-1.41] |
| [`digest`] | [Cryptographic hash function] | [![crates.io](https://img.shields.io/crates/v/digest.svg)](https://crates.io/crates/digest) | [![Documentation](https://docs.rs/digest/badge.svg)](https://docs.rs/digest) | ![MSRV 1.41][msrv-1.41] |
| [`digest`] | [Cryptographic hash function] | [![crates.io](https://img.shields.io/crates/v/digest.svg)](https://crates.io/crates/digest) | [![Documentation](https://docs.rs/digest/badge.svg)](https://docs.rs/digest) | ![MSRV 1.52][msrv-1.52] |
| [`elliptic‑curve`] | [Elliptic curve cryptography] | [![crates.io](https://img.shields.io/crates/v/elliptic-curve.svg)](https://crates.io/crates/elliptic-curve) | [![Documentation](https://docs.rs/elliptic-curve/badge.svg)](https://docs.rs/elliptic-curve) | ![MSRV 1.57][msrv-1.57] |
| [`kem`] | [Key encapsulation mechanism] | [![crates.io](https://img.shields.io/crates/v/kem.svg)](https://crates.io/crates/kem) | [![Documentation](https://docs.rs/kem/badge.svg)](https://docs.rs/kem) | ![MSRV 1.56][msrv-1.56] |
| [`password-hash`] | [Password hashing] | [![crates.io](https://img.shields.io/crates/v/password-hash.svg)](https://crates.io/crates/password-hash) | [![Documentation](https://docs.rs/password-hash/badge.svg)](https://docs.rs/password-hash) | ![MSRV 1.57][msrv-1.57] |
Expand Down Expand Up @@ -50,6 +50,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
[deps-image]: https://deps.rs/repo/github/RustCrypto/traits/status.svg
[deps-link]: https://deps.rs/repo/github/RustCrypto/traits
[msrv-1.41]: https://img.shields.io/badge/rustc-1.41.0+-blue.svg
[msrv-1.52]: https://img.shields.io/badge/rustc-1.52.0+-blue.svg
[msrv-1.56]: https://img.shields.io/badge/rustc-1.56.0+-blue.svg
[msrv-1.57]: https://img.shields.io/badge/rustc-1.57.0+-blue.svg

Expand Down
4 changes: 2 additions & 2 deletions digest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ See [RustCrypto/hashes][1] for implementations which use this trait.

## Minimum Supported Rust Version

Rust **1.41** or higher.
Rust **1.52** or higher.

Minimum supported Rust version can be changed in the future, but it will be
done with a minor version bump.
Expand Down Expand Up @@ -147,7 +147,7 @@ dual licensed as above, without any additional terms or conditions.
[docs-image]: https://docs.rs/digest/badge.svg
[docs-link]: https://docs.rs/digest/
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.52+-blue.svg
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260041-hashes
[build-image]: https://github.com/RustCrypto/traits/workflows/digest/badge.svg?branch=master&event=push
Expand Down
11 changes: 11 additions & 0 deletions digest/src/core_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use crate::InvalidOutputSize;
pub use crypto_common::{AlgorithmName, Block, BlockSizeUser, OutputSizeUser, Reset};

use block_buffer::{BlockBuffer, BufferKind};
use core::convert::TryFrom;
use crypto_common::{
generic_array::{ArrayLength, GenericArray},
typenum::{IsLess, Le, NonZero, U256},
Output,
};
Expand Down Expand Up @@ -117,3 +119,12 @@ pub enum TruncSide {
/// Truncate right side, i.e. `&out[m..]`.
Right,
}

/// Core trait for serializing the internal state of the hash core and restoring it later.
pub trait HashCoreSerializableState:
TryFrom<GenericArray<u8, Self::SerializedStateSize>>
+ Into<GenericArray<u8, Self::SerializedStateSize>>
{
/// Serialized internal state of the hash core.
type SerializedStateSize: ArrayLength<u8>;
}
53 changes: 50 additions & 3 deletions digest/src/core_api/ct_variable.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use super::{
AlgorithmName, Buffer, BufferKindUser, FixedOutputCore, Reset, TruncSide, UpdateCore,
VariableOutputCore,
AlgorithmName, Buffer, BufferKindUser, FixedOutputCore, HashCoreSerializableState, Reset,
TruncSide, UpdateCore, VariableOutputCore,
};
use crate::HashMarker;
#[cfg(feature = "mac")]
use crate::MacMarker;
use core::{fmt, marker::PhantomData};
use core::{convert::TryFrom, fmt, marker::PhantomData};
use crypto_common::{
generic_array::{ArrayLength, GenericArray},
typenum::{IsLess, IsLessOrEqual, Le, LeEq, NonZero, U256},
Expand Down Expand Up @@ -165,3 +165,50 @@ where
write!(f, "{}", OutSize::USIZE)
}
}

impl<T, OutSize> HashCoreSerializableState for CtVariableCoreWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
T: HashCoreSerializableState,
{
type SerializedStateSize = T::SerializedStateSize;
}

impl<T, OutSize> From<CtVariableCoreWrapper<T, OutSize>>
for GenericArray<u8, T::SerializedStateSize>
where
T: VariableOutputCore,
OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
T: HashCoreSerializableState,
{
fn from(core: CtVariableCoreWrapper<T, OutSize>) -> Self {
core.inner.into()
}
}

impl<T, OutSize> TryFrom<GenericArray<u8, T::SerializedStateSize>>
for CtVariableCoreWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
T: HashCoreSerializableState,
{
type Error = T::Error;

fn try_from(buffer: GenericArray<u8, T::SerializedStateSize>) -> Result<Self, Self::Error> {
Ok(Self {
inner: T::try_from(buffer)?,
_out: PhantomData,
})
}
}
39 changes: 39 additions & 0 deletions digest/src/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,42 @@ pub fn feed_rand_16mib<D: crate::Update>(d: &mut D) {
d.update(&[42]);
}
}

/// Define [`HashCoreSerializableState`][crate::HashCoreSerializableState] implementation test.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! test_internal_state {
($name:ident, $hasher:ty, $hash_core:ty, $serialized_state:ty) => {
#[test]
fn $name() {
let mut h = <$hasher>::new();

// First part of data.
feed_rand_16mib(&mut h);

// Save internal state.
let (core, input_cache) = h.decompose();
let serialized_state = <$serialized_state>::from(core);

// Restore from internal state.
let core = <$hash_core>::try_from(serialized_state).unwrap();
let mut h = <$hasher>::from_core(core);
h.update(input_cache.get_data());

// Second part of data.
feed_rand_16mib(&mut h);

let output1 = h.finalize();

let mut h = <$hasher>::new();

// First and second part of data together.
feed_rand_16mib(&mut h);
feed_rand_16mib(&mut h);

let output2 = h.finalize();

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

0 comments on commit 45e5ef5

Please sign in to comment.