C/C++ API Reference
Loading...
Searching...
No Matches
random.h
1// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// 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, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <climits>
17#include <cstddef>
18#include <cstdint>
19#include <limits>
20
21#include "pw_assert/assert.h"
22#include "pw_bytes/span.h"
23#include "pw_span/span.h"
24#include "pw_status/status_with_size.h"
25
26namespace pw::random {
27
29
37 public:
38 virtual ~RandomGenerator() = default;
39
40 template <class T>
41 void GetInt(T& dest) {
42 static_assert(std::is_integral<T>::value,
43 "Use Get() for non-integral types");
44 Get({reinterpret_cast<std::byte*>(&dest), sizeof(T)});
45 }
46
59 template <class T>
60 void GetInt(T& dest, const T& exclusive_upper_bound) {
61 static_assert(std::is_unsigned_v<T>, "T must be an unsigned integer");
62 PW_ASSERT(exclusive_upper_bound != 0);
63
64 if (exclusive_upper_bound < 2) {
65 dest = 0;
66 return;
67 }
68
69 const uint8_t leading_zeros_in_upper_bound =
70 CountLeadingZeros(exclusive_upper_bound);
71
72 // Create a mask that discards the higher order bits of the random number.
73 const T mask =
74 std::numeric_limits<T>::max() >> leading_zeros_in_upper_bound;
75
76 // This loop should end fairly soon. It discards all the values that aren't
77 // below exclusive_upper_bound. The probability of values being greater or
78 // equal than exclusive_upper_bound is less than 1/2, which means that the
79 // expected amount of iterations is less than 2.
80 while (true) {
81 GetInt(dest);
82 dest &= mask;
83 if (dest < exclusive_upper_bound) {
84 return;
85 }
86 }
87 }
88
92 virtual void Get(ByteSpan dest) = 0;
93
100 virtual void InjectEntropyBits(uint32_t data, uint_fast8_t num_bits) = 0;
101
104 for (std::byte b : data) {
105 InjectEntropyBits(std::to_integer<uint32_t>(b), /*num_bits=*/8);
106 }
107 }
108
109 private:
110 template <class T>
111 uint8_t CountLeadingZeros(T value) {
112 if constexpr (std::is_same_v<T, unsigned>) {
113 return static_cast<uint8_t>(__builtin_clz(value));
114 } else if constexpr (std::is_same_v<T, unsigned long>) {
115 return static_cast<uint8_t>(__builtin_clzl(value));
116 } else if constexpr (std::is_same_v<T, unsigned long long>) {
117 return static_cast<uint8_t>(__builtin_clzll(value));
118 } else {
119 static_assert(sizeof(T) < sizeof(unsigned));
120 // __builtin_clz returns the count of leading zeros in an unsigned , so we
121 // need to subtract the size difference of T in bits.
122 return static_cast<uint8_t>(__builtin_clz(value) -
123 ((sizeof(unsigned) - sizeof(T)) * CHAR_BIT));
124 }
125 }
126};
127
128} // namespace pw::random
Definition: random.h:36
virtual void InjectEntropyBits(uint32_t data, uint_fast8_t num_bits)=0
void GetInt(T &dest, const T &exclusive_upper_bound)
Definition: random.h:60
virtual void Get(ByteSpan dest)=0
void InjectEntropy(ConstByteSpan data)
Injects entropy into the pool byte-by-byte.
Definition: random.h:103