A Python port of the Invisible Internet Project (I2P)
1"""Fortuna-based cryptographically secure PRNG.
2
3Wraps Python's secrets/os.urandom with a Fortuna-style interface
4matching Java's FortunaRandomSource API.
5
6Ported from net.i2p.util.FortunaRandomSource.
7"""
8
9from __future__ import annotations
10
11import hashlib
12import os
13import struct
14
15
16class FortunaRandomSource:
17 """Fortuna-inspired CSPRNG.
18
19 Uses os.urandom as the entropy source with optional seed mixing.
20 """
21
22 def __init__(self, seed: bytes | None = None) -> None:
23 self._state = os.urandom(32)
24 if seed is not None:
25 self._state = hashlib.sha256(self._state + seed).digest()
26
27 def _generate(self, n: int) -> bytes:
28 """Generate n bytes of random data."""
29 result = bytearray()
30 while len(result) < n:
31 self._state = hashlib.sha256(
32 self._state + os.urandom(32)
33 ).digest()
34 result.extend(self._state)
35 return bytes(result[:n])
36
37 def next_bytes(self, count: int) -> bytes:
38 """Generate count random bytes."""
39 return self._generate(count)
40
41 def next_int(self, bound: int) -> int:
42 """Generate a random int in [0, bound)."""
43 raw = struct.unpack(">I", self._generate(4))[0]
44 return raw % bound
45
46 def next_boolean(self) -> bool:
47 """Generate a random boolean."""
48 return self._generate(1)[0] & 1 == 1