From e2fa9be7e2c02ad950e4f3205f5e67c9ebd3a70c Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sun, 21 Apr 2024 21:16:50 +0900 Subject: [PATCH] core/math/rand: Use `core:crypto` for the system RNG This removes some code duplication and expands support for the system RNG to all targets that `core:crypto` supports. --- core/math/rand/rand.odin | 39 ++++++++++++++++-------------- core/math/rand/system_darwin.odin | 22 ----------------- core/math/rand/system_js.odin | 14 ----------- core/math/rand/system_linux.odin | 29 ---------------------- core/math/rand/system_windows.odin | 13 ---------- 5 files changed, 21 insertions(+), 96 deletions(-) delete mode 100644 core/math/rand/system_darwin.odin delete mode 100644 core/math/rand/system_js.odin delete mode 100644 core/math/rand/system_linux.odin delete mode 100644 core/math/rand/system_windows.odin diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index d6a20bd1e..664d6abc9 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -5,6 +5,7 @@ Package core:math/rand implements various random number generators package rand import "base:intrinsics" +import "core:crypto" import "core:math" import "core:mem" @@ -104,27 +105,30 @@ init :: proc(r: ^Rand, seed: u64) { } /* -Initialises a random number generator to use the system random number generator. -The system random number generator is platform specific. -On `linux` refer to the `getrandom` syscall. -On `darwin` refer to `getentropy`. -On `windows` refer to `BCryptGenRandom`. - -All other platforms are not supported +Initialises a random number generator to use the system random number generator. +The system random number generator is platform specific, and not supported +on all targets. Inputs: - r: The random number generator to use the system random number generator -WARNING: Panics if the system is not either `windows`, `darwin` or `linux` +WARNING: Panics if the system random number generator is not supported. +Support can be determined via the `core:crypto.HAS_RAND_BYTES` constant. Example: + import "core:crypto" import "core:math/rand" import "core:fmt" init_as_system_example :: proc() { my_rand: rand.Rand - rand.init_as_system(&my_rand) - fmt.println(rand.uint64(&my_rand)) + switch crypto.HAS_RAND_BYTES { + case true: + rand.init_as_system(&my_rand) + fmt.println(rand.uint64(&my_rand)) + case false: + fmt.println("system random not supported!") + } } Possible Output: @@ -133,7 +137,7 @@ Possible Output: */ init_as_system :: proc(r: ^Rand) { - if !#defined(_system_random) { + if !crypto.HAS_RAND_BYTES { panic(#procedure + " is not supported on this platform yet") } r.state = 0 @@ -144,15 +148,14 @@ init_as_system :: proc(r: ^Rand) { @(private) _random_u64 :: proc(r: ^Rand) -> u64 { r := r - if r == nil { + switch { + case r == nil: r = &global_rand + case r.is_system: + value: u64 + crypto.rand_bytes((cast([^]u8)&value)[:size_of(u64)]) + return value } - when #defined(_system_random) { - if r.is_system { - return _system_random() - } - } - old_state := r.state r.state = old_state * 6364136223846793005 + (r.inc|1) diff --git a/core/math/rand/system_darwin.odin b/core/math/rand/system_darwin.odin deleted file mode 100644 index 756f7fcae..000000000 --- a/core/math/rand/system_darwin.odin +++ /dev/null @@ -1,22 +0,0 @@ -package rand - -import "core:sys/darwin" - -@(require_results) -_system_random :: proc() -> u64 { - for { - value: u64 - ret := darwin.syscall_getentropy(([^]u8)(&value), size_of(value)) - if ret < 0 { - switch ret { - case -4: // EINTR - continue - case -78: // ENOSYS - panic("getentropy not available in kernel") - case: - panic("getentropy failed") - } - } - return value - } -} \ No newline at end of file diff --git a/core/math/rand/system_js.odin b/core/math/rand/system_js.odin deleted file mode 100644 index b9b71c4a6..000000000 --- a/core/math/rand/system_js.odin +++ /dev/null @@ -1,14 +0,0 @@ -package rand - -foreign import "odin_env" -foreign odin_env { - @(link_name = "rand_bytes") - env_rand_bytes :: proc "contextless" (buf: []byte) --- -} - -@(require_results) -_system_random :: proc() -> u64 { - buf: [8]u8 - env_rand_bytes(buf[:]) - return transmute(u64)buf -} diff --git a/core/math/rand/system_linux.odin b/core/math/rand/system_linux.odin deleted file mode 100644 index 42c9f86fa..000000000 --- a/core/math/rand/system_linux.odin +++ /dev/null @@ -1,29 +0,0 @@ -package rand - -import "core:sys/linux" - -@(require_results) -_system_random :: proc() -> u64 { - for { - value: u64 - value_buf := (cast([^]u8)&value)[:size_of(u64)] - _, errno := linux.getrandom(value_buf, {}) - #partial switch errno { - case .NONE: - // Do nothing - case .EINTR: - // Call interupted by a signal handler, just retry the request. - continue - case .ENOSYS: - // The kernel is apparently prehistoric (< 3.17 circa 2014) - // and does not support getrandom. - panic("getrandom not available in kernel") - case: - // All other failures are things that should NEVER happen - // unless the kernel interface changes (ie: the Linux - // developers break userland). - panic("getrandom failed") - } - return value - } -} \ No newline at end of file diff --git a/core/math/rand/system_windows.odin b/core/math/rand/system_windows.odin deleted file mode 100644 index c6d68816d..000000000 --- a/core/math/rand/system_windows.odin +++ /dev/null @@ -1,13 +0,0 @@ -package rand - -import win32 "core:sys/windows" - -@(require_results) -_system_random :: proc() -> u64 { - value: u64 - status := win32.BCryptGenRandom(nil, ([^]u8)(&value), size_of(value), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG) - if status < 0 { - panic("BCryptGenRandom failed") - } - return value -} \ No newline at end of file