Skip to content

Commit ce237a2

Browse files
authored
ascon-xof128: replace implementation of CustomizedInit with TryCustomizedInit (#859)
1 parent 8a46c3b commit ce237a2

6 files changed

Lines changed: 52 additions & 22 deletions

File tree

ascon-xof128/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
### Changed
99
- Internal implementation by removing unnecessary buffering ([#849])
1010
- Serialization format used by `SerializableState` implementations ([#849])
11+
- Replaced implementation of `CustomizedInit` with `TryCustomizedInit` ([#857])
1112

1213
[#849]: https://github.com/RustCrypto/hashes/pull/849
14+
[#857]: https://github.com/RustCrypto/hashes/pull/857
1315

1416
## 0.1.0 (2026-04-24)
1517
- Initial release ([#841])

ascon-xof128/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ categories = ["cryptography", "no-std"]
1313
description = "Implementation of Ascon-XOF128 and Ascon-СXOF128"
1414

1515
[dependencies]
16-
digest = { version = "0.11", default-features = false }
16+
digest = { version = "0.11.3", default-features = false }
1717
ascon = "0.5"
1818
sponge-cursor = "0.1"
1919

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

2424
[features]

ascon-xof128/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ assert_eq!(dst, hex!("8C7DD114A0"));
3030
Ascon-CXOF128 works similarly, but you must specify a customization string to initialize it:
3131

3232
```rust
33-
use ascon_xof128::{AsconCxof128, CustomizedInit, ExtendableOutput, Update, XofReader};
33+
use ascon_xof128::{AsconCxof128, ExtendableOutput, TryCustomizedInit, Update, XofReader};
3434
use hex_literal::hex;
3535

36-
let mut xof = AsconCxof128::new_customized(b"some customization string");
36+
let mut xof = AsconCxof128::try_new_customized(b"some customization string").unwrap();
3737
xof.update(b"some bytes");
3838
let mut reader = xof.finalize_xof();
3939
let mut dst = [0u8; 5];
@@ -45,8 +45,8 @@ Note that the NIST specifies that:
4545

4646
>The length of the customization string **shall** be at most 2048 bits (i.e., 256 bytes).
4747
48-
This limit is not enforced by the `new_customized` method; users must ensure their customization
49-
strings meet the size requirement if they intend to claim conformance to the standard.
48+
Implementation of the `TryCustomizedInit` trait for this type returns `InvalidCustomizationError`
49+
for longer customization strings.
5050

5151
See the [`digest`] crate docs for additional examples.
5252

ascon-xof128/src/cxof.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,45 @@
11
use ascon::State;
2+
use core::fmt;
23
use digest::{
3-
CollisionResistance, CustomizedInit, ExtendableOutput, HashMarker, OutputSizeUser, Update,
4-
common::AlgorithmName,
5-
common::hazmat::{DeserializeStateError, SerializableState, SerializedState},
4+
CollisionResistance, ExtendableOutput, HashMarker, OutputSizeUser, TryCustomizedInit, Update,
5+
common::{
6+
AlgorithmName,
7+
hazmat::{DeserializeStateError, SerializableState, SerializedState},
8+
},
69
consts::{U16, U32, U41},
710
};
811
use sponge_cursor::SpongeCursor;
912

1013
use crate::{AsconXof128Reader, consts::CXOF_INIT_STATE};
1114

15+
const MAX_CUSTOMIZATION_LEN: usize = 256;
16+
1217
/// Ascon-CXOF128 hasher.
1318
///
1419
/// Note that NIST SP 800-232 specifies the following:
1520
///
1621
/// >The length of the customization string **shall** be at most 2048 bits (i.e., 256 bytes).
1722
///
18-
/// We do not check this condition as part of [`CustomizedInit::new_customized`] and
19-
/// consider it the user's responsibility to use appropriately sized customization strings.
23+
/// Implementation of the [`TryCustomizedInit`] trait for this type returns
24+
/// [`InvalidCustomizationError`] for longer customization strings.
2025
#[derive(Clone, Debug)]
2126
pub struct AsconCxof128 {
2227
state: State,
2328
cursor: SpongeCursor<8>,
2429
}
2530

26-
impl CustomizedInit for AsconCxof128 {
31+
impl TryCustomizedInit for AsconCxof128 {
32+
type Error = InvalidCustomizationError;
2733
#[inline]
28-
fn new_customized(customization: &[u8]) -> Self {
29-
// We assume that in practice customization strings are always smaller than 2^61 bytes.
34+
fn try_new_customized(customization: &[u8]) -> Result<Self, InvalidCustomizationError> {
35+
if customization.len() > MAX_CUSTOMIZATION_LEN {
36+
return Err(InvalidCustomizationError);
37+
}
38+
3039
let bit_len = 8 * customization.len();
3140
let mut state = CXOF_INIT_STATE;
3241

33-
state[0] ^= u64::try_from(bit_len).expect("`usize` always fits into `u64` in practice");
42+
state[0] ^= u64::try_from(bit_len).expect("`bit_len` can not be greater than 2048");
3443

3544
ascon::permute12(&mut state);
3645

@@ -53,7 +62,7 @@ impl CustomizedInit for AsconCxof128 {
5362
ascon::permute12(&mut state);
5463

5564
let cursor = Default::default();
56-
Self { state, cursor }
65+
Ok(Self { state, cursor })
5766
}
5867
}
5968

@@ -141,3 +150,18 @@ impl Drop for AsconCxof128 {
141150

142151
#[cfg(feature = "zeroize")]
143152
impl digest::zeroize::ZeroizeOnDrop for AsconCxof128 {}
153+
154+
/// Invalid Ascon-CXOF128 customization string error.
155+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
156+
pub struct InvalidCustomizationError;
157+
158+
impl fmt::Display for InvalidCustomizationError {
159+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160+
f.write_str(
161+
"Invalid Ascon-CXOF128 customization string. \
162+
The length of the customization string shall be at most 256 bytes.",
163+
)
164+
}
165+
}
166+
167+
impl core::error::Error for InvalidCustomizationError {}

ascon-xof128/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#![warn(missing_docs, unreachable_pub)]
99
#![forbid(unsafe_code)]
1010

11-
pub use digest::{self, CustomizedInit, ExtendableOutput, Update, XofReader};
11+
pub use digest::{self, ExtendableOutput, TryCustomizedInit, Update, XofReader};
1212

1313
mod consts;
1414
mod cxof;

ascon-xof128/tests/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use ascon_xof128::{AsconCxof128, AsconXof128};
22
use core::fmt::Debug;
33
use digest::{
4-
CustomizedInit, ExtendableOutput, Update,
4+
ExtendableOutput, TryCustomizedInit, Update,
55
common::hazmat::SerializableState,
66
dev::{feed_rand_16mib, xof_reset_test},
77
};
@@ -59,7 +59,7 @@ fn ascon_xof128_rand() {
5959

6060
#[test]
6161
fn ascon_cxof128_rand() {
62-
let mut h = AsconCxof128::new_customized(b"randomized cxof test");
62+
let mut h = AsconCxof128::try_new_customized(b"randomized cxof test").unwrap();
6363
h.update(b"hello");
6464
feed_rand_16mib(&mut h);
6565

@@ -90,14 +90,16 @@ struct CxofTestVector {
9090
}
9191

9292
/// Customized XOF test.
93-
fn cxof_reset_test<D: ExtendableOutput + CustomizedInit + Debug + Clone>(
93+
fn cxof_reset_test<D: ExtendableOutput + TryCustomizedInit + Debug + Clone>(
9494
&CxofTestVector {
9595
customization,
9696
input,
9797
output,
9898
}: &CxofTestVector,
9999
) -> Result<(), &'static str> {
100-
let mut hasher = D::new_customized(customization);
100+
let Ok(mut hasher) = D::try_new_customized(customization) else {
101+
return Err("initialization error");
102+
};
101103
let mut buf = [0u8; 1024];
102104
let buf = &mut buf[..output.len()];
103105
// Test that it works when accepting the message all at once
@@ -110,7 +112,9 @@ fn cxof_reset_test<D: ExtendableOutput + CustomizedInit + Debug + Clone>(
110112

111113
// Test that it works when accepting the message in chunks
112114
for n in 1..core::cmp::min(17, input.len()) {
113-
let mut hasher = D::new_customized(customization);
115+
let Ok(mut hasher) = D::try_new_customized(customization) else {
116+
return Err("initialization error");
117+
};
114118
for chunk in input.chunks(n) {
115119
hasher.update(chunk);
116120
}

0 commit comments

Comments
 (0)