def sample(modulus):
'''
Sample a uniformly distributed value from the SystemRandom CSPRNG
(uses rejection sampling to avoid bias)
returns a long uniformly distributed in [0, modulus)
'''
# sanitise input
modulus = long(modulus)
assert modulus > 0
# to get values up to modulus-1, we need this many bits
sample_bit_count = (modulus-1).bit_length()
# handle the case where modulus is 1
if sample_bit_count == 0:
sample_bit_count = 1
# check the bit count is sane
assert modulus <= 2L**sample_bit_count
assert modulus >= 2L**(sample_bit_count-1)
## Unbiased sampling through rejection sampling
while True:
# sample that many bits
v = SystemRandom().getrandbits(sample_bit_count)
assert v >= 0
assert v < 2L**sample_bit_count
# the maximum rejection rate is 1 in 2, when modulus is 2**N + 1
if 0L <= v < modulus:
break
return v
评论列表
文章目录