| from functools import reduce | |
| from os import urandom | |
| from ufastrsa.util import get_bit_length | |
| class Random: | |
| def __init__(self, seed=None, rndsrc=None): | |
| if rndsrc is None: | |
| rndsrc = urandom | |
| self.rndsrc = rndsrc | |
| def getrandbits(self, k): | |
| if not k >= 0: | |
| raise ValueError("number of bits must be >= 0") | |
| return reduce( | |
| lambda x, y: x << 8 | y, | |
| self.rndsrc(k >> 3), | |
| int.from_bytes(self.rndsrc(1), "little") & ((1 << (k & 7)) - 1), | |
| ) | |
| def randint(self, a, b): | |
| if a > b: | |
| raise ValueError("empty range for randint(): %d, %d" % (a, b)) | |
| c = 1 + b - a | |
| k = get_bit_length(c - 1) | |
| while True: | |
| r = self.getrandbits(k) | |
| if r <= c: | |
| break | |
| return a + r | |
| def rndsrcnz(self, size): | |
| rv = self.rndsrc(size).replace(b"\x00", b"") | |
| mv = size - len(rv) | |
| while mv > 0: | |
| rv += self.rndsrc(mv).replace(b"\x00", b"") | |
| mv = size - len(rv) | |
| assert len(rv) == size | |
| return rv | |
| basernd = Random() | |
| rndsrc = basernd.rndsrc | |
| getrandbits = basernd.getrandbits | |
| randint = basernd.randint | |
| rndsrcnz = basernd.rndsrcnz | |