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