ascon_hash/
lib.rs

1// Copyright 2022-2025 Sebastian Ramacher
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4#![no_std]
5#![cfg_attr(docsrs, feature(doc_auto_cfg))]
6#![doc = include_str!("../README.md")]
7#![warn(missing_docs)]
8
9//! ## Usage (Hashing)
10//!
11//! ```
12//! use ascon_hash::{AsconHash256, Digest};
13//!
14//! let mut hasher = AsconHash256::new();
15//! hasher.update(b"some bytes");
16//! let digest = hasher.finalize();
17//! assert_eq!(&digest[..], b"\xe9\x09\xc2\xf6\xda\x9c\xb3\x02\x84\x23\x26\x5c\x8f\x23\xfc\x2d\x26\xbf\xc0\xf3\xdb\x70\x46\x83\xef\x16\xb7\x87\xa9\x45\xed\x68");
18//! ```
19//!
20//! ## Usage (XOF)
21//!
22//! ```
23//! use ascon_hash::{AsconXof128, ExtendableOutput, Update, XofReader};
24//!
25//! let mut xof = AsconXof128::default();
26//! xof.update(b"some bytes");
27//! let mut reader = xof.finalize_xof();
28//! let mut dst = [0u8; 5];
29//! reader.read(&mut dst);
30//! assert_eq!(&dst, b"\x8c\x7d\xd1\x14\xa0");
31//! ```
32
33use core::{fmt, marker::PhantomData};
34
35use ascon_core::State;
36pub use digest::{self, Digest, ExtendableOutput, Reset, Update, XofReader};
37use digest::{
38    HashMarker, Output, OutputSizeUser,
39    block_buffer::Eager,
40    consts::{U8, U32},
41    core_api::{
42        AlgorithmName, Block, Buffer, BufferKindUser, CoreWrapper, ExtendableOutputCore,
43        FixedOutputCore, UpdateCore, XofReaderCore, XofReaderCoreWrapper,
44    },
45    crypto_common::BlockSizeUser,
46};
47
48/// Produce mask for padding.
49#[inline(always)]
50const fn pad(n: usize) -> u64 {
51    0x01_u64 << (8 * n)
52}
53
54/// Parameters for Ascon hash instances.
55///
56/// These parameters represent the permutation applied to the zero-extended IV.
57trait HashParameters {
58    /// Part of the IV.
59    const IV0: u64;
60    /// Part of the IV.
61    const IV1: u64;
62    /// Part of the IV.
63    const IV2: u64;
64    /// Part of the IV.
65    const IV3: u64;
66    /// Part of the IV.
67    const IV4: u64;
68}
69
70/// Parameters for Ascon-Hash256.
71#[derive(Clone, Debug)]
72struct Parameters;
73
74impl HashParameters for Parameters {
75    const IV0: u64 = 0x9b1e5494e934d681;
76    const IV1: u64 = 0x4bc3a01e333751d2;
77    const IV2: u64 = 0xae65396c6b34b81a;
78    const IV3: u64 = 0x3c7fd4a4d56a4db3;
79    const IV4: u64 = 0x1a5c464906c5976d;
80}
81
82/// Parameters for Ascon-XOF128
83#[derive(Clone, Debug)]
84struct ParametersXof;
85
86impl HashParameters for ParametersXof {
87    const IV0: u64 = 0xda82ce768d9447eb;
88    const IV1: u64 = 0xcc7ce6c75f1ef969;
89    const IV2: u64 = 0xe7508fd780085631;
90    const IV3: u64 = 0x0ee0ea53416b58cc;
91    const IV4: u64 = 0xe0547524db6f0bde;
92}
93
94#[derive(Clone, Debug)]
95struct HashCore<P: HashParameters> {
96    state: State,
97    phantom: PhantomData<P>,
98}
99
100impl<P: HashParameters> HashCore<P> {
101    fn absorb_block(&mut self, block: &[u8; 8]) {
102        self.state[0] ^= u64::from_le_bytes(*block);
103        self.permute_state();
104    }
105
106    fn absorb_last_block(&mut self, block: &[u8]) {
107        debug_assert!(block.len() < 8);
108
109        let len = block.len();
110        if len > 0 {
111            let mut tmp = [0u8; 8];
112            tmp[0..len].copy_from_slice(block);
113            self.state[0] ^= u64::from_le_bytes(tmp);
114        }
115        self.state[0] ^= pad(len);
116        self.state.permute_12();
117    }
118
119    // for fixed-sized output
120    fn squeeze(&mut self, mut block: &mut [u8]) {
121        debug_assert_eq!(block.len() % 8, 0);
122
123        while block.len() > 8 {
124            block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0]));
125            self.permute_state();
126            block = &mut block[8..];
127        }
128        block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0]));
129    }
130
131    // for XOF output
132    fn squeeze_block(&mut self) -> [u8; 8] {
133        let ret = u64::to_le_bytes(self.state[0]);
134        self.permute_state();
135        ret
136    }
137
138    #[inline(always)]
139    fn permute_state(&mut self) {
140        self.state.permute_12();
141    }
142}
143
144impl<P: HashParameters> Default for HashCore<P> {
145    fn default() -> Self {
146        Self {
147            state: State::new(P::IV0, P::IV1, P::IV2, P::IV3, P::IV4),
148            phantom: PhantomData,
149        }
150    }
151}
152
153/// Ascon hash implementation
154#[derive(Clone, Debug, Default)]
155pub struct AsconCore {
156    state: HashCore<Parameters>,
157}
158
159impl HashMarker for AsconCore {}
160
161impl BlockSizeUser for AsconCore {
162    type BlockSize = U8;
163}
164
165impl BufferKindUser for AsconCore {
166    type BufferKind = Eager;
167}
168
169impl OutputSizeUser for AsconCore {
170    type OutputSize = U32;
171}
172
173impl UpdateCore for AsconCore {
174    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
175        for block in blocks {
176            self.state.absorb_block(block.as_ref());
177        }
178    }
179}
180
181impl FixedOutputCore for AsconCore {
182    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
183        debug_assert!(buffer.get_pos() < 8);
184        self.state
185            .absorb_last_block(&buffer.get_data()[..buffer.get_pos()]);
186        self.state.squeeze(out);
187    }
188}
189
190impl Reset for AsconCore {
191    fn reset(&mut self) {
192        *self = Default::default();
193    }
194}
195
196impl AlgorithmName for AsconCore {
197    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        f.write_str("Ascon-Hash256")
199    }
200}
201
202/// Ascon XOF
203#[derive(Clone, Debug, Default)]
204pub struct AsconXofCore {
205    state: HashCore<ParametersXof>,
206}
207
208impl HashMarker for AsconXofCore {}
209
210impl BlockSizeUser for AsconXofCore {
211    type BlockSize = U8;
212}
213
214impl BufferKindUser for AsconXofCore {
215    type BufferKind = Eager;
216}
217
218impl UpdateCore for AsconXofCore {
219    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
220        for block in blocks {
221            self.state.absorb_block(block.as_ref());
222        }
223    }
224}
225
226/// Reader for XOF output
227#[derive(Clone, Debug)]
228pub struct AsconXofReaderCore {
229    hasher: HashCore<ParametersXof>,
230}
231
232impl BlockSizeUser for AsconXofReaderCore {
233    type BlockSize = U8;
234}
235
236impl XofReaderCore for AsconXofReaderCore {
237    fn read_block(&mut self) -> Block<Self> {
238        self.hasher.squeeze_block().into()
239    }
240}
241
242impl ExtendableOutputCore for AsconXofCore {
243    type ReaderCore = AsconXofReaderCore;
244
245    fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
246        debug_assert!(buffer.get_pos() < 8);
247        self.state
248            .absorb_last_block(&buffer.get_data()[..buffer.get_pos()]);
249        Self::ReaderCore {
250            hasher: self.state.clone(),
251        }
252    }
253}
254
255impl Reset for AsconXofCore {
256    fn reset(&mut self) {
257        *self = Default::default();
258    }
259}
260
261impl AlgorithmName for AsconXofCore {
262    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
263        f.write_str("Ascon-XOF128")
264    }
265}
266
267/// Ascon-Hash256
268///
269/// ```
270/// use ascon_hash::{AsconHash256, Digest};
271///
272/// let mut hasher = AsconHash256::new();
273/// hasher.update(b"some bytes");
274/// let digest = hasher.finalize();
275/// assert_eq!(&digest[..], b"\xe9\x09\xc2\xf6\xda\x9c\xb3\x02\x84\x23\x26\x5c\x8f\x23\xfc\x2d\x26\xbf\xc0\xf3\xdb\x70\x46\x83\xef\x16\xb7\x87\xa9\x45\xed\x68");
276/// ```
277pub type AsconHash256 = CoreWrapper<AsconCore>;
278/// Ascon-XOF128
279///
280/// ```
281/// use ascon_hash::{AsconXof128, ExtendableOutput, Update, XofReader};
282///
283/// let mut xof = AsconXof128::default();
284/// xof.update(b"some bytes");
285/// let mut reader = xof.finalize_xof();
286/// let mut dst = [0u8; 5];
287/// reader.read(&mut dst);
288/// assert_eq!(&dst, b"\x8c\x7d\xd1\x14\xa0");
289/// ```
290pub type AsconXof128 = CoreWrapper<AsconXofCore>;
291/// Reader for AsconXOF output
292pub type AsconXof128Reader = XofReaderCoreWrapper<AsconXofReaderCore>;