Skip to content

Commit ca9dee0

Browse files
committed
feat: add public API and type hints
- Complete public API: random, randint, randbool, choice, etc. - Global singleton pool and tap instances - start_collector/stop_collector for background operation - py.typed marker for PEP 561 compliance
1 parent e56cc2f commit ca9dee0

2 files changed

Lines changed: 416 additions & 0 deletions

File tree

src/trueentropy/__init__.py

Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
# =============================================================================
2+
# TrueEntropy - True Randomness from Real-World Entropy Sources
3+
# =============================================================================
4+
#
5+
# This is the main public API for the TrueEntropy library.
6+
# It provides a simple interface for generating random numbers using
7+
# entropy collected from various real-world sources.
8+
#
9+
# The library works by:
10+
# 1. Collecting entropy from multiple sources (timing, network, system, APIs)
11+
# 2. Mixing the entropy using SHA-256 cryptographic hashing
12+
# 3. Storing the mixed entropy in a secure pool
13+
# 4. Extracting random values from the pool on demand
14+
#
15+
# Example usage:
16+
# import trueentropy
17+
#
18+
# # Generate random values
19+
# value = trueentropy.random() # float [0.0, 1.0)
20+
# number = trueentropy.randint(1, 10) # integer [1, 10]
21+
# coin = trueentropy.randbool() # True or False
22+
#
23+
# # Check entropy health
24+
# health = trueentropy.health()
25+
# print(f"Entropy score: {health['score']}/100")
26+
#
27+
# =============================================================================
28+
29+
"""
30+
TrueEntropy - True randomness from real-world entropy sources.
31+
32+
This library harvests chaos from the physical world to generate truly random
33+
numbers. Unlike pseudo-random number generators (PRNGs) that use deterministic
34+
algorithms, TrueEntropy collects entropy from CPU timing jitter, network
35+
latency, system state, and external APIs.
36+
"""
37+
38+
from __future__ import annotations
39+
40+
# -----------------------------------------------------------------------------
41+
# Version Information
42+
# -----------------------------------------------------------------------------
43+
__version__ = "0.1.0"
44+
__author__ = "TrueEntropy Contributors"
45+
__license__ = "MIT"
46+
47+
# -----------------------------------------------------------------------------
48+
# Type Imports (for type hints)
49+
# -----------------------------------------------------------------------------
50+
from typing import TYPE_CHECKING, Any, MutableSequence, Sequence, TypeVar
51+
52+
if TYPE_CHECKING:
53+
pass
54+
55+
# -----------------------------------------------------------------------------
56+
# Internal Module Imports
57+
# -----------------------------------------------------------------------------
58+
from trueentropy.pool import EntropyPool
59+
from trueentropy.tap import EntropyTap
60+
from trueentropy.health import entropy_health, HealthStatus
61+
62+
# -----------------------------------------------------------------------------
63+
# Type Variables for Generic Functions
64+
# -----------------------------------------------------------------------------
65+
T = TypeVar("T")
66+
67+
# -----------------------------------------------------------------------------
68+
# Global Singleton Instances
69+
# -----------------------------------------------------------------------------
70+
# We maintain a single global entropy pool and tap for convenience.
71+
# Users can also create their own instances if needed.
72+
73+
_pool: EntropyPool = EntropyPool()
74+
_tap: EntropyTap = EntropyTap(_pool)
75+
76+
# Flag to track if background collector is running
77+
_collector_running: bool = False
78+
79+
80+
# =============================================================================
81+
# PUBLIC API - Random Value Generation
82+
# =============================================================================
83+
84+
85+
def random() -> float:
86+
"""
87+
Generate a random floating-point number in the range [0.0, 1.0).
88+
89+
This function extracts entropy from the pool and converts it to a
90+
uniformly distributed float. The distribution is uniform, meaning
91+
all values in the range are equally likely.
92+
93+
Returns:
94+
A float value where 0.0 <= value < 1.0
95+
96+
Example:
97+
>>> import trueentropy
98+
>>> value = trueentropy.random()
99+
>>> print(f"Random value: {value}")
100+
Random value: 0.7234891623...
101+
"""
102+
return _tap.random()
103+
104+
105+
def randint(a: int, b: int) -> int:
106+
"""
107+
Generate a random integer N such that a <= N <= b.
108+
109+
Both endpoints are inclusive. The distribution is uniform.
110+
111+
Args:
112+
a: The lower bound (inclusive)
113+
b: The upper bound (inclusive)
114+
115+
Returns:
116+
A random integer in the range [a, b]
117+
118+
Raises:
119+
ValueError: If a > b
120+
121+
Example:
122+
>>> import trueentropy
123+
>>> dice = trueentropy.randint(1, 6)
124+
>>> print(f"Dice roll: {dice}")
125+
Dice roll: 4
126+
"""
127+
return _tap.randint(a, b)
128+
129+
130+
def randbool() -> bool:
131+
"""
132+
Generate a random boolean value (True or False).
133+
134+
This is equivalent to a fair coin flip. Each outcome has
135+
exactly 50% probability.
136+
137+
Returns:
138+
True or False with equal probability
139+
140+
Example:
141+
>>> import trueentropy
142+
>>> coin = trueentropy.randbool()
143+
>>> print("Heads" if coin else "Tails")
144+
Heads
145+
"""
146+
return _tap.randbool()
147+
148+
149+
def choice(seq: Sequence[T]) -> T:
150+
"""
151+
Return a random element from a non-empty sequence.
152+
153+
Each element has an equal probability of being selected.
154+
155+
Args:
156+
seq: A non-empty sequence (list, tuple, string, etc.)
157+
158+
Returns:
159+
A randomly selected element from the sequence
160+
161+
Raises:
162+
IndexError: If the sequence is empty
163+
164+
Example:
165+
>>> import trueentropy
166+
>>> colors = ["red", "green", "blue"]
167+
>>> color = trueentropy.choice(colors)
168+
>>> print(f"Selected: {color}")
169+
Selected: green
170+
"""
171+
return _tap.choice(seq)
172+
173+
174+
def randbytes(n: int) -> bytes:
175+
"""
176+
Generate n random bytes.
177+
178+
This function extracts raw entropy from the pool and returns it
179+
as a bytes object. Useful for generating cryptographic keys,
180+
tokens, or other binary data.
181+
182+
Args:
183+
n: The number of bytes to generate (must be positive)
184+
185+
Returns:
186+
A bytes object of length n
187+
188+
Raises:
189+
ValueError: If n is not positive
190+
191+
Example:
192+
>>> import trueentropy
193+
>>> secret = trueentropy.randbytes(32)
194+
>>> print(f"Secret: {secret.hex()}")
195+
Secret: a1b2c3d4e5f6...
196+
"""
197+
return _tap.randbytes(n)
198+
199+
200+
def shuffle(seq: MutableSequence[Any]) -> None:
201+
"""
202+
Shuffle a mutable sequence in-place.
203+
204+
Uses the Fisher-Yates shuffle algorithm with true random numbers
205+
to ensure a uniform distribution of permutations.
206+
207+
Args:
208+
seq: A mutable sequence (list) to shuffle in-place
209+
210+
Example:
211+
>>> import trueentropy
212+
>>> cards = list(range(1, 53))
213+
>>> trueentropy.shuffle(cards)
214+
>>> print(cards[:5])
215+
[32, 7, 45, 12, 28]
216+
"""
217+
_tap.shuffle(seq)
218+
219+
220+
def sample(seq: Sequence[T], k: int) -> list[T]:
221+
"""
222+
Return a k-length list of unique elements from the sequence.
223+
224+
Used for random sampling without replacement.
225+
226+
Args:
227+
seq: A sequence to sample from
228+
k: Number of unique elements to select
229+
230+
Returns:
231+
A list of k unique elements from the sequence
232+
233+
Raises:
234+
ValueError: If k is larger than the sequence length
235+
236+
Example:
237+
>>> import trueentropy
238+
>>> lottery = trueentropy.sample(range(1, 61), 6)
239+
>>> print(f"Winning numbers: {lottery}")
240+
Winning numbers: [42, 7, 23, 56, 11, 39]
241+
"""
242+
return _tap.sample(seq, k)
243+
244+
245+
# =============================================================================
246+
# PUBLIC API - Entropy Management
247+
# =============================================================================
248+
249+
250+
def health() -> HealthStatus:
251+
"""
252+
Get the current health status of the entropy pool.
253+
254+
Returns a dictionary containing:
255+
- score: 0-100 indicating entropy quality
256+
- status: "healthy", "degraded", or "critical"
257+
- entropy_bits: Estimated bits of entropy in the pool
258+
- recommendation: Suggested action if health is low
259+
260+
Returns:
261+
A HealthStatus TypedDict with pool health information
262+
263+
Example:
264+
>>> import trueentropy
265+
>>> status = trueentropy.health()
266+
>>> print(f"Health: {status['score']}/100 ({status['status']})")
267+
Health: 85/100 (healthy)
268+
"""
269+
return entropy_health(_pool)
270+
271+
272+
def feed(data: bytes) -> None:
273+
"""
274+
Manually feed entropy into the pool.
275+
276+
This allows you to add your own entropy sources to the pool.
277+
The data will be mixed using SHA-256 hashing to ensure it
278+
properly contributes to the pool state.
279+
280+
Args:
281+
data: Raw bytes to add to the entropy pool
282+
283+
Example:
284+
>>> import trueentropy
285+
>>> # Add some external entropy (e.g., from a hardware RNG)
286+
>>> external_entropy = b'\\x12\\x34\\x56\\x78'
287+
>>> trueentropy.feed(external_entropy)
288+
"""
289+
_pool.feed(data)
290+
291+
292+
def start_collector(interval: float = 1.0) -> None:
293+
"""
294+
Start the background entropy collector thread.
295+
296+
When running, the collector periodically harvests entropy from
297+
all available sources and feeds it into the pool. This ensures
298+
the pool stays full even during heavy random number generation.
299+
300+
Args:
301+
interval: Seconds between collection cycles (default: 1.0)
302+
303+
Example:
304+
>>> import trueentropy
305+
>>> trueentropy.start_collector(interval=2.0)
306+
>>> # ... application runs ...
307+
>>> trueentropy.stop_collector()
308+
"""
309+
global _collector_running
310+
311+
if _collector_running:
312+
return # Already running
313+
314+
from trueentropy.collector import start_background_collector
315+
start_background_collector(_pool, interval)
316+
_collector_running = True
317+
318+
319+
def stop_collector() -> None:
320+
"""
321+
Stop the background entropy collector thread.
322+
323+
Call this before your application exits to cleanly shut down
324+
the collector thread.
325+
326+
Example:
327+
>>> import trueentropy
328+
>>> trueentropy.stop_collector()
329+
"""
330+
global _collector_running
331+
332+
if not _collector_running:
333+
return # Not running
334+
335+
from trueentropy.collector import stop_background_collector
336+
stop_background_collector()
337+
_collector_running = False
338+
339+
340+
# =============================================================================
341+
# PUBLIC API - Advanced Usage
342+
# =============================================================================
343+
344+
345+
def get_pool() -> EntropyPool:
346+
"""
347+
Get the global entropy pool instance.
348+
349+
This is useful for advanced users who want to inspect or
350+
manipulate the pool directly.
351+
352+
Returns:
353+
The global EntropyPool instance
354+
"""
355+
return _pool
356+
357+
358+
def get_tap() -> EntropyTap:
359+
"""
360+
Get the global entropy tap instance.
361+
362+
This is useful for advanced users who want to use the tap
363+
directly or create their own tap with custom settings.
364+
365+
Returns:
366+
The global EntropyTap instance
367+
"""
368+
return _tap
369+
370+
371+
# =============================================================================
372+
# Module Exports
373+
# =============================================================================
374+
# Define what gets exported when using "from trueentropy import *"
375+
376+
__all__ = [
377+
# Version info
378+
"__version__",
379+
# Random value generation
380+
"random",
381+
"randint",
382+
"randbool",
383+
"choice",
384+
"randbytes",
385+
"shuffle",
386+
"sample",
387+
# Entropy management
388+
"health",
389+
"feed",
390+
"start_collector",
391+
"stop_collector",
392+
# Advanced usage
393+
"get_pool",
394+
"get_tap",
395+
# Classes (for type hints and advanced usage)
396+
"EntropyPool",
397+
"EntropyTap",
398+
"HealthStatus",
399+
]

0 commit comments

Comments
 (0)