Browse Source

Add `runtime.Random_Generator` interface

gingerBill 1 year ago
parent
commit
dc4ec8638c
3 changed files with 66 additions and 0 deletions
  1. 19 0
      base/runtime/core.odin
  2. 20 0
      core/crypto/crypto.odin
  3. 27 0
      core/math/rand/rand.odin

+ 19 - 0
base/runtime/core.odin

@@ -397,11 +397,30 @@ Logger :: struct {
 	options:      Logger_Options,
 }
 
+
+Random_Generator_Mode :: enum {
+	Read,
+	Query_Info,
+}
+
+Random_Generator_Query_Info_Flag :: enum u32 {
+	Cryptographic,
+	Uniform,
+	External_Entropy,
+}
+Random_Generator_Query_Info :: distinct bit_set[Random_Generator_Query_Info_Flag; u32]
+
+Random_Generator :: struct {
+	procedure: proc(data: rawptr, mode: Random_Generator_Mode, p: []byte),
+	data:      rawptr,
+}
+
 Context :: struct {
 	allocator:              Allocator,
 	temp_allocator:         Allocator,
 	assertion_failure_proc: Assertion_Failure_Proc,
 	logger:                 Logger,
+	random_generator:       Random_Generator,
 
 	user_ptr:   rawptr,
 	user_index: int,

+ 20 - 0
core/crypto/crypto.odin

@@ -4,6 +4,7 @@ helper routines.
 */
 package crypto
 
+import "base:runtime"
 import "core:mem"
 
 // compare_constant_time returns 1 iff a and b are equal, 0 otherwise.
@@ -58,3 +59,22 @@ rand_bytes :: proc (dst: []byte) {
 
 	_rand_bytes(dst)
 }
+
+
+to_random_generator :: proc() -> runtime.Random_Generator {
+	return {
+		procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) {
+			switch mode {
+			case .Read:
+				rand_bytes(p)
+			case .Query_Info:
+				if len(p) != size_of(runtime.Random_Generator_Query_Info) {
+					return
+				}
+				info := (^runtime.Random_Generator_Query_Info)(raw_data(p))
+				info^ += {.Uniform, .Cryptographic, .External_Entropy}
+			}
+		},
+		data = nil,
+	}
+}

+ 27 - 0
core/math/rand/rand.odin

@@ -5,6 +5,7 @@ Package core:math/rand implements various random number generators
 package rand
 
 import "base:intrinsics"
+import "base:runtime"
 import "core:crypto"
 import "core:math"
 import "core:mem"
@@ -15,6 +16,28 @@ Rand :: struct {
 	is_system: bool,
 }
 
+to_random_generator :: proc(r: ^Rand) -> runtime.Random_Generator {
+	return {
+		procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) {
+			r := (^Rand)(data)
+			switch mode {
+			case .Read:
+				_ = read(p, r)
+			case .Query_Info:
+				if len(p) != size_of(runtime.Random_Generator_Query_Info) {
+					return
+				}
+				info := (^runtime.Random_Generator_Query_Info)(raw_data(p))
+				info^ += {.Uniform}
+				if r.is_system {
+					info^ += {.External_Entropy}
+				}
+			}
+		},
+		data = r,
+	}
+}
+
 
 @(private)
 global_rand := create(u64(intrinsics.read_cycle_counter()))
@@ -150,6 +173,10 @@ _random_u64 :: proc(r: ^Rand) -> u64 {
 	r := r
 	switch {
 	case r == nil:
+		if res: u64; runtime.random_generator_read_ptr(context.random_generator, &res, size_of(res)) {
+			return res
+		}
+
 		r = &global_rand
 	case r.is_system:
 		value: u64