#ifndef ALCRYPTOLIB_MATH_MATH_UTILS_2019_08_06_H #define ALCRYPTOLIB_MATH_MATH_UTILS_2019_08_06_H #include #include #include #if(__cplusplus >= 201703L) namespace al::crypto::math::utils { #else namespace al { namespace crypto { namespace math { namespace utils { #endif template constexpr auto make_lo(const LT& u) -> ST { // From an unsigned integral input parameter of type LT, // extract the low part of it. The type of the extracted // low part is ST, which has half the width of LT. using local_ushort_type = ST; using local_ularge_type = LT; // Compile-time checks. static_assert(( (std::numeric_limits::is_integer) && ( (std::numeric_limits::is_integer) && ((!std::numeric_limits::is_signed) && ((!std::numeric_limits::is_signed) && ((std::numeric_limits::digits * 2) == std::numeric_limits::digits))))), "Error: Please check the characteristics of the template parameters ST and LT"); return static_cast(u); } template constexpr auto make_hi(const LT& u) -> ST { // From an unsigned integral input parameter of type LT, // extract the high part of it. The type of the extracted // high part is ST, which has half the width of LT. using local_ushort_type = ST; using local_ularge_type = LT; // Compile-time checks. static_assert(( (std::numeric_limits::is_integer) && ( (std::numeric_limits::is_integer) && ((!std::numeric_limits::is_signed) && ((!std::numeric_limits::is_signed) && (((std::numeric_limits::digits * 2) == std::numeric_limits::digits)))))), "Error: Please check the characteristics of the template parameters ST and LT"); return static_cast(u >> static_cast(std::numeric_limits::digits)); } template inline auto msb_helper(const UnsignedIntegralType& x) -> std::uint_fast8_t { static_cast(x); return std::uint_fast8_t(); } // Make a template specialization of msb_helper() for std::uint8_t. template<> inline auto msb_helper(const std::uint8_t& x) -> std::uint_fast8_t { auto r = std::uint_fast8_t { }; auto u = x; // Use O(log2[N]) binary-halving in an unrolled loop to find the msb. if(static_cast(u & static_cast(UINT8_C(0xF0))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C(4))); r |= static_cast(UINT8_C(4)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT8_C(0x0C))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C(2))); r |= static_cast(UINT8_C(2)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT8_C(0x02))) != static_cast(UINT8_C(0))) { r |= static_cast(UINT8_C(1)); } // NOLINT(hicpp-signed-bitwise) return static_cast(r); } // Make a template specialization of msb_helper() for std::uint16_t. template<> inline auto msb_helper(const std::uint16_t& x) -> std::uint_fast8_t { auto r = std::uint_fast8_t { }; auto u = x; // Use O(log2[N]) binary-halving in an unrolled loop to find the msb. if(static_cast(u & static_cast(UINT16_C(0xFF00))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C(8))); r |= static_cast(UINT8_C(8)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT16_C(0x00F0))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C(4))); r |= static_cast(UINT8_C(4)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT16_C(0x000C))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C(2))); r |= static_cast(UINT8_C(2)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT16_C(0x0002))) != static_cast(UINT8_C(0))) { r |= static_cast(UINT8_C(1)); } // NOLINT(hicpp-signed-bitwise) return static_cast(r); } // Make a template specialization of msb_helper() for std::uint32_t. template<> inline auto msb_helper(const std::uint32_t& x) -> std::uint_fast8_t { auto r = std::uint_fast8_t { }; auto u = x; // Use O(log2[N]) binary-halving in an unrolled loop to find the msb. if(static_cast(u & static_cast(UINT32_C(0xFFFF0000))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C(16))); r |= static_cast(UINT8_C(16)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT32_C(0x0000FF00))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C( 8))); r |= static_cast(UINT8_C( 8)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT32_C(0x000000F0))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C( 4))); r |= static_cast(UINT8_C( 4)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT32_C(0x0000000C))) != static_cast(UINT8_C(0))) { u = static_cast(u >> static_cast(UINT8_C( 2))); r |= static_cast(UINT8_C( 2)); } // NOLINT(hicpp-signed-bitwise) if(static_cast(u & static_cast(UINT32_C(0x00000002))) != static_cast(UINT8_C(0))) { r |= static_cast(UINT8_C( 1)); } // NOLINT(hicpp-signed-bitwise) return static_cast(r); } // Make a template specialization of msb_helper() for std::uint64_t. template<> inline auto msb_helper(const std::uint64_t& x) -> std::uint_fast8_t { const auto u_hi = static_cast(x >> static_cast(UINT8_C(32))); const auto u_lo = static_cast(x); return ((u_hi != 0U) ? static_cast(UINT8_C(32) + msb_helper(u_hi)) : msb_helper(u_lo)); } template auto XorBlocks(InputIteratorType1 a_first, // NOLINT(bugprone-easily-swappable-parameters) InputIteratorType1 a_last, InputIteratorType2 b, OutputIteratorType c) -> void { while(a_first != a_last) { *c++ = (*a_first++) ^ (*b++); } } template auto rotr(const arithmetic_type& value_being_shifted, const std::size_t bits_to_shift) -> arithmetic_type { static_assert(std::is_unsigned::value, "Error: The arithmetic type used by circular right shift must be unsigned."); const auto bits_of_type = static_cast(std::numeric_limits::digits); const auto shift_limit = (std::min)(bits_to_shift, bits_of_type); const auto bits_to_shift_is_limited_to_range = (shift_limit > static_cast(UINT8_C(0))); const auto left_shift_amount = static_cast(std::numeric_limits::digits - shift_limit); // AXIVION Next Line AutosarC++19_03-A5.16.1: AUTOSAR permitted const auto part1 = static_cast(bits_to_shift_is_limited_to_range ? static_cast(value_being_shifted >> shift_limit) : value_being_shifted); // AXIVION Next Line AutosarC++19_03-A5.16.1: AUTOSAR permitted const auto part2 = static_cast(bits_to_shift_is_limited_to_range ? static_cast(value_being_shifted << left_shift_amount) : 0U); return static_cast(part1 | part2); } template auto rotl(const arithmetic_type& value_being_shifted, const std::size_t bits_to_shift) -> arithmetic_type { static_assert(std::is_unsigned::value, "Error: The arithmetic type used by circular left shift must be unsigned."); const auto right_shift_amount = static_cast(std::numeric_limits::digits - bits_to_shift); const auto part1 = static_cast(static_cast(value_being_shifted) << (bits_to_shift)); const auto part2 = static_cast(static_cast(value_being_shifted) >> right_shift_amount); return static_cast(part1 | part2); } template inline constexpr auto ashr(SignedIntegralType x, std::size_t bits_to_shift) -> SignedIntegralType { using signed_integral_type = SignedIntegralType; return static_cast(x >> bits_to_shift); // NOLINT(hicpp-signed-bitwise) } template inline auto load_u32(const std::uint8_t* in) -> std::uint32_t { return static_cast ( // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted static_cast( *(in + static_cast(UINT8_C(0)))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted | static_cast(static_cast(*(in + static_cast(UINT8_C(1)))) << static_cast(UINT8_C( 8))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted | static_cast(static_cast(*(in + static_cast(UINT8_C(2)))) << static_cast(UINT8_C(16))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted | static_cast(static_cast(*(in + static_cast(UINT8_C(3)))) << static_cast(UINT8_C(24))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) ); } template<> inline auto load_u32<3U>(const std::uint8_t* in) -> std::uint32_t { return static_cast ( // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted static_cast( *(in + static_cast(UINT8_C(0)))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted | static_cast(static_cast(*(in + static_cast(UINT8_C(1)))) << static_cast(UINT8_C( 8))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted | static_cast(static_cast(*(in + static_cast(UINT8_C(2)))) << static_cast(UINT8_C(16))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) ); } template<> inline auto load_u32<2U>(const std::uint8_t* in) -> std::uint32_t { return static_cast ( // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted static_cast( *(in + static_cast(UINT8_C(0)))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) // AXIVION Next Line AutosarC++19_03-M5.0.15: AUTOSAR permitted | static_cast(static_cast(*(in + static_cast(UINT8_C(1)))) << static_cast(UINT8_C(8))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) ); } template<> inline auto load_u32<1U>(const std::uint8_t* in) -> std::uint32_t { return static_cast(*in); } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) template<> inline auto load_u32<0U>(const std::uint8_t* in) -> std::uint32_t { static_cast(in); return static_cast(0U); } #if(__cplusplus >= 201703L) } // namespace al::crypto::math::utils #else } // namespace utils } // namespace math } // namespace crypto } // namespace al #endif #endif // ALCRYPTOLIB_MATH_MATH_UTILS_2019_08_06_H