#ifndef RANDOM_PCG32_2019_10_22_H #define RANDOM_PCG32_2019_10_22_H #include #include #include #include #include #if(__cplusplus >= 201703L) namespace al::crypto::random { #else namespace al { namespace crypto { namespace random { #endif namespace detail { template struct xsh_rr_mixin { static auto output(itype internal_value) -> xtype { // XSH RR -- high xorshift, followed by a random rotate using bitcount_t = std::uint8_t; constexpr auto bits = static_cast(sizeof(itype) * 8U); constexpr auto xtypebits = static_cast(sizeof(xtype) * 8U); constexpr bitcount_t sparebits = bits - xtypebits; constexpr bitcount_t wantedopbits = ((xtypebits >= 128U) ? 7U : ((xtypebits >= 64U) ? 6U : ((xtypebits >= 32U) ? 5U : ((xtypebits >= 16U) ? 4U : 3U)))); constexpr bitcount_t opbits = ((sparebits >= wantedopbits) ? wantedopbits : sparebits); constexpr bitcount_t amplifier = wantedopbits - opbits; constexpr bitcount_t mask = (1ULL << opbits) - 1U; constexpr bitcount_t topspare = opbits; constexpr bitcount_t bottomspare = sparebits - topspare; constexpr bitcount_t xshift = (topspare + xtypebits)/2; const auto rot = static_cast ( ((opbits != 0U) ? static_cast(static_cast(internal_value >> static_cast(bits - opbits)) & mask) : 0U) ); const auto amprot = static_cast(static_cast(rot << amplifier) & mask); internal_value ^= static_cast(internal_value >> xshift); const xtype result = al::crypto::math::utils::rotr(xtype(internal_value >> bottomspare), amprot); return result; } }; } // namespace detail class random_pcg32 : public random_base { private: using base_class_type = random_base; public: static_assert(std::is_same::value, "Error: Wrong result type for derived random class"); static_assert(std::is_same::value, "Error: Wrong internal type for derived random class"); using itype = base_class_type::internal_type; static constexpr auto default_seed = static_cast(UINT64_C(0xCAFEF00DD15EA5E5)); explicit random_pcg32(const itype state = default_seed) : base_class_type(state), my_inc (default_increment), my_state(is_mcg ? state | static_cast(3U) : bump(state + increment())) { } random_pcg32(const random_pcg32& other) : base_class_type(static_cast(other)), my_inc (other.my_inc), my_state(other.my_state) { } random_pcg32(random_pcg32&& other) noexcept : base_class_type(static_cast(other)), my_inc (other.my_inc), my_state(other.my_state) { } ~random_pcg32() override = default; auto operator=(const random_pcg32& other) -> random_pcg32& { if(this != &other) { static_cast(base_class_type::operator=(static_cast(other))); my_inc = other.my_inc; my_state = other.my_state; } return *this; } auto operator=(random_pcg32&& other) noexcept -> random_pcg32& { static_cast(base_class_type::operator=(static_cast(other))); my_inc = other.my_inc; my_state = other.my_state; return *this; } virtual auto seed(const itype state) -> void { my_inc = default_increment; my_state = (is_mcg ? state | static_cast(3U) : bump(state + increment())); } auto operator()() -> result_type override { const result_type value = detail::xsh_rr_mixin::output(base_generate0()); return value; } private: static constexpr auto is_mcg = false; static constexpr auto default_multiplier = static_cast(UINT64_C(6364136223846793005)); static constexpr auto default_increment = static_cast(UINT64_C(1442695040888963407)); itype my_inc; itype my_state; static auto multiplier() -> itype { return default_multiplier; } AL_CRYPTO_NODISCARD auto increment() const -> itype { return my_inc; } auto bump(itype state) -> itype { return static_cast ( static_cast(state * multiplier()) + increment() ); } auto base_generate0() -> itype { const auto old_state = my_state; my_state = bump(my_state); return old_state; } }; #if(__cplusplus >= 201703L) } // namespace al::crypto::random #else } // namespace random } // namespace crypto } // namespace al #endif #endif // RANDOM_PCG32_2019_10_22_H