17#include <TargetConditionals.h>
18#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
20extern "C" int getentropy(
void*
buffer,
size_t length);
22#include <sys/random.h>
24#elif defined(__ANDROID__)
32#include <sys/random.h>
39#if defined(__wasm__) || defined(__APPLE__) || defined(__ANDROID__)
43constexpr size_t RANDOM_BUFFER_SIZE = 256;
44constexpr size_t BYTES_PER_GETENTROPY_READ = 256;
49constexpr size_t RANDOM_BUFFER_SIZE = 1UL << 20;
54constexpr size_t RANDOM_BUFFER_SIZE = 1UL << 20;
57struct RandomBufferWrapper {
64thread_local RandomBufferWrapper random_buffer_wrapper;
73 static_assert(size_in_unsigned_ints > 0);
74 static_assert(size_in_unsigned_ints <= 32);
76 constexpr size_t random_data_buffer_size =
sizeof(random_data);
80 if (random_buffer_wrapper.offset == -1 ||
81 (
static_cast<size_t>(random_buffer_wrapper.offset) + random_data_buffer_size) > RANDOM_BUFFER_SIZE) {
82 if (!random_buffer_wrapper.buffer) {
85 size_t bytes_left = RANDOM_BUFFER_SIZE;
86 uint8_t* current_offset = random_buffer_wrapper.buffer.get();
89 [[maybe_unused]]
constexpr int MAX_EINTR_RETRIES = 16;
90 [[maybe_unused]]
int eintr_retries = 0;
92 while (bytes_left != 0) {
93#if defined(__wasm__) || defined(__APPLE__)
97 getentropy(current_offset, BYTES_PER_GETENTROPY_READ) == -1 ? -1 : BYTES_PER_GETENTROPY_READ;
98#elif defined(__ANDROID__)
100 static thread_local int urandom_fd = -1;
101 if (urandom_fd == -1) {
103 urandom_fd = open(
"/dev/urandom", O_RDONLY | O_CLOEXEC);
105 ssize_t read_bytes =
::read(urandom_fd, current_offset, BYTES_PER_GETENTROPY_READ);
109 BCryptGenRandom(NULL, current_offset,
static_cast<ULONG
>(bytes_left), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
110 ssize_t read_bytes = (status == 0) ?
static_cast<ssize_t
>(bytes_left) : -1;
113 auto read_bytes = getrandom(current_offset, bytes_left, 0);
115 if (read_bytes > 0) {
116 current_offset += read_bytes;
117 bytes_left -=
static_cast<size_t>(read_bytes);
124 if (read_bytes == -1 && errno == EINTR && eintr_retries++ < MAX_EINTR_RETRIES) {
128 throw_or_abort(
"CSPRNG read failed: cannot retrieve entropy from system source");
130 random_buffer_wrapper.offset = 0;
133 memcpy(&random_data, random_buffer_wrapper.buffer.get() + random_buffer_wrapper.offset, random_data_buffer_size);
134 random_buffer_wrapper.offset +=
static_cast<ssize_t
>(random_data_buffer_size);
143 auto buf = generate_random_data<1>();
144 uint32_t out = buf[0];
145 return static_cast<uint8_t
>(out);
150 auto buf = generate_random_data<1>();
151 uint32_t out = buf[0];
152 return static_cast<uint16_t
>(out);
157 auto buf = generate_random_data<1>();
158 uint32_t out = buf[0];
159 return static_cast<uint32_t
>(out);
164 auto buf = generate_random_data<2>();
165 auto lo =
static_cast<uint64_t
>(buf[0]);
166 auto hi =
static_cast<uint64_t
>(buf[1]);
167 return (lo + (hi << 32ULL));
172 const auto get64 = [](
const std::array<uint32_t, 4>&
buffer,
const size_t offset) {
175 return (lo + (hi << 32ULL));
177 auto buf = generate_random_data<4>();
178 auto lo =
static_cast<uint128_t>(get64(buf, 0));
179 auto hi =
static_cast<uint128_t>(get64(buf, 2));
181 return (lo + (hi <<
static_cast<uint128_t>(64ULL)));
186 const auto get64 = [](
const std::array<uint32_t, 8>&
buffer,
const size_t offset) {
189 return (lo + (hi << 32ULL));
191 auto buf = generate_random_data<8>();
192 uint64_t lolo = get64(buf, 0);
193 uint64_t lohi = get64(buf, 2);
194 uint64_t hilo = get64(buf, 4);
195 uint64_t hihi = get64(buf, 6);
196 return { lolo, lohi, hilo, hihi };
224 return (hi << 64) | lo;
234 return {
a,
b, c, d };
260#ifdef BBERG_DEBUG_LOG
uint8_t get_random_uint8() override
DebugEngine(std::uint_fast64_t seed)
std::uniform_int_distribution< uint64_t > dist
uint32_t get_random_uint32() override
uint16_t get_random_uint16() override
uint64_t get_random_uint64() override
uint128_t get_random_uint128() override
uint256_t get_random_uint256() override
uint32_t get_random_uint32() override
uint8_t get_random_uint8() override
uint16_t get_random_uint16() override
uint256_t get_random_uint256() override
uint64_t get_random_uint64() override
uint128_t get_random_uint128() override
std::unique_ptr< uint8_t[]> buffer
void read(B &it, uint256_t &value)
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
unsigned __int128 uint128_t
void throw_or_abort(std::string const &err)