Skip to main content

ascon_hash256/
block_api.rs

1use ascon::State;
2use digest::{
3    HashMarker, Output, OutputSizeUser, Reset,
4    block_api::{
5        AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, Eager, FixedOutputCore,
6        UpdateCore,
7    },
8    common::hazmat::{DeserializeStateError, SerializableState, SerializedState},
9    consts::{U8, U32, U40},
10};
11
12const IV: u64 = 0x0000_0801_00CC_0002;
13
14/// Initial state of Ascon-Hash256
15const INIT_STATE: State = {
16    let mut state = [IV, 0, 0, 0, 0];
17    ascon::permute12(&mut state);
18    state
19};
20
21/// Ascon-Hash256 block-level hasher
22#[derive(Clone, Debug)]
23pub struct AsconHash256Core {
24    state: State,
25}
26
27impl Default for AsconHash256Core {
28    #[inline]
29    fn default() -> Self {
30        Self { state: INIT_STATE }
31    }
32}
33
34impl HashMarker for AsconHash256Core {}
35
36impl BlockSizeUser for AsconHash256Core {
37    type BlockSize = U8;
38}
39
40impl BufferKindUser for AsconHash256Core {
41    type BufferKind = Eager;
42}
43
44impl OutputSizeUser for AsconHash256Core {
45    type OutputSize = U32;
46}
47
48impl UpdateCore for AsconHash256Core {
49    #[inline]
50    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
51        for block in blocks {
52            self.state[0] ^= u64::from_le_bytes(block.0);
53            ascon::permute12(&mut self.state);
54        }
55    }
56}
57
58impl FixedOutputCore for AsconHash256Core {
59    #[inline]
60    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
61        let len = buffer.get_pos();
62        let last_block = buffer.pad_with_zeros();
63        let pad = 1u64 << (8 * len);
64        self.state[0] ^= u64::from_le_bytes(last_block.0) ^ pad;
65
66        ascon::permute12(&mut self.state);
67
68        let mut chunks = out.chunks_exact_mut(size_of::<u64>());
69        for chunk in &mut chunks {
70            chunk.copy_from_slice(&self.state[0].to_le_bytes());
71            ascon::permute12(&mut self.state);
72        }
73        assert!(chunks.into_remainder().is_empty());
74    }
75}
76
77impl Reset for AsconHash256Core {
78    #[inline]
79    fn reset(&mut self) {
80        self.state = INIT_STATE;
81    }
82}
83
84impl AlgorithmName for AsconHash256Core {
85    #[inline]
86    fn write_alg_name(f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
87        f.write_str("Ascon-Hash256")
88    }
89}
90
91impl SerializableState for AsconHash256Core {
92    type SerializedStateSize = U40;
93
94    #[inline]
95    fn serialize(&self) -> SerializedState<Self> {
96        let mut res = SerializedState::<Self>::default();
97        let mut chunks = res.chunks_exact_mut(size_of::<u64>());
98        for (src, dst) in self.state.iter().zip(&mut chunks) {
99            dst.copy_from_slice(&src.to_le_bytes());
100        }
101        assert!(chunks.into_remainder().is_empty());
102        res
103    }
104
105    #[inline]
106    fn deserialize(
107        serialized_state: &SerializedState<Self>,
108    ) -> Result<Self, DeserializeStateError> {
109        let state = core::array::from_fn(|i| {
110            let n = size_of::<u64>();
111            let chunk = &serialized_state[n * i..][..n];
112            u64::from_le_bytes(chunk.try_into().expect("chunk has correct length"))
113        });
114        Ok(Self { state })
115    }
116}
117
118impl Drop for AsconHash256Core {
119    #[inline]
120    fn drop(&mut self) {
121        #[cfg(feature = "zeroize")]
122        {
123            use digest::zeroize::Zeroize;
124            self.state.zeroize()
125        }
126    }
127}
128
129#[cfg(feature = "zeroize")]
130impl digest::zeroize::ZeroizeOnDrop for AsconHash256Core {}