Skip to content

Commit b207e71

Browse files
committed
add block-level API, remove the dirty traits, reorganize code
1 parent fdff330 commit b207e71

12 files changed

+355
-408
lines changed

Cargo.lock

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

digest/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ categories = ["cryptography", "no-std"]
1414
[dependencies]
1515
generic-array = "0.14"
1616
blobby = { version = "0.2", optional = true }
17+
block-buffer = { version = "0.9", 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: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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.
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.
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+
#[cfg(feature = "core-api")]
44+
pub trait ExtendableOutputCore: crate::UpdateCore {
45+
/// XOF reader.
46+
type Reader: XofReader;
47+
48+
/// Retrieve XOF reader using remaining data stored in the block buffer
49+
/// and leave hasher in a dirty state.
50+
///
51+
/// This method is expected to only be called once unless [`Reset::reset`]
52+
/// is called, after which point it can be called again and reset again
53+
/// (and so on).
54+
fn finalize_xof_core(
55+
&mut self,
56+
buffer: &mut block_buffer::BlockBuffer<Self::BlockSize>,
57+
) -> Self::Reader;
58+
}
59+
60+
/// Wrapper around core trait implementations.
61+
///
62+
/// It handles data buffering and implements the mid-level traits.
63+
#[derive(Clone, Default)]
64+
pub struct CoreWrapper<D: UpdateCore> {
65+
core: D,
66+
buffer: BlockBuffer<D::BlockSize>,
67+
}
68+
69+
impl<D: Reset + UpdateCore> Reset for CoreWrapper<D> {
70+
#[inline]
71+
fn reset(&mut self) {
72+
self.core.reset();
73+
self.buffer.reset();
74+
}
75+
}
76+
77+
impl<D: UpdateCore> Update for CoreWrapper<D> {
78+
#[inline]
79+
fn update(&mut self, input: &[u8]) {
80+
let Self { core, buffer } = self;
81+
buffer.input_blocks(input, |blocks| core.update_blocks(blocks));
82+
}
83+
}
84+
85+
impl<D: FixedOutputCore + Reset> FixedOutput for CoreWrapper<D> {
86+
type OutputSize = D::OutputSize;
87+
88+
#[inline]
89+
fn finalize_into(self, out: &mut GenericArray<u8, Self::OutputSize>) {
90+
let Self {
91+
mut core,
92+
mut buffer,
93+
} = self;
94+
core.finalize_fixed_core(&mut buffer, out);
95+
}
96+
97+
#[inline]
98+
fn finalize_into_reset(&mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
99+
let Self { core, buffer } = self;
100+
core.finalize_fixed_core(buffer, out);
101+
self.reset();
102+
}
103+
}
104+
105+
impl<D: ExtendableOutputCore + Reset> ExtendableOutput for CoreWrapper<D> {
106+
type Reader = D::Reader;
107+
108+
#[inline]
109+
fn finalize_xof(self) -> Self::Reader {
110+
let Self {
111+
mut core,
112+
mut buffer,
113+
} = self;
114+
core.finalize_xof_core(&mut buffer)
115+
}
116+
117+
#[inline]
118+
fn finalize_xof_reset(&mut self) -> Self::Reader {
119+
let Self { core, buffer } = self;
120+
let reader = core.finalize_xof_core(buffer);
121+
self.reset();
122+
reader
123+
}
124+
}
125+
126+
#[cfg(feature = "std")]
127+
impl<D: UpdateCore> std::io::Write for CoreWrapper<D> {
128+
#[inline]
129+
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
130+
Update::update(self, buf);
131+
Ok(buf.len())
132+
}
133+
134+
#[inline]
135+
fn flush(&mut self) -> std::io::Result<()> {
136+
Ok(())
137+
}
138+
}

digest/src/dev.rs

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
pub use blobby;
44

5-
use super::{ExtendableOutput, Reset, Update, VariableOutput, XofReader};
5+
use super::{ExtendableOutput, Reset, Update, XofReader};
66
use core::fmt::Debug;
77

88
/// Define test
@@ -165,56 +165,6 @@ where
165165
None
166166
}
167167

168-
/// Variable-output digest test
169-
pub fn variable_test<D>(input: &[u8], output: &[u8]) -> Option<&'static str>
170-
where
171-
D: Update + VariableOutput + Reset + Debug + Clone,
172-
{
173-
let mut hasher = D::new(output.len()).unwrap();
174-
let mut buf = [0u8; 128];
175-
let buf = &mut buf[..output.len()];
176-
// Test that it works when accepting the message all at once
177-
hasher.update(input);
178-
let mut hasher2 = hasher.clone();
179-
hasher.finalize_variable(|res| buf.copy_from_slice(res));
180-
if buf != output {
181-
return Some("whole message");
182-
}
183-
184-
// Test if reset works correctly
185-
hasher2.reset();
186-
hasher2.update(input);
187-
hasher2.finalize_variable(|res| buf.copy_from_slice(res));
188-
if buf != output {
189-
return Some("whole message after reset");
190-
}
191-
192-
// Test that it works when accepting the message in pieces
193-
let mut hasher = D::new(output.len()).unwrap();
194-
let len = input.len();
195-
let mut left = len;
196-
while left > 0 {
197-
let take = (left + 1) / 2;
198-
hasher.update(&input[len - left..take + len - left]);
199-
left -= take;
200-
}
201-
hasher.finalize_variable(|res| buf.copy_from_slice(res));
202-
if buf != output {
203-
return Some("message in pieces");
204-
}
205-
206-
// Test processing byte-by-byte
207-
let mut hasher = D::new(output.len()).unwrap();
208-
for chunk in input.chunks(1) {
209-
hasher.update(chunk)
210-
}
211-
hasher.finalize_variable(|res| buf.copy_from_slice(res));
212-
if buf != output {
213-
return Some("message byte-by-byte");
214-
}
215-
None
216-
}
217-
218168
/// Define benchmark
219169
#[macro_export]
220170
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]

digest/src/digest.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,39 +52,48 @@ pub trait Digest {
5252
impl<D: Update + FixedOutput + Reset + Clone + Default> Digest for D {
5353
type OutputSize = <Self as FixedOutput>::OutputSize;
5454

55+
#[inline]
5556
fn new() -> Self {
5657
Self::default()
5758
}
5859

60+
#[inline]
5961
fn update(&mut self, data: impl AsRef<[u8]>) {
60-
Update::update(self, data);
62+
Update::update(self, data.as_ref());
6163
}
6264

63-
fn chain(self, data: impl AsRef<[u8]>) -> Self
65+
#[inline]
66+
fn chain(mut self, data: impl AsRef<[u8]>) -> Self
6467
where
6568
Self: Sized,
6669
{
67-
Update::chain(self, data)
70+
Update::update(&mut self, data.as_ref());
71+
self
6872
}
6973

74+
#[inline]
7075
fn finalize(self) -> Output<Self> {
7176
self.finalize_fixed()
7277
}
7378

79+
#[inline]
7480
fn finalize_reset(&mut self) -> Output<Self> {
7581
let res = self.clone().finalize_fixed();
7682
self.reset();
7783
res
7884
}
7985

86+
#[inline]
8087
fn reset(&mut self) {
81-
<Self as Reset>::reset(self)
88+
Reset::reset(self)
8289
}
8390

91+
#[inline]
8492
fn output_size() -> usize {
8593
Self::OutputSize::to_usize()
8694
}
8795

96+
#[inline]
8897
fn digest(data: &[u8]) -> Output<Self> {
8998
let mut hasher = Self::default();
9099
Update::update(&mut hasher, data);

digest/src/dyn_digest.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ impl<D: Update + FixedOutput + Reset + Clone + 'static> DynDigest for D {
3535
}
3636

3737
fn finalize_reset(&mut self) -> Box<[u8]> {
38-
let res = self.finalize_fixed_reset().to_vec().into_boxed_slice();
39-
Reset::reset(self);
40-
res
38+
self.finalize_fixed_reset().to_vec().into_boxed_slice()
4139
}
4240

4341
fn finalize(self: Box<Self>) -> Box<[u8]> {

digest/src/errors.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.

digest/src/fixed.rs

Lines changed: 0 additions & 71 deletions
This file was deleted.

0 commit comments

Comments
 (0)