diff --git a/vlib/rand/rand.c.v b/vlib/rand/rand.c.v index cfd91b411f..a58359118a 100644 --- a/vlib/rand/rand.c.v +++ b/vlib/rand/rand.c.v @@ -138,3 +138,17 @@ fn init() { default_rng = new_default() C.atexit(deinit) } + +// read fills in `buf` a maximum of `buf.len` random bytes +pub fn read(mut buf []byte) { + p64 := unsafe { &u64(buf.data) } + u64s := buf.len / 8 + for i in 0 .. u64s { + unsafe { + *(p64 + i) = default_rng.u64() + } + } + for i in u64s * 8 .. buf.len { + buf[i] = byte(default_rng.u32()) + } +} diff --git a/vlib/rand/rand.js.v b/vlib/rand/rand.js.v index 4171801be0..1403c5f1df 100644 --- a/vlib/rand/rand.js.v +++ b/vlib/rand/rand.js.v @@ -65,3 +65,10 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string { return res } + +// read fills in `buf` a maximum of `buf.len` random bytes +pub fn read(mut buf []byte) { + for i in 0 .. buf.len { + buf[i] = byte(default_rng.u32()) + } +} diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v index 13d4e18236..5c62e5bea5 100644 --- a/vlib/rand/rand.v +++ b/vlib/rand/rand.v @@ -174,6 +174,16 @@ pub fn f64_in_range(min f64, max f64) f64 { return default_rng.f64_in_range(min, max) } +// bytes returns a buffer of `bytes_needed` random bytes +pub fn bytes(bytes_needed int) ?[]byte { + if bytes_needed < 0 { + return error('can not read < 0 random bytes') + } + mut res := []byte{len: bytes_needed} + read(mut res) + return res +} + const ( english_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' hex_chars = 'abcdef0123456789' diff --git a/vlib/rand/random_bytes_test.v b/vlib/rand/random_bytes_test.v new file mode 100644 index 0000000000..477db66fd5 --- /dev/null +++ b/vlib/rand/random_bytes_test.v @@ -0,0 +1,51 @@ +import rand + +fn test_rand_bytes() ? { + mut randoms := []string{} + for i in 0 .. 100 { + x := rand.bytes(i) ?.hex() + if x.len > 0 { + randoms << x + } + assert x.len == i * 2 + } + mut differences := 0 + for idx in 1 .. randoms.len { + start := randoms[idx]#[0..8] + prev_start := randoms[idx - 1]#[0..8] + if start != prev_start { + differences++ + } + } + assert differences > 95 // normally around 98 + dump(differences) +} + +fn test_rand_read() ? { + max := 50 + mut a := []byte{len: max} + mut differences := 0 + for j in 1 .. max { + start := '00'.repeat(j) + for k in j + 1 .. max { + end := '00'.repeat(max - k) + middle := '00'.repeat(k - j) + // eprintln('> j: $j | k: $k | start: $start | middle: $middle | end: $end') + for i in 0 .. max { + a[i] = 0 + } + assert a[j..k].hex() == middle + for i in 0 .. 10 { + rand.read(mut a[j..k]) + // dump(a.hex()) + assert a[0..j].hex() == start + assert a[k..].hex() == end + if a[j..k].hex() != middle { + differences++ + } + } + } + } + dump(differences) + assert differences > 11700 // normally around 11758 +}