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