mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 17:05:36 +00:00
[core] Use SplitMix32 PRNG for random_uint32() across platforms
Replace platform-specific random_uint32() implementations with a unified SplitMix32 PRNG seeded from random_bytes(). This provides consistent, fast, non-cryptographic random numbers on all platforms. ESP8266 retains os_random() as it is already faster on that platform. Benchmarked on real hardware (ns/call, before -> after): - RP2040: 2815 -> 333 (8.5x faster) - ESP32: 871 -> 354 (2.5x faster) - BK72xx: 1073 -> 882 (1.2x faster, replaces weak rand()) - RTL87xx: 330 -> 283 (1.2x faster, replaces weak rand()) - ESP8266: 763 (unchanged, keeps os_random()) random_bytes() remains platform-specific hardware RNG for crypto use.
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
uint32_t random_uint32() { return esp_random(); }
|
||||
bool random_bytes(uint8_t *data, size_t len) {
|
||||
esp_fill_random(data, len);
|
||||
return true;
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
@@ -18,13 +16,6 @@ namespace esphome {
|
||||
|
||||
static const char *const TAG = "helpers.host";
|
||||
|
||||
uint32_t random_uint32() {
|
||||
std::random_device dev;
|
||||
std::mt19937 rng(dev());
|
||||
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint32_t>::max());
|
||||
return dist(rng);
|
||||
}
|
||||
|
||||
bool random_bytes(uint8_t *data, size_t len) {
|
||||
FILE *fp = fopen("/dev/urandom", "r");
|
||||
if (fp == nullptr) {
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
uint32_t random_uint32() { return rand(); }
|
||||
|
||||
bool random_bytes(uint8_t *data, size_t len) {
|
||||
lt_rand_bytes(data, len);
|
||||
return true;
|
||||
|
||||
@@ -16,15 +16,6 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
uint32_t random_uint32() {
|
||||
uint32_t result = 0;
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
result <<= 1;
|
||||
result |= rosc_hw->randombit;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool random_bytes(uint8_t *data, size_t len) {
|
||||
while (len-- != 0) {
|
||||
uint8_t result = 0;
|
||||
|
||||
@@ -75,7 +75,6 @@ IRAM_ATTR InterruptLock::~InterruptLock() { irq_unlock(state_); }
|
||||
|
||||
// Zephyr LwIPLock is defined inline as a no-op in helpers.h
|
||||
|
||||
uint32_t random_uint32() { return rand(); } // NOLINT(cert-msc30-c, cert-msc50-cpp)
|
||||
bool random_bytes(uint8_t *data, size_t len) {
|
||||
sys_rand_get(data, len);
|
||||
return true;
|
||||
|
||||
@@ -156,6 +156,25 @@ uint32_t fnv1_hash(const char *str) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
// SplitMix32 PRNG — MurmurHash3 finalizer with golden-ratio increment.
|
||||
// Provides fast, uniform, non-cryptographic random numbers.
|
||||
// Seeded lazily from the platform's hardware RNG via random_bytes().
|
||||
// ESP8266 uses os_random() instead (defined in esp8266/helpers.cpp).
|
||||
#ifndef USE_ESP8266
|
||||
static uint32_t splitmix32_state; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
uint32_t random_uint32() {
|
||||
if (splitmix32_state == 0) {
|
||||
random_bytes(reinterpret_cast<uint8_t *>(&splitmix32_state), sizeof(splitmix32_state));
|
||||
}
|
||||
splitmix32_state += 0x9e3779b9u;
|
||||
uint32_t z = splitmix32_state;
|
||||
z = (z ^ (z >> 16)) * 0x85ebca6bu;
|
||||
z = (z ^ (z >> 13)) * 0xc2b2ae35u;
|
||||
return z ^ (z >> 16);
|
||||
}
|
||||
#endif
|
||||
|
||||
float random_float() { return static_cast<float>(random_uint32()) / static_cast<float>(UINT32_MAX); }
|
||||
|
||||
// Strings
|
||||
|
||||
@@ -842,10 +842,15 @@ template<typename ReturnT = uint32_t> inline constexpr ESPHOME_ALWAYS_INLINE Ret
|
||||
}
|
||||
|
||||
/// Return a random 32-bit unsigned integer.
|
||||
/// Not thread-safe. Must only be called from the main loop.
|
||||
/// Not suitable for cryptographic use; use random_bytes() instead.
|
||||
uint32_t random_uint32();
|
||||
/// Return a random float between 0 and 1.
|
||||
/// Not thread-safe. Must only be called from the main loop.
|
||||
/// Not suitable for cryptographic use; use random_bytes() instead.
|
||||
float random_float();
|
||||
/// Generate \p len number of random bytes.
|
||||
/// Generate \p len number of random bytes from the platform's hardware RNG.
|
||||
/// Thread-safe. Suitable for cryptographic use.
|
||||
bool random_bytes(uint8_t *data, size_t len);
|
||||
|
||||
///@}
|
||||
|
||||
Reference in New Issue
Block a user