mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
Add rand.init_as_system to allow for system-level based random number generation
This commit is contained in:
@@ -5,6 +5,7 @@ import "core:intrinsics"
|
|||||||
Rand :: struct {
|
Rand :: struct {
|
||||||
state: u64,
|
state: u64,
|
||||||
inc: u64,
|
inc: u64,
|
||||||
|
is_system: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -29,6 +30,16 @@ init :: proc(r: ^Rand, seed: u64) {
|
|||||||
_random(r)
|
_random(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init_as_system :: proc(r: ^Rand) {
|
||||||
|
if !#defined(_system_random) {
|
||||||
|
panic(#procedure + " is not supported on this platform yet")
|
||||||
|
}
|
||||||
|
r.state = 0
|
||||||
|
r.inc = 0
|
||||||
|
r.is_system = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
_random :: proc(r: ^Rand) -> u32 {
|
_random :: proc(r: ^Rand) -> u32 {
|
||||||
r := r
|
r := r
|
||||||
if r == nil {
|
if r == nil {
|
||||||
@@ -36,6 +47,12 @@ _random :: proc(r: ^Rand) -> u32 {
|
|||||||
// enforce the global random state if necessary with `nil`
|
// enforce the global random state if necessary with `nil`
|
||||||
r = &global_rand
|
r = &global_rand
|
||||||
}
|
}
|
||||||
|
when #defined(_system_random) {
|
||||||
|
if r.is_system {
|
||||||
|
return _system_random()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
old_state := r.state
|
old_state := r.state
|
||||||
r.state = old_state * 6364136223846793005 + (r.inc|1)
|
r.state = old_state * 6364136223846793005 + (r.inc|1)
|
||||||
xor_shifted := u32(((old_state>>18) ~ old_state) >> 27)
|
xor_shifted := u32(((old_state>>18) ~ old_state) >> 27)
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package rand
|
||||||
|
|
||||||
|
import "core:sys/unix"
|
||||||
|
|
||||||
|
_system_random :: proc() -> u32 {
|
||||||
|
for {
|
||||||
|
value: u32
|
||||||
|
ret := unix.sys_getrandom(([^]u8)(&value), 4, 0)
|
||||||
|
if ret < 0 {
|
||||||
|
switch ret {
|
||||||
|
case -4: // EINTR
|
||||||
|
// Call interupted by a signal handler, just retry the request.
|
||||||
|
continue
|
||||||
|
case -38: // 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package rand
|
||||||
|
|
||||||
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
|
_system_random :: proc() -> u32 {
|
||||||
|
value: u32
|
||||||
|
status := win32.BCryptGenRandom(nil, ([^]u8)(&value), 4, win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)
|
||||||
|
if status < 0 {
|
||||||
|
panic("BCryptGenRandom failed")
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user