ascon_hash/
lib.rs

1// Copyright 2022-2023 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::{AsconHash, Digest}; // Or `AsconAHash`
13//!
14//! let mut hasher = AsconHash::new();
15//! hasher.update(b"some bytes");
16//! let digest = hasher.finalize();
17//! assert_eq!(&digest[..], b"\xb7\x42\xca\x75\xe5\x70\x38\x75\x70\x59\xcc\xcc\x68\x74\x71\x4f\x9d\xbd\x7f\xc5\x92\x4a\x7d\xf4\xe3\x16\x59\x4f\xd1\x42\x6c\xa8");
18//! ```
19//!
20//! ## Usage (XOF)
21//!
22//! ```
23//! use ascon_hash::{AsconXof, ExtendableOutput, Update, XofReader};
24//!
25//! let mut xof = AsconXof::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"\xc2\x19\x72\xfd\xe9");
31//! ```
32
33use core::marker::PhantomData;
34
35use ascon_core::{pad, State};
36pub use digest::{self, Digest, ExtendableOutput, Reset, Update, XofReader};
37use digest::{
38    block_buffer::Eager,
39    consts::{U32, U8},
40    core_api::{
41        AlgorithmName, Block, Buffer, BufferKindUser, CoreWrapper, ExtendableOutputCore,
42        FixedOutputCore, UpdateCore, XofReaderCore, XofReaderCoreWrapper,
43    },
44    crypto_common::BlockSizeUser,
45    HashMarker, Output, OutputSizeUser,
46};
47
48/// Parameters for Ascon hash instances.
49trait HashParameters {
50    /// Number of rounds for the permutation.
51    const ROUNDS: usize;
52    /// Part of the IV.
53    const IV0: u64;
54    /// Part of the IV.
55    const IV1: u64;
56    /// Part of the IV.
57    const IV2: u64;
58    /// Part of the IV.
59    const IV3: u64;
60    /// Part of the IV.
61    const IV4: u64;
62}
63
64/// Parameters for AsconA hash.
65#[derive(Clone, Debug)]
66struct Parameters;
67
68impl HashParameters for Parameters {
69    const ROUNDS: usize = 12;
70    const IV0: u64 = 0xee9398aadb67f03d;
71    const IV1: u64 = 0x8bb21831c60f1002;
72    const IV2: u64 = 0xb48a92db98d5da62;
73    const IV3: u64 = 0x43189921b8f8e3e8;
74    const IV4: u64 = 0x348fa5c9d525e140;
75}
76
77/// Parameters for AsconA hash.
78#[derive(Clone, Debug)]
79struct ParametersA;
80
81impl HashParameters for ParametersA {
82    const ROUNDS: usize = 8;
83    const IV0: u64 = 0x01470194fc6528a6;
84    const IV1: u64 = 0x738ec38ac0adffa7;
85    const IV2: u64 = 0x2ec8e3296c76384c;
86    const IV3: u64 = 0xd6f6a54d7f52377d;
87    const IV4: u64 = 0xa13c42a223be8d87;
88}
89
90#[derive(Clone, Debug)]
91struct ParametersXof;
92
93impl HashParameters for ParametersXof {
94    const ROUNDS: usize = 12;
95    const IV0: u64 = 0xb57e273b814cd416;
96    const IV1: u64 = 0x2b51042562ae2420;
97    const IV2: u64 = 0x66a3a7768ddf2218;
98    const IV3: u64 = 0x5aad0a7a8153650c;
99    const IV4: u64 = 0x4f3e0e32539493b6;
100}
101
102#[derive(Clone, Debug)]
103struct ParametersAXof;
104
105impl HashParameters for ParametersAXof {
106    const ROUNDS: usize = 8;
107    const IV0: u64 = 0x44906568b77b9832;
108    const IV1: u64 = 0xcd8d6cae53455532;
109    const IV2: u64 = 0xf7b5212756422129;
110    const IV3: u64 = 0x246885e1de0d225b;
111    const IV4: u64 = 0xa8cb5ce33449973f;
112}
113
114#[derive(Clone, Debug)]
115struct HashCore<P: HashParameters> {
116    state: State,
117    phantom: PhantomData<P>,
118}
119
120impl<P: HashParameters> HashCore<P> {
121    fn absorb_block(&mut self, block: &[u8; 8]) {
122        self.state[0] ^= u64::from_be_bytes(*block);
123        self.permute_state();
124    }
125
126    fn absorb_last_block(&mut self, block: &[u8]) {
127        debug_assert!(block.len() < 8);
128
129        let len = block.len();
130        if len > 0 {
131            let mut tmp = [0u8; 8];
132            tmp[0..len].copy_from_slice(block);
133            self.state[0] ^= u64::from_be_bytes(tmp);
134        }
135        self.state[0] ^= pad(len);
136        self.state.permute_12();
137    }
138
139    // for fixed-sized output
140    fn squeeze(&mut self, mut block: &mut [u8]) {
141        debug_assert_eq!(block.len() % 8, 0);
142
143        while block.len() > 8 {
144            block[..8].copy_from_slice(&u64::to_be_bytes(self.state[0]));
145            self.permute_state();
146            block = &mut block[8..];
147        }
148        block[..8].copy_from_slice(&u64::to_be_bytes(self.state[0]));
149    }
150
151    // for XOF output
152    fn squeeze_block(&mut self) -> [u8; 8] {
153        let ret = u64::to_be_bytes(self.state[0]);
154        self.permute_state();
155        ret
156    }
157
158    #[inline(always)]
159    fn permute_state(&mut self) {
160        if P::ROUNDS == 12 {
161            self.state.permute_12();
162        } else if P::ROUNDS == 8 {
163            self.state.permute_8();
164        } else if P::ROUNDS == 6 {
165            self.state.permute_6();
166        }
167    }
168}
169
170impl<P: HashParameters> Default for HashCore<P> {
171    fn default() -> Self {
172        Self {
173            state: State::new(P::IV0, P::IV1, P::IV2, P::IV3, P::IV4),
174            phantom: PhantomData,
175        }
176    }
177}
178
179/// Ascon hash implementation
180#[derive(Clone, Debug, Default)]
181pub struct AsconCore {
182    state: HashCore<Parameters>,
183}
184
185impl HashMarker for AsconCore {}
186
187impl BlockSizeUser for AsconCore {
188    type BlockSize = U8;
189}
190
191impl BufferKindUser for AsconCore {
192    type BufferKind = Eager;
193}
194
195impl OutputSizeUser for AsconCore {
196    type OutputSize = U32;
197}
198
199impl UpdateCore for AsconCore {
200    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
201        for block in blocks {
202            self.state.absorb_block(block.as_ref());
203        }
204    }
205}
206
207impl FixedOutputCore for AsconCore {
208    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
209        debug_assert!(buffer.get_pos() < 8);
210        self.state
211            .absorb_last_block(&buffer.get_data()[..buffer.get_pos()]);
212        self.state.squeeze(out);
213    }
214}
215
216impl Reset for AsconCore {
217    fn reset(&mut self) {
218        *self = Default::default();
219    }
220}
221
222impl AlgorithmName for AsconCore {
223    fn write_alg_name(f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
224        f.write_str("AsconHash")
225    }
226}
227
228/// Ascon hash implementation
229#[derive(Clone, Debug, Default)]
230pub struct AsconACore {
231    state: HashCore<ParametersA>,
232}
233
234impl HashMarker for AsconACore {}
235
236impl BlockSizeUser for AsconACore {
237    type BlockSize = U8;
238}
239
240impl BufferKindUser for AsconACore {
241    type BufferKind = Eager;
242}
243
244impl OutputSizeUser for AsconACore {
245    type OutputSize = U32;
246}
247
248impl UpdateCore for AsconACore {
249    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
250        for block in blocks {
251            self.state.absorb_block(block.as_ref());
252        }
253    }
254}
255
256impl FixedOutputCore for AsconACore {
257    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
258        debug_assert!(buffer.get_pos() < 8);
259        self.state
260            .absorb_last_block(&buffer.get_data()[..buffer.get_pos()]);
261        self.state.squeeze(out);
262    }
263}
264
265impl Reset for AsconACore {
266    fn reset(&mut self) {
267        *self = Default::default();
268    }
269}
270
271impl AlgorithmName for AsconACore {
272    fn write_alg_name(f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
273        f.write_str("AsconAHash")
274    }
275}
276
277/// Ascon XOF
278#[derive(Clone, Debug, Default)]
279pub struct AsconXofCore {
280    state: HashCore<ParametersXof>,
281}
282
283impl HashMarker for AsconXofCore {}
284
285impl BlockSizeUser for AsconXofCore {
286    type BlockSize = U8;
287}
288
289impl BufferKindUser for AsconXofCore {
290    type BufferKind = Eager;
291}
292
293impl UpdateCore for AsconXofCore {
294    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
295        for block in blocks {
296            self.state.absorb_block(block.as_ref());
297        }
298    }
299}
300
301/// Reader for XOF output
302#[derive(Clone, Debug)]
303pub struct AsconXofReaderCore {
304    hasher: HashCore<ParametersXof>,
305}
306
307impl BlockSizeUser for AsconXofReaderCore {
308    type BlockSize = U8;
309}
310
311impl XofReaderCore for AsconXofReaderCore {
312    fn read_block(&mut self) -> Block<Self> {
313        self.hasher.squeeze_block().into()
314    }
315}
316
317impl ExtendableOutputCore for AsconXofCore {
318    type ReaderCore = AsconXofReaderCore;
319
320    fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
321        debug_assert!(buffer.get_pos() < 8);
322        self.state
323            .absorb_last_block(&buffer.get_data()[..buffer.get_pos()]);
324        Self::ReaderCore {
325            hasher: self.state.clone(),
326        }
327    }
328}
329
330impl Reset for AsconXofCore {
331    fn reset(&mut self) {
332        *self = Default::default();
333    }
334}
335
336impl AlgorithmName for AsconXofCore {
337    fn write_alg_name(f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
338        f.write_str("AsconXOF")
339    }
340}
341
342/// AsconA XOF
343#[derive(Clone, Debug, Default)]
344pub struct AsconAXofCore {
345    state: HashCore<ParametersAXof>,
346}
347
348impl HashMarker for AsconAXofCore {}
349
350impl BlockSizeUser for AsconAXofCore {
351    type BlockSize = U8;
352}
353
354impl BufferKindUser for AsconAXofCore {
355    type BufferKind = Eager;
356}
357
358impl UpdateCore for AsconAXofCore {
359    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
360        for block in blocks {
361            self.state.absorb_block(block.as_ref());
362        }
363    }
364}
365
366/// Reader for XOF output
367#[derive(Clone, Debug)]
368pub struct AsconAXofReaderCore {
369    hasher: HashCore<ParametersAXof>,
370}
371
372impl BlockSizeUser for AsconAXofReaderCore {
373    type BlockSize = U8;
374}
375
376impl XofReaderCore for AsconAXofReaderCore {
377    fn read_block(&mut self) -> Block<Self> {
378        self.hasher.squeeze_block().into()
379    }
380}
381
382impl ExtendableOutputCore for AsconAXofCore {
383    type ReaderCore = AsconAXofReaderCore;
384
385    fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
386        debug_assert!(buffer.get_pos() < 8);
387        self.state
388            .absorb_last_block(&buffer.get_data()[..buffer.get_pos()]);
389        Self::ReaderCore {
390            hasher: self.state.clone(),
391        }
392    }
393}
394
395impl Reset for AsconAXofCore {
396    fn reset(&mut self) {
397        *self = Default::default();
398    }
399}
400
401impl AlgorithmName for AsconAXofCore {
402    fn write_alg_name(f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
403        f.write_str("AsconAXOF")
404    }
405}
406
407/// Ascon hash
408///
409/// ```
410/// use ascon_hash::{AsconHash, Digest};
411///
412/// let mut hasher = AsconHash::new();
413/// hasher.update(b"some bytes");
414/// let digest = hasher.finalize();
415/// assert_eq!(&digest[..], b"\xb7\x42\xca\x75\xe5\x70\x38\x75\x70\x59\xcc\xcc\x68\x74\x71\x4f\x9d\xbd\x7f\xc5\x92\x4a\x7d\xf4\xe3\x16\x59\x4f\xd1\x42\x6c\xa8");
416/// ```
417pub type AsconHash = CoreWrapper<AsconCore>;
418/// AsconA hash
419///
420/// ```
421/// use ascon_hash::{AsconAHash, Digest};
422///
423/// let mut hasher = AsconAHash::new();
424/// hasher.update(b"some bytes");
425/// let digest = hasher.finalize();
426/// assert_eq!(&digest[..], b"\x1d\x1a\xc8\x74\x4a\x4a\x05\x81\x33\x7d\x5a\xf2\x78\xc2\x55\x88\xe1\xa3\xdd\x2d\x86\x73\x07\x64\x26\x53\xdc\xa4\x45\xf5\x5c\x2a");
427/// ```
428pub type AsconAHash = CoreWrapper<AsconACore>;
429/// AsconXof
430///
431/// ```
432/// use ascon_hash::{AsconXof, ExtendableOutput, Update, XofReader};
433///
434/// let mut xof = AsconXof::default();
435/// xof.update(b"some bytes");
436/// let mut reader = xof.finalize_xof();
437/// let mut dst = [0u8; 5];
438/// reader.read(&mut dst);
439/// assert_eq!(&dst, b"\xc2\x19\x72\xfd\xe9");
440/// ```
441pub type AsconXof = CoreWrapper<AsconXofCore>;
442/// Reader for AsconXof output
443pub type AsconXofReader = XofReaderCoreWrapper<AsconXofReaderCore>;
444/// AsconAXof
445///
446/// ```
447/// use ascon_hash::{AsconAXof, ExtendableOutput, Update, XofReader};
448///
449/// let mut xof = AsconAXof::default();
450/// xof.update(b"some bytes");
451/// let mut reader = xof.finalize_xof();
452/// let mut dst = [0u8; 5];
453/// reader.read(&mut dst);
454/// assert_eq!(&dst, b"\xb8\xd6\xbd\xf0\xa7");
455/// ```
456pub type AsconAXof = CoreWrapper<AsconAXofCore>;
457/// Reader for AsconAXof output
458pub type AsconAXofReader = XofReaderCoreWrapper<AsconAXofReaderCore>;