ascon_core/
lib.rs

1// Copyright 2021-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#![forbid(unsafe_code)]
8#![warn(missing_docs)]
9
10use core::{
11    mem::size_of,
12    ops::{Index, IndexMut},
13};
14
15#[cfg(feature = "zeroize")]
16use zeroize::{Zeroize, ZeroizeOnDrop};
17
18/// Compute round constant
19#[inline(always)]
20const fn round_constant(round: u64) -> u64 {
21    ((0xfu64 - round) << 4) | round
22}
23
24#[cfg(not(ascon_impl = "no_unroll"))]
25macro_rules! apply_permutation {
26    ($state:expr, $rc:literal) => {
27        round($state, $rc)
28    };
29    ($state:expr, $rc:literal, $($rcs:literal),+) => {
30        apply_permutation!(round($state, $rc), $($rcs),+)
31    };
32}
33
34#[cfg(ascon_impl = "no_unroll")]
35macro_rules! apply_permutation {
36    ($state:expr, $($rcs:literal),+) => {
37        [$($rcs),+].into_iter().fold($state, round)
38    };
39}
40
41/// The state of Ascon's permutation.
42///
43/// The permutation operates on a state of 320 bits represented as 5 64 bit words.
44#[derive(Clone, Debug, Default)]
45#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))]
46pub struct State {
47    x: [u64; 5],
48}
49
50/// Ascon's round function
51const fn round(x: [u64; 5], c: u64) -> [u64; 5] {
52    // S-box layer
53    let x0 = x[0] ^ x[4];
54    let x2 = x[2] ^ x[1] ^ c; // with round constant
55    let x4 = x[4] ^ x[3];
56
57    let tx0 = x0 ^ (!x[1] & x2);
58    let tx1 = x[1] ^ (!x2 & x[3]);
59    let tx2 = x2 ^ (!x[3] & x4);
60    let tx3 = x[3] ^ (!x4 & x0);
61    let tx4 = x4 ^ (!x0 & x[1]);
62    let tx1 = tx1 ^ tx0;
63    let tx3 = tx3 ^ tx2;
64    let tx0 = tx0 ^ tx4;
65
66    // linear layer
67    let x0 = tx0 ^ tx0.rotate_right(9);
68    let x1 = tx1 ^ tx1.rotate_right(22);
69    let x2 = tx2 ^ tx2.rotate_right(5);
70    let x3 = tx3 ^ tx3.rotate_right(7);
71    let x4 = tx4 ^ tx4.rotate_right(34);
72    [
73        tx0 ^ x0.rotate_right(19),
74        tx1 ^ x1.rotate_right(39),
75        !(tx2 ^ x2.rotate_right(1)),
76        tx3 ^ x3.rotate_right(10),
77        tx4 ^ x4.rotate_right(7),
78    ]
79}
80
81impl State {
82    /// Instantiate new state from the given values.
83    pub fn new(x0: u64, x1: u64, x2: u64, x3: u64, x4: u64) -> Self {
84        State {
85            x: [x0, x1, x2, x3, x4],
86        }
87    }
88
89    /// Perform permutation with 12 rounds.
90    pub fn permute_12(&mut self) {
91        self.x = apply_permutation!(
92            self.x, 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b
93        );
94    }
95
96    /// Perform permutation with 8 rounds.
97    pub fn permute_8(&mut self) {
98        self.x = apply_permutation!(self.x, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b);
99    }
100
101    #[cfg(feature = "permute_6")]
102    /// Perform permutation with 6 rounds.
103    pub fn permute_6(&mut self) {
104        self.x = apply_permutation!(self.x, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b);
105    }
106
107    #[cfg(feature = "permute_1")]
108    /// Perform permutation with 1 round
109    pub fn permute_1(&mut self) {
110        self.x = round(self.x, 0x4b);
111    }
112
113    /// Perform a given number (up to 12) of permutations
114    ///
115    /// Panics (in debug mode) if `rounds` is larger than 12.
116    pub fn permute_n(&mut self, rounds: usize) {
117        debug_assert!(rounds <= 12);
118
119        let start = 12 - rounds;
120        self.x = (start..12).fold(self.x, |x, round_index| {
121            round(x, round_constant(round_index as u64))
122        });
123    }
124
125    /// Convert state to bytes.
126    pub fn as_bytes(&self) -> [u8; 40] {
127        let mut bytes = [0u8; size_of::<u64>() * 5];
128        for (dst, src) in bytes
129            .chunks_exact_mut(size_of::<u64>())
130            .zip(self.x.into_iter())
131        {
132            dst.copy_from_slice(&u64::to_be_bytes(src));
133        }
134        bytes
135    }
136}
137
138impl Index<usize> for State {
139    type Output = u64;
140
141    #[inline(always)]
142    fn index(&self, index: usize) -> &Self::Output {
143        &self.x[index]
144    }
145}
146
147impl IndexMut<usize> for State {
148    #[inline(always)]
149    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
150        &mut self.x[index]
151    }
152}
153
154impl TryFrom<&[u64]> for State {
155    type Error = ();
156
157    fn try_from(value: &[u64]) -> Result<Self, Self::Error> {
158        match value.len() {
159            5 => Ok(Self::new(value[0], value[1], value[2], value[3], value[4])),
160            _ => Err(()),
161        }
162    }
163}
164
165impl From<&[u64; 5]> for State {
166    fn from(value: &[u64; 5]) -> Self {
167        Self { x: *value }
168    }
169}
170
171impl TryFrom<&[u8]> for State {
172    type Error = ();
173
174    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
175        if value.len() != core::mem::size_of::<u64>() * 5 {
176            return Err(());
177        }
178
179        let mut state = Self::default();
180        for (src, dst) in value
181            .chunks_exact(core::mem::size_of::<u64>())
182            .zip(state.x.iter_mut())
183        {
184            *dst = u64::from_be_bytes(src.try_into().unwrap());
185        }
186        Ok(state)
187    }
188}
189
190impl From<&[u8; size_of::<u64>() * 5]> for State {
191    fn from(value: &[u8; size_of::<u64>() * 5]) -> Self {
192        let mut state = Self::default();
193        for (src, dst) in value
194            .chunks_exact(core::mem::size_of::<u64>())
195            .zip(state.x.iter_mut())
196        {
197            *dst = u64::from_be_bytes(src.try_into().unwrap());
198        }
199        state
200    }
201}
202
203impl AsRef<[u64]> for State {
204    fn as_ref(&self) -> &[u64] {
205        &self.x
206    }
207}
208
209#[cfg(test)]
210mod tests {
211    use super::*;
212
213    #[test]
214    fn round_constants() {
215        assert_eq!(round_constant(0), 0xf0);
216        assert_eq!(round_constant(1), 0xe1);
217        assert_eq!(round_constant(2), 0xd2);
218        assert_eq!(round_constant(3), 0xc3);
219        assert_eq!(round_constant(4), 0xb4);
220        assert_eq!(round_constant(5), 0xa5);
221        assert_eq!(round_constant(6), 0x96);
222        assert_eq!(round_constant(7), 0x87);
223        assert_eq!(round_constant(8), 0x78);
224        assert_eq!(round_constant(9), 0x69);
225        assert_eq!(round_constant(10), 0x5a);
226        assert_eq!(round_constant(11), 0x4b);
227    }
228
229    #[test]
230    fn one_round() {
231        let state = round(
232            [
233                0x0123456789abcdef,
234                0x23456789abcdef01,
235                0x456789abcdef0123,
236                0x6789abcdef012345,
237                0x89abcde01234567f,
238            ],
239            0x1f,
240        );
241        assert_eq!(
242            state,
243            [
244                0x3c1748c9be2892ce,
245                0x5eafb305cd26164f,
246                0xf9470254bb3a4213,
247                0xf0428daf0c5d3948,
248                0x281375af0b294899
249            ]
250        );
251    }
252
253    #[test]
254    fn state_permute_12() {
255        let mut state = State::new(
256            0x0123456789abcdef,
257            0xef0123456789abcd,
258            0xcdef0123456789ab,
259            0xabcdef0123456789,
260            0x89abcdef01234567,
261        );
262        state.permute_12();
263        assert_eq!(state[0], 0x206416dfc624bb14);
264        assert_eq!(state[1], 0x1b0c47a601058aab);
265        assert_eq!(state[2], 0x8934cfc93814cddd);
266        assert_eq!(state[3], 0xa9738d287a748e4b);
267        assert_eq!(state[4], 0xddd934f058afc7e1);
268    }
269
270    #[test]
271    fn state_permute_8() {
272        let mut state = State::new(
273            0x0123456789abcdef,
274            0xef0123456789abcd,
275            0xcdef0123456789ab,
276            0xabcdef0123456789,
277            0x89abcdef01234567,
278        );
279        state.permute_8();
280        assert_eq!(state[0], 0x67ed228272f46eee);
281        assert_eq!(state[1], 0x80bc0b097aad7944);
282        assert_eq!(state[2], 0x2fa599382c6db215);
283        assert_eq!(state[3], 0x368133fae2f7667a);
284        assert_eq!(state[4], 0x28cefb195a7c651c);
285    }
286
287    #[cfg(feature = "permute_6")]
288    #[test]
289    fn state_permute_6() {
290        let mut state = State::new(
291            0x0123456789abcdef,
292            0xef0123456789abcd,
293            0xcdef0123456789ab,
294            0xabcdef0123456789,
295            0x89abcdef01234567,
296        );
297        state.permute_6();
298        assert_eq!(state[0], 0xc27b505c635eb07f);
299        assert_eq!(state[1], 0xd388f5d2a72046fa);
300        assert_eq!(state[2], 0x9e415c204d7b15e7);
301        assert_eq!(state[3], 0xce0d71450fe44581);
302        assert_eq!(state[4], 0xdd7c5fef57befe48);
303    }
304
305    #[test]
306    fn state_permute_n() {
307        let mut state = State::new(
308            0x0123456789abcdef,
309            0xef0123456789abcd,
310            0xcdef0123456789ab,
311            0xabcdef0123456789,
312            0x89abcdef01234567,
313        );
314        let mut state2 = state.clone();
315
316        #[cfg(feature = "permute_6")]
317        {
318            state.permute_6();
319            state2.permute_n(6);
320            assert_eq!(state.x, state2.x);
321        }
322
323        state.permute_8();
324        state2.permute_n(8);
325        assert_eq!(state.x, state2.x);
326
327        state.permute_12();
328        state2.permute_n(12);
329        assert_eq!(state.x, state2.x);
330    }
331
332    #[test]
333    fn state_convert_bytes() {
334        let state = State::new(
335            0x0123456789abcdef,
336            0xef0123456789abcd,
337            0xcdef0123456789ab,
338            0xabcdef0123456789,
339            0x89abcdef01234567,
340        );
341        let bytes = state.as_bytes();
342
343        // test TryFrom<&[u8]>
344        let state2 = State::try_from(&bytes[..]);
345        assert_eq!(state2.expect("try_from bytes").x, state.x);
346
347        let state2 = State::from(&bytes);
348        assert_eq!(state2.x, state.x);
349    }
350}