#ifndef RANDOM_PCG32_2019_10_22_H_ #define RANDOM_PCG32_2019_10_22_H_ #include #include #include #include namespace al { namespace crypto { namespace random { namespace detail { template struct xsh_rr_mixin { static xtype output(itype internal_value) { // XSH RR -- high xorshift, followed by a random rotate using bitcount_t = std::uint8_t; constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8U); constexpr bitcount_t xtypebits = bitcount_t(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 bitcount_t rot = ((opbits != 0U) ? (bitcount_t(internal_value >> (bits - opbits)) & mask) : 0U); const bitcount_t amprot = (rot << amplifier) & mask; internal_value ^= itype(internal_value >> xshift); const xtype result = al::crypto::math::utils::rotr(xtype(internal_value >> bottomspare), amprot); return result; } }; } class random_pcg32 : public random_base { private: using base_class_type = random_base; public: static_assert(std::is_same::value == true, "Error: Wrong result type for derived random class"); static_assert(std::is_same::value == true, "Error: Wrong internal type for derived random class"); using itype = base_class_type::internal_type; static const itype default_seed = UINT64_C(0xCAFEF00DD15EA5E5); explicit random_pcg32(const itype state = default_seed) : base_class_type(state), my_inc (default_increment), my_state(is_mcg ? state | itype(3U) : bump(state + increment())) { } random_pcg32(const random_pcg32& other) : base_class_type(other), my_inc (other.my_inc), my_state(other.my_state) { } virtual ~random_pcg32() = default; random_pcg32& operator=(const random_pcg32& other) { if(this != &other) { my_inc = other.my_inc; my_state = other.my_state; } return *this; } virtual void seed(const itype state = default_seed) { my_inc = default_increment; my_state = (is_mcg ? state | itype(3U) : bump(state + increment())); } virtual result_type operator()() { const result_type value = detail::xsh_rr_mixin::output(base_generate0()); return value; } private: static const bool is_mcg = false; static const itype default_multiplier = UINT64_C(6364136223846793005); static const itype default_increment = UINT64_C(1442695040888963407); itype my_inc; itype my_state; itype multiplier() const { return default_multiplier; } itype increment() const { return my_inc; } itype bump(itype state) { return itype(state * multiplier()) + increment(); } itype base_generate0() { const itype old_state = my_state; my_state = bump(my_state); return old_state; } }; } } } // al::crpyto::random #endif // RANDOM_PCG32_2019_10_22_H_