Skip to content

Commit bcd6ad0

Browse files
committed
update turboshake
1 parent 5f4fc77 commit bcd6ad0

5 files changed

Lines changed: 51 additions & 92 deletions

File tree

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ opt-level = 2
3636
[patch.crates-io]
3737
sha1 = { path = "sha1" }
3838
whirlpool = { path = "whirlpool" }
39+
sponge-cursor = { git = "https://github.com/RustCrypto/utils", branch = "add-sponge-cursor" }

cshake/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ description = "Implementation of the cSHAKE family of extendable-output function
1515
[dependencies]
1616
digest = { version = "0.11", default-features = false }
1717
keccak = "0.2"
18-
sponge-cursor = { git = "https://github.com/RustCrypto/utils", branch = "add-sponge-cursor" }
18+
sponge-cursor = "0.1"
1919

2020
[dev-dependencies]
21-
digest = { version = "0.11", features = ["dev"] }
21+
digest = { version = "0.11", default-features = false, features = ["dev"] }
2222
hex-literal = "1"
2323

2424
[features]

turboshake/Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,18 @@ categories = ["cryptography", "no-std"]
1313
description = "Implementation of the TurboSHAKE family of extendable-output functions (XOFs)"
1414

1515
[dependencies]
16-
digest = "0.11"
16+
digest = { version = "0.11", default-features = false }
1717
keccak = "0.2"
18+
sponge-cursor = "0.1"
1819

1920
[dev-dependencies]
20-
digest = { version = "0.11", features = ["dev"] }
21+
digest = { version = "0.11", default-features = false, features = ["dev"] }
2122
hex-literal = "1"
2223

2324
[features]
2425
default = ["alloc"]
2526
alloc = ["digest/alloc"]
26-
zeroize = ["digest/zeroize"]
27+
zeroize = ["digest/zeroize", "sponge-cursor/zeroize"]
2728

2829
[package.metadata.docs.rs]
2930
all-features = true

turboshake/src/lib.rs

Lines changed: 43 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111

1212
pub use digest;
1313
use keccak::{Keccak, State1600};
14+
use sponge_cursor::SpongeCursor;
1415

1516
use core::fmt;
1617
use digest::{
17-
CollisionResistance, ExtendableOutput, ExtendableOutputReset, HashMarker, Update, XofReader,
18-
block_api::{AlgorithmName, BlockSizeUser, Reset},
19-
block_buffer::{BlockSizes, EagerBuffer, ReadBuffer},
18+
CollisionResistance, ExtendableOutput, ExtendableOutputReset, HashMarker, Reset, Update,
19+
XofReader,
20+
array::ArraySize,
21+
common::{AlgorithmName, BlockSizeUser},
2022
consts::{U16, U32, U136, U168},
2123
};
2224

@@ -33,13 +35,13 @@ pub const DEFAULT_DS: u8 = 0x1F;
3335
///
3436
/// Rate MUST be either [`U168`] or [`U136`] for TurboSHAKE128 and TurboSHAKE256 respectively.
3537
#[derive(Clone)]
36-
pub struct TurboShake<Rate: BlockSizes, const DS: u8> {
38+
pub struct TurboShake<Rate: ArraySize, const DS: u8> {
3739
state: State1600,
40+
cursor: SpongeCursor<Rate>,
3841
keccak: Keccak,
39-
buffer: EagerBuffer<Rate>,
4042
}
4143

42-
impl<Rate: BlockSizes, const DS: u8> Default for TurboShake<Rate, DS> {
44+
impl<Rate: ArraySize, const DS: u8> Default for TurboShake<Rate, DS> {
4345
#[inline]
4446
fn default() -> Self {
4547
const {
@@ -48,96 +50,76 @@ impl<Rate: BlockSizes, const DS: u8> Default for TurboShake<Rate, DS> {
4850
}
4951
Self {
5052
state: Default::default(),
53+
cursor: Default::default(),
5154
keccak: Keccak::new(),
52-
buffer: Default::default(),
5355
}
5456
}
5557
}
5658

57-
impl<Rate: BlockSizes, const DS: u8> HashMarker for TurboShake<Rate, DS> {}
59+
impl<Rate: ArraySize, const DS: u8> HashMarker for TurboShake<Rate, DS> {}
5860

59-
impl<Rate: BlockSizes, const DS: u8> BlockSizeUser for TurboShake<Rate, DS> {
61+
impl<Rate: ArraySize, const DS: u8> BlockSizeUser for TurboShake<Rate, DS> {
6062
type BlockSize = Rate;
6163
}
6264

63-
impl<Rate: BlockSizes, const DS: u8> Update for TurboShake<Rate, DS> {
65+
impl<Rate: ArraySize, const DS: u8> Update for TurboShake<Rate, DS> {
6466
#[inline]
6567
fn update(&mut self, data: &[u8]) {
66-
let Self {
67-
state,
68-
keccak,
69-
buffer,
70-
} = self;
71-
72-
keccak.with_p1600::<ROUNDS>(|p1600| {
73-
buffer.digest_blocks(data, |blocks| {
74-
for block in blocks {
75-
xor_block(state, block);
76-
p1600(state);
77-
}
78-
});
68+
self.keccak.with_p1600::<ROUNDS>(|p1600| {
69+
self.cursor.absorb_u64_le(&mut self.state, p1600, data);
7970
});
8071
}
8172
}
8273

83-
impl<Rate: BlockSizes, const DS: u8> TurboShake<Rate, DS> {
84-
fn finalize_dirty(&mut self) {
85-
let Self {
86-
state,
87-
keccak,
88-
buffer,
89-
} = self;
90-
91-
let pos = buffer.get_pos();
92-
let mut block = buffer.pad_with_zeros();
93-
block[pos] = DS;
94-
let n = block.len();
95-
block[n - 1] |= 0x80;
74+
impl<Rate: ArraySize, const DS: u8> TurboShake<Rate, DS> {
75+
fn pad(&mut self) {
76+
let pos = self.cursor.pos();
77+
let word_offset = pos / 8;
78+
let byte_offset = pos % 8;
9679

97-
keccak.with_p1600::<ROUNDS>(|p1600| {
98-
xor_block(state, &block);
99-
p1600(state);
100-
});
80+
let pad = u64::from(DS) << (8 * byte_offset);
81+
self.state[word_offset] ^= pad;
82+
self.state[Rate::USIZE / 8 - 1] ^= 1 << 63;
10183
}
10284
}
10385

104-
impl<Rate: BlockSizes, const DS: u8> ExtendableOutput for TurboShake<Rate, DS> {
86+
impl<Rate: ArraySize, const DS: u8> ExtendableOutput for TurboShake<Rate, DS> {
10587
type Reader = TurboShakeReader<Rate>;
10688

10789
#[inline]
10890
fn finalize_xof(mut self) -> Self::Reader {
109-
self.finalize_dirty();
91+
self.pad();
11092
Self::Reader {
11193
state: self.state,
94+
cursor: Default::default(),
11295
keccak: self.keccak,
113-
buffer: Default::default(),
11496
}
11597
}
11698
}
11799

118-
impl<Rate: BlockSizes, const DS: u8> ExtendableOutputReset for TurboShake<Rate, DS> {
100+
impl<Rate: ArraySize, const DS: u8> ExtendableOutputReset for TurboShake<Rate, DS> {
119101
#[inline]
120102
fn finalize_xof_reset(&mut self) -> Self::Reader {
121-
self.finalize_dirty();
103+
self.pad();
122104
let reader = Self::Reader {
123105
state: self.state,
106+
cursor: Default::default(),
124107
keccak: self.keccak,
125-
buffer: Default::default(),
126108
};
127109
self.reset();
128110
reader
129111
}
130112
}
131113

132-
impl<Rate: BlockSizes, const DS: u8> Reset for TurboShake<Rate, DS> {
114+
impl<Rate: ArraySize, const DS: u8> Reset for TurboShake<Rate, DS> {
133115
#[inline]
134116
fn reset(&mut self) {
135117
self.state = Default::default();
136-
self.buffer.reset();
118+
self.cursor = Default::default();
137119
}
138120
}
139121

140-
impl<Rate: BlockSizes, const DS: u8> AlgorithmName for TurboShake<Rate, DS> {
122+
impl<Rate: ArraySize, const DS: u8> AlgorithmName for TurboShake<Rate, DS> {
141123
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
142124
let alg_name = match Rate::USIZE {
143125
168 => "TurboSHAKE128",
@@ -148,7 +130,7 @@ impl<Rate: BlockSizes, const DS: u8> AlgorithmName for TurboShake<Rate, DS> {
148130
}
149131
}
150132

151-
impl<Rate: BlockSizes, const DS: u8> fmt::Debug for TurboShake<Rate, DS> {
133+
impl<Rate: ArraySize, const DS: u8> fmt::Debug for TurboShake<Rate, DS> {
152134
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153135
let debug_str = match Rate::USIZE {
154136
168 => "TurboShake128 { ... }",
@@ -159,7 +141,7 @@ impl<Rate: BlockSizes, const DS: u8> fmt::Debug for TurboShake<Rate, DS> {
159141
}
160142
}
161143

162-
impl<Rate: BlockSizes, const DS: u8> Drop for TurboShake<Rate, DS> {
144+
impl<Rate: ArraySize, const DS: u8> Drop for TurboShake<Rate, DS> {
163145
fn drop(&mut self) {
164146
#[cfg(feature = "zeroize")]
165147
{
@@ -171,40 +153,26 @@ impl<Rate: BlockSizes, const DS: u8> Drop for TurboShake<Rate, DS> {
171153
}
172154

173155
#[cfg(feature = "zeroize")]
174-
impl<Rate: BlockSizes, const DS: u8> digest::zeroize::ZeroizeOnDrop for TurboShake<Rate, DS> {}
156+
impl<Rate: ArraySize, const DS: u8> digest::zeroize::ZeroizeOnDrop for TurboShake<Rate, DS> {}
175157

176158
/// Generic TurboSHAKE XOF reader
177159
#[derive(Clone)]
178-
pub struct TurboShakeReader<Rate: BlockSizes> {
160+
pub struct TurboShakeReader<Rate: ArraySize> {
179161
state: State1600,
162+
cursor: SpongeCursor<Rate>,
180163
keccak: Keccak,
181-
buffer: ReadBuffer<Rate>,
182164
}
183165

184-
impl<Rate: BlockSizes> XofReader for TurboShakeReader<Rate> {
166+
impl<Rate: ArraySize> XofReader for TurboShakeReader<Rate> {
185167
#[inline]
186168
fn read(&mut self, buf: &mut [u8]) {
187-
let Self {
188-
state,
189-
keccak,
190-
buffer,
191-
} = self;
192-
193-
buffer.read(buf, |block| {
194-
let mut chunks = block.chunks_exact_mut(8);
195-
for (src, dst) in state.iter().zip(&mut chunks) {
196-
dst.copy_from_slice(&src.to_le_bytes());
197-
}
198-
assert!(
199-
chunks.into_remainder().is_empty(),
200-
"rate is either 136 or 168",
201-
);
202-
keccak.with_p1600::<ROUNDS>(|p1600| p1600(state));
169+
self.keccak.with_p1600::<ROUNDS>(|p1600| {
170+
self.cursor.squeeze_u64_le(&mut self.state, p1600, buf);
203171
});
204172
}
205173
}
206174

207-
impl<Rate: BlockSizes> fmt::Debug for TurboShakeReader<Rate> {
175+
impl<Rate: ArraySize> fmt::Debug for TurboShakeReader<Rate> {
208176
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209177
let debug_str = match Rate::USIZE {
210178
168 => "TurboShakeReader128 { ... }",
@@ -215,19 +183,19 @@ impl<Rate: BlockSizes> fmt::Debug for TurboShakeReader<Rate> {
215183
}
216184
}
217185

218-
impl<Rate: BlockSizes> Drop for TurboShakeReader<Rate> {
186+
impl<Rate: ArraySize> Drop for TurboShakeReader<Rate> {
219187
fn drop(&mut self) {
220188
#[cfg(feature = "zeroize")]
221189
{
222190
use digest::zeroize::Zeroize;
223191
self.state.zeroize();
224-
// self.buffer is zeroized by its `Drop`
192+
self.cursor.zeroize();
225193
}
226194
}
227195
}
228196

229197
#[cfg(feature = "zeroize")]
230-
impl<Rate: BlockSizes> digest::zeroize::ZeroizeOnDrop for TurboShakeReader<Rate> {}
198+
impl<Rate: ArraySize> digest::zeroize::ZeroizeOnDrop for TurboShakeReader<Rate> {}
231199

232200
/// TurboSHAKE128 hasher with domain separator.
233201
pub type TurboShake128<const DS: u8 = DEFAULT_DS> = TurboShake<U168, DS>;
@@ -248,15 +216,3 @@ impl<const DS: u8> CollisionResistance for TurboShake256<DS> {
248216
// https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-17.html#section-7-8
249217
type CollisionResistance = U32;
250218
}
251-
252-
fn xor_block(state: &mut State1600, block: &[u8]) {
253-
assert!(size_of_val(block) < size_of_val(state));
254-
255-
let mut chunks = block.chunks_exact(8);
256-
for (s, chunk) in state.iter_mut().zip(&mut chunks) {
257-
*s ^= u64::from_le_bytes(chunk.try_into().unwrap());
258-
}
259-
260-
let rem = chunks.remainder();
261-
assert!(rem.is_empty(), "block size is equal to 136 or 168");
262-
}

0 commit comments

Comments
 (0)