Skip to content

Commit 12105d3

Browse files
authored
Use sponge-cursor to remove unnecessary buffering (#849)
Removes unnecessary buffering from sponge-based constructions using the `sponge-cursor` crate (see RustCrypto/utils#1477).
1 parent 65a1694 commit 12105d3

45 files changed

Lines changed: 912 additions & 912 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

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

ascon-xof128/CHANGELOG.md

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

7+
## 0.2.0 (UNRELEASED)
8+
### Changed
9+
- Internal implementation by removing unnecessary buffering ([#849])
10+
- Serialization format used by `SerializableState` implementations ([#849])
11+
12+
[#849]: https://github.com/RustCrypto/hashes/pull/849
13+
714
## 0.1.0 (2026-04-24)
815
- Initial release ([#841])
916

ascon-xof128/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 Ascon-XOF128 and Ascon-СXOF128"
1414

1515
[dependencies]
16-
digest = "0.11"
16+
digest = { version = "0.11", default-features = false }
1717
ascon = "0.5"
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

ascon-xof128/src/cxof.rs

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use ascon::State;
22
use digest::{
33
CollisionResistance, CustomizedInit, ExtendableOutput, HashMarker, OutputSizeUser, Update,
4-
block_api::AlgorithmName,
5-
block_buffer::EagerBuffer,
4+
common::AlgorithmName,
65
common::hazmat::{DeserializeStateError, SerializableState, SerializedState},
7-
consts::{U8, U16, U32, U48},
6+
consts::{U16, U32, U41},
87
};
8+
use sponge_cursor::SpongeCursor;
99

1010
use crate::{AsconXof128Reader, consts::CXOF_INIT_STATE};
1111

@@ -20,7 +20,7 @@ use crate::{AsconXof128Reader, consts::CXOF_INIT_STATE};
2020
#[derive(Clone, Debug)]
2121
pub struct AsconCxof128 {
2222
state: State,
23-
buffer: EagerBuffer<U8>,
23+
cursor: SpongeCursor<8>,
2424
}
2525

2626
impl CustomizedInit for AsconCxof128 {
@@ -52,8 +52,8 @@ impl CustomizedInit for AsconCxof128 {
5252

5353
ascon::permute12(&mut state);
5454

55-
let buffer = Default::default();
56-
Self { state, buffer }
55+
let cursor = Default::default();
56+
Self { state, cursor }
5757
}
5858
}
5959

@@ -71,26 +71,18 @@ impl CollisionResistance for AsconCxof128 {
7171
impl Update for AsconCxof128 {
7272
#[inline]
7373
fn update(&mut self, data: &[u8]) {
74-
self.buffer.digest_blocks(data, |blocks| {
75-
for block in blocks {
76-
self.state[0] ^= u64::from_le_bytes(block.0);
77-
ascon::permute12(&mut self.state);
78-
}
79-
});
74+
self.cursor
75+
.absorb_u64_le(&mut self.state, ascon::permute12, data);
8076
}
8177
}
8278

8379
impl ExtendableOutput for AsconCxof128 {
8480
type Reader = AsconXof128Reader;
8581

8682
fn finalize_xof(mut self) -> Self::Reader {
87-
let Self { state, buffer } = &mut self;
88-
let len = buffer.get_pos();
89-
let last_block = buffer.pad_with_zeros();
90-
let pad = 1u64 << (8 * len);
91-
state[0] ^= u64::from_le_bytes(last_block.0) ^ pad;
92-
93-
AsconXof128Reader::new(state)
83+
let pos = self.cursor.pos();
84+
self.state[0] ^= 1u64 << (8 * pos);
85+
AsconXof128Reader::new(&self.state)
9486
}
9587
}
9688

@@ -102,37 +94,36 @@ impl AlgorithmName for AsconCxof128 {
10294
}
10395

10496
impl SerializableState for AsconCxof128 {
105-
type SerializedStateSize = U48;
97+
type SerializedStateSize = U41;
10698

10799
#[inline]
108100
fn serialize(&self) -> SerializedState<Self> {
109101
let mut res = SerializedState::<Self>::default();
110-
let (state_dst, buffer_dst) = res.split_at_mut(size_of::<State>());
102+
let (state_dst, cursor_dst) = res.split_at_mut(size_of::<State>());
111103
let mut chunks = state_dst.chunks_exact_mut(size_of::<u64>());
112104
for (src, dst) in self.state.iter().zip(&mut chunks) {
113105
dst.copy_from_slice(&src.to_le_bytes());
114106
}
115107
assert!(chunks.into_remainder().is_empty());
116-
buffer_dst.copy_from_slice(&self.buffer.serialize());
108+
assert_eq!(cursor_dst.len(), 1);
109+
cursor_dst[0] = self.cursor.raw_pos();
117110
res
118111
}
119112

120113
#[inline]
121114
fn deserialize(
122115
serialized_state: &SerializedState<Self>,
123116
) -> Result<Self, DeserializeStateError> {
124-
let (state_src, buffer_src) = serialized_state.split_at(size_of::<State>());
117+
let (state_src, cursor_src) = serialized_state.split_at(size_of::<State>());
125118
let state = core::array::from_fn(|i| {
126119
let n = size_of::<u64>();
127120
let chunk = &state_src[n * i..][..n];
128121
u64::from_le_bytes(chunk.try_into().expect("chunk has correct length"))
129122
});
130-
let buffer_src = buffer_src
131-
.try_into()
132-
.expect("buffer_src has correct length");
133-
EagerBuffer::deserialize(buffer_src)
134-
.map_err(|_| DeserializeStateError)
135-
.map(|buffer| Self { state, buffer })
123+
assert_eq!(cursor_src.len(), 1);
124+
SpongeCursor::new(cursor_src[0])
125+
.ok_or(DeserializeStateError)
126+
.map(|cursor| Self { state, cursor })
136127
}
137128
}
138129

@@ -141,10 +132,9 @@ impl Drop for AsconCxof128 {
141132
fn drop(&mut self) {
142133
#[cfg(feature = "zeroize")]
143134
{
144-
use digest::zeroize::{Zeroize, ZeroizeOnDrop};
145-
fn assert_zeroize_on_drop<T: ZeroizeOnDrop>(_: &mut T) {}
135+
use digest::zeroize::Zeroize;
146136
self.state.zeroize();
147-
assert_zeroize_on_drop(&mut self.buffer);
137+
self.cursor.zeroize();
148138
}
149139
}
150140
}

ascon-xof128/src/reader.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,42 @@
11
use ascon::State;
2-
use digest::{XofReader, block_buffer::ReadBuffer, consts::U8};
2+
use digest::XofReader;
3+
use sponge_cursor::SpongeCursor;
34

45
/// XOF reader used by Ascon-XOF128 and Ascon-CXOF128
56
#[derive(Clone, Debug)]
67
pub struct AsconXof128Reader {
78
state: State,
8-
buffer: ReadBuffer<U8>,
9+
cursor: SpongeCursor<8>,
910
}
1011

1112
impl AsconXof128Reader {
1213
pub(super) fn new(state: &State) -> Self {
1314
Self {
1415
state: *state,
15-
buffer: Default::default(),
16+
cursor: Default::default(),
1617
}
1718
}
1819
}
1920

2021
impl XofReader for AsconXof128Reader {
22+
#[inline]
2123
fn read(&mut self, buf: &mut [u8]) {
22-
self.buffer.read(buf, |dst| {
23-
ascon::permute12(&mut self.state);
24-
*dst = self.state[0].to_le_bytes().into();
25-
});
24+
self.cursor
25+
.squeeze_read_u64_le(&mut self.state, ascon::permute12, buf);
2626
}
2727
}
28+
29+
impl Drop for AsconXof128Reader {
30+
#[inline]
31+
fn drop(&mut self) {
32+
#[cfg(feature = "zeroize")]
33+
{
34+
use digest::zeroize::Zeroize;
35+
self.state.zeroize();
36+
self.cursor.zeroize();
37+
}
38+
}
39+
}
40+
41+
#[cfg(feature = "zeroize")]
42+
impl digest::zeroize::ZeroizeOnDrop for AsconXof128Reader {}

0 commit comments

Comments
 (0)