abseil-cpp/absl/random/internal/randen_engine.h
Go to the documentation of this file.
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_RANDEN_ENGINE_H_
16 #define ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_
17 
18 #include <algorithm>
19 #include <cinttypes>
20 #include <cstdlib>
21 #include <iostream>
22 #include <iterator>
23 #include <limits>
24 #include <type_traits>
25 
26 #include "absl/base/internal/endian.h"
27 #include "absl/meta/type_traits.h"
28 #include "absl/random/internal/iostream_state_saver.h"
29 #include "absl/random/internal/randen.h"
30 
31 namespace absl {
33 namespace random_internal {
34 
35 // Deterministic pseudorandom byte generator with backtracking resistance
36 // (leaking the state does not compromise prior outputs). Based on Reverie
37 // (see "A Robust and Sponge-Like PRNG with Improved Efficiency") instantiated
38 // with an improved Simpira-like permutation.
39 // Returns values of type "T" (must be a built-in unsigned integer type).
40 //
41 // RANDen = RANDom generator or beetroots in Swiss High German.
42 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
43 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
44 template <typename T>
45 class alignas(8) randen_engine {
46  public:
47  // C++11 URBG interface:
48  using result_type = T;
50  "randen_engine template argument must be a built-in unsigned "
51  "integer type");
52 
53  static constexpr result_type(min)() {
55  }
56 
57  static constexpr result_type(max)() {
59  }
60 
62  explicit randen_engine(result_type seed_value) { seed(seed_value); }
63 
64  template <class SeedSequence,
65  typename = typename absl::enable_if_t<
67  explicit randen_engine(SeedSequence&& seq) {
68  seed(seq);
69  }
70 
71  // alignment requirements dictate custom copy and move constructors.
73  : next_(other.next_), impl_(other.impl_) {
74  std::memcpy(state(), other.state(), kStateSizeT * sizeof(result_type));
75  }
77  next_ = other.next_;
78  impl_ = other.impl_;
79  std::memcpy(state(), other.state(), kStateSizeT * sizeof(result_type));
80  return *this;
81  }
82 
83  // Returns random bits from the buffer in units of result_type.
85  // Refill the buffer if needed (unlikely).
86  auto* begin = state();
87  if (next_ >= kStateSizeT) {
88  next_ = kCapacityT;
90  }
92  }
93 
94  template <class SeedSequence>
95  typename absl::enable_if_t<
97  seed(SeedSequence&& seq) {
98  // Zeroes the state.
99  seed();
100  reseed(seq);
101  }
102 
103  void seed(result_type seed_value = 0) {
104  next_ = kStateSizeT;
105  // Zeroes the inner state and fills the outer state with seed_value to
106  // mimic the behaviour of reseed
107  auto* begin = state();
109  std::fill(begin + kCapacityT, begin + kStateSizeT, seed_value);
110  }
111 
112  // Inserts entropy into (part of) the state. Calling this periodically with
113  // sufficient entropy ensures prediction resistance (attackers cannot predict
114  // future outputs even if state is compromised).
115  template <class SeedSequence>
116  void reseed(SeedSequence& seq) {
117  using sequence_result_type = typename SeedSequence::result_type;
118  static_assert(sizeof(sequence_result_type) == 4,
119  "SeedSequence::result_type must be 32-bit");
120  constexpr size_t kBufferSize =
121  Randen::kSeedBytes / sizeof(sequence_result_type);
122  alignas(16) sequence_result_type buffer[kBufferSize];
123 
124  // Randen::Absorb XORs the seed into state, which is then mixed by a call
125  // to Randen::Generate. Seeding with only the provided entropy is preferred
126  // to using an arbitrary generate() call, so use [rand.req.seed_seq]
127  // size as a proxy for the number of entropy units that can be generated
128  // without relying on seed sequence mixing...
129  const size_t entropy_size = seq.size();
130  if (entropy_size < kBufferSize) {
131  // ... and only request that many values, or 256-bits, when unspecified.
132  const size_t requested_entropy = (entropy_size == 0) ? 8u : entropy_size;
133  std::fill(buffer + requested_entropy, buffer + kBufferSize, 0);
134  seq.generate(buffer, buffer + requested_entropy);
135 #ifdef ABSL_IS_BIG_ENDIAN
136  // Randen expects the seed buffer to be in Little Endian; reverse it on
137  // Big Endian platforms.
138  for (sequence_result_type& e : buffer) {
140  }
141 #endif
142  // The Randen paper suggests preferentially initializing even-numbered
143  // 128-bit vectors of the randen state (there are 16 such vectors).
144  // The seed data is merged into the state offset by 128-bits, which
145  // implies prefering seed bytes [16..31, ..., 208..223]. Since the
146  // buffer is 32-bit values, we swap the corresponding buffer positions in
147  // 128-bit chunks.
148  size_t dst = kBufferSize;
149  while (dst > 7) {
150  // leave the odd bucket as-is.
151  dst -= 4;
152  size_t src = dst >> 1;
153  // swap 128-bits into the even bucket
154  std::swap(buffer[--dst], buffer[--src]);
155  std::swap(buffer[--dst], buffer[--src]);
156  std::swap(buffer[--dst], buffer[--src]);
157  std::swap(buffer[--dst], buffer[--src]);
158  }
159  } else {
160  seq.generate(buffer, buffer + kBufferSize);
161  }
162  impl_.Absorb(buffer, state());
163 
164  // Generate will be called when operator() is called
165  next_ = kStateSizeT;
166  }
167 
169  uint64_t step = std::min<uint64_t>(kStateSizeT - next_, count);
170  count -= step;
171 
172  constexpr uint64_t kRateT = kStateSizeT - kCapacityT;
173  auto* begin = state();
174  while (count > 0) {
175  next_ = kCapacityT;
176  impl_.Generate(*reinterpret_cast<result_type(*)[kStateSizeT]>(begin));
177  step = std::min<uint64_t>(kRateT, count);
178  count -= step;
179  }
180  next_ += step;
181  }
182 
183  bool operator==(const randen_engine& other) const {
184  const auto* begin = state();
185  return next_ == other.next_ &&
186  std::equal(begin, begin + kStateSizeT, other.state());
187  }
188 
189  bool operator!=(const randen_engine& other) const {
190  return !(*this == other);
191  }
192 
193  template <class CharT, class Traits>
194  friend std::basic_ostream<CharT, Traits>& operator<<(
195  std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
196  const randen_engine<T>& engine) { // NOLINT(runtime/references)
197  using numeric_type =
200  auto* it = engine.state();
201  for (auto* end = it + kStateSizeT; it < end; ++it) {
202  // In the case that `elem` is `uint8_t`, it must be cast to something
203  // larger so that it prints as an integer rather than a character. For
204  // simplicity, apply the cast all circumstances.
205  os << static_cast<numeric_type>(little_endian::FromHost(*it))
206  << os.fill();
207  }
208  os << engine.next_;
209  return os;
210  }
211 
212  template <class CharT, class Traits>
213  friend std::basic_istream<CharT, Traits>& operator>>(
214  std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
215  randen_engine<T>& engine) { // NOLINT(runtime/references)
216  using numeric_type =
219  size_t next;
220  for (auto& elem : state) {
221  // It is not possible to read uint8_t from wide streams, so it is
222  // necessary to read a wider type and then cast it to uint8_t.
223  numeric_type value;
224  is >> value;
225  elem = little_endian::ToHost(static_cast<result_type>(value));
226  }
227  is >> next;
228  if (is.fail()) {
229  return is;
230  }
231  std::memcpy(engine.state(), state, sizeof(state));
232  engine.next_ = next;
233  return is;
234  }
235 
236  private:
237  static constexpr size_t kStateSizeT =
239  static constexpr size_t kCapacityT =
241 
242  // Returns the state array pointer, which is aligned to 16 bytes.
243  // The first kCapacityT are the `inner' sponge; the remainder are available.
245  return reinterpret_cast<result_type*>(
246  (reinterpret_cast<uintptr_t>(&raw_state_) & 0xf) ? (raw_state_ + 8)
247  : raw_state_);
248  }
249  const result_type* state() const {
250  return const_cast<randen_engine*>(this)->state();
251  }
252 
253  // raw state array, manually aligned in state(). This overallocates
254  // by 8 bytes since C++ does not guarantee extended heap alignment.
255  alignas(8) char raw_state_[Randen::kStateBytes + 8];
256  size_t next_; // index within state()
258 };
259 
260 } // namespace random_internal
262 } // namespace absl
263 
264 #endif // ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_
absl::random_internal::randen_engine::state
result_type * state()
Definition: abseil-cpp/absl/random/internal/randen_engine.h:244
absl::random_internal::randen_engine::state
const result_type * state() const
Definition: abseil-cpp/absl/random/internal/randen_engine.h:249
dst
static const char dst[]
Definition: test-fs-copyfile.c:37
regen-readme.it
it
Definition: regen-readme.py:15
absl::random_internal::randen_engine::kCapacityT
static constexpr size_t kCapacityT
Definition: abseil-cpp/absl/random/internal/randen_engine.h:239
kBufferSize
static const int kBufferSize
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:135
absl::random_internal::randen_engine::randen_engine
randen_engine(SeedSequence &&seq)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:67
begin
char * begin
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1007
elem
Timer elem
Definition: event_engine/iomgr_event_engine/timer_heap_test.cc:109
u
OPENSSL_EXPORT pem_password_cb void * u
Definition: pem.h:351
absl::random_internal::randen_engine::operator=
randen_engine & operator=(const randen_engine &other)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:76
absl::enable_if_t
typename std::enable_if< B, T >::type enable_if_t
Definition: abseil-cpp/absl/meta/type_traits.h:631
absl::random_internal::Randen::Generate
void Generate(void *state) const
Definition: abseil-cpp/absl/random/internal/randen.h:47
absl::random_internal::randen_engine::operator!=
bool operator!=(const randen_engine &other) const
Definition: abseil-cpp/absl/random/internal/randen_engine.h:189
absl::random_internal::randen_engine::max
static constexpr result_type() max()
Definition: abseil-cpp/absl/random/internal/randen_engine.h:57
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::random_internal::randen_engine::randen_engine
randen_engine(result_type seed_value)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:62
absl::random_internal::randen_engine::operator<<
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const randen_engine< T > &engine)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:194
T
#define T(upbtypeconst, upbtype, ctype, default_value)
absl::random_internal::randen_engine::min
static constexpr result_type() min()
Definition: abseil-cpp/absl/random/internal/randen_engine.h:53
absl::random_internal::stream_format_type
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:174
absl::random_internal::randen_engine
Definition: abseil-cpp/absl/random/internal/randen_engine.h:45
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
absl::FormatConversionChar::e
@ e
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
absl::random_internal::randen_engine::randen_engine
randen_engine(const randen_engine &other)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:72
absl::random_internal::randen_engine::reseed
void reseed(SeedSequence &seq)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:116
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
absl::random_internal::randen_engine::kStateSizeT
static constexpr size_t kStateSizeT
Definition: abseil-cpp/absl/random/internal/randen_engine.h:237
result_type
const typedef int * result_type
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:4325
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
absl::random_internal::Randen
Definition: abseil-cpp/absl/random/internal/randen.h:34
absl::random_internal::Randen::kCapacityBytes
static constexpr size_t kCapacityBytes
Definition: abseil-cpp/absl/random/internal/randen.h:37
absl::little_endian::FromHost
uint8_t FromHost(uint8_t x)
Definition: abseil-cpp/absl/base/internal/endian.h:132
absl::random_internal::Randen::kStateBytes
static constexpr size_t kStateBytes
Definition: abseil-cpp/absl/random/internal/randen.h:36
std::swap
void swap(Json::Value &a, Json::Value &b)
Specialize std::swap() for Json::Value.
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:1226
absl::random_internal::randen_engine::impl_
Randen impl_
Definition: abseil-cpp/absl/random/internal/randen_engine.h:257
buffer
char buffer[1024]
Definition: libuv/docs/code/idle-compute/main.c:8
uintptr_t
_W64 unsigned int uintptr_t
Definition: stdint-msvc2008.h:119
min
#define min(a, b)
Definition: qsort.h:83
absl::random_internal::Randen::kSeedBytes
static constexpr size_t kSeedBytes
Definition: abseil-cpp/absl/random/internal/randen.h:38
value
const char * value
Definition: hpack_parser_table.cc:165
absl::random_internal::randen_engine::randen_engine
randen_engine()
Definition: abseil-cpp/absl/random/internal/randen_engine.h:61
absl::random_internal::randen_engine::discard
void discard(uint64_t count)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:168
absl::random_internal::randen_engine::operator==
bool operator==(const randen_engine &other) const
Definition: abseil-cpp/absl/random/internal/randen_engine.h:183
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
absl::random_internal::randen_engine::operator>>
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, randen_engine< T > &engine)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:213
absl::little_endian::ToHost
uint8_t ToHost(uint8_t x)
Definition: abseil-cpp/absl/base/internal/endian.h:136
next
AllocList * next[kMaxLevel]
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:100
step
static int step
Definition: test-mutexes.c:31
absl::random_internal::randen_engine::raw_state_
char raw_state_[Randen::kStateBytes+8]
Definition: abseil-cpp/absl/random/internal/randen_engine.h:255
absl::random_internal::randen_engine::next_
size_t next_
Definition: abseil-cpp/absl/random/internal/randen_engine.h:256
state
Definition: bloaty/third_party/zlib/contrib/blast/blast.c:41
absl::random_internal::randen_engine::seed
void seed(result_type seed_value=0)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:103
absl::random_internal::Randen::Absorb
void Absorb(const void *seed, void *state) const
Definition: abseil-cpp/absl/random/internal/randen.h:68
fill
int fill
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:47
absl::random_internal::randen_engine::seed
absl::enable_if_t< !std::is_convertible< SeedSequence, result_type >::value > seed(SeedSequence &&seq)
Definition: abseil-cpp/absl/random/internal/randen_engine.h:97
absl::random_internal::randen_engine< uint64_t >::result_type
uint64_t result_type
Definition: abseil-cpp/absl/random/internal/randen_engine.h:48
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::random_internal::make_ostream_state_saver
ostream_state_saver< std::basic_ostream< CharT, Traits > > make_ostream_state_saver(std::basic_ostream< CharT, Traits > &os, std::ios_base::fmtflags flags=std::ios_base::dec|std::ios_base::left|std::ios_base::scientific)
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:82
absl::random_internal::randen_engine::operator()
result_type operator()()
Definition: abseil-cpp/absl/random/internal/randen_engine.h:84


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:50