ascon_core/
lib.rs

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