mirror of
https://github.com/vlang/v.git
synced 2025-09-08 14:51:53 -04:00
crypto.rand: add support for convenient generation of a random big integer in the interval [0, n)
(#22266)
This commit is contained in:
parent
8ae627ff79
commit
5e624a5b23
@ -5,6 +5,7 @@
|
|||||||
module rand
|
module rand
|
||||||
|
|
||||||
import math.bits
|
import math.bits
|
||||||
|
import math.big
|
||||||
import encoding.binary
|
import encoding.binary
|
||||||
|
|
||||||
// int_u64 returns a random unsigned 64-bit integer `u64` read from a real OS source of entropy.
|
// int_u64 returns a random unsigned 64-bit integer `u64` read from a real OS source of entropy.
|
||||||
@ -53,3 +54,42 @@ fn bytes_to_u64(b []u8) []u64 {
|
|||||||
}
|
}
|
||||||
return z
|
return z
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int_big creates a random `big.Integer` with range [0, n)
|
||||||
|
// returns an error if `n` is 0 or negative.
|
||||||
|
pub fn int_big(n big.Integer) !big.Integer {
|
||||||
|
if n.signum < 1 {
|
||||||
|
return error('`n` cannot be 0 or negative.')
|
||||||
|
}
|
||||||
|
|
||||||
|
max := n - big.integer_from_int(1)
|
||||||
|
len := max.bit_len()
|
||||||
|
|
||||||
|
if len == 0 {
|
||||||
|
// max = n - 1, if max = 0 then return max, as it is the only valid integer in [0, 1)
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
|
||||||
|
// k is the maximum byte length needed to encode a value < n
|
||||||
|
k := (len + 7) / 8
|
||||||
|
|
||||||
|
// b is the number of bits in the most significant byte of n-1
|
||||||
|
mut b := u8(len % 8)
|
||||||
|
if b == 0 {
|
||||||
|
b = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
mut result := big.Integer{}
|
||||||
|
for {
|
||||||
|
mut bytes := read(k)!
|
||||||
|
|
||||||
|
// Clear bits in the first byte to increase the probability that the result is < max
|
||||||
|
bytes[0] &= u8(int(1 << b) - 1)
|
||||||
|
|
||||||
|
result = big.integer_from_bytes(bytes)
|
||||||
|
if result < max {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
23
vlib/crypto/rand/utils_test.v
Normal file
23
vlib/crypto/rand/utils_test.v
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import math.big
|
||||||
|
import crypto.rand
|
||||||
|
|
||||||
|
fn test_int_big() {
|
||||||
|
z := big.integer_from_int(0)
|
||||||
|
if _ := rand.int_big(z) {
|
||||||
|
assert false
|
||||||
|
} else {
|
||||||
|
assert true
|
||||||
|
}
|
||||||
|
|
||||||
|
n := big.integer_from_int(-1)
|
||||||
|
if _ := rand.int_big(n) {
|
||||||
|
assert false
|
||||||
|
} else {
|
||||||
|
assert true
|
||||||
|
}
|
||||||
|
|
||||||
|
m := big.integer_from_int(1).left_shift(128)
|
||||||
|
l := rand.int_big(m)! // actual large number
|
||||||
|
assert l < m
|
||||||
|
assert l > n
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user