1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ 16 #define ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ 17 18 #include <algorithm> 19 #include <cstdint> 20 #include <iostream> 21 #include <iterator> 22 #include <random> 23 #include <string> 24 #include <type_traits> 25 #include <vector> 26 27 #include "absl/base/macros.h" 28 #include "absl/meta/type_traits.h" 29 #include "absl/random/internal/pool_urbg.h" 30 #include "absl/random/internal/salted_seed_seq.h" 31 #include "absl/random/internal/seed_material.h" 32 #include "absl/types/optional.h" 33 #include "absl/types/span.h" 34 35 namespace absl { 36 ABSL_NAMESPACE_BEGIN 37 namespace random_internal { 38 39 // Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced 40 // by a thread-unique URBG-instance. 41 template <typename URBG> 42 class NonsecureURBGBase { 43 public: 44 using result_type = typename URBG::result_type; 45 46 // Default constructor NonsecureURBGBase()47 NonsecureURBGBase() : urbg_(ConstructURBG()) {} 48 49 // Copy disallowed, move allowed. 50 NonsecureURBGBase(const NonsecureURBGBase&) = delete; 51 NonsecureURBGBase& operator=(const NonsecureURBGBase&) = delete; 52 NonsecureURBGBase(NonsecureURBGBase&&) = default; 53 NonsecureURBGBase& operator=(NonsecureURBGBase&&) = default; 54 55 // Constructor using a seed 56 template <class SSeq, typename = typename absl::enable_if_t< 57 !std::is_same<SSeq, NonsecureURBGBase>::value>> NonsecureURBGBase(SSeq && seq)58 explicit NonsecureURBGBase(SSeq&& seq) 59 : urbg_(ConstructURBG(std::forward<SSeq>(seq))) {} 60 61 // Note: on MSVC, min() or max() can be interpreted as MIN() or MAX(), so we 62 // enclose min() or max() in parens as (min)() and (max)(). 63 // Additionally, clang-format requires no space before this construction. 64 65 // NonsecureURBGBase::min() result_type(min)66 static constexpr result_type(min)() { return (URBG::min)(); } 67 68 // NonsecureURBGBase::max() result_type(max)69 static constexpr result_type(max)() { return (URBG::max)(); } 70 71 // NonsecureURBGBase::operator()() operator()72 result_type operator()() { return urbg_(); } 73 74 // NonsecureURBGBase::discard() discard(unsigned long long values)75 void discard(unsigned long long values) { // NOLINT(runtime/int) 76 urbg_.discard(values); 77 } 78 79 bool operator==(const NonsecureURBGBase& other) const { 80 return urbg_ == other.urbg_; 81 } 82 83 bool operator!=(const NonsecureURBGBase& other) const { 84 return !(urbg_ == other.urbg_); 85 } 86 87 private: 88 // Seeder is a custom seed sequence type where generate() fills the provided 89 // buffer via the RandenPool entropy source. 90 struct Seeder { 91 using result_type = uint32_t; 92 sizeSeeder93 size_t size() { return 0; } 94 95 template <typename OutIterator> paramSeeder96 void param(OutIterator) const {} 97 98 template <typename RandomAccessIterator> generateSeeder99 void generate(RandomAccessIterator begin, RandomAccessIterator end) { 100 if (begin != end) { 101 // begin, end must be random access iterators assignable from uint32_t. 102 generate_impl( 103 std::integral_constant<bool, sizeof(*begin) == sizeof(uint32_t)>{}, 104 begin, end); 105 } 106 } 107 108 // Commonly, generate is invoked with a pointer to a buffer which 109 // can be cast to a uint32_t. 110 template <typename RandomAccessIterator> generate_implSeeder111 void generate_impl(std::integral_constant<bool, true>, 112 RandomAccessIterator begin, RandomAccessIterator end) { 113 auto buffer = absl::MakeSpan(begin, end); 114 auto target = absl::MakeSpan(reinterpret_cast<uint32_t*>(buffer.data()), 115 buffer.size()); 116 RandenPool<uint32_t>::Fill(target); 117 } 118 119 // The non-uint32_t case should be uncommon, and involves an extra copy, 120 // filling the uint32_t buffer and then mixing into the output. 121 template <typename RandomAccessIterator> generate_implSeeder122 void generate_impl(std::integral_constant<bool, false>, 123 RandomAccessIterator begin, RandomAccessIterator end) { 124 const size_t n = std::distance(begin, end); 125 absl::InlinedVector<uint32_t, 8> data(n, 0); 126 RandenPool<uint32_t>::Fill(absl::MakeSpan(data.begin(), data.end())); 127 std::copy(std::begin(data), std::end(data), begin); 128 } 129 }; 130 ConstructURBG()131 static URBG ConstructURBG() { 132 Seeder seeder; 133 return URBG(seeder); 134 } 135 136 template <typename SSeq> ConstructURBG(SSeq && seq)137 static URBG ConstructURBG(SSeq&& seq) { // NOLINT(runtime/references) 138 auto salted_seq = 139 random_internal::MakeSaltedSeedSeq(std::forward<SSeq>(seq)); 140 return URBG(salted_seq); 141 } 142 143 URBG urbg_; 144 }; 145 146 } // namespace random_internal 147 ABSL_NAMESPACE_END 148 } // namespace absl 149 150 #endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ 151