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