Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 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
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
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;
330 changes: 330 additions & 0 deletions digest/src/buffer_macros/fixed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
/// Creates a buffered wrapper around block-level "core" type which implements fixed output size traits.
#[macro_export]
macro_rules! buffer_fixed {
(
$(#[$attr:meta])*
$v:vis struct $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could simplify the macro by removing the $(<$gp:ident: $bound:ident>)? part. Currently it's used only by gost94 and skein.

My initial intent was for this macro to support cases covered by the buffer_ct_variable macro, but, unfortunately, the required pattern becomes annoyingly complex, so I decided against it.

impl: $($trait_name:ident)*;
) => {
$(#[$attr])*
$v struct $name$(<$gp: $bound>)? {
core: $core_ty,
buffer: $crate::core_api::Buffer<$core_ty>,
}

$crate::buffer_fixed!(
impl_inner: $name$(<$gp: $bound>)?($core_ty);
$($trait_name)*;
);
};

(
$(#[$attr:meta])*
$v:vis struct $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
oid: $oid:literal;
impl: $($trait_name:ident)*;
) => {
$crate::buffer_fixed!(
$(#[$attr])*
$v struct $name$(<$gp: $bound>)?($core_ty);
impl: $($trait_name)*;
);

#[cfg(feature = "oid")]
impl$(<$gp: $bound>)? $crate::const_oid::AssociatedOid for $name$(<$gp>)? {
const OID: $crate::const_oid::ObjectIdentifier =
$crate::const_oid::ObjectIdentifier::new_unwrap($oid);
}
};

// Terminates `impl_inner` sequences.
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty); ;
) => {};

// Implements the set of traits common for fixed output hashes:
// `Default`, `Clone`, `HashMarker`, `Reset`, `FixedOutputReset`, `SerializableState`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
FixedHashTraits $($trait_name:ident)*;
) => {
$crate::buffer_fixed!(
impl_inner: $name$(<$gp: $bound>)?($core_ty);
BaseFixedTraits Default Clone HashMarker Reset FixedOutputReset SerializableState $($trait_name)*;
);
};

// Implements basic fixed traits:
// `Debug`, `AlgorithmName`, `BlockSizeUser`, `OutputSizeUser`,
// `CoreProxy`, `Update`, and `FixedOutput`.
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
BaseFixedTraits $($trait_name:ident)*;
) => {
$crate::buffer_fixed!(
impl_inner: $name$(<$gp: $bound>)?($core_ty);
Debug AlgorithmName BlockSizeUser OutputSizeUser CoreProxy Update FixedOutput $($trait_name)*;
);
};

// Implements `Debug`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
Debug $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? core::fmt::Debug for $name$(<$gp>)? {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(concat!(stringify!($name), " { ... }"))
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `AlgorithmName`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
AlgorithmName $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::crypto_common::AlgorithmName for $name$(<$gp>)? {
#[inline]
fn write_alg_name(f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
<$core_ty as $crate::crypto_common::AlgorithmName>::write_alg_name(f)
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `BlockSizeUser`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
BlockSizeUser $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::core_api::BlockSizeUser for $name$(<$gp>)? {
type BlockSize = <$core_ty as $crate::crypto_common::BlockSizeUser>::BlockSize;
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `OutputSizeUser`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
OutputSizeUser $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::OutputSizeUser for $name$(<$gp>)? {
type OutputSize = <$core_ty as $crate::core_api::OutputSizeUser>::OutputSize;
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `CoreProxy`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
CoreProxy $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::core_api::CoreProxy for $name$(<$gp>)? {
type Core = $core_ty;
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `Update`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
Update $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::Update for $name$(<$gp>)? {
#[inline]
fn update(&mut self, data: &[u8]) {
let Self { core, buffer } = self;
buffer.digest_blocks(data, |blocks| {
$crate::core_api::UpdateCore::update_blocks(core, blocks)
});
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `FixedOutput`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
FixedOutput $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::FixedOutput for $name$(<$gp>)? {
#[inline]
fn finalize_into(mut self, out: &mut $crate::Output<Self>) {
let Self { core, buffer } = &mut self;
$crate::core_api::FixedOutputCore::finalize_fixed_core(core, buffer, out);
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `Default`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
Default $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? Default for $name$(<$gp>)? {
#[inline]
fn default() -> Self {
Self {
core: Default::default(),
buffer: Default::default(),
}
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `CustomizedInit`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
CustomizedInit $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::CustomizedInit for $name$(<$gp>)? {
#[inline]
fn new_customized(customization: &[u8]) -> Self {
Self {
core: $crate::CustomizedInit::new_customized(customization),
buffer: Default::default(),
}
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `Clone`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
Clone $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? Clone for $name$(<$gp>)? {
#[inline]
fn clone(&self) -> Self {
Self {
core: Clone::clone(&self.core),
buffer: Clone::clone(&self.buffer),
}
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `HashMarker` and asserts that `$core_ty` implements it
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
HashMarker $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::HashMarker for $name$(<$gp>)? {}

// Verify that `$core_ty` implements `HashMarker`
const _: () = {
fn check$(<$gp: $bound>)?(v: &$core_ty) {
v as &dyn $crate::HashMarker;
}
};

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `Reset`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
Reset $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::Reset for $name$(<$gp>)? {
#[inline]
fn reset(&mut self) {
$crate::Reset::reset(&mut self.core);
self.buffer.reset();
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `FixedOutputReset`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
FixedOutputReset $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::FixedOutputReset for $name$(<$gp>)? {
#[inline]
fn finalize_into_reset(&mut self, out: &mut $crate::Output<Self>) {
let Self { core, buffer } = self;
$crate::core_api::FixedOutputCore::finalize_fixed_core(core, buffer, out);
$crate::Reset::reset(self);
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
};

// Implements `SerializableState`
(
impl_inner: $name:ident$(<$gp:ident: $bound:ident>)?($core_ty:ty);
SerializableState $($trait_name:ident)*;
) => {
impl$(<$gp: $bound>)? $crate::crypto_common::hazmat::SerializableState for $name$(<$gp>)? {
type SerializedStateSize = $crate::typenum::Sum<
<$core_ty as $crate::crypto_common::hazmat::SerializableState>::SerializedStateSize,
$crate::typenum::Add1<
<$core_ty as $crate::core_api::BlockSizeUser>::BlockSize
>
>;

#[inline]
fn serialize(&self) -> $crate::crypto_common::hazmat::SerializedState<Self> {
use $crate::{
array::Array,
consts::U1,
block_buffer::BlockBuffer,
crypto_common::hazmat::SerializableState,
};

let serialized_core = self.core.serialize();
let pos = u8::try_from(self.buffer.get_pos()).unwrap();
let serialized_pos: Array<u8, U1> = Array([pos]);
let serialized_data = self.buffer.clone().pad_with_zeros();

serialized_core
.concat(serialized_pos)
.concat(serialized_data)
}

#[inline]
fn deserialize(
serialized_state: &$crate::crypto_common::hazmat::SerializedState<Self>,
) -> Result<Self, $crate::crypto_common::hazmat::DeserializeStateError> {
use $crate::{
block_buffer::BlockBuffer,
consts::U1,
crypto_common::hazmat::{SerializableState, DeserializeStateError},
};

let (serialized_core, remaining_buffer) = serialized_state
.split_ref::<<$core_ty as SerializableState>::SerializedStateSize>();
let (serialized_pos, serialized_data) = remaining_buffer.split_ref::<U1>();

Ok(Self {
core: <$core_ty as SerializableState>::deserialize(serialized_core)?,
buffer: BlockBuffer::try_new(&serialized_data[..serialized_pos[0].into()])
.map_err(|_| DeserializeStateError)?,
})
}
}

$crate::buffer_fixed!(impl_inner: $name$(<$gp: $bound>)?($core_ty); $($trait_name)*;);
}
}
Loading