#ifndef ALCRYPTOLIB_STREAM_HASH_HASH_GOST_2019_04_25_H #define ALCRYPTOLIB_STREAM_HASH_HASH_GOST_2019_04_25_H #include #include #include // A macro that performs a full encryption round of GOST 28147-89. // Temporary variable t assumed and variables r and l for left and right // blocks #if defined(AL_CRYPTO_CFG_GOST_USE_MACROS) #define GOST_ENCRYPT_ROUND(k1, k2) \ t = (k1) + r; \ l ^= gost_sbox_1()[(t >> 0U) & 0xFFU] \ ^ gost_sbox_2()[(t >> 8U) & 0xFFU] \ ^ gost_sbox_3()[(t >> 16U) & 0xFFU] \ ^ gost_sbox_4()[(t >> 24U)]; \ t = (k2) + l; \ r ^= gost_sbox_1()[(t >> 0U) & 0xFFU] \ ^ gost_sbox_2()[(t >> 8U) & 0xFFU] \ ^ gost_sbox_3()[(t >> 16U) & 0xFFU] \ ^ gost_sbox_4()[ t >> 24U]; // encrypt a block with the given key #define GOST_ENCRYPT(key) \ GOST_ENCRYPT_ROUND(key[0U], key[1U]) \ GOST_ENCRYPT_ROUND(key[2U], key[3U]) \ GOST_ENCRYPT_ROUND(key[4U], key[5U]) \ GOST_ENCRYPT_ROUND(key[6U], key[7U]) \ GOST_ENCRYPT_ROUND(key[0U], key[1U]) \ GOST_ENCRYPT_ROUND(key[2U], key[3U]) \ GOST_ENCRYPT_ROUND(key[4U], key[5U]) \ GOST_ENCRYPT_ROUND(key[6U], key[7U]) \ GOST_ENCRYPT_ROUND(key[0U], key[1U]) \ GOST_ENCRYPT_ROUND(key[2U], key[3U]) \ GOST_ENCRYPT_ROUND(key[4U], key[5U]) \ GOST_ENCRYPT_ROUND(key[6U], key[7U]) \ GOST_ENCRYPT_ROUND(key[7U], key[6U]) \ GOST_ENCRYPT_ROUND(key[5U], key[4U]) \ GOST_ENCRYPT_ROUND(key[3U], key[2U]) \ GOST_ENCRYPT_ROUND(key[1U], key[0U]) \ t = r; \ r = l; \ l = t; #endif // AL_CRYPTO_CFG_GOST_USE_MACROS // Gost transforms messages of different lengths // into a specific result, having 256 bit width. #if(__cplusplus >= 201703L) namespace al::crypto::stream::hash { #else namespace al { namespace crypto { namespace stream { namespace hash { #endif class hash_gost // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) : public al::crypto::stream::hash::hash_base<256U, 256U, std::uint32_t, 32U> { private: using base_class_type = al::crypto::stream::hash::hash_base<256U, 256U, std::uint32_t, 32U>; public: hash_gost() : local_sum() { local_sum.fill(0U); if(!gost_is_initialized()) { gosthash_init(); gost_is_initialized() = true; } } hash_gost(const hash_gost& other) : base_class_type(other), local_sum(other.local_sum) { if(!gost_is_initialized()) { gosthash_init(); gost_is_initialized() = true; } } auto operator=(const hash_gost& other) -> hash_gost& { if(!gost_is_initialized()) { gosthash_init(); gost_is_initialized() = true; } static_cast(base_class_type::operator=(other)); if(this != &other) { local_sum = other.local_sum; } return *this; } ~hash_gost() override = default; auto initialize() -> void override { base_class_type::initialize(); local_sum.fill(0U); } auto finalize() -> void override { // Adjust (TBD: adjust what?) and mix in the last chunk. if(base_class_type::message_index > 0) { // Clear the unused bytes in the message buffer. std::fill(base_class_type::message_buffer.begin() + static_cast(base_class_type::message_index), base_class_type::message_buffer.end(), 0U); transform(); } // mix in the length and the sum { // TBD: Is there any way to improve efficiency here? // TBD: How is local_sum really used in the entire class? // Can it be a local variable? std::array message_length_total_temporary { }; message_length_total_temporary.fill(0U); const std::uint64_t message_bits_total = base_class_type::message_length_total << 3U; message_length_total_temporary[0U] = static_cast(message_bits_total >> 0U); message_length_total_temporary[1U] = static_cast(message_bits_total >> 32U); gosthash_compress(message_length_total_temporary.data()); } gosthash_compress(local_sum.data()); } AL_CRYPTO_NODISCARD auto get_result() const -> base_class_type::result_type override { base_class_type::result_type result; // Extract the message digest result from the message digest state. copy_transform_context_forward(result.data()); return result; } private: std::array local_sum; static auto gost_is_initialized() -> bool& { static bool gost_is_initialized_value; return gost_is_initialized_value; }; static auto gost_sbox_1() -> std::array& { static std::array gost_sbox_1_values; return gost_sbox_1_values; } static auto gost_sbox_2() -> std::array& { static std::array gost_sbox_2_values; return gost_sbox_2_values; } static auto gost_sbox_3() -> std::array& { static std::array gost_sbox_3_values; return gost_sbox_3_values; } static auto gost_sbox_4() -> std::array& { static std::array gost_sbox_4_values; return gost_sbox_4_values; } static auto gosthash_init() -> void; auto transform() -> void override { // Mix in a 32-byte chunk ("stage 3") //std::uint32_t m[8U]; std::array m { }; auto carry = static_cast(UINT8_C(0)); // Convert the message bytes to a 32-bit words. // TBD: Also compute the sum and (do what with it?). for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(8)); ++i) { const auto value32 = static_cast ( static_cast(static_cast(base_class_type::message_buffer[(i * 4U) + 0U]) << 0U) | static_cast(static_cast(base_class_type::message_buffer[(i * 4U) + 1U]) << 8U) | static_cast(static_cast(base_class_type::message_buffer[(i * 4U) + 2U]) << 16U) | static_cast(static_cast(base_class_type::message_buffer[(i * 4U) + 3U]) << 24U) ); m[i] = value32; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) const std::uint32_t local_sum_tmp = local_sum[i]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) carry += value32 + local_sum[i]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) local_sum[i] = carry; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) carry = (((carry < value32) || (carry < local_sum_tmp)) ? 1U : 0U); } gosthash_compress(m.data()); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) base_class_type::message_index = 0U; base_class_type::message_buffer.fill(0U); } static auto gost_sbox(const std::uint32_t& t) -> std::uint32_t { return std::uint32_t( gost_sbox_1()[ t & 0xFFU] // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) ^ gost_sbox_2()[(t >> 8U) & 0xFFU]) // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) ^ std::uint32_t( gost_sbox_3()[(t >> 16U) & 0xFFU] // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) ^ gost_sbox_4()[ t >> 24U]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) } auto gosthash_compress(const std::uint32_t* m) -> void { // Perform the "chi" compression function. // The result is stored in the transform_context. std::array u { }; std::array v { }; std::array s { }; std::copy(base_class_type::transform_context.cbegin(), base_class_type::transform_context.cend(), u.begin()); std::copy(m, m + v.size(), v.begin()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(auto ix = static_cast(UINT8_C(0)); ix < static_cast(UINT8_C(8)); ix += static_cast(UINT8_C(2))) { // w = u xor v const std::array w = { static_cast(u[0U] ^ v[0U]), static_cast(u[1U] ^ v[1U]), static_cast(u[2U] ^ v[2U]), static_cast(u[3U] ^ v[3U]), static_cast(u[4U] ^ v[4U]), static_cast(u[5U] ^ v[5U]), static_cast(u[6U] ^ v[6U]), static_cast(u[7U] ^ v[7U]), }; // P-Transformation const std::array key = {{ static_cast ( (w[0U] & UINT32_C(0x000000FF)) | ((w[2U] & UINT32_C(0x000000FF)) << 8U) | ((w[4U] & UINT32_C(0x000000FF)) << 16U) | ((w[6U] & UINT32_C(0x000000FF)) << 24U) ), static_cast ( ((w[0U] & UINT32_C(0x0000FF00)) >> 8U) | (w[2U] & UINT32_C(0x0000FF00)) | ((w[4U] & UINT32_C(0x0000FF00)) << 8U) | ((w[6U] & UINT32_C(0x0000FF00)) << 16U) ), static_cast ( ((w[0U] & UINT32_C(0x00FF0000)) >> 16U) | ((w[2U] & UINT32_C(0x00FF0000)) >> 8U) | (w[4U] & UINT32_C(0x00FF0000)) | ((w[6U] & UINT32_C(0x00FF0000)) << 8U) ), static_cast ( ((w[0U] & UINT32_C(0xFF000000)) >> 24U) | ((w[2U] & UINT32_C(0xFF000000)) >> 16U) | ((w[4U] & UINT32_C(0xFF000000)) >> 8U) | (w[6U] & UINT32_C(0xFF000000)) ), static_cast ( (w[1U] & UINT32_C(0x000000FF)) | ((w[3U] & UINT32_C(0x000000FF)) << 8U) | ((w[5U] & UINT32_C(0x000000FF)) << 16U) | ((w[7U] & UINT32_C(0x000000FF)) << 24U) ), static_cast ( ((w[1U] & UINT32_C(0x0000FF00)) >> 8U) | (w[3U] & UINT32_C(0x0000FF00)) | ((w[5U] & UINT32_C(0x0000FF00)) << 8U) | ((w[7U] & UINT32_C(0x0000FF00)) << 16U) ), static_cast ( ((w[1U] & UINT32_C(0x00FF0000)) >> 16U) | ((w[3U] & UINT32_C(0x00FF0000)) >> 8U) | (w[5U] & UINT32_C(0x00FF0000)) | ((w[7U] & UINT32_C(0x00FF0000)) << 8U) ), static_cast ( ((w[1U] & UINT32_C(0xFF000000)) >> 24U) | ((w[3U] & UINT32_C(0xFF000000)) >> 16U) | ((w[5U] & UINT32_C(0xFF000000)) >> 8U) | (w[7U] & UINT32_C(0xFF000000)) ) }}; // encriphering transformation std::uint32_t r = base_class_type::transform_context[ix + 0U]; std::uint32_t l = base_class_type::transform_context[ix + 1U]; std::uint32_t t = 0U; #if defined(AL_CRYPTO_CFG_GOST_USE_MACROS) GOST_ENCRYPT(key); #else // Perform a full encryption round of GOST 28147-89. // Temporary variable t assumed and variables r and l // for left and right blocks for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(3)); ++i) { for(auto j = static_cast(UINT8_C(0)); j <= static_cast(UINT8_C(6)); j += static_cast(UINT8_C(2))) { t = key[j + 0U] + r; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) l ^= gost_sbox(t); t = key[j + 1U] + l; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) r ^= gost_sbox(t); } } for(auto j = static_cast(INT8_C(6)); j >= static_cast(INT8_C(0)); j -= static_cast(INT8_C(2))) { t = key[static_cast(j) + 1U] + r; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) l ^= gost_sbox(t); t = key[static_cast(j) + 0U] + l; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) r ^= gost_sbox(t); } t = r; r = l; l = t; #endif s[ix + 0U] = r; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) s[ix + 1U] = l; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) if(ix == 6U) { break; } // U = A(U) l = u[0U] ^ u[2U]; r = u[1U] ^ u[3U]; u[0U] = u[2U]; u[1U] = u[3U]; u[2U] = u[4U]; u[3U] = u[5U]; u[4U] = u[6U]; u[5U] = u[7U]; u[6U] = l; u[7U] = r; // Constant C_3 if(ix == 2U) { u[0U] ^= UINT32_C(0xFF00FF00); u[1U] ^= UINT32_C(0xFF00FF00); u[2U] ^= UINT32_C(0x00FF00FF); u[3U] ^= UINT32_C(0x00FF00FF); u[4U] ^= UINT32_C(0x00FFFF00); u[5U] ^= UINT32_C(0xFF0000FF); u[6U] ^= UINT32_C(0x000000FF); u[7U] ^= UINT32_C(0xFF00FFFF); } // V = A(A(V)) l = v[0U]; r = v[2U]; v[0U] = v[4U]; v[2U] = v[6U]; v[4U] = l ^ r; v[6U] = v[0U] ^ r; l = v[1U]; r = v[3U]; v[1U] = v[5U]; v[3U] = v[7U]; v[5U] = l ^ r; v[7U] = v[1U] ^ r; } constexpr auto x_lo = UINT32_C(0x0000FFFF); constexpr auto x_hi = UINT32_C(0xFFFF0000); // 12 rounds of the LFSR (computed from a product matrix) and xor in M u[0U] = m[0U] ^ s[6U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u[1U] = m[1U] ^ s[7U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u[2U] = m[2U] ^ (s[0U] << 16U) ^ (s[0U] >> 16U) ^ (s[0U] & x_lo) ^ (s[1U] & x_lo) ^ (s[1U] >> 16U) ^ (s[2U] << 16U) ^ s[6U] ^ (s[6U] << 16U) ^ (s[7U] & x_hi) ^ (s[7U] >> 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u[3U] = m[3U] ^ (s[0U] & x_lo) ^ (s[0U] << 16U) ^ (s[1U] & x_lo) ^ (s[1U] << 16U) ^ (s[1U] >> 16U) ^ (s[2U] << 16U) ^ (s[2U] >> 16U) ^ (s[3U] << 16U) ^ s[6U] ^ (s[6U] << 16U) ^ (s[6U] >> 16U) ^ (s[7U] & x_lo) ^ (s[7U] << 16U) ^ (s[7U] >> 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u[4U] = m[4U] ^ (s[0U] & x_hi) ^ (s[0U] << 16U) ^ (s[0U] >> 16U) ^ (s[1U] & x_hi) ^ (s[1U] >> 16U) ^ (s[2U] << 16U) ^ (s[2U] >> 16U) ^ (s[3U] << 16U) ^ (s[3U] >> 16U) ^ (s[4U] << 16U) ^ (s[6U] << 16U) ^ (s[6U] >> 16U) ^ (s[7U] & x_lo) ^ (s[7U] << 16U) ^ (s[7U] >> 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u[5U] = m[5U] ^ (s[0U] << 16U) ^ (s[0U] >> 16U) ^ (s[0U] & x_hi) ^ (s[1U] & x_lo) ^ s[2U] ^ (s[2U] >> 16U) ^ (s[3U] << 16U) ^ (s[3U] >> 16U) ^ (s[4U] << 16U) ^ (s[4U] >> 16U) ^ (s[5U] << 16U) ^ (s[6U] << 16U) ^ (s[6U] >> 16U) ^ (s[7U] & x_hi) ^ (s[7U] << 16U) ^ (s[7U] >> 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u[6U] = m[6U] ^ s[0U] ^ (s[1U] >> 16U) ^ (s[2U] << 16U) ^ s[3U] ^ (s[3U] >> 16U) ^ (s[4U] << 16U) ^ (s[4U] >> 16U) ^ (s[5U] << 16U) ^ (s[5U] >> 16U) ^ s[6U] ^ (s[6U] << 16U) ^ (s[6U] >> 16U) ^ (s[7U] << 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u[7U] = m[7U] ^ (s[0U] & x_hi) ^ (s[0U] << 16U) ^ (s[1U] & x_lo) ^ (s[1U] << 16U) ^ (s[2U] >> 16U) ^ (s[3U] << 16U) ^ s[4U] ^ (s[4U] >> 16U) ^ (s[5U] << 16U) ^ (s[5U] >> 16U) ^ (s[6U] >> 16U) ^ (s[7U] & x_lo) ^ (s[7U] << 16U) ^ (s[7U] >> 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) // 16 * 1 round of the LFSR and xor in H v[0U] = base_class_type::transform_context[0U] ^ (u[1U] << 16U) ^ (u[0U] >> 16U); v[1U] = base_class_type::transform_context[1U] ^ (u[2U] << 16U) ^ (u[1U] >> 16U); v[2U] = base_class_type::transform_context[2U] ^ (u[3U] << 16U) ^ (u[2U] >> 16U); v[3U] = base_class_type::transform_context[3U] ^ (u[4U] << 16U) ^ (u[3U] >> 16U); v[4U] = base_class_type::transform_context[4U] ^ (u[5U] << 16U) ^ (u[4U] >> 16U); v[5U] = base_class_type::transform_context[5U] ^ (u[6U] << 16U) ^ (u[5U] >> 16U); v[6U] = base_class_type::transform_context[6U] ^ (u[7U] << 16U) ^ (u[6U] >> 16U); v[7U] = base_class_type::transform_context[7U] ^ (u[0U] & x_hi) ^ (u[0U] << 16U) ^ (u[7U] >> 16U) ^ (u[1] & x_hi) ^ (u[1U] << 16U) ^ (u[6U] << 16U) ^ (u[7U] & x_hi); // 61 rounds of LFSR, mixing up h (computed from a product matrix) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) base_class_type::transform_context[0U] = (v[0U] & x_hi) ^ (v[0U] << 16U) ^ (v[0U] >> 16U) ^ (v[1U] >> 16U) ^ (v[1U] & x_hi) ^ (v[2U] << 16U) ^ (v[3U] >> 16U) ^ (v[4U] << 16U) ^ (v[5U] >> 16U) ^ v[5U] ^ (v[6U] >> 16U) ^ (v[7U] << 16U) ^ (v[7U] >> 16U) ^ (v[7U] & x_lo); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) base_class_type::transform_context[1U] = (v[0U] << 16U) ^ (v[0U] >> 16U) ^ (v[0U] & x_hi) ^ (v[1U] & x_lo) ^ v[2U] ^ (v[2U] >> 16U) ^ (v[3U] << 16U) ^ (v[4U] >> 16U) ^ (v[5U] << 16U) ^ (v[6U] << 16U) ^ v[6U] ^ (v[7U] & x_hi) ^ (v[7U] >> 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) base_class_type::transform_context[2U] = (v[0U] & x_lo) ^ (v[0U] << 16U) ^ (v[1U] << 16U) ^ (v[1U] >> 16U) ^ (v[1U] & x_hi) ^ (v[2U] << 16U) ^ (v[3U] >> 16U) ^ v[3U] ^ (v[4U] << 16U) ^ (v[5U] >> 16U) ^ v[6U] ^ (v[6U] >> 16U) ^ (v[7U] & x_lo) ^ (v[7U] << 16U) ^ (v[7U] >> 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) base_class_type::transform_context[3U] = (v[0U] << 16U) ^ (v[0U] >> 16U) ^ (v[0U] & x_hi) ^ (v[1U] & x_hi) ^ (v[1U] >> 16U) ^ (v[2U] << 16U) ^ (v[2U] >> 16U) ^ v[2U] ^ (v[3U] << 16U) ^ (v[4U] >> 16U) ^ v[4U] ^ (v[5U] << 16U) ^ (v[6U] << 16U) ^ (v[7U] & x_lo) ^ (v[7U] >> 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) base_class_type::transform_context[4U] = (v[0U] >> 16U) ^ (v[1U] << 16U) ^ v[1U] ^ (v[2U] >> 16U) ^ v[2U] ^ (v[3U] << 16U) ^ (v[3U] >> 16U) ^ v[3U] ^ (v[4U] << 16U) ^ (v[5U] >> 16U) ^ v[5U] ^ (v[6U] << 16U) ^ (v[6U] >> 16U) ^ (v[7U] << 16U); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) base_class_type::transform_context[5U] = (v[0U] << 16U) ^ (v[0U] & x_hi) ^ (v[1U] << 16U) ^ (v[1U] >> 16U) ^ (v[1U] & x_hi) ^ (v[2U] << 16U) ^ v[2U] ^ (v[3U] >> 16U) ^ v[3U] ^ (v[4U] << 16U) ^ (v[4U] >> 16U) ^ v[4U] ^ (v[5U] << 16U) ^ (v[6U] << 16U) ^ (v[6U] >> 16U) ^ v[6U] ^ (v[7U] << 16U) ^ (v[7U] >> 16U) ^ (v[7U] & x_hi); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) base_class_type::transform_context[6U] = v[0U] ^ v[2U] ^ (v[2U] >> 16U) ^ v[3U] ^ (v[3U] << 16U) ^ v[4U] ^ (v[4U] >> 16U) ^ (v[5U] << 16U) ^ (v[5U] >> 16U) ^ v[5U] ^ (v[6U] << 16U) ^ (v[6U] >> 16U) ^ v[6U] ^ (v[7U] << 16U) ^ v[7U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) base_class_type::transform_context[7U] = v[0U] ^ (v[0U] >> 16U) ^ (v[1U] << 16U) ^ (v[1U] >> 16U) ^ (v[2U] << 16U) ^ (v[3U] >> 16U) ^ v[3U] ^ (v[4U] << 16U) ^ v[4U] ^ (v[5U] >> 16U) ^ v[5U] ^ (v[6U] << 16U) ^ (v[6U] >> 16U) ^ (v[7U] << 16U) ^ v[7U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) }; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) AL_CRYPTO_CFG_INLINE auto hash_gost::gosthash_init() -> void { // initialize the lookup tables // 4-bit S-Boxes // CryptoPro S-box // The CryptoPro S-box comes from "production ready" parameter set developed by // CryptoPro company, it is also specified as part of RFC 4357 using inner_array_type = std::array; // 4-bit S-Boxes #if defined(AL_CRYPTO_CFG_GOST_USE_TEST_PARAMETERS) // RFC 5831 specifies only these parameters, but RFC 4357 names them as "test parameters" // and does not recommend them for use in production applications. static constexpr std::array sbox = { { { 4U, 10U, 9U, 2U, 13U, 8U, 0U, 14U, 6U, 11U, 1U, 12U, 7U, 15U, 5U, 3U }, { 14U, 11U, 4U, 12U, 6U, 13U, 15U, 10U, 2U, 3U, 8U, 1U, 0U, 7U, 5U, 9U }, { 5U, 8U, 1U, 13U, 10U, 3U, 4U, 2U, 14U, 15U, 12U, 7U, 6U, 0U, 9U, 11U }, { 7U, 13U, 10U, 1U, 0U, 8U, 9U, 15U, 14U, 4U, 6U, 12U, 11U, 2U, 5U, 3U }, { 6U, 12U, 7U, 1U, 5U, 15U, 13U, 8U, 4U, 10U, 9U, 14U, 0U, 3U, 11U, 2U }, { 4U, 11U, 10U, 0U, 7U, 2U, 1U, 13U, 3U, 6U, 8U, 5U, 9U, 12U, 15U, 14U }, { 13U, 11U, 4U, 1U, 3U, 15U, 5U, 9U, 0U, 10U, 14U, 7U, 6U, 8U, 2U, 12U }, { 1U, 15U, 13U, 0U, 5U, 7U, 10U, 4U, 9U, 2U, 3U, 14U, 6U, 11U, 8U, 12U } } }; #else static constexpr std::array sbox = { { { 10U, 4U, 5U, 6U, 8U, 1U, 3U, 7U, 13U, 12U, 14U, 0U, 9U, 2U, 11U, 15U }, { 5U, 15U, 4U, 0U, 2U, 13U, 11U, 9U, 1U, 7U, 6U, 3U, 12U, 14U, 10U, 8U }, { 7U, 15U, 12U, 14U, 9U, 4U, 1U, 0U, 3U, 11U, 5U, 2U, 6U, 10U, 8U, 13U }, { 4U, 10U, 7U, 12U, 0U, 15U, 2U, 8U, 14U, 1U, 6U, 5U, 13U, 11U, 9U, 3U }, { 7U, 6U, 4U, 11U, 9U, 12U, 2U, 10U, 1U, 8U, 0U, 14U, 15U, 13U, 3U, 5U }, { 7U, 6U, 2U, 4U, 13U, 9U, 15U, 0U, 10U, 1U, 5U, 11U, 8U, 14U, 12U, 3U }, { 13U, 14U, 4U, 1U, 7U, 0U, 5U, 10U, 3U, 12U, 8U, 15U, 6U, 2U, 9U, 11U }, { 1U, 3U, 10U, 9U, 5U, 11U, 4U, 15U, 8U, 6U, 7U, 14U, 13U, 0U, 2U, 12U }, } }; #endif // s-box precomputation auto i = static_cast(UINT8_C(0)); for(auto a = static_cast(UINT8_C(0)); a < std::tuple_size::value; ++a) { auto ax = static_cast(sbox[1U][a]) << 15U; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) auto bx = static_cast(sbox[3U][a]) << 23U; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) auto cx = static_cast(sbox[5U][a]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) cx = (cx >> 1U) | (cx << 31U); auto dx = static_cast(sbox[7U][a]) << 7U; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) for(auto b = static_cast(UINT8_C(0)); b < std::tuple_size::value; ++b) { gost_sbox_1()[i] = ax | (static_cast(sbox[0U][b]) << 11U); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) gost_sbox_2()[i] = bx | (static_cast(sbox[2U][b]) << 19U); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) gost_sbox_3()[i] = cx | (static_cast(sbox[4U][b]) << 27U); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) gost_sbox_4()[i] = dx | (static_cast(sbox[6U][b]) << 3U); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) ++i; } } } #if(__cplusplus >= 201703L) } // namespace al::crypto::stream::hash #else } // namespace hash } // namespace stream } // namespace crypto } // namespace al #endif #endif // ALCRYPTOLIB_STREAM_HASH_HASH_GOST_2019_04_25_H