| // Copyright 2017 The Abseil Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #ifndef ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ | |
| #define ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ | |
| #include <algorithm> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <iterator> | |
| #include <type_traits> | |
| #include <utility> | |
| #include <vector> | |
| #include "absl/base/config.h" | |
| #include "absl/container/inlined_vector.h" | |
| #include "absl/meta/type_traits.h" | |
| #include "absl/random/internal/entropy_pool.h" | |
| #include "absl/random/internal/salted_seed_seq.h" | |
| #include "absl/random/internal/seed_material.h" | |
| namespace absl { | |
| ABSL_NAMESPACE_BEGIN | |
| namespace random_internal { | |
| // RandenPoolSeedSeq is a custom seed sequence type where generate() fills the | |
| // provided buffer via the RandenPool entropy source. | |
| class RandenPoolSeedSeq { | |
| private: | |
| struct ContiguousTag {}; | |
| struct BufferTag {}; | |
| // Generate random unsigned values directly into the buffer. | |
| template <typename Contiguous> | |
| void generate_impl(ContiguousTag, Contiguous begin, Contiguous end) { | |
| const size_t n = static_cast<size_t>(std::distance(begin, end)); | |
| auto* a = &(*begin); | |
| GetEntropyFromRandenPool(a, sizeof(*a) * n); | |
| } | |
| // Construct a buffer of size n and fill it with values, then copy | |
| // those values into the seed iterators. | |
| template <typename RandomAccessIterator> | |
| void generate_impl(BufferTag, RandomAccessIterator begin, | |
| RandomAccessIterator end) { | |
| const size_t n = std::distance(begin, end); | |
| absl::InlinedVector<uint32_t, 8> data(n, 0); | |
| GetEntropyFromRandenPool(data.begin(), sizeof(data[0]) * n); | |
| std::copy(std::begin(data), std::end(data), begin); | |
| } | |
| public: | |
| using result_type = uint32_t; | |
| size_t size() { return 0; } | |
| template <typename OutIterator> | |
| void param(OutIterator) const {} | |
| template <typename RandomAccessIterator> | |
| void generate(RandomAccessIterator begin, RandomAccessIterator end) { | |
| // RandomAccessIterator must be assignable from uint32_t | |
| if (begin != end) { | |
| using U = typename std::iterator_traits<RandomAccessIterator>::value_type; | |
| // ContiguousTag indicates the common case of a known contiguous buffer, | |
| // which allows directly filling the buffer. In C++20, | |
| // std::contiguous_iterator_tag provides a mechanism for testing this | |
| // capability, however until Abseil's support requirements allow us to | |
| // assume C++20, limit checks to a few common cases. | |
| using TagType = std::conditional_t< | |
| (std::is_pointer_v<RandomAccessIterator> || | |
| std::is_same_v<RandomAccessIterator, | |
| typename std::vector<U>::iterator>), | |
| ContiguousTag, BufferTag>; | |
| generate_impl(TagType{}, begin, end); | |
| } | |
| } | |
| }; | |
| // Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced | |
| // by a thread-unique URBG-instance. | |
| template <typename URBG, typename Seeder = RandenPoolSeedSeq> | |
| class NonsecureURBGBase { | |
| public: | |
| using result_type = typename URBG::result_type; | |
| // Default constructor | |
| NonsecureURBGBase() : urbg_(ConstructURBG()) {} | |
| // Copy disallowed, move allowed. | |
| NonsecureURBGBase(const NonsecureURBGBase&) = delete; | |
| NonsecureURBGBase& operator=(const NonsecureURBGBase&) = delete; | |
| NonsecureURBGBase(NonsecureURBGBase&&) = default; | |
| NonsecureURBGBase& operator=(NonsecureURBGBase&&) = default; | |
| // Constructor using a seed | |
| template <class SSeq, typename = typename std::enable_if_t< | |
| !std::is_same_v<SSeq, NonsecureURBGBase>>> | |
| explicit NonsecureURBGBase(SSeq&& seq) | |
| : urbg_(ConstructURBG(std::forward<SSeq>(seq))) {} | |
| // Note: on MSVC, min() or max() can be interpreted as MIN() or MAX(), so we | |
| // enclose min() or max() in parens as (min)() and (max)(). | |
| // Additionally, clang-format requires no space before this construction. | |
| // NonsecureURBGBase::min() | |
| static constexpr result_type(min)() { return (URBG::min)(); } | |
| // NonsecureURBGBase::max() | |
| static constexpr result_type(max)() { return (URBG::max)(); } | |
| // NonsecureURBGBase::operator()() | |
| result_type operator()() { return urbg_(); } | |
| // NonsecureURBGBase::discard() | |
| void discard(unsigned long long values) { // NOLINT(runtime/int) | |
| urbg_.discard(values); | |
| } | |
| bool operator==(const NonsecureURBGBase& other) const { | |
| return urbg_ == other.urbg_; | |
| } | |
| bool operator!=(const NonsecureURBGBase& other) const { | |
| return !(urbg_ == other.urbg_); | |
| } | |
| private: | |
| static URBG ConstructURBG() { | |
| Seeder seeder; | |
| return URBG(seeder); | |
| } | |
| template <typename SSeq> | |
| static URBG ConstructURBG(SSeq&& seq) { // NOLINT(runtime/references) | |
| auto salted_seq = | |
| random_internal::MakeSaltedSeedSeq(std::forward<SSeq>(seq)); | |
| return URBG(salted_seq); | |
| } | |
| URBG urbg_; | |
| }; | |
| } // namespace random_internal | |
| ABSL_NAMESPACE_END | |
| } // namespace absl | |
| #endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ |