From 902e877467bb4bb1705652e36e5f43a2776adeb7 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sun, 21 Apr 2024 21:21:46 +0900 Subject: [PATCH 1/3] repo: Add more test binaries to .gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 228f006a3..f6c3927a2 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,8 @@ tests/documentation/all.odin-doc tests/internal/test_map tests/internal/test_pow tests/internal/test_rtti +tests/core/test_base64 +tests/core/test_cbor tests/core/test_core_compress tests/core/test_core_container tests/core/test_core_filepath @@ -40,8 +42,10 @@ tests/core/test_core_net tests/core/test_core_os_exit tests/core/test_core_reflect tests/core/test_core_strings +tests/core/test_core_time tests/core/test_crypto tests/core/test_hash +tests/core/test_hex tests/core/test_hxa tests/core/test_json tests/core/test_linalg_glsl_math From a6eb64df6cd136639d1234e5a157ad280a1a32a8 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sun, 21 Apr 2024 21:06:21 +0900 Subject: [PATCH 2/3] core/crypto: Add a `HAS_RAND_BYTES` constant --- core/crypto/crypto.odin | 9 +++------ core/crypto/rand_bsd.odin | 7 +++---- core/crypto/rand_darwin.odin | 7 +++---- core/crypto/rand_generic.odin | 7 +++---- core/crypto/rand_js.odin | 8 ++++---- core/crypto/rand_linux.odin | 8 ++++---- core/crypto/rand_windows.odin | 7 +++---- tests/core/crypto/test_core_crypto.odin | 2 +- 8 files changed, 24 insertions(+), 31 deletions(-) diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin index 05f25111a..f0874cc6d 100644 --- a/core/crypto/crypto.odin +++ b/core/crypto/crypto.odin @@ -49,15 +49,12 @@ compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> i // the system entropy source. This routine will block if the system entropy // source is not ready yet. All system entropy source failures are treated // as catastrophic, resulting in a panic. +// +// Support for the system entropy source can be checked with the +// `HAS_RAND_BYTES` boolean constant. rand_bytes :: proc (dst: []byte) { // zero-fill the buffer first mem.zero_explicit(raw_data(dst), len(dst)) _rand_bytes(dst) } - -// has_rand_bytes returns true iff the target has support for accessing the -// system entropty source. -has_rand_bytes :: proc () -> bool { - return _has_rand_bytes() -} diff --git a/core/crypto/rand_bsd.odin b/core/crypto/rand_bsd.odin index 7a0c42683..a31e4f2b2 100644 --- a/core/crypto/rand_bsd.odin +++ b/core/crypto/rand_bsd.odin @@ -3,14 +3,13 @@ package crypto foreign import libc "system:c" +HAS_RAND_BYTES :: true + foreign libc { arc4random_buf :: proc(buf: [^]byte, nbytes: uint) --- } +@(private) _rand_bytes :: proc(dst: []byte) { arc4random_buf(raw_data(dst), len(dst)) } - -_has_rand_bytes :: proc() -> bool { - return true -} diff --git a/core/crypto/rand_darwin.odin b/core/crypto/rand_darwin.odin index c1a3d1dbc..5355f31c5 100644 --- a/core/crypto/rand_darwin.odin +++ b/core/crypto/rand_darwin.odin @@ -5,6 +5,9 @@ import "core:fmt" import CF "core:sys/darwin/CoreFoundation" import Sec "core:sys/darwin/Security" +HAS_RAND_BYTES :: true + +@(private) _rand_bytes :: proc(dst: []byte) { err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst)) if err != .Success { @@ -12,7 +15,3 @@ _rand_bytes :: proc(dst: []byte) { panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg)) } } - -_has_rand_bytes :: proc() -> bool { - return true -} diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin index cba49f700..4ea61ec91 100644 --- a/core/crypto/rand_generic.odin +++ b/core/crypto/rand_generic.odin @@ -6,10 +6,9 @@ //+build !js package crypto +HAS_RAND_BYTES :: false + +@(private) _rand_bytes :: proc(dst: []byte) { unimplemented("crypto: rand_bytes not supported on this OS") } - -_has_rand_bytes :: proc() -> bool { - return false -} diff --git a/core/crypto/rand_js.odin b/core/crypto/rand_js.odin index 90f60b99b..72093810e 100644 --- a/core/crypto/rand_js.odin +++ b/core/crypto/rand_js.odin @@ -6,8 +6,12 @@ foreign odin_env { env_rand_bytes :: proc "contextless" (buf: []byte) --- } +HAS_RAND_BYTES :: true + +@(private) _MAX_PER_CALL_BYTES :: 65536 // 64kiB +@(private) _rand_bytes :: proc(dst: []byte) { dst := dst @@ -18,7 +22,3 @@ _rand_bytes :: proc(dst: []byte) { dst = dst[to_read:] } } - -_has_rand_bytes :: proc() -> bool { - return true -} diff --git a/core/crypto/rand_linux.odin b/core/crypto/rand_linux.odin index a9dc37415..43b3b3075 100644 --- a/core/crypto/rand_linux.odin +++ b/core/crypto/rand_linux.odin @@ -4,8 +4,12 @@ import "core:fmt" import "core:sys/linux" +HAS_RAND_BYTES :: true + +@(private) _MAX_PER_CALL_BYTES :: 33554431 // 2^25 - 1 +@(private) _rand_bytes :: proc (dst: []byte) { dst := dst l := len(dst) @@ -34,7 +38,3 @@ _rand_bytes :: proc (dst: []byte) { dst = dst[n_read:] } } - -_has_rand_bytes :: proc() -> bool { - return true -} diff --git a/core/crypto/rand_windows.odin b/core/crypto/rand_windows.odin index 5cafe7fb5..a92d376cb 100644 --- a/core/crypto/rand_windows.odin +++ b/core/crypto/rand_windows.odin @@ -4,6 +4,9 @@ import win32 "core:sys/windows" import "core:os" import "core:fmt" +HAS_RAND_BYTES :: true + +@(private) _rand_bytes :: proc(dst: []byte) { ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) if ret != os.ERROR_NONE { @@ -21,7 +24,3 @@ _rand_bytes :: proc(dst: []byte) { } } } - -_has_rand_bytes :: proc() -> bool { - return true -} diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 72d8e7c78..95db3f292 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -277,7 +277,7 @@ test_chacha20poly1305 :: proc(t: ^testing.T) { test_rand_bytes :: proc(t: ^testing.T) { tc.log(t, "Testing rand_bytes") - if !crypto.has_rand_bytes() { + if !crypto.HAS_RAND_BYTES { tc.log(t, "rand_bytes not supported - skipping") return } From e2fa9be7e2c02ad950e4f3205f5e67c9ebd3a70c Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sun, 21 Apr 2024 21:16:50 +0900 Subject: [PATCH 3/3] 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