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