crypto.rand: add PRNG function read_u64

pull/2022/head
joe-conigliaro 2019-09-18 05:03:54 +10:00 committed by Alexander Medvednikov
parent 1796869da7
commit 32ad33558d
2 changed files with 77 additions and 1 deletions

View File

@ -4,7 +4,7 @@
import crypto.rand import crypto.rand
fn test_crypto_rand() { fn test_crypto_rand_read() {
no_bytes := 100 no_bytes := 100
max_percentage_diff := 20 max_percentage_diff := 20
@ -28,3 +28,16 @@ fn test_crypto_rand() {
assert diff_percentage <= max_percentage_diff assert diff_percentage <= max_percentage_diff
} }
fn test_crypto_rand_read_u64() {
max := u64(200)
r1 := rand.read_u64(max) or {
assert false
return
}
r2 := rand.read_u64(max) or {
assert false
return
}
assert r1 > u64(0) && r2 > u64(0) && r1 < max && r2 < max
}

View File

@ -0,0 +1,63 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
import(
math
encoding.binary
)
pub fn read_u64(max u64) u64? {
if max <= u64(0) {
return error('crypto.rand: argument to read_u64 is <= 0')
}
// bitlen := int(math.floor(math.log2(f64(max))+1))
bitlen := int(math.floor(math.log(f64(max))/math.log(2)) + 1)
if bitlen == 0 {
return u64(0)
}
k := (bitlen + 7) / 8
mut b := u64(bitlen % 8)
if b == u64(0) {
b = u64(8)
}
mut n := u64(0)
for {
mut bytes := read(k) or {
return error(err)
}
bytes[0] &= byte(int(u64(1)<<b) - 1)
x := bytes_to_u64(bytes)
n = x[0]
if x.len > 1 {
n = u64(u32(x[1])<<u32(32)) | n
}
if int(n) < 0 {
n = -n
}
if n < max {
return n
}
}
return n
}
fn bytes_to_u64(b []byte) []u64 {
mut z := [u64(0)].repeat((b.len + 8 - 1) / 8)
mut i := b.len
for k := 0; i >= 8; k++ {
z[k] = binary.big_endian_u64(b.slice(i-8, i))
i -= 8
}
if i > 0 {
mut d := u64(0)
for s := u64(0); i > 0; s += u64(8) {
d |= u64(u64(b[i-1]) << s)
i--
}
z[z.len-1] = d
}
return z
}