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