1*9356374aSAndroid Build Coastguard Worker // Copyright 2017 The Abseil Authors. 2*9356374aSAndroid Build Coastguard Worker // 3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*9356374aSAndroid Build Coastguard Worker // 7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0 8*9356374aSAndroid Build Coastguard Worker // 9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*9356374aSAndroid Build Coastguard Worker // limitations under the License. 14*9356374aSAndroid Build Coastguard Worker 15*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ 16*9356374aSAndroid Build Coastguard Worker #define ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ 17*9356374aSAndroid Build Coastguard Worker 18*9356374aSAndroid Build Coastguard Worker #include <algorithm> 19*9356374aSAndroid Build Coastguard Worker #include <cinttypes> 20*9356374aSAndroid Build Coastguard Worker #include <cstdlib> 21*9356374aSAndroid Build Coastguard Worker #include <iostream> 22*9356374aSAndroid Build Coastguard Worker #include <iterator> 23*9356374aSAndroid Build Coastguard Worker #include <limits> 24*9356374aSAndroid Build Coastguard Worker #include <type_traits> 25*9356374aSAndroid Build Coastguard Worker 26*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/endian.h" 27*9356374aSAndroid Build Coastguard Worker #include "absl/meta/type_traits.h" 28*9356374aSAndroid Build Coastguard Worker #include "absl/random/internal/iostream_state_saver.h" 29*9356374aSAndroid Build Coastguard Worker #include "absl/random/internal/randen.h" 30*9356374aSAndroid Build Coastguard Worker 31*9356374aSAndroid Build Coastguard Worker namespace absl { 32*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN 33*9356374aSAndroid Build Coastguard Worker namespace random_internal { 34*9356374aSAndroid Build Coastguard Worker 35*9356374aSAndroid Build Coastguard Worker // Deterministic pseudorandom byte generator with backtracking resistance 36*9356374aSAndroid Build Coastguard Worker // (leaking the state does not compromise prior outputs). Based on Reverie 37*9356374aSAndroid Build Coastguard Worker // (see "A Robust and Sponge-Like PRNG with Improved Efficiency") instantiated 38*9356374aSAndroid Build Coastguard Worker // with an improved Simpira-like permutation. 39*9356374aSAndroid Build Coastguard Worker // Returns values of type "T" (must be a built-in unsigned integer type). 40*9356374aSAndroid Build Coastguard Worker // 41*9356374aSAndroid Build Coastguard Worker // RANDen = RANDom generator or beetroots in Swiss High German. 42*9356374aSAndroid Build Coastguard Worker // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random 43*9356374aSAndroid Build Coastguard Worker // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. 44*9356374aSAndroid Build Coastguard Worker template <typename T> 45*9356374aSAndroid Build Coastguard Worker class alignas(8) randen_engine { 46*9356374aSAndroid Build Coastguard Worker public: 47*9356374aSAndroid Build Coastguard Worker // C++11 URBG interface: 48*9356374aSAndroid Build Coastguard Worker using result_type = T; 49*9356374aSAndroid Build Coastguard Worker static_assert(std::is_unsigned<result_type>::value, 50*9356374aSAndroid Build Coastguard Worker "randen_engine template argument must be a built-in unsigned " 51*9356374aSAndroid Build Coastguard Worker "integer type"); 52*9356374aSAndroid Build Coastguard Worker result_type(min)53*9356374aSAndroid Build Coastguard Worker static constexpr result_type(min)() { 54*9356374aSAndroid Build Coastguard Worker return (std::numeric_limits<result_type>::min)(); 55*9356374aSAndroid Build Coastguard Worker } 56*9356374aSAndroid Build Coastguard Worker result_type(max)57*9356374aSAndroid Build Coastguard Worker static constexpr result_type(max)() { 58*9356374aSAndroid Build Coastguard Worker return (std::numeric_limits<result_type>::max)(); 59*9356374aSAndroid Build Coastguard Worker } 60*9356374aSAndroid Build Coastguard Worker randen_engine()61*9356374aSAndroid Build Coastguard Worker randen_engine() : randen_engine(0) {} randen_engine(result_type seed_value)62*9356374aSAndroid Build Coastguard Worker explicit randen_engine(result_type seed_value) { seed(seed_value); } 63*9356374aSAndroid Build Coastguard Worker 64*9356374aSAndroid Build Coastguard Worker template <class SeedSequence, 65*9356374aSAndroid Build Coastguard Worker typename = typename absl::enable_if_t< 66*9356374aSAndroid Build Coastguard Worker !std::is_same<SeedSequence, randen_engine>::value>> randen_engine(SeedSequence && seq)67*9356374aSAndroid Build Coastguard Worker explicit randen_engine(SeedSequence&& seq) { 68*9356374aSAndroid Build Coastguard Worker seed(seq); 69*9356374aSAndroid Build Coastguard Worker } 70*9356374aSAndroid Build Coastguard Worker 71*9356374aSAndroid Build Coastguard Worker // alignment requirements dictate custom copy and move constructors. randen_engine(const randen_engine & other)72*9356374aSAndroid Build Coastguard Worker randen_engine(const randen_engine& other) 73*9356374aSAndroid Build Coastguard Worker : next_(other.next_), impl_(other.impl_) { 74*9356374aSAndroid Build Coastguard Worker std::memcpy(state(), other.state(), kStateSizeT * sizeof(result_type)); 75*9356374aSAndroid Build Coastguard Worker } 76*9356374aSAndroid Build Coastguard Worker randen_engine& operator=(const randen_engine& other) { 77*9356374aSAndroid Build Coastguard Worker next_ = other.next_; 78*9356374aSAndroid Build Coastguard Worker impl_ = other.impl_; 79*9356374aSAndroid Build Coastguard Worker std::memcpy(state(), other.state(), kStateSizeT * sizeof(result_type)); 80*9356374aSAndroid Build Coastguard Worker return *this; 81*9356374aSAndroid Build Coastguard Worker } 82*9356374aSAndroid Build Coastguard Worker 83*9356374aSAndroid Build Coastguard Worker // Returns random bits from the buffer in units of result_type. operator()84*9356374aSAndroid Build Coastguard Worker result_type operator()() { 85*9356374aSAndroid Build Coastguard Worker // Refill the buffer if needed (unlikely). 86*9356374aSAndroid Build Coastguard Worker auto* begin = state(); 87*9356374aSAndroid Build Coastguard Worker if (next_ >= kStateSizeT) { 88*9356374aSAndroid Build Coastguard Worker next_ = kCapacityT; 89*9356374aSAndroid Build Coastguard Worker impl_.Generate(begin); 90*9356374aSAndroid Build Coastguard Worker } 91*9356374aSAndroid Build Coastguard Worker return little_endian::ToHost(begin[next_++]); 92*9356374aSAndroid Build Coastguard Worker } 93*9356374aSAndroid Build Coastguard Worker 94*9356374aSAndroid Build Coastguard Worker template <class SeedSequence> 95*9356374aSAndroid Build Coastguard Worker typename absl::enable_if_t< 96*9356374aSAndroid Build Coastguard Worker !std::is_convertible<SeedSequence, result_type>::value> seed(SeedSequence && seq)97*9356374aSAndroid Build Coastguard Worker seed(SeedSequence&& seq) { 98*9356374aSAndroid Build Coastguard Worker // Zeroes the state. 99*9356374aSAndroid Build Coastguard Worker seed(); 100*9356374aSAndroid Build Coastguard Worker reseed(seq); 101*9356374aSAndroid Build Coastguard Worker } 102*9356374aSAndroid Build Coastguard Worker 103*9356374aSAndroid Build Coastguard Worker void seed(result_type seed_value = 0) { 104*9356374aSAndroid Build Coastguard Worker next_ = kStateSizeT; 105*9356374aSAndroid Build Coastguard Worker // Zeroes the inner state and fills the outer state with seed_value to 106*9356374aSAndroid Build Coastguard Worker // mimic the behaviour of reseed 107*9356374aSAndroid Build Coastguard Worker auto* begin = state(); 108*9356374aSAndroid Build Coastguard Worker std::fill(begin, begin + kCapacityT, 0); 109*9356374aSAndroid Build Coastguard Worker std::fill(begin + kCapacityT, begin + kStateSizeT, seed_value); 110*9356374aSAndroid Build Coastguard Worker } 111*9356374aSAndroid Build Coastguard Worker 112*9356374aSAndroid Build Coastguard Worker // Inserts entropy into (part of) the state. Calling this periodically with 113*9356374aSAndroid Build Coastguard Worker // sufficient entropy ensures prediction resistance (attackers cannot predict 114*9356374aSAndroid Build Coastguard Worker // future outputs even if state is compromised). 115*9356374aSAndroid Build Coastguard Worker template <class SeedSequence> reseed(SeedSequence & seq)116*9356374aSAndroid Build Coastguard Worker void reseed(SeedSequence& seq) { 117*9356374aSAndroid Build Coastguard Worker using sequence_result_type = typename SeedSequence::result_type; 118*9356374aSAndroid Build Coastguard Worker static_assert(sizeof(sequence_result_type) == 4, 119*9356374aSAndroid Build Coastguard Worker "SeedSequence::result_type must be 32-bit"); 120*9356374aSAndroid Build Coastguard Worker constexpr size_t kBufferSize = 121*9356374aSAndroid Build Coastguard Worker Randen::kSeedBytes / sizeof(sequence_result_type); 122*9356374aSAndroid Build Coastguard Worker alignas(16) sequence_result_type buffer[kBufferSize]; 123*9356374aSAndroid Build Coastguard Worker 124*9356374aSAndroid Build Coastguard Worker // Randen::Absorb XORs the seed into state, which is then mixed by a call 125*9356374aSAndroid Build Coastguard Worker // to Randen::Generate. Seeding with only the provided entropy is preferred 126*9356374aSAndroid Build Coastguard Worker // to using an arbitrary generate() call, so use [rand.req.seed_seq] 127*9356374aSAndroid Build Coastguard Worker // size as a proxy for the number of entropy units that can be generated 128*9356374aSAndroid Build Coastguard Worker // without relying on seed sequence mixing... 129*9356374aSAndroid Build Coastguard Worker const size_t entropy_size = seq.size(); 130*9356374aSAndroid Build Coastguard Worker if (entropy_size < kBufferSize) { 131*9356374aSAndroid Build Coastguard Worker // ... and only request that many values, or 256-bits, when unspecified. 132*9356374aSAndroid Build Coastguard Worker const size_t requested_entropy = (entropy_size == 0) ? 8u : entropy_size; 133*9356374aSAndroid Build Coastguard Worker std::fill(buffer + requested_entropy, buffer + kBufferSize, 0); 134*9356374aSAndroid Build Coastguard Worker seq.generate(buffer, buffer + requested_entropy); 135*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_IS_BIG_ENDIAN 136*9356374aSAndroid Build Coastguard Worker // Randen expects the seed buffer to be in Little Endian; reverse it on 137*9356374aSAndroid Build Coastguard Worker // Big Endian platforms. 138*9356374aSAndroid Build Coastguard Worker for (sequence_result_type& e : buffer) { 139*9356374aSAndroid Build Coastguard Worker e = absl::little_endian::FromHost(e); 140*9356374aSAndroid Build Coastguard Worker } 141*9356374aSAndroid Build Coastguard Worker #endif 142*9356374aSAndroid Build Coastguard Worker // The Randen paper suggests preferentially initializing even-numbered 143*9356374aSAndroid Build Coastguard Worker // 128-bit vectors of the randen state (there are 16 such vectors). 144*9356374aSAndroid Build Coastguard Worker // The seed data is merged into the state offset by 128-bits, which 145*9356374aSAndroid Build Coastguard Worker // implies preferring seed bytes [16..31, ..., 208..223]. Since the 146*9356374aSAndroid Build Coastguard Worker // buffer is 32-bit values, we swap the corresponding buffer positions in 147*9356374aSAndroid Build Coastguard Worker // 128-bit chunks. 148*9356374aSAndroid Build Coastguard Worker size_t dst = kBufferSize; 149*9356374aSAndroid Build Coastguard Worker while (dst > 7) { 150*9356374aSAndroid Build Coastguard Worker // leave the odd bucket as-is. 151*9356374aSAndroid Build Coastguard Worker dst -= 4; 152*9356374aSAndroid Build Coastguard Worker size_t src = dst >> 1; 153*9356374aSAndroid Build Coastguard Worker // swap 128-bits into the even bucket 154*9356374aSAndroid Build Coastguard Worker std::swap(buffer[--dst], buffer[--src]); 155*9356374aSAndroid Build Coastguard Worker std::swap(buffer[--dst], buffer[--src]); 156*9356374aSAndroid Build Coastguard Worker std::swap(buffer[--dst], buffer[--src]); 157*9356374aSAndroid Build Coastguard Worker std::swap(buffer[--dst], buffer[--src]); 158*9356374aSAndroid Build Coastguard Worker } 159*9356374aSAndroid Build Coastguard Worker } else { 160*9356374aSAndroid Build Coastguard Worker seq.generate(buffer, buffer + kBufferSize); 161*9356374aSAndroid Build Coastguard Worker } 162*9356374aSAndroid Build Coastguard Worker impl_.Absorb(buffer, state()); 163*9356374aSAndroid Build Coastguard Worker 164*9356374aSAndroid Build Coastguard Worker // Generate will be called when operator() is called 165*9356374aSAndroid Build Coastguard Worker next_ = kStateSizeT; 166*9356374aSAndroid Build Coastguard Worker } 167*9356374aSAndroid Build Coastguard Worker discard(uint64_t count)168*9356374aSAndroid Build Coastguard Worker void discard(uint64_t count) { 169*9356374aSAndroid Build Coastguard Worker uint64_t step = std::min<uint64_t>(kStateSizeT - next_, count); 170*9356374aSAndroid Build Coastguard Worker count -= step; 171*9356374aSAndroid Build Coastguard Worker 172*9356374aSAndroid Build Coastguard Worker constexpr uint64_t kRateT = kStateSizeT - kCapacityT; 173*9356374aSAndroid Build Coastguard Worker auto* begin = state(); 174*9356374aSAndroid Build Coastguard Worker while (count > 0) { 175*9356374aSAndroid Build Coastguard Worker next_ = kCapacityT; 176*9356374aSAndroid Build Coastguard Worker impl_.Generate(*reinterpret_cast<result_type(*)[kStateSizeT]>(begin)); 177*9356374aSAndroid Build Coastguard Worker step = std::min<uint64_t>(kRateT, count); 178*9356374aSAndroid Build Coastguard Worker count -= step; 179*9356374aSAndroid Build Coastguard Worker } 180*9356374aSAndroid Build Coastguard Worker next_ += step; 181*9356374aSAndroid Build Coastguard Worker } 182*9356374aSAndroid Build Coastguard Worker 183*9356374aSAndroid Build Coastguard Worker bool operator==(const randen_engine& other) const { 184*9356374aSAndroid Build Coastguard Worker const auto* begin = state(); 185*9356374aSAndroid Build Coastguard Worker return next_ == other.next_ && 186*9356374aSAndroid Build Coastguard Worker std::equal(begin, begin + kStateSizeT, other.state()); 187*9356374aSAndroid Build Coastguard Worker } 188*9356374aSAndroid Build Coastguard Worker 189*9356374aSAndroid Build Coastguard Worker bool operator!=(const randen_engine& other) const { 190*9356374aSAndroid Build Coastguard Worker return !(*this == other); 191*9356374aSAndroid Build Coastguard Worker } 192*9356374aSAndroid Build Coastguard Worker 193*9356374aSAndroid Build Coastguard Worker template <class CharT, class Traits> 194*9356374aSAndroid Build Coastguard Worker friend std::basic_ostream<CharT, Traits>& operator<<( 195*9356374aSAndroid Build Coastguard Worker std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) 196*9356374aSAndroid Build Coastguard Worker const randen_engine<T>& engine) { // NOLINT(runtime/references) 197*9356374aSAndroid Build Coastguard Worker using numeric_type = 198*9356374aSAndroid Build Coastguard Worker typename random_internal::stream_format_type<result_type>::type; 199*9356374aSAndroid Build Coastguard Worker auto saver = random_internal::make_ostream_state_saver(os); 200*9356374aSAndroid Build Coastguard Worker auto* it = engine.state(); 201*9356374aSAndroid Build Coastguard Worker for (auto* end = it + kStateSizeT; it < end; ++it) { 202*9356374aSAndroid Build Coastguard Worker // In the case that `elem` is `uint8_t`, it must be cast to something 203*9356374aSAndroid Build Coastguard Worker // larger so that it prints as an integer rather than a character. For 204*9356374aSAndroid Build Coastguard Worker // simplicity, apply the cast all circumstances. 205*9356374aSAndroid Build Coastguard Worker os << static_cast<numeric_type>(little_endian::FromHost(*it)) 206*9356374aSAndroid Build Coastguard Worker << os.fill(); 207*9356374aSAndroid Build Coastguard Worker } 208*9356374aSAndroid Build Coastguard Worker os << engine.next_; 209*9356374aSAndroid Build Coastguard Worker return os; 210*9356374aSAndroid Build Coastguard Worker } 211*9356374aSAndroid Build Coastguard Worker 212*9356374aSAndroid Build Coastguard Worker template <class CharT, class Traits> 213*9356374aSAndroid Build Coastguard Worker friend std::basic_istream<CharT, Traits>& operator>>( 214*9356374aSAndroid Build Coastguard Worker std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) 215*9356374aSAndroid Build Coastguard Worker randen_engine<T>& engine) { // NOLINT(runtime/references) 216*9356374aSAndroid Build Coastguard Worker using numeric_type = 217*9356374aSAndroid Build Coastguard Worker typename random_internal::stream_format_type<result_type>::type; 218*9356374aSAndroid Build Coastguard Worker result_type state[kStateSizeT]; 219*9356374aSAndroid Build Coastguard Worker size_t next; 220*9356374aSAndroid Build Coastguard Worker for (auto& elem : state) { 221*9356374aSAndroid Build Coastguard Worker // It is not possible to read uint8_t from wide streams, so it is 222*9356374aSAndroid Build Coastguard Worker // necessary to read a wider type and then cast it to uint8_t. 223*9356374aSAndroid Build Coastguard Worker numeric_type value; 224*9356374aSAndroid Build Coastguard Worker is >> value; 225*9356374aSAndroid Build Coastguard Worker elem = little_endian::ToHost(static_cast<result_type>(value)); 226*9356374aSAndroid Build Coastguard Worker } 227*9356374aSAndroid Build Coastguard Worker is >> next; 228*9356374aSAndroid Build Coastguard Worker if (is.fail()) { 229*9356374aSAndroid Build Coastguard Worker return is; 230*9356374aSAndroid Build Coastguard Worker } 231*9356374aSAndroid Build Coastguard Worker std::memcpy(engine.state(), state, sizeof(state)); 232*9356374aSAndroid Build Coastguard Worker engine.next_ = next; 233*9356374aSAndroid Build Coastguard Worker return is; 234*9356374aSAndroid Build Coastguard Worker } 235*9356374aSAndroid Build Coastguard Worker 236*9356374aSAndroid Build Coastguard Worker private: 237*9356374aSAndroid Build Coastguard Worker static constexpr size_t kStateSizeT = 238*9356374aSAndroid Build Coastguard Worker Randen::kStateBytes / sizeof(result_type); 239*9356374aSAndroid Build Coastguard Worker static constexpr size_t kCapacityT = 240*9356374aSAndroid Build Coastguard Worker Randen::kCapacityBytes / sizeof(result_type); 241*9356374aSAndroid Build Coastguard Worker 242*9356374aSAndroid Build Coastguard Worker // Returns the state array pointer, which is aligned to 16 bytes. 243*9356374aSAndroid Build Coastguard Worker // The first kCapacityT are the `inner' sponge; the remainder are available. state()244*9356374aSAndroid Build Coastguard Worker result_type* state() { 245*9356374aSAndroid Build Coastguard Worker return reinterpret_cast<result_type*>( 246*9356374aSAndroid Build Coastguard Worker (reinterpret_cast<uintptr_t>(&raw_state_) & 0xf) ? (raw_state_ + 8) 247*9356374aSAndroid Build Coastguard Worker : raw_state_); 248*9356374aSAndroid Build Coastguard Worker } state()249*9356374aSAndroid Build Coastguard Worker const result_type* state() const { 250*9356374aSAndroid Build Coastguard Worker return const_cast<randen_engine*>(this)->state(); 251*9356374aSAndroid Build Coastguard Worker } 252*9356374aSAndroid Build Coastguard Worker 253*9356374aSAndroid Build Coastguard Worker // raw state array, manually aligned in state(). This overallocates 254*9356374aSAndroid Build Coastguard Worker // by 8 bytes since C++ does not guarantee extended heap alignment. 255*9356374aSAndroid Build Coastguard Worker alignas(8) char raw_state_[Randen::kStateBytes + 8]; 256*9356374aSAndroid Build Coastguard Worker size_t next_; // index within state() 257*9356374aSAndroid Build Coastguard Worker Randen impl_; 258*9356374aSAndroid Build Coastguard Worker }; 259*9356374aSAndroid Build Coastguard Worker 260*9356374aSAndroid Build Coastguard Worker } // namespace random_internal 261*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END 262*9356374aSAndroid Build Coastguard Worker } // namespace absl 263*9356374aSAndroid Build Coastguard Worker 264*9356374aSAndroid Build Coastguard Worker #endif // ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ 265