From 3eccff336036dc7030a6d9f4a2d4b6ca0796b4aa Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 1 Nov 2024 14:01:08 +0000 Subject: [PATCH 1/7] faster sampling --- .../barretenberg/numeric/random/engine.cpp | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp index 8af63177345..9ff2fd75e97 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp @@ -1,17 +1,54 @@ #include "engine.hpp" #include "barretenberg/common/assert.hpp" #include +#include #include +#include #include +#include namespace bb::numeric { namespace { +#ifndef __wasm__ +constexpr size_t RANDOM_BUFFER_SIZE = 1UL << 20; +#else +constexpr size_t RANDOM_BUFFER_SIZE = 256; +constexpr size_t BYTES_PER_GETENTROPY_READ = 256; +#endif +uint8_t random_buffer[RANDOM_BUFFER_SIZE]; +ssize_t random_buffer_offset = -1; +#ifndef NO_MULTITHREADING +std::mutex random_buffer_mutex; +#endif auto generate_random_data() { std::array random_data; - std::random_device source; - std::generate(std::begin(random_data), std::end(random_data), std::ref(source)); + constexpr size_t random_data_buffer_size = sizeof(random_data); + // if the buffer is not initialized or doesn't contain enough bytes, sample randomness +#ifndef NO_MULTITHREADING + std::unique_lock lock(random_buffer_mutex); +#endif + if (random_data_buffer_size == 1 || + (static_cast(random_buffer_offset) + random_data_buffer_size) > RANDOM_BUFFER_SIZE) { + size_t bytes_left = RANDOM_BUFFER_SIZE; + uint8_t* current_offset = random_buffer; + while (bytes_left != 0) { +#ifndef __wasm__ + auto read_bytes = getrandom(current_offset, bytes_left, 0); +#else + ssize_t read_bytes = + getentropy(current_offset, BYTES_PER_GETENTROPY_READ) == -1 ? -1 : BYTES_PER_GETENTROPY_READ; +#endif + if (read_bytes != -1) { + current_offset += read_bytes; + bytes_left -= static_cast(read_bytes); + } + } + random_buffer_offset = 0; + } + memcpy(&random_data, random_buffer + random_buffer_offset, random_data_buffer_size); + random_buffer_offset += random_data_buffer_size; return random_data; } } // namespace From 86be54bc51b82d078a2555fc12ba578e3b38af07 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 1 Nov 2024 16:07:01 +0000 Subject: [PATCH 2/7] works for both --- .../barretenberg/numeric/random/engine.cpp | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp index 9ff2fd75e97..6577e6603d8 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp @@ -10,6 +10,7 @@ namespace bb::numeric { namespace { + #ifndef __wasm__ constexpr size_t RANDOM_BUFFER_SIZE = 1UL << 20; #else @@ -21,9 +22,11 @@ ssize_t random_buffer_offset = -1; #ifndef NO_MULTITHREADING std::mutex random_buffer_mutex; #endif -auto generate_random_data() +template auto generate_random_data() { - std::array random_data; + static_assert(size_in_unsigned_ints > 0); + static_assert(size_in_unsigned_ints <= 32); + std::array random_data; constexpr size_t random_data_buffer_size = sizeof(random_data); // if the buffer is not initialized or doesn't contain enough bytes, sample randomness #ifndef NO_MULTITHREADING @@ -57,28 +60,28 @@ class RandomEngine : public RNG { public: uint8_t get_random_uint8() override { - auto buf = generate_random_data(); + auto buf = generate_random_data<1>(); uint32_t out = buf[0]; return static_cast(out); } uint16_t get_random_uint16() override { - auto buf = generate_random_data(); + auto buf = generate_random_data<1>(); uint32_t out = buf[0]; return static_cast(out); } uint32_t get_random_uint32() override { - auto buf = generate_random_data(); + auto buf = generate_random_data<1>(); uint32_t out = buf[0]; return static_cast(out); } uint64_t get_random_uint64() override { - auto buf = generate_random_data(); + auto buf = generate_random_data<2>(); auto lo = static_cast(buf[0]); auto hi = static_cast(buf[1]); return (lo + (hi << 32ULL)); @@ -86,20 +89,26 @@ class RandomEngine : public RNG { uint128_t get_random_uint128() override { - auto big = get_random_uint256(); - auto lo = static_cast(big.data[0]); - auto hi = static_cast(big.data[1]); + const auto get64 = [](const std::array& buffer, const size_t offset) { + auto lo = static_cast(buffer[0 + offset]); + auto hi = static_cast(buffer[1 + offset]); + return (lo + (hi << 32ULL)); + }; + auto buf = generate_random_data<4>(); + auto lo = static_cast(get64(buf, 0)); + auto hi = static_cast(get64(buf, 2)); + return (lo + (hi << static_cast(64ULL))); } uint256_t get_random_uint256() override { - const auto get64 = [](const std::array& buffer, const size_t offset) { + const auto get64 = [](const std::array& buffer, const size_t offset) { auto lo = static_cast(buffer[0 + offset]); auto hi = static_cast(buffer[1 + offset]); return (lo + (hi << 32ULL)); }; - auto buf = generate_random_data(); + auto buf = generate_random_data<8>(); uint64_t lolo = get64(buf, 0); uint64_t lohi = get64(buf, 2); uint64_t hilo = get64(buf, 4); From 19e49d7e4bfa794af522de2b2c11559b64bd548e Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 1 Nov 2024 16:26:41 +0000 Subject: [PATCH 3/7] comments --- .../barretenberg/numeric/random/engine.cpp | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp index 6577e6603d8..e9453a7ff81 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp @@ -12,37 +12,58 @@ namespace bb::numeric { namespace { #ifndef __wasm__ +// When working on native we allocate 1M of memory to sample randomness from urandom constexpr size_t RANDOM_BUFFER_SIZE = 1UL << 20; #else +// In wasm the API we are using can only give 256 bytes per call, so there is no point in creating a larger buffer constexpr size_t RANDOM_BUFFER_SIZE = 256; constexpr size_t BYTES_PER_GETENTROPY_READ = 256; #endif +// Buffer with randomness sampled from a CSPRNG uint8_t random_buffer[RANDOM_BUFFER_SIZE]; +// Offset into the unused part of the buffer ssize_t random_buffer_offset = -1; + #ifndef NO_MULTITHREADING +// We don't want races to happen std::mutex random_buffer_mutex; #endif -template auto generate_random_data() + +/** + * @brief Generate an array of random unsigned ints sampled from a CSPRNG + * + * @tparam size_in_unsigned_ints Size of the array + * @return std::array + */ +template std::array generate_random_data() { static_assert(size_in_unsigned_ints > 0); static_assert(size_in_unsigned_ints <= 32); std::array random_data; constexpr size_t random_data_buffer_size = sizeof(random_data); - // if the buffer is not initialized or doesn't contain enough bytes, sample randomness + #ifndef NO_MULTITHREADING std::unique_lock lock(random_buffer_mutex); #endif - if (random_data_buffer_size == 1 || + + // if the buffer is not initialized or doesn't contain enough bytes, sample randomness + // We could preserve the leftover bytes, but it's a bit messy + if (random_buffer_offset == -1 || (static_cast(random_buffer_offset) + random_data_buffer_size) > RANDOM_BUFFER_SIZE) { size_t bytes_left = RANDOM_BUFFER_SIZE; uint8_t* current_offset = random_buffer; + // Sample until we fill the buffer while (bytes_left != 0) { #ifndef __wasm__ + // Sample from urandom on native auto read_bytes = getrandom(current_offset, bytes_left, 0); #else + // Sample through a "syscall" on wasm. We can't request more than 256, it fails and results in an infinite + // loop ssize_t read_bytes = getentropy(current_offset, BYTES_PER_GETENTROPY_READ) == -1 ? -1 : BYTES_PER_GETENTROPY_READ; #endif + // If we read something, update the leftover if (read_bytes != -1) { current_offset += read_bytes; bytes_left -= static_cast(read_bytes); @@ -50,6 +71,7 @@ template auto generate_random_data() } random_buffer_offset = 0; } + memcpy(&random_data, random_buffer + random_buffer_offset, random_data_buffer_size); random_buffer_offset += random_data_buffer_size; return random_data; From 417c055b7cf037f8d2da6ca1db395bc81c7eeed6 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 1 Nov 2024 16:56:37 +0000 Subject: [PATCH 4/7] Fix an accidental bad push --- .../cpp/src/barretenberg/ecc/fields/field_impl.hpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl.hpp index 17f034e40d7..0ed0c481dec 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl.hpp @@ -691,14 +691,8 @@ template field field::random_element(numeric::RNG* engine) noexc constexpr field pow_2_256 = field(uint256_t(1) << 128).sqr(); field lo; field hi; - *(uint256_t*)lo.data = engine->get_random_uint256(); - *(uint256_t*)hi.data = engine->get_random_uint256(); - lo.self_reduce_once(); - lo.self_reduce_once(); - lo.self_reduce_once(); - hi.self_reduce_once(); - hi.self_reduce_once(); - hi.self_reduce_once(); + lo = engine->get_random_uint256(); + hi = engine->get_random_uint256(); return lo + (pow_2_256 * hi); } From 7cda806cfcb230441e24e65834918fa9e172be90 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 1 Nov 2024 17:53:25 +0000 Subject: [PATCH 5/7] thread-local instead of mutexes --- .../cpp/src/barretenberg/numeric/random/engine.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp index e9453a7ff81..860c3c6cea5 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -20,14 +19,9 @@ constexpr size_t RANDOM_BUFFER_SIZE = 256; constexpr size_t BYTES_PER_GETENTROPY_READ = 256; #endif // Buffer with randomness sampled from a CSPRNG -uint8_t random_buffer[RANDOM_BUFFER_SIZE]; +thread_local uint8_t random_buffer[RANDOM_BUFFER_SIZE]; // Offset into the unused part of the buffer -ssize_t random_buffer_offset = -1; - -#ifndef NO_MULTITHREADING -// We don't want races to happen -std::mutex random_buffer_mutex; -#endif +thread_local ssize_t random_buffer_offset = -1; /** * @brief Generate an array of random unsigned ints sampled from a CSPRNG @@ -42,10 +36,6 @@ template std::array random_data; constexpr size_t random_data_buffer_size = sizeof(random_data); -#ifndef NO_MULTITHREADING - std::unique_lock lock(random_buffer_mutex); -#endif - // if the buffer is not initialized or doesn't contain enough bytes, sample randomness // We could preserve the leftover bytes, but it's a bit messy if (random_buffer_offset == -1 || From c9da865b9e8ac175bc31690356a79d5cccd8e47a Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 1 Nov 2024 19:00:20 +0000 Subject: [PATCH 6/7] put into one structure --- .../barretenberg/numeric/random/engine.cpp | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp index 860c3c6cea5..40df6b891ee 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp @@ -18,11 +18,13 @@ constexpr size_t RANDOM_BUFFER_SIZE = 1UL << 20; constexpr size_t RANDOM_BUFFER_SIZE = 256; constexpr size_t BYTES_PER_GETENTROPY_READ = 256; #endif -// Buffer with randomness sampled from a CSPRNG -thread_local uint8_t random_buffer[RANDOM_BUFFER_SIZE]; -// Offset into the unused part of the buffer -thread_local ssize_t random_buffer_offset = -1; - +struct RandomBufferWrapper { + // Buffer with randomness sampled from a CSPRNG + uint8_t buffer[RANDOM_BUFFER_SIZE]; + // Offset into the unused part of the buffer + ssize_t offset = -1; +}; +thread_local RandomBufferWrapper random_buffer_wrapper; /** * @brief Generate an array of random unsigned ints sampled from a CSPRNG * @@ -38,10 +40,10 @@ template std::array(random_buffer_offset) + random_data_buffer_size) > RANDOM_BUFFER_SIZE) { + if (random_buffer_wrapper.offset == -1 || + (static_cast(random_buffer_wrapper.offset) + random_data_buffer_size) > RANDOM_BUFFER_SIZE) { size_t bytes_left = RANDOM_BUFFER_SIZE; - uint8_t* current_offset = random_buffer; + uint8_t* current_offset = random_buffer_wrapper.buffer; // Sample until we fill the buffer while (bytes_left != 0) { #ifndef __wasm__ @@ -59,11 +61,11 @@ template std::array(read_bytes); } } - random_buffer_offset = 0; + random_buffer_wrapper.offset = 0; } - memcpy(&random_data, random_buffer + random_buffer_offset, random_data_buffer_size); - random_buffer_offset += random_data_buffer_size; + memcpy(&random_data, random_buffer_wrapper.buffer + random_buffer_wrapper.offset, random_data_buffer_size); + random_buffer_wrapper.offset += random_data_buffer_size; return random_data; } } // namespace From d7793541dd7e6deb620ee4a40924b2f7e601bd41 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 1 Nov 2024 19:58:57 +0000 Subject: [PATCH 7/7] fix --- barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp index 40df6b891ee..a6cc39686c6 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp @@ -65,7 +65,7 @@ template std::array(random_data_buffer_size); return random_data; } } // namespace