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 <cstddef> 20 #include <cstdint> 21 #include <iterator> 22 #include <type_traits> 23 #include <utility> 24 #include <vector> 25 26 #include "absl/base/config.h" 27 #include "absl/container/inlined_vector.h" 28 #include "absl/meta/type_traits.h" 29 #include "absl/random/internal/entropy_pool.h" 30 #include "absl/random/internal/salted_seed_seq.h" 31 #include "absl/random/internal/seed_material.h" 32 33 namespace absl { 34 ABSL_NAMESPACE_BEGIN 35 namespace random_internal { 36 37 // RandenPoolSeedSeq is a custom seed sequence type where generate() fills the 38 // provided buffer via the RandenPool entropy source. 39 class RandenPoolSeedSeq { 40 private: 41 struct ContiguousTag {}; 42 struct BufferTag {}; 43 44 // Generate random unsigned values directly into the buffer. 45 template <typename Contiguous> generate_impl(ContiguousTag,Contiguous begin,Contiguous end)46 void generate_impl(ContiguousTag, Contiguous begin, Contiguous end) { 47 const size_t n = static_cast<size_t>(std::distance(begin, end)); 48 auto* a = &(*begin); 49 GetEntropyFromRandenPool(a, sizeof(*a) * n); 50 } 51 52 // Construct a buffer of size n and fill it with values, then copy 53 // those values into the seed iterators. 54 template <typename RandomAccessIterator> generate_impl(BufferTag,RandomAccessIterator begin,RandomAccessIterator end)55 void generate_impl(BufferTag, RandomAccessIterator begin, 56 RandomAccessIterator end) { 57 const size_t n = std::distance(begin, end); 58 absl::InlinedVector<uint32_t, 8> data(n, 0); 59 GetEntropyFromRandenPool(data.begin(), sizeof(data[0]) * n); 60 std::copy(std::begin(data), std::end(data), begin); 61 } 62 63 public: 64 using result_type = uint32_t; 65 size()66 size_t size() { return 0; } 67 68 template <typename OutIterator> param(OutIterator)69 void param(OutIterator) const {} 70 71 template <typename RandomAccessIterator> generate(RandomAccessIterator begin,RandomAccessIterator end)72 void generate(RandomAccessIterator begin, RandomAccessIterator end) { 73 // RandomAccessIterator must be assignable from uint32_t 74 if (begin != end) { 75 using U = typename std::iterator_traits<RandomAccessIterator>::value_type; 76 // ContiguousTag indicates the common case of a known contiguous buffer, 77 // which allows directly filling the buffer. In C++20, 78 // std::contiguous_iterator_tag provides a mechanism for testing this 79 // capability, however until Abseil's support requirements allow us to 80 // assume C++20, limit checks to a few common cases. 81 using TagType = absl::conditional_t< 82 (std::is_pointer<RandomAccessIterator>::value || 83 std::is_same<RandomAccessIterator, 84 typename std::vector<U>::iterator>::value), 85 ContiguousTag, BufferTag>; 86 87 generate_impl(TagType{}, begin, end); 88 } 89 } 90 }; 91 92 // Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced 93 // by a thread-unique URBG-instance. 94 template <typename URBG, typename Seeder = RandenPoolSeedSeq> 95 class NonsecureURBGBase { 96 public: 97 using result_type = typename URBG::result_type; 98 99 // Default constructor NonsecureURBGBase()100 NonsecureURBGBase() : urbg_(ConstructURBG()) {} 101 102 // Copy disallowed, move allowed. 103 NonsecureURBGBase(const NonsecureURBGBase&) = delete; 104 NonsecureURBGBase& operator=(const NonsecureURBGBase&) = delete; 105 NonsecureURBGBase(NonsecureURBGBase&&) = default; 106 NonsecureURBGBase& operator=(NonsecureURBGBase&&) = default; 107 108 // Constructor using a seed 109 template <class SSeq, typename = typename absl::enable_if_t< 110 !std::is_same<SSeq, NonsecureURBGBase>::value>> NonsecureURBGBase(SSeq && seq)111 explicit NonsecureURBGBase(SSeq&& seq) 112 : urbg_(ConstructURBG(std::forward<SSeq>(seq))) {} 113 114 // Note: on MSVC, min() or max() can be interpreted as MIN() or MAX(), so we 115 // enclose min() or max() in parens as (min)() and (max)(). 116 // Additionally, clang-format requires no space before this construction. 117 118 // NonsecureURBGBase::min() result_type(min)119 static constexpr result_type(min)() { return (URBG::min)(); } 120 121 // NonsecureURBGBase::max() result_type(max)122 static constexpr result_type(max)() { return (URBG::max)(); } 123 124 // NonsecureURBGBase::operator()() operator()125 result_type operator()() { return urbg_(); } 126 127 // NonsecureURBGBase::discard() discard(unsigned long long values)128 void discard(unsigned long long values) { // NOLINT(runtime/int) 129 urbg_.discard(values); 130 } 131 132 bool operator==(const NonsecureURBGBase& other) const { 133 return urbg_ == other.urbg_; 134 } 135 136 bool operator!=(const NonsecureURBGBase& other) const { 137 return !(urbg_ == other.urbg_); 138 } 139 140 private: ConstructURBG()141 static URBG ConstructURBG() { 142 Seeder seeder; 143 return URBG(seeder); 144 } 145 146 template <typename SSeq> ConstructURBG(SSeq && seq)147 static URBG ConstructURBG(SSeq&& seq) { // NOLINT(runtime/references) 148 auto salted_seq = 149 random_internal::MakeSaltedSeedSeq(std::forward<SSeq>(seq)); 150 return URBG(salted_seq); 151 } 152 153 URBG urbg_; 154 }; 155 156 } // namespace random_internal 157 ABSL_NAMESPACE_END 158 } // namespace absl 159 160 #endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ 161