Skip to main content

ascon/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
7)]
8#![forbid(unsafe_code)]
9
10/// Compute round constant
11#[inline(always)]
12const fn round_constant(round: u64) -> u64 {
13    ((0xFu64 - round) << 4) | round
14}
15
16/// Maximum number of rounds supported by the Ascon permutation.
17const MAX_ROUNDS: usize = 12;
18
19/// Ascon's permutation state
20pub type State = [u64; 5];
21
22/// Ascon's round function
23#[inline(always)]
24const fn round(state: &mut State, c: u64) {
25    let [mut x0, mut x1, mut x2, mut x3, mut x4] = *state;
26
27    // Addition of round constant
28    x2 ^= c;
29
30    // Substitution Layer.
31    // BGC Optimized Implementations from:
32    // Optimizing S-box Implementations Using SAT Solvers: Revisited
33    // https://eprint.iacr.org/2023/1721.pdf
34    let t0 = x0 ^ x4;
35    let t1 = !x4;
36    let t2 = t1 | x3;
37    let t3 = x1 ^ x2;
38    let t4 = x3 ^ x2;
39    let t5 = x3 ^ x4;
40    let t6 = t0 | x1;
41    let t7 = x0 | t5;
42    let t8 = t4 | t3;
43    x1 = t0 ^ t8;
44    x3 = t3 ^ t7;
45    let t11 = x2 & t3;
46    let t12 = t6 ^ t5;
47    x2 = t3 ^ t2;
48    x0 = t12 ^ t11;
49    x4 = t0 ^ t12;
50
51    // Linear Diffusion Layer
52    *state = [
53        x0 ^ x0.rotate_right(19) ^ x0.rotate_right(28),
54        x1 ^ x1.rotate_right(61) ^ x1.rotate_right(39),
55        x2 ^ x2.rotate_right(1) ^ x2.rotate_right(6),
56        x3 ^ x3.rotate_right(10) ^ x3.rotate_right(17),
57        x4 ^ x4.rotate_right(7) ^ x4.rotate_right(41),
58    ];
59}
60
61/// Apply Ascon permutation with the given number of rounds.
62///
63/// Results in a compilation error if `ROUNDS` is greater than 12.
64#[inline]
65pub const fn permute<const ROUNDS: usize>(state: &mut State) {
66    const { assert!(ROUNDS <= MAX_ROUNDS) };
67
68    #[cfg(not(ascon_backend = "soft-compact"))]
69    {
70        macro_rules! unroll_round {
71            ($state:ident, $round:literal, $rounds:expr) => {
72                if $round >= MAX_ROUNDS - $rounds {
73                    let rc = round_constant($round);
74                    round($state, rc);
75                }
76            };
77        }
78
79        unroll_round!(state, 0, ROUNDS);
80        unroll_round!(state, 1, ROUNDS);
81        unroll_round!(state, 2, ROUNDS);
82        unroll_round!(state, 3, ROUNDS);
83        unroll_round!(state, 4, ROUNDS);
84        unroll_round!(state, 5, ROUNDS);
85        unroll_round!(state, 6, ROUNDS);
86        unroll_round!(state, 7, ROUNDS);
87        unroll_round!(state, 8, ROUNDS);
88        unroll_round!(state, 9, ROUNDS);
89        unroll_round!(state, 10, ROUNDS);
90        unroll_round!(state, 11, ROUNDS);
91    }
92
93    #[cfg(ascon_backend = "soft-compact")]
94    {
95        let mut i = MAX_ROUNDS - ROUNDS;
96        while i < MAX_ROUNDS {
97            round(state, round_constant(i as u64));
98            i += 1;
99        }
100    }
101}
102
103/// Apply Ascon permutation with 12 rounds.
104#[inline]
105pub const fn permute12(state: &mut State) {
106    permute::<12>(state);
107}
108
109/// Apply Ascon permutation with 8 rounds.
110#[inline]
111pub const fn permute8(state: &mut State) {
112    permute::<8>(state);
113}
114
115/// Apply Ascon permutation with 6 rounds.
116#[inline]
117pub const fn permute6(state: &mut State) {
118    permute::<6>(state);
119}