Expose random number generators using types instead of module methods
Random number generation is provided by various module methods in the module std::random
. While the resulting API is easy to use, it doesn't support the use of custom seeds. std::test
in turn uses std::random
to randomise the test order. Because std::random
doesn't support custom seeds, there's no way to reproduce test runs by setting a fixed seed (e.g. using the seed of a run that failed).
Instead of using module methods, std::random
should provide a Random
class. This class wraps an instance of the VM's random number generator. We should ensure creating instances of Random
doesn't result in the VM gathering entropy (e.g. using getrandom()
) on every call, as that would likely make this too slow. Instead, each worker thread in the VM has its own seed that it uses for the Random
instances created by it. This is essentially the same as the current use of rand::thread_rng()
. If a custom seed is given we use that seed instead of the thread-local seed. As Inko integers are 64 bits and this isn't suitable for cryptography, we should somehow make this clear as part of the method name. For example:
Random.new # Secure, seeded using a thread-local seed/generator
Random.with_seed(1, 2, 3, 4) # Secure, this would be interpreted as 256 bits by basically combining the values into a `[u8; 32]`
Random.with_insecure_seed(123) # Insecure, mostly used outside of cryptography (e.g. std::test)
The Random
type would expose methods to cover the current API, such as Random.int
, Random.float
, etc. Dropping a Random
should also release the underlying random number generator.