blob: 8847e74bef6bbc7a370074a6183b6cc659be2f8c [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// 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
35namespace absl {
36namespace random_internal {
37
38// Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced
39// by a thread-unique URBG-instance.
40template <typename URBG>
41class NonsecureURBGBase {
42 public:
43 using result_type = typename URBG::result_type;
44
45 // Default constructor
46 NonsecureURBGBase() : urbg_(ConstructURBG()) {}
47
48 // Copy disallowed, move allowed.
49 NonsecureURBGBase(const NonsecureURBGBase&) = delete;
50 NonsecureURBGBase& operator=(const NonsecureURBGBase&) = delete;
51 NonsecureURBGBase(NonsecureURBGBase&&) = default;
52 NonsecureURBGBase& operator=(NonsecureURBGBase&&) = default;
53
54 // Constructor using a seed
55 template <class SSeq, typename = typename absl::enable_if_t<
56 !std::is_same<SSeq, NonsecureURBGBase>::value>>
57 explicit NonsecureURBGBase(SSeq&& seq)
58 : urbg_(ConstructURBG(std::forward<SSeq>(seq))) {}
59
60 // Note: on MSVC, min() or max() can be interpreted as MIN() or MAX(), so we
61 // enclose min() or max() in parens as (min)() and (max)().
62 // Additionally, clang-format requires no space before this construction.
63
64 // NonsecureURBGBase::min()
65 static constexpr result_type(min)() { return (URBG::min)(); }
66
67 // NonsecureURBGBase::max()
68 static constexpr result_type(max)() { return (URBG::max)(); }
69
70 // NonsecureURBGBase::operator()()
71 result_type operator()() { return urbg_(); }
72
73 // NonsecureURBGBase::discard()
74 void discard(unsigned long long values) { // NOLINT(runtime/int)
75 urbg_.discard(values);
76 }
77
78 bool operator==(const NonsecureURBGBase& other) const {
79 return urbg_ == other.urbg_;
80 }
81
82 bool operator!=(const NonsecureURBGBase& other) const {
83 return !(urbg_ == other.urbg_);
84 }
85
86 private:
87 // Seeder is a custom seed sequence type where generate() fills the provided
88 // buffer via the RandenPool entropy source.
89 struct Seeder {
90 using result_type = uint32_t;
91
92 size_t size() { return 0; }
93
94 template <typename OutIterator>
95 void param(OutIterator) const {}
96
97 template <typename RandomAccessIterator>
98 void generate(RandomAccessIterator begin, RandomAccessIterator end) {
99 if (begin != end) {
100 // begin, end must be random access iterators assignable from uint32_t.
101 generate_impl(
102 std::integral_constant<bool, sizeof(*begin) == sizeof(uint32_t)>{},
103 begin, end);
104 }
105 }
106
107 // Commonly, generate is invoked with a pointer to a buffer which
108 // can be cast to a uint32_t.
109 template <typename RandomAccessIterator>
110 void generate_impl(std::integral_constant<bool, true>,
111 RandomAccessIterator begin, RandomAccessIterator end) {
112 auto buffer = absl::MakeSpan(begin, end);
113 auto target = absl::MakeSpan(reinterpret_cast<uint32_t*>(buffer.data()),
114 buffer.size());
115 RandenPool<uint32_t>::Fill(target);
116 }
117
118 // The non-uint32_t case should be uncommon, and involves an extra copy,
119 // filling the uint32_t buffer and then mixing into the output.
120 template <typename RandomAccessIterator>
121 void generate_impl(std::integral_constant<bool, false>,
122 RandomAccessIterator begin, RandomAccessIterator end) {
123 const size_t n = std::distance(begin, end);
124 absl::InlinedVector<uint32_t, 8> data(n, 0);
125 RandenPool<uint32_t>::Fill(absl::MakeSpan(data.begin(), data.end()));
126 std::copy(std::begin(data), std::end(data), begin);
127 }
128 };
129
130 static URBG ConstructURBG() {
131 Seeder seeder;
132 return URBG(seeder);
133 }
134
135 template <typename SSeq>
136 static URBG ConstructURBG(SSeq&& seq) { // NOLINT(runtime/references)
137 auto salted_seq =
138 random_internal::MakeSaltedSeedSeq(std::forward<SSeq>(seq));
139 return URBG(salted_seq);
140 }
141
142 URBG urbg_;
143};
144
145} // namespace random_internal
146} // namespace absl
147
148#endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_