"""RandomSource — cryptographically secure random number generator. Ported from net.i2p.util.RandomSource. Wraps Python's secrets/os.urandom which use the OS CSPRNG. """ import os import secrets import threading class RandomSource: """Cryptographically secure random source. In Java, this extends SecureRandom and adds Fortuna PRNG. In Python, we delegate to the OS CSPRNG via secrets module. """ _instance: "RandomSource | None" = None _lock = threading.Lock() def __init__(self) -> None: pass @classmethod def get_instance(cls) -> "RandomSource": if cls._instance is None: with cls._lock: if cls._instance is None: cls._instance = RandomSource() return cls._instance def next_int(self, n: int) -> int: """Return random int in [0, n).""" if n <= 0: raise ValueError("bound must be positive") return secrets.randbelow(n) def signed_next_int(self) -> int: """Return random int across full 32-bit signed range.""" return int.from_bytes(os.urandom(4), "big", signed=True) def next_long(self, n: int) -> int: """Return random long in [0, n).""" if n <= 0: raise ValueError("bound must be positive") return secrets.randbelow(n) def next_bytes(self, length: int) -> bytes: """Return `length` random bytes.""" return os.urandom(length) def next_bytes_into(self, buf: bytearray, offset: int = 0, length: int = -1) -> None: """Fill buffer with random bytes.""" if length < 0: length = len(buf) - offset rand = os.urandom(length) buf[offset : offset + length] = rand def next_boolean(self) -> bool: return bool(secrets.randbelow(2))