Skip to content

digest: add buffering macros #1799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
May 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
bae5896
digest: add `newtype!` macro
newpavlov Mar 19, 2025
f86022a
Gate tests
newpavlov Mar 19, 2025
5356490
Merge branch 'master' into digest/newtype
newpavlov Apr 7, 2025
740b5fa
Remove outdated docs
newpavlov Apr 7, 2025
1261c02
Remove `io::Write` impl
newpavlov Apr 7, 2025
9938471
Merge branch 'master' into digest/newtype
newpavlov Apr 7, 2025
6b9c5a9
Move dummy hash to the tests folder
newpavlov Apr 7, 2025
f4d7559
rename dummy to dummy fixed
newpavlov Apr 7, 2025
eb0f258
Add delegate template, improve macro robustness
newpavlov Apr 7, 2025
4f68309
Add OID helper
newpavlov Apr 7, 2025
3e59212
add ExtendableOutputHash template
newpavlov Apr 10, 2025
dbcd0bd
fix CustomizedInit delegation
newpavlov Apr 10, 2025
c0725f1
Introduce separate newtype macros
newpavlov May 4, 2025
17c5263
Merge branch 'master' into digest/newtype
newpavlov May 4, 2025
24d0f6a
add variable newtype and support generics in fixed newtype
newpavlov May 4, 2025
185b475
remove old code
newpavlov May 4, 2025
19b2e43
update newtype_variable_hash
newpavlov May 4, 2025
75445cc
Add HashMarker checks
newpavlov May 4, 2025
de0daef
Implement fixed traits directly instead of delegating
newpavlov May 5, 2025
727f9f5
tweak newtype_xof
newpavlov May 6, 2025
01f3055
introduce separate `newtype_rt_variable_hash` macro
newpavlov May 7, 2025
2aced1d
change `newtype_ct_variable_hash!`
newpavlov May 7, 2025
e3794b0
Rename CtVariableCoreWrapper to CtOutWrapper
newpavlov May 16, 2025
58d65d9
Update macros
newpavlov May 19, 2025
0bd68a4
tweak cof macro
newpavlov May 19, 2025
f3d7a4f
rename macros
newpavlov May 19, 2025
844f043
Add MAC support to `buffer_fixed`
newpavlov May 25, 2025
b3cd57b
remove wrappers
newpavlov May 25, 2025
b5bac43
fix docs
newpavlov May 25, 2025
954e8ff
rename `core_api` to `block_api`
newpavlov May 25, 2025
774c061
fix docs
newpavlov May 25, 2025
3e7a605
Merge branch 'master' into digest/newtype
newpavlov May 26, 2025
99be71b
Update changelog
newpavlov May 26, 2025
161c42b
Add changelog entry for #1820
newpavlov May 26, 2025
c61b646
Tweak `buffer_fixed`
newpavlov May 26, 2025
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
9 changes: 8 additions & 1 deletion digest/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## 0.11.0 (UNRELEASED)
### Added
- `CustomizedInit` trait ([#1334]).
- `CustomizedInit` trait ([#1334])
- `buffer_fixed`, `buffer_ct_variable`, `buffer_rt_variable`, and `buffer_xof` macros ([#1799])
- `CollisionResistance` trait ([#1820])

### Changed
- `crypto-common` dependency bumped to v0.2 ([#1173])
- Edition changed to 2024 and MSRV bumped to 1.85 ([#1759])
- `CtVariableCoreWrapper` renamed to `CtOutWrapper` ([#1799])
- Removed the OID type parameter from `CtOutWrapper` ([#1799])

### Removed
- `Mac::new`, `Mac::new_from_slice`, and `Mac::generate_key` methods ([#1173])
- `CoreWrapper`, `RtVariableCoreWrapper`, and `XofReaderCoreWrapper` types ([#1799])
- `HashReader` and `HashWriter` are moved to the `digest-io` crate ([#1809])
- `io::Write/Read` implementations in favor of the `digest_io::IoWrapper` type ([#1809])

[#1173]: https://github.com/RustCrypto/traits/pull/1173
[#1334]: https://github.com/RustCrypto/traits/pull/1334
[#1759]: https://github.com/RustCrypto/traits/pull/1759
[#1799]: https://github.com/RustCrypto/traits/pull/1799
[#1809]: https://github.com/RustCrypto/traits/pull/1809
[#1820]: https://github.com/RustCrypto/traits/pull/1820

## 0.10.7 (2023-05-19)
### Changed
Expand Down
4 changes: 2 additions & 2 deletions digest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ const-oid = { version = "0.10", optional = true }
zeroize = { version = "1.7", optional = true, default-features = false }

[features]
default = ["core-api"]
core-api = ["block-buffer"] # Enable Core API traits
default = ["block-api"]
block-api = ["block-buffer"] # Enable block API traits
mac = ["subtle"] # Enable MAC traits
rand_core = ["crypto-common/rand_core"] # Enable random key generation methods
os_rng = ["crypto-common/rand_core", "rand_core"]
Expand Down
19 changes: 0 additions & 19 deletions digest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,6 @@ let hash = Sha256::digest(b"my message");
println!("Result: {:x}", hash);
```

### Hashing `Read`-able objects

If you want to hash data from [`Read`][3] trait (e.g. from file) you can rely on
implementation of [`Write`][4] trait (requires enabled-by-default `std` feature):

```rust
use sha2::{Sha256, Digest};
use std::{fs, io};

let mut file = fs::File::open(&path)?;
let mut hasher = Sha256::new();
let n = io::copy(&mut file, &mut hasher)?;
let hash = hasher.finalize();

println!("Path: {}", path);
println!("Bytes processed: {}", n);
println!("Hash value: {:x}", hash);
```

### Generic code

You can write generic code over `Digest` (or other traits from `digest` crate)
Expand Down
16 changes: 8 additions & 8 deletions digest/src/core_api.rs → digest/src/block_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,14 @@
//! higher-level traits.
use crate::InvalidOutputSize;

pub use block_buffer::{Eager, Lazy};
pub use crypto_common::{AlgorithmName, Block, BlockSizeUser, OutputSizeUser, Reset};

use block_buffer::{BlockBuffer, BufferKind};
use crypto_common::Output;

mod ct_variable;
mod rt_variable;
mod wrapper;
mod xof_reader;

pub use ct_variable::CtVariableCoreWrapper;
pub use rt_variable::RtVariableCoreWrapper;
pub use wrapper::{CoreProxy, CoreWrapper};
pub use xof_reader::XofReaderCoreWrapper;
pub use ct_variable::CtOutWrapper;

/// Buffer type used by type which implements [`BufferKindUser`].
pub type Buffer<S> =
Expand Down Expand Up @@ -102,3 +96,9 @@ pub enum TruncSide {
/// Truncate right side, i.e. `&out[m..]`.
Right,
}

/// A proxy trait to a core type.
pub trait CoreProxy {
/// Wrapped block-level type.
type Core;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ use super::{
#[cfg(feature = "mac")]
use crate::MacMarker;
use crate::{CollisionResistance, CustomizedInit, HashMarker, VarOutputCustomized};
#[cfg(feature = "oid")]
use const_oid::{AssociatedOid, ObjectIdentifier};
use core::{
fmt,
marker::PhantomData,
Expand All @@ -16,97 +14,82 @@ use crypto_common::{
Block, BlockSizeUser, OutputSizeUser,
array::{Array, ArraySize},
hazmat::{DeserializeStateError, SerializableState, SerializedState, SubSerializedStateSize},
typenum::{IsLess, IsLessOrEqual, Le, LeEq, NonZero, Sum, U1, U256},
typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, True, U1, U256},
};

/// Dummy type used with [`CtVariableCoreWrapper`] in cases when
/// resulting hash does not have a known OID.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct NoOid;

/// Wrapper around [`VariableOutputCore`] which selects output size
/// at compile time.
/// Wrapper around [`VariableOutputCore`] which selects output size at compile time.
#[derive(Clone)]
pub struct CtVariableCoreWrapper<T, OutSize, O = NoOid>
pub struct CtOutWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
inner: T,
_out: PhantomData<(OutSize, O)>,
_out: PhantomData<OutSize>,
}

impl<T, OutSize, O> HashMarker for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> HashMarker for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore + HashMarker,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
}

#[cfg(feature = "mac")]
impl<T, OutSize, O> MacMarker for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> MacMarker for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore + MacMarker,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
}

impl<T, OutSize> CollisionResistance for CtVariableCoreWrapper<T, OutSize>
impl<T, OutSize> CollisionResistance for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore + CollisionResistance,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
type CollisionResistance = T::CollisionResistance;
}

impl<T, OutSize, O> BlockSizeUser for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> BlockSizeUser for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
type BlockSize = T::BlockSize;
}

impl<T, OutSize, O> UpdateCore for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> UpdateCore for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
#[inline]
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
self.inner.update_blocks(blocks);
}
}

impl<T, OutSize, O> OutputSizeUser for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> OutputSizeUser for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
type OutputSize = OutSize;
}

impl<T, OutSize, O> BufferKindUser for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> BufferKindUser for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
type BufferKind = T::BufferKind;
}

impl<T, OutSize, O> FixedOutputCore for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> FixedOutputCore for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
#[inline]
fn finalize_fixed_core(
Expand All @@ -125,11 +108,10 @@ where
}
}

impl<T, OutSize, O> Default for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> Default for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
#[inline]
fn default() -> Self {
Expand All @@ -140,11 +122,10 @@ where
}
}

impl<T, OutSize, O> CustomizedInit for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> CustomizedInit for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore + VarOutputCustomized,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
#[inline]
fn new_customized(customization: &[u8]) -> Self {
Expand All @@ -155,23 +136,21 @@ where
}
}

impl<T, OutSize, O> Reset for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> Reset for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
#[inline]
fn reset(&mut self) {
*self = Default::default();
}
}

impl<T, OutSize, O> AlgorithmName for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> AlgorithmName for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore + AlgorithmName,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
T::write_alg_name(f)?;
Expand All @@ -180,61 +159,31 @@ where
}
}

#[cfg(feature = "oid")]
impl<T, OutSize, O> AssociatedOid for CtVariableCoreWrapper<T, OutSize, O>
where
T: VariableOutputCore,
O: AssociatedOid,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
{
const OID: ObjectIdentifier = O::OID;
}

#[cfg(feature = "zeroize")]
impl<T, OutSize, O> zeroize::ZeroizeOnDrop for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> zeroize::ZeroizeOnDrop for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore + zeroize::ZeroizeOnDrop,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
}

impl<T, OutSize, O> fmt::Debug for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> fmt::Debug for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore + AlgorithmName,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Self::write_alg_name(f)
}
}

/// Implement dummy type with hidden docs which is used to "carry" hasher
/// OID for [`CtVariableCoreWrapper`].
#[macro_export]
macro_rules! impl_oid_carrier {
($name:ident, $oid:literal) => {
#[doc(hidden)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct $name;

#[cfg(feature = "oid")]
impl AssociatedOid for $name {
const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap($oid);
}
};
}

type CtVariableCoreWrapperSerializedStateSize<T> =
Sum<<T as SerializableState>::SerializedStateSize, U1>;

impl<T, OutSize, O> SerializableState for CtVariableCoreWrapper<T, OutSize, O>
impl<T, OutSize> SerializableState for CtOutWrapper<T, OutSize>
where
T: VariableOutputCore + SerializableState,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize>,
LeEq<OutSize, T::OutputSize>: NonZero,
OutSize: ArraySize + IsLessOrEqual<T::OutputSize, Output = True>,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
T::SerializedStateSize: Add<U1>,
Expand Down
4 changes: 4 additions & 0 deletions digest/src/buffer_macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod fixed;
mod variable_ct;
mod variable_rt;
mod xof;
Loading