/* * Copyright (C) 2021 Southern Storm Software, Pty Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef LW_INTERNAL_ASCON_H #define LW_INTERNAL_ASCON_H #include "internal-util.h" /** * \file internal-ascon.h * \brief Internal implementation of the ASCON permutation. * * References: http://competitions.cr.yp.to/round3/asconv12.pdf, * http://ascon.iaik.tugraz.at/ */ #ifdef __cplusplus extern "C" { #endif /** * \brief Defined to 1 if the 32-bit sliced version of ASCON is preferred. */ #if !defined(__AVR__) && !defined(LW_UTIL_CPU_IS_64BIT) #define ASCON_SLICED 1 #else #define ASCON_SLICED 0 #endif /** * \brief Initialization vector for ASCON-128. */ #define ASCON128_IV 0x80400c0600000000ULL /** * \brief Initialization vector for ASCON-128a. */ #define ASCON128a_IV 0x80800c0800000000ULL /** * \brief Initialization vector for ASCON-80pq. */ #define ASCON80PQ_IV 0xa0400c06U /** * \brief Structure of the internal state of the ASCON permutation. */ typedef union { uint64_t S[5]; /**< 64-bit words of the state */ uint32_t W[10]; /**< 32-bit words of the state */ uint8_t B[40]; /**< Bytes of the state */ } ascon_state_t; /** * \brief Permutes the ASCON state. * * \param state The ASCON state to be permuted. * \param first_round The first round (of 12) to be performed; 0, 4, or 6. * * The input and output \a state will be in big-endian byte order. */ void ascon_permute(ascon_state_t *state, uint8_t first_round); #if ASCON_SLICED /** * \brief Converts an ASCON state from byte form into sliced form. * * \param state The ASCON state to be converted, in big-endian byte order * on entry and in host byte order on exit. */ void ascon_to_sliced(ascon_state_t *state); /** * \brief Converts an ASCON state from sliced form into byte form. * * \param state The ASCON state to be converted, in host byte order * on entry and in big-endian byte order on exit. */ void ascon_from_sliced(ascon_state_t *state); /** * \brief Permutes the ASCON state in sliced form. * * \param state The ASCON state to be permuted. * \param first_round The first round (of 12) to be performed; 0, 4, or 6. * * The input and output \a state will be in host byte order. */ void ascon_permute_sliced(ascon_state_t *state, uint8_t first_round); /** @cond ascon_bit_separation */ /* http://programming.sirrida.de/perm_fn.html#bit_permute_step */ #define ascon_bit_permute_step(_y, mask, shift) \ do { \ uint32_t y = (_y); \ uint32_t t = ((y >> (shift)) ^ y) & (mask); \ (_y) = (y ^ t) ^ (t << (shift)); \ } while (0) /* Separates a 32-bit word into two 16-bit halves with all the even * bits in the bottom half and all the odd bits in the top half. * * Permutation generated with "http://programming.sirrida.de/calcperm.php" * * P = [0 16 1 17 2 18 3 19 4 20 5 21 6 22 7 23 8 24 * 9 25 10 26 11 27 12 28 13 29 14 30 15 31] */ #define ascon_separate(x) \ do { \ ascon_bit_permute_step((x), 0x22222222, 1); \ ascon_bit_permute_step((x), 0x0c0c0c0c, 2); \ ascon_bit_permute_step((x), 0x00f000f0, 4); \ ascon_bit_permute_step((x), 0x0000ff00, 8); \ } while (0) #define ascon_combine(x) \ do { \ ascon_bit_permute_step((x), 0x0000aaaa, 15); \ ascon_bit_permute_step((x), 0x0000cccc, 14); \ ascon_bit_permute_step((x), 0x0000f0f0, 12); \ ascon_bit_permute_step((x), 0x0000ff00, 8); \ } while (0) /** @endcond */ /** * \brief Sets data into the ASCON state in sliced form. * * \param state The ASCON state for the data to be absorbed into. * \param data Points to 8 bytes of data in big-endian byte order to set. * \param offset Offset of the 64-bit word within the state to set at, * between 0 and 4. */ #define ascon_set_sliced(state, data, offset) \ do { \ ascon_state_t *s = (state); \ uint32_t high = be_load_word32((data)); \ uint32_t low = be_load_word32((data) + 4); \ ascon_separate(high); \ ascon_separate(low); \ s->W[(offset) * 2] = (high << 16) | (low & 0x0000FFFFU); \ s->W[(offset) * 2 + 1] = (high & 0xFFFF0000U) | (low >> 16); \ } while (0) /** * \brief Absorbs data into the ASCON state in sliced form. * * \param state The ASCON state for the data to be absorbed into. * \param data Points to 8 bytes of data in big-endian byte order to absorb. * \param offset Offset of the 64-bit word within the state to absorb at, * between 0 and 4. */ #define ascon_absorb_sliced(state, data, offset) \ do { \ ascon_state_t *s = (state); \ uint32_t high = be_load_word32((data)); \ uint32_t low = be_load_word32((data) + 4); \ ascon_separate(high); \ ascon_separate(low); \ s->W[(offset) * 2] ^= (high << 16) | (low & 0x0000FFFFU); \ s->W[(offset) * 2 + 1] ^= (high & 0xFFFF0000U) | (low >> 16); \ } while (0) /** * \brief Absorbs 32 bits of data into the ASCON state in sliced form. * * \param state The ASCON state for the data to be absorbed into. * \param data Points to 4 bytes of data in big-endian byte order to absorb. * \param offset Offset of the 64-bit word within the state to absorb at, * between 0 and 4. * * The data is absorbed into the low bits of the 64-bit word at \a offset. */ #define ascon_absorb32_low_sliced(state, data, offset) \ do { \ ascon_state_t *s = (state); \ uint32_t low = be_load_word32((data)); \ ascon_separate(low); \ s->W[(offset) * 2] ^= (low & 0x0000FFFFU); \ s->W[(offset) * 2 + 1] ^= (low >> 16); \ } while (0) /** * \brief Absorbs 32 bits of data into the ASCON state in sliced form. * * \param state The ASCON state for the data to be absorbed into. * \param data Points to 4 bytes of data in big-endian byte order to absorb. * \param offset Offset of the 64-bit word within the state to absorb at, * between 0 and 4. * * The data is absorbed into the high bits of the 64-bit word at \a offset. */ #define ascon_absorb32_high_sliced(state, data, offset) \ do { \ ascon_state_t *s = (state); \ uint32_t high = be_load_word32((data)); \ ascon_separate(high); \ s->W[(offset) * 2] ^= (high << 16); \ s->W[(offset) * 2 + 1] ^= (high & 0xFFFF0000U); \ } while (0) /** * \brief Squeezes data from the ASCON state in sliced form. * * \param state The ASCON state to extract the data from. * \param data Points to the 8 bytes to be extracted from the state. * \param offset Offset of the 64-bit word within the state to extract, * between 0 and 4. */ #define ascon_squeeze_sliced(state, data, offset) \ do { \ ascon_state_t *s = (state); \ uint32_t high, low; \ high = (s->W[(offset) * 2] >> 16) | \ (s->W[(offset) * 2 + 1] & 0xFFFF0000U); \ low = (s->W[(offset) * 2] & 0x0000FFFFU) | \ (s->W[(offset) * 2 + 1] << 16); \ ascon_combine(high); \ ascon_combine(low); \ be_store_word32((data), high); \ be_store_word32((data) + 4, low); \ } while (0) /** * \brief Encrypts data using the ASCON state in sliced form. * * \param state The ASCON state. * \param c Points to 8 bytes of output ciphertext in big-endian byte order. * \param m Points to 8 bytes of input plaintext in big-endian byte order. * \param offset Offset of the 64-bit word within the state to absorb * and squeeze at, between 0 and 4. */ #define ascon_encrypt_sliced(state, c, m, offset) \ do { \ ascon_state_t *s = (state); \ uint32_t high = be_load_word32((m)); \ uint32_t low = be_load_word32((m) + 4); \ ascon_separate(high); \ ascon_separate(low); \ s->W[(offset) * 2] ^= (high << 16) | (low & 0x0000FFFFU); \ s->W[(offset) * 2 + 1] ^= (high & 0xFFFF0000U) | (low >> 16); \ high = (s->W[(offset) * 2] >> 16) | \ (s->W[(offset) * 2 + 1] & 0xFFFF0000U); \ low = (s->W[(offset) * 2] & 0x0000FFFFU) | \ (s->W[(offset) * 2 + 1] << 16); \ ascon_combine(high); \ ascon_combine(low); \ be_store_word32((c), high); \ be_store_word32((c) + 4, low); \ } while (0) /** * \brief Decrypts data using the ASCON state in sliced form. * * \param state The ASCON state. * \param m Points to 8 bytes of output plaintext in big-endian byte order. * \param c Points to 8 bytes of input ciphertext in big-endian byte order. * \param offset Offset of the 64-bit word within the state to absorb * and squeeze at, between 0 and 4. */ #define ascon_decrypt_sliced(state, m, c, offset) \ do { \ ascon_state_t *s = (state); \ uint32_t high, low, high2, low2; \ high = be_load_word32((c)); \ low = be_load_word32((c) + 4); \ ascon_separate(high); \ ascon_separate(low); \ high2 = high ^ ((s->W[(offset) * 2] >> 16) | \ (s->W[(offset) * 2 + 1] & 0xFFFF0000U)); \ low2 = low ^ ((s->W[(offset) * 2] & 0x0000FFFFU) | \ (s->W[(offset) * 2 + 1] << 16)); \ s->W[(offset) * 2] = (high << 16) | (low & 0x0000FFFFU); \ s->W[(offset) * 2 + 1] = (high & 0xFFFF0000U) | (low >> 16); \ ascon_combine(high2); \ ascon_combine(low2); \ be_store_word32((m), high2); \ be_store_word32((m) + 4, low2); \ } while (0) #endif /* ASCON_SLICED */ /** * \def ascon_separator() * \brief Absorbs the standard ASCON separator for switching between * associated data and message payload. */ #if ASCON_SLICED #define ascon_separator() (state.W[8] ^= 0x01) #else #define ascon_separator() (state.B[39] ^= 0x01) #endif #ifdef __cplusplus } #endif #endif