Skip to content

Commit 7875ef6

Browse files
authored
digest: add block-level API (#380)
1 parent 8c0ead9 commit 7875ef6

13 files changed

+397
-441
lines changed

Cargo.lock

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

crypto/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ edition = "2018"
1414
[dependencies]
1515
aead = { version = "0.3", optional = true, path = "../aead" }
1616
cipher = { version = "=0.3.0-pre.4", optional = true, path = "../cipher" }
17-
digest = { version = "0.9", optional = true, path = "../digest" }
17+
digest = { version = "0.10.0-pre", optional = true, path = "../digest" }
1818
elliptic-curve = { version = "=0.9.0-pre", optional = true, path = "../elliptic-curve" }
1919
mac = { version = "=0.11.0-pre", package = "crypto-mac", optional = true, path = "../crypto-mac" }
2020
signature = { version = "1.3.0", optional = true, default-features = false, path = "../signature" }

digest/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 0.10.0 (2021-01-18)
9+
### Breaking changes
10+
- Dirty traits are removed and instead block-level traits are introduced.
11+
Variable output traits are removed as well in favor of fixed output tratis,
12+
implementors of variable output hashes are expected to be generic over
13+
output size. ([#380])
14+
15+
[#380]: https://github.com/RustCrypto/traits/pull/380
16+
817
## 0.9.0 (2020-06-09)
918
### Added
1019
- `ExtendableOutputDirty` and `VariableOutputDirty` traits ([#183])

digest/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "digest"
33
description = "Traits for cryptographic hash functions"
4-
version = "0.9.0"
4+
version = "0.10.0-pre"
55
authors = ["RustCrypto Developers"]
66
license = "MIT OR Apache-2.0"
77
readme = "README.md"
@@ -13,12 +13,14 @@ categories = ["cryptography", "no-std"]
1313

1414
[dependencies]
1515
generic-array = "0.14"
16-
blobby = { version = "0.2", optional = true }
16+
blobby = { version = "0.3", optional = true }
17+
block-buffer = { version = "0.10.0-pre", optional = true }
1718

1819
[features]
1920
alloc = []
2021
std = ["alloc"]
2122
dev = ["blobby"]
23+
core-api = ["block-buffer"]
2224

2325
[package.metadata.docs.rs]
2426
all-features = true

digest/src/core_api.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
use crate::{ExtendableOutput, FixedOutput, Reset, Update, XofReader};
2+
use block_buffer::BlockBuffer;
3+
use generic_array::{ArrayLength, GenericArray};
4+
5+
/// Trait for updating hasher state with input data divided into blocks.
6+
pub trait UpdateCore {
7+
/// Block size in bytes.
8+
type BlockSize: ArrayLength<u8>;
9+
10+
/// Update the hasher state using the provided data.
11+
fn update_blocks(&mut self, blocks: &[GenericArray<u8, Self::BlockSize>]);
12+
}
13+
14+
/// Trait for fixed-output digest implementations to use to retrieve the
15+
/// hash output.
16+
///
17+
/// Usage of this trait in user code is discouraged. Instead use core algorithm
18+
/// wrapped by [`crate::CoreWrapper`], which implements the [`FixedOutput`]
19+
/// trait.
20+
pub trait FixedOutputCore: crate::UpdateCore {
21+
/// Digest output size in bytes.
22+
type OutputSize: ArrayLength<u8>;
23+
24+
/// Retrieve result into provided buffer using remaining data stored
25+
/// in the block buffer and leave hasher in a dirty state.
26+
///
27+
/// This method is expected to only be called once unless [`Reset::reset`]
28+
/// is called, after which point it can be called again and reset again
29+
/// (and so on).
30+
fn finalize_fixed_core(
31+
&mut self,
32+
buffer: &mut block_buffer::BlockBuffer<Self::BlockSize>,
33+
out: &mut GenericArray<u8, Self::OutputSize>,
34+
);
35+
}
36+
37+
/// Trait for extendable-output function (XOF) core implementations to use to
38+
/// retrieve the hash output.
39+
///
40+
/// Usage of this trait in user code is discouraged. Instead use core algorithm
41+
/// wrapped by [`crate::CoreWrapper`], which implements the
42+
/// [`ExtendableOutput`] trait.
43+
pub trait ExtendableOutputCore: crate::UpdateCore {
44+
/// XOF reader core state.
45+
type ReaderCore: XofReaderCore;
46+
47+
/// Retrieve XOF reader using remaining data stored in the block buffer
48+
/// and leave hasher in a dirty state.
49+
///
50+
/// This method is expected to only be called once unless [`Reset::reset`]
51+
/// is called, after which point it can be called again and reset again
52+
/// (and so on).
53+
fn finalize_xof_core(
54+
&mut self,
55+
buffer: &mut block_buffer::BlockBuffer<Self::BlockSize>,
56+
) -> Self::ReaderCore;
57+
}
58+
59+
/// Core reader trait for extendable-output function (XOF) result.
60+
pub trait XofReaderCore {
61+
/// Block size in bytes.
62+
type BlockSize: ArrayLength<u8>;
63+
64+
/// Read next XOF block.
65+
fn read_block(&mut self) -> GenericArray<u8, Self::BlockSize>;
66+
}
67+
68+
/// Wrapper around core trait implementations.
69+
///
70+
/// It handles data buffering and implements the mid-level traits.
71+
#[derive(Clone, Default)]
72+
pub struct CoreWrapper<C, BlockSize: ArrayLength<u8>> {
73+
core: C,
74+
buffer: BlockBuffer<BlockSize>,
75+
}
76+
77+
impl<D: Reset + UpdateCore> Reset for CoreWrapper<D, D::BlockSize> {
78+
#[inline]
79+
fn reset(&mut self) {
80+
self.core.reset();
81+
self.buffer.reset();
82+
}
83+
}
84+
85+
impl<D: UpdateCore> Update for CoreWrapper<D, D::BlockSize> {
86+
#[inline]
87+
fn update(&mut self, input: &[u8]) {
88+
let Self { core, buffer } = self;
89+
buffer.digest_blocks(input, |blocks| core.update_blocks(blocks));
90+
}
91+
}
92+
93+
impl<D: FixedOutputCore + Reset> FixedOutput for CoreWrapper<D, D::BlockSize> {
94+
type OutputSize = D::OutputSize;
95+
96+
#[inline]
97+
fn finalize_into(mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
98+
let Self { core, buffer } = &mut self;
99+
core.finalize_fixed_core(buffer, out);
100+
}
101+
102+
#[inline]
103+
fn finalize_into_reset(&mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
104+
let Self { core, buffer } = self;
105+
core.finalize_fixed_core(buffer, out);
106+
self.reset();
107+
}
108+
}
109+
110+
impl<R: XofReaderCore> XofReader for CoreWrapper<R, R::BlockSize> {
111+
#[inline]
112+
fn read(&mut self, buffer: &mut [u8]) {
113+
let Self { core, buffer: buf } = self;
114+
buf.set_data(buffer, || core.read_block());
115+
}
116+
}
117+
118+
impl<D: ExtendableOutputCore + Reset> ExtendableOutput for CoreWrapper<D, D::BlockSize> {
119+
type Reader = CoreWrapper<D::ReaderCore, <D::ReaderCore as XofReaderCore>::BlockSize>;
120+
121+
#[inline]
122+
fn finalize_xof(mut self) -> Self::Reader {
123+
let Self { core, buffer } = &mut self;
124+
let reader_core = core.finalize_xof_core(buffer);
125+
CoreWrapper {
126+
core: reader_core,
127+
buffer: Default::default(),
128+
}
129+
}
130+
131+
#[inline]
132+
fn finalize_xof_reset(&mut self) -> Self::Reader {
133+
let Self { core, buffer } = self;
134+
let reader_core = core.finalize_xof_core(buffer);
135+
self.reset();
136+
CoreWrapper {
137+
core: reader_core,
138+
buffer: Default::default(),
139+
}
140+
}
141+
}
142+
143+
#[cfg(feature = "std")]
144+
impl<D: UpdateCore> std::io::Write for CoreWrapper<D, D::BlockSize> {
145+
#[inline]
146+
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
147+
Update::update(self, buf);
148+
Ok(buf.len())
149+
}
150+
151+
#[inline]
152+
fn flush(&mut self) -> std::io::Result<()> {
153+
Ok(())
154+
}
155+
}
156+
157+
#[cfg(feature = "std")]
158+
impl<R: XofReaderCore> std::io::Read for CoreWrapper<R, R::BlockSize> {
159+
#[inline]
160+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
161+
XofReader::read(self, buf);
162+
Ok(buf.len())
163+
}
164+
}

0 commit comments

Comments
 (0)