Metadata-Version: 2.4
Name: bigbangentropy
Version: 0.1.0
Summary: Python client for the Big Bang Entropy API.
Project-URL: Homepage, https://entropy.sparksome.pl
Project-URL: Repository, https://gitlab.com/sparksome-venture/big-bang-entropy
Author: Sparksome
License: MIT License
        
        Copyright (c) 2026 Sparksome
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: crypto,entropy,password,random,rng,token
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security :: Cryptography
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.25
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: twine>=5; extra == 'dev'
Description-Content-Type: text/markdown

# bigbangentropy

Python client for the Big Bang Entropy API.

Big Bang Entropy is a public physical entropy project. Its entropy stream is derived from cosmic radio noise captured by an antenna and SDR hardware, then processed by the Big Bang Entropy generator and exposed through simple binary HTTP endpoints.

At a high level, the source pipeline looks like this:

```txt
antenna -> SDR (e.g. PlutoSDR, RTL-SDR) -> sdr-node -> UDP -> generator -> entropy pool -> HTTP/TCP clients
```

This package makes that API easy to use from Python. It can fetch raw entropy bytes, return them as text, mix remote entropy with the local Python RNG, and generate tokens or passwords.

The recommended API is `get_mixed_entropy()`: it fetches entropy from Big Bang Entropy, reads local entropy with `secrets.token_bytes()`, and mixes both sources with SHA-512.

This library does not replace the operating system RNG. It lets you add an external physical entropy source to your local randomness pipeline. Do not use the raw API signal directly for security-sensitive work without mixing it with local RNG unless you have a very specific threat model.

## Why Physical Entropy?

Physical entropy gives your application an independent randomness source outside the host operating system and cloud runtime. Mixing it with Python `secrets.token_bytes()` adds source diversity, which is useful as a defense-in-depth measure when tokens, secrets, test vectors, or long-lived cryptographic material matter. Cosmic radio noise is not deterministic application state, not a PRNG seed, and not generated by the same machine that consumes it. The safest pattern is still to combine it with local RNG, so security does not depend on any single source.

## Installation

```bash
pip install bigbangentropy
```

## Quick Start

```python
from bigbangentropy import get_mixed_entropy, generate_token

entropy = get_mixed_entropy(32)
token = generate_token()

print(entropy.hex())
print(token)
```

## Default Endpoints

Default `base_url`:

```txt
https://entropy.sparksome.pl
```

Default entropy endpoints:

```txt
https://entropy.sparksome.pl/raw
https://entropy.sparksome.pl/raw/stream?bytes=1048576
```

For direct unbuffered small requests, the client can use `/raw`. For larger requests and buffer refills, it uses `/raw/stream?bytes=<bytes>`. The default threshold is `1024` bytes and can be changed with `stream_threshold_bytes`.

By default, the client keeps a small on-demand local entropy buffer of `4096` bytes to avoid one HTTP request per token in loops. It does not download entropy in the background. The buffer is filled only when needed, consumed once, and never reused. Set `entropy_buffer_size_bytes=0` to disable buffering entirely.

## Examples

### Fetch Entropy as Hex

```python
from bigbangentropy import get_entropy_hex

hex_entropy = get_entropy_hex(32)
print(hex_entropy)
```

### Fetch 1 MB of Entropy

```python
from bigbangentropy import get_entropy

one_megabyte = get_entropy(1_048_576)
print(len(one_megabyte))
```

With the default configuration, this call uses:

```txt
/raw/stream?bytes=1048576
```

### Generate a Token

```python
from bigbangentropy import generate_token

token = generate_token()
print(token)
```

`generate_token(32)` returns a 64-character hex token by default.

### Generate a Password

```python
from bigbangentropy import generate_password

password = generate_password({
    "length": 24,
    "uppercase": True,
    "lowercase": True,
    "numbers": True,
    "symbols": True,
})

print(password)
```

The password generator does not use `random.random()`. Its randomness comes from `get_mixed_entropy()`.

### Use a Custom `base_url`

```python
from bigbangentropy import create_client

entropy = create_client({
    "base_url": "https://entropy.example.com",
    "timeout_sec": 5,
    "retries": 2,
    "user_agent": "my-service/1.0.0",
    "stream_threshold_bytes": 1_024,
})

token = entropy.generate_token(32)
print(token)
```

You can also use keyword arguments:

```python
from bigbangentropy import create_client

entropy = create_client(base_url="https://entropy.example.com")
```

### Health Check

```python
from bigbangentropy import create_client

entropy = create_client({
    "health_url": "/health",
})

health = entropy.get_health()

if not health["ok"]:
    print("Big Bang Entropy API unavailable", health)
```

If a dedicated health endpoint is not available, `get_health()` checks `/raw` by default. You can later pass `health_url` without changing the calling code.

### Fetch Entropy as Base64

```python
from bigbangentropy import get_entropy_base64

base64_entropy = get_entropy_base64(48)
print(base64_entropy)
```

Base64 output is convenient when entropy needs to be passed through JSON, environment variables, or text-only storage.

### Generate Mixed Bytes for Your Own Crypto Flow

```python
from bigbangentropy import get_mixed_entropy

seed_material = get_mixed_entropy(64)

# Use seed_material with your own KDF, envelope encryption, or key rotation flow.
print(seed_material.hex())
```

Use this when you need bytes instead of a formatted token. The returned `bytes` are already mixed with local Python RNG.

### Handle API Errors

```python
from bigbangentropy import BigBangEntropyError, get_mixed_entropy

try:
    entropy = get_mixed_entropy(32)
    print(entropy.hex())
except BigBangEntropyError as error:
    print(f"Entropy request failed: {error.code}", error)
```

The client fails loudly when the API is unavailable, times out, or returns too little data.

### Explicit Local Fallback

```python
from bigbangentropy import create_client

entropy = create_client({
    "allow_local_fallback": True,
    "timeout_sec": 2,
})

raw_bytes = entropy.get_entropy(32)
print(raw_bytes.hex())
```

This mode is intentionally opt-in. Use it only when your application can continue with local RNG alone and you are comfortable knowing that external physical entropy may not have been used for that call.

### Optimize Token Loops with an Entropy Buffer

```python
from bigbangentropy import create_client

entropy = create_client({
    "entropy_buffer_size_bytes": 65_536,
})

tokens = []

for _ in range(1_000):
    tokens.append(entropy.generate_token())

print(len(tokens))
```

The client already uses a `4096` byte buffer by default. Raising it can reduce HTTP requests further in larger loops. The client fetches entropy chunks on demand, stores unused API bytes locally, and consumes them once across later calls. There is no background polling and no repeated use of buffered bytes.

### Async API

```python
import asyncio
from bigbangentropy import create_async_client


async def main() -> None:
    async with create_async_client() as entropy:
        token = await entropy.generate_token()
        print(token)


asyncio.run(main())
```

## API

### `create_client(options)`

```python
from bigbangentropy import create_client

client = create_client({
    "base_url": "https://entropy.sparksome.pl",
    "timeout_sec": 5,
    "retries": 2,
    "user_agent": "bigbangentropy/0.1.0",
    "stream_threshold_bytes": 1_024,
    "entropy_buffer_size_bytes": 4_096,
    "allow_local_fallback": False,
})
```

Options:

- `base_url` - defaults to `https://entropy.sparksome.pl`
- `timeout_sec` - defaults to `5`
- `retries` - defaults to `2`
- `user_agent` - defaults to `bigbangentropy/0.1.0`
- `stream_threshold_bytes` - defaults to `1024`
- `entropy_buffer_size_bytes` - defaults to `4096`; small calls consume a local one-time-use API entropy buffer; set to `0` to disable buffering
- `health_url` - optional health endpoint, for example `/health`
- `allow_local_fallback` - defaults to `False`; when set to `True`, the client may explicitly use local RNG if the API is unavailable

### Sync Methods

- `get_entropy(byte_count: int) -> bytes`
- `get_entropy_hex(byte_count: int) -> str`
- `get_entropy_base64(byte_count: int) -> str`
- `get_mixed_entropy(byte_count: int) -> bytes`
- `generate_token(byte_count: int = 32) -> str`
- `generate_password(options: PasswordOptions | None = None) -> str`
- `get_health() -> HealthResult`

### Async Methods

The async client exposes the same method names, but they are `await`able:

```python
from bigbangentropy import create_async_client

async with create_async_client() as client:
    data = await client.get_mixed_entropy(32)
```

## Error Handling

The client does not silently fall back to local RNG. If the API is unavailable, the call fails unless you explicitly set `allow_local_fallback=True`.

Exported error classes:

- `InvalidBytesError`
- `EntropyApiError`
- `EntropyTimeoutError`
- `InsufficientEntropyError`
- `InvalidPasswordOptionsError`

All exported errors extend `BigBangEntropyError` and expose a `code` field, such as `API_UNAVAILABLE`, `TIMEOUT`, `INSUFFICIENT_ENTROPY`, or `INVALID_BYTES`.
