std.rand.Random
type pub Random
A cryptographically secure pseudo random number generator (CSPRNG).
The underlying algorithm is ChaCha8, loosely based on Go's ChaCha8 CSPRNG as described here, and Pony's random number generation code as found here and here.
Fast-key-erasure is applied in an attempt to make attacks against the RNG more difficult.
While the current implementation should be sufficient/not obviously broken, it hasn't been formally verified or audited and thus may still contain some flaws.
Static methods
from_int
Show source codeHide source code
fn pub static from_int(value: Int) -> Self {
let seed = ByteArray.filled(with: 0, times: SEED_SIZE)
little.write_i64(value, into: seed, at: 0)
with_seed(seed)
}
fn pub static from_int(value: Int) -> Random
Returns a new Random
using the given Int
as its seed.
Random
instances created using this method are not suitable for
cryptography, as a single Int
doesn't produce enough entropy. For
cryptography you must use Random.new
instead.
Refer to the documentation of Random.new
for more details.
Examples
import std.rand (Random)
Random.from_int(42)
new
Show source codeHide source code
fn pub static new -> Self {
let seed = ByteArray.new
sys.random_bytes(into: seed, size: SEED_SIZE)
with_seed(seed)
}
fn pub static new -> Random
Returns a new Random
seeded using a cryptographically secure seed.
The seed is generated using the operating system's CSPRNG.
While creating a Random
instance isn't necessarily expensive, it's not
cheap either. As such it's best to create an instance (or multiple
instances) ahead of time and reuse them, instead of creating them on the
fly.
Examples
import std.rand (Random)
Random.new
Instance methods
bytes
Show source codeHide source code
fn pub mut bytes(into: mut ByteArray, size: Int) {
let mut rem = size
while rem > 0 {
if @index == BUFFER_SIZE { refill }
let idx = @index
let end = min(idx + rem, @buffer.size)
let len = end - idx
into.append(@buffer.slice(start: idx, end: end))
zero(idx, len)
rem = rem.wrapping_sub(len)
@index = idx.wrapping_add(len)
}
}
fn pub mut bytes(into: mut ByteArray, size: Int)
Generates size
random bytes and appends them to into
.
Examples
import std.rand (Random)
let rng = Random.from_int(10)
let buf = ByteArray.new
rng.bytes(into: buf, size: 8)
buf # => ByteArray.from_array([14, 98, 139, 15, 133, 67, 84, 178])
float
Show source codeHide source code
fn pub mut float -> Float {
(int >>> 11).to_float * (1.0 / 9007199254740992.0)
}
fn pub mut float -> Float
Returns a randomly generated Float
in the end exclusive range
0.0..1.0
.
Examples
import std.rand (Random)
let rng = Random.from_int(10)
rng.float # => 0.6965982627730631
float_between
Show source codeHide source code
fn pub mut float_between(min: Float, max: Float) -> Float {
if min > max { invalid_range_error(min, max) }
float * (max - min) + min
}
fn pub mut float_between(min: Float, max: Float) -> Float
Returns a randomly generated Float
uniformly distributed in the given end
exclusive range.
Panics
This method panics if min
is greater than max
.
Examples
import std.rand (Random)
let rng = Random.from_int(10)
rng.float_between(1.0, 10.0) # => 7.269384364957569
int
Show source codeHide source code
fn pub mut int -> Int {
if @index == BUFFER_SIZE { refill }
let idx = @index := @index.wrapping_add(8)
let val = little.read_i64(@buffer, at: idx)
zero(idx, size: 8)
val
}
fn pub mut int -> Int
Returns a randomly generated Int
in the end exclusive range MIN..MAX
where MIN
is the minimum value of a 64-bits signed integer and MAX
the
maximum value.
Examples
import std.rand (Random)
let rng = Random.from_int(10)
rng.int # => -5596774198144179698
int_between
Show source codeHide source code
fn pub mut int_between(min: Int, max: Int) -> Int {
if min > max { invalid_range_error(min, max) }
# Apple's approach as taken from
# https://www.pcg-random.org/posts/bounded-rands.html, as we can't use
# Lemire's approach as that requires 128 bits integer support.
let mut mask = -1
let range = max.wrapping_sub(min).wrapping_sub(1)
mask >>>= (range | 1).leading_zeros
loop {
match int & mask {
case v if v <= range -> return min.wrapping_add(v)
case _ -> {}
}
}
}
fn pub mut int_between(min: Int, max: Int) -> Int
Returns a randomly generated Int
uniformly distributed in the given end
exclusive range.
Panics
This method panics if min
is greater than max
.
Examples
import std.rand (Random)
let rng = Random.from_int(10)
rng.int_between(1, 10) # => 8