Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
engine.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Luke], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#include "engine.hpp"
9#include <array>
10#include <cstring>
11#include <functional>
12#include <random>
13#if defined(__APPLE__)
14#include <TargetConditionals.h>
15#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
16#include <unistd.h>
17extern "C" int getentropy(void* buffer, size_t length); // getentropy on iOS
18#else
19#include <sys/random.h> // getentropy on macOS
20#endif
21#elif defined(__ANDROID__)
22// Android API 24 doesn't have getrandom/getentropy, use /dev/urandom
23#include <fcntl.h>
24#include <unistd.h>
25#else
26#include <sys/random.h>
27#endif
28
29namespace bb::numeric {
30
31namespace {
32
33#if defined(__wasm__) || defined(__APPLE__) || defined(__ANDROID__)
34
35// In wasm, on mac os, and on Android the API we are using can only give 256 bytes per call,
36// so there is no point in creating a larger buffer
37constexpr size_t RANDOM_BUFFER_SIZE = 256;
38constexpr size_t BYTES_PER_GETENTROPY_READ = 256;
39
40#else
41
42// When working on native we allocate 1M of memory to sample randomness from urandom
43constexpr size_t RANDOM_BUFFER_SIZE = 1UL << 20;
44
45#endif
46struct RandomBufferWrapper {
47 // Buffer with randomness sampled from a CSPRNG
48 uint8_t buffer[RANDOM_BUFFER_SIZE];
49 // Offset into the unused part of the buffer
50 ssize_t offset = -1;
51};
52thread_local RandomBufferWrapper random_buffer_wrapper;
59template <size_t size_in_unsigned_ints> std::array<unsigned int, size_in_unsigned_ints> generate_random_data()
60{
61 static_assert(size_in_unsigned_ints > 0);
62 static_assert(size_in_unsigned_ints <= 32);
64 constexpr size_t random_data_buffer_size = sizeof(random_data);
65
66 // if the buffer is not initialized or doesn't contain enough bytes, sample randomness
67 // We could preserve the leftover bytes, but it's a bit messy
68 if (random_buffer_wrapper.offset == -1 ||
69 (static_cast<size_t>(random_buffer_wrapper.offset) + random_data_buffer_size) > RANDOM_BUFFER_SIZE) {
70 size_t bytes_left = RANDOM_BUFFER_SIZE;
71 uint8_t* current_offset = random_buffer_wrapper.buffer;
72 // Sample until we fill the buffer
73 while (bytes_left != 0) {
74#if defined(__wasm__) || defined(__APPLE__)
75 // Sample through a "syscall" on wasm. We can't request more than 256, it fails and results in an infinite
76 // loop
77 ssize_t read_bytes =
78 getentropy(current_offset, BYTES_PER_GETENTROPY_READ) == -1 ? -1 : BYTES_PER_GETENTROPY_READ;
79#elif defined(__ANDROID__)
80 // Android API 24 doesn't have getrandom/getentropy, read from /dev/urandom
81 static thread_local int urandom_fd = -1;
82 if (urandom_fd == -1) {
83 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
84 urandom_fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
85 }
86 ssize_t read_bytes = ::read(urandom_fd, current_offset, BYTES_PER_GETENTROPY_READ);
87#else
88 // Sample from urandom on native
89 auto read_bytes = getrandom(current_offset, bytes_left, 0);
90#endif
91 // If we read something, update the leftover
92 if (read_bytes != -1) {
93 current_offset += read_bytes;
94 bytes_left -= static_cast<size_t>(read_bytes);
95 }
96 }
97 random_buffer_wrapper.offset = 0;
98 }
99
100 memcpy(&random_data, random_buffer_wrapper.buffer + random_buffer_wrapper.offset, random_data_buffer_size);
101 random_buffer_wrapper.offset += static_cast<ssize_t>(random_data_buffer_size);
102 return random_data;
103}
104} // namespace
105
106class RandomEngine : public RNG {
107 public:
108 uint8_t get_random_uint8() override
109 {
110 auto buf = generate_random_data<1>();
111 uint32_t out = buf[0];
112 return static_cast<uint8_t>(out);
113 }
114
115 uint16_t get_random_uint16() override
116 {
117 auto buf = generate_random_data<1>();
118 uint32_t out = buf[0];
119 return static_cast<uint16_t>(out);
120 }
121
122 uint32_t get_random_uint32() override
123 {
124 auto buf = generate_random_data<1>();
125 uint32_t out = buf[0];
126 return static_cast<uint32_t>(out);
127 }
128
129 uint64_t get_random_uint64() override
130 {
131 auto buf = generate_random_data<2>();
132 auto lo = static_cast<uint64_t>(buf[0]);
133 auto hi = static_cast<uint64_t>(buf[1]);
134 return (lo + (hi << 32ULL));
135 }
136
138 {
139 const auto get64 = [](const std::array<uint32_t, 4>& buffer, const size_t offset) {
140 auto lo = static_cast<uint64_t>(buffer[0 + offset]);
141 auto hi = static_cast<uint64_t>(buffer[1 + offset]);
142 return (lo + (hi << 32ULL));
143 };
144 auto buf = generate_random_data<4>();
145 auto lo = static_cast<uint128_t>(get64(buf, 0));
146 auto hi = static_cast<uint128_t>(get64(buf, 2));
147
148 return (lo + (hi << static_cast<uint128_t>(64ULL)));
149 }
150
152 {
153 const auto get64 = [](const std::array<uint32_t, 8>& buffer, const size_t offset) {
154 auto lo = static_cast<uint64_t>(buffer[0 + offset]);
155 auto hi = static_cast<uint64_t>(buffer[1 + offset]);
156 return (lo + (hi << 32ULL));
157 };
158 auto buf = generate_random_data<8>();
159 uint64_t lolo = get64(buf, 0);
160 uint64_t lohi = get64(buf, 2);
161 uint64_t hilo = get64(buf, 4);
162 uint64_t hihi = get64(buf, 6);
163 return { lolo, lohi, hilo, hihi };
164 }
165};
166
167class DebugEngine : public RNG {
168 public:
170 // disable linting for this line: we want the DEBUG engine to produce predictable pseudorandom numbers!
171 // NOLINTNEXTLINE(cert-msc32-c, cert-msc51-cpp)
172 : engine(std::mt19937_64(12345))
173 {}
174
176 : engine(std::mt19937_64(seed))
177 {}
178
179 uint8_t get_random_uint8() override { return static_cast<uint8_t>(dist(engine)); }
180
181 uint16_t get_random_uint16() override { return static_cast<uint16_t>(dist(engine)); }
182
183 uint32_t get_random_uint32() override { return static_cast<uint32_t>(dist(engine)); }
184
185 uint64_t get_random_uint64() override { return dist(engine); }
186
188 {
189 uint128_t hi = dist(engine);
190 uint128_t lo = dist(engine);
191 return (hi << 64) | lo;
192 }
193
195 {
196 // Do not inline in constructor call. Evaluation order is important for cross-compiler consistency.
197 auto a = dist(engine);
198 auto b = dist(engine);
199 auto c = dist(engine);
200 auto d = dist(engine);
201 return { a, b, c, d };
202 }
203
204 private:
207};
208
213{
214 // static std::seed_seq seed({ 1, 2, 3, 4, 5 });
215 static DebugEngine debug_engine = DebugEngine();
216 if (reset) {
217 debug_engine = DebugEngine(seed);
218 }
219 return debug_engine;
220}
221
226{
227#ifdef BBERG_DEBUG_LOG
228 // Use determinism for logging
229 return get_debug_randomness();
230#else
231 static RandomEngine engine;
232 return engine;
233#endif
234}
235
236} // namespace bb::numeric
uint8_t get_random_uint8() override
Definition engine.cpp:179
DebugEngine(std::uint_fast64_t seed)
Definition engine.cpp:175
std::mt19937_64 engine
Definition engine.cpp:205
std::uniform_int_distribution< uint64_t > dist
Definition engine.cpp:206
uint32_t get_random_uint32() override
Definition engine.cpp:183
uint16_t get_random_uint16() override
Definition engine.cpp:181
uint64_t get_random_uint64() override
Definition engine.cpp:185
uint128_t get_random_uint128() override
Definition engine.cpp:187
uint256_t get_random_uint256() override
Definition engine.cpp:194
uint32_t get_random_uint32() override
Definition engine.cpp:122
uint8_t get_random_uint8() override
Definition engine.cpp:108
uint16_t get_random_uint16() override
Definition engine.cpp:115
uint256_t get_random_uint256() override
Definition engine.cpp:151
uint64_t get_random_uint64() override
Definition engine.cpp:129
uint128_t get_random_uint128() override
Definition engine.cpp:137
FF a
FF b
uint8_t const size_t length
Definition data_store.hpp:9
uint8_t const * buf
Definition data_store.hpp:9
numeric::RNG & engine
ssize_t offset
Definition engine.cpp:50
uint8_t buffer[RANDOM_BUFFER_SIZE]
Definition engine.cpp:48
void read(B &it, uint256_t &value)
Definition uint256.hpp:267
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:212
RNG & get_randomness()
Definition engine.cpp:225
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
unsigned __int128 uint128_t
Definition serialize.hpp:45