sdr-random
Hardware true-random number generation from software-defined radio
How It Works · Quick Start · API Reference · Python Integration
sdr-random extracts true entropy from the ADC quantization noise of RTL-SDR hardware. No pseudorandom generators, no deterministic seeds — raw thermal noise from a radio receiver, served over HTTP.
Built for seeding ML training runs, cryptographic applications, or anywhere you need hardware randomness without a dedicated HWRNG.
RTL-SDR dongles digitize radio signals with an 8-bit ADC. The least significant bits of each sample are dominated by thermal and quantization noise — physically random processes that are fundamentally unpredictable.
sdr-random captures raw IQ samples via rtl_sdr, extracts the LSB from every 37th sample (for decorrelation), packs them into bytes, and accumulates them into a 4 KB circular entropy pool. The pool is served over HTTP with the same API as Gnosis Radio.
RTL-SDR ADC -> IQ capture (rtl_sdr) -> LSB extraction -> entropy pool -> HTTP API
8-bit 96K bytes/burst ~324 bytes/burst 4096 bytes JSON/hex/raw
| Dependency | Install |
|---|---|
| Rust toolchain | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh |
| RTL-SDR dongle | Any RTL2832U-based USB dongle |
| rtl-sdr tools | apt install rtl-sdr (Debian/Ubuntu) |
The default DVB-T kernel driver claims the device. Blacklist it:
echo 'blacklist dvb_usb_rtl28xxu
blacklist rtl2832
blacklist rtl2830' | sudo tee /etc/modprobe.d/blacklist-rtlsdr.conf
sudo modprobe -r dvb_usb_rtl28xxu rtl2832_sdr rtl2832git clone git@github.com:DeepBlueDynamics/sdr-random.git
cd sdr-random
cargo build --release# Start the entropy server with a local SDR
./target/release/sdr-rand local --port 9090
# Verify
curl http://localhost:9090/api/entropy?bytes=8Run on a machine with an RTL-SDR attached. Captures IQ data and serves entropy over HTTP.
sdr-rand local [OPTIONS]
Options:
-p, --port <PORT> HTTP port [default: 9090]
-f, --frequency <HZ> SDR center frequency [default: 433000000]
-i, --interval <SECONDS> Capture interval [default: 2]Relay entropy from a remote sdr-random or Gnosis Radio instance. No local SDR needed.
sdr-rand relay --remote http://nemesis:9090 --port 9091Print a single u64 to stdout. Designed for piping into training scripts.
sdr-rand seed --remote http://localhost:9090
# 14560685981594524047# 64 bytes as hex
sdr-rand drain --remote http://localhost:9090 --bytes 64
# 256 raw bytes to file
sdr-rand drain --remote http://localhost:9090 --bytes 256 --format raw > entropy.binAll endpoints are compatible with the Gnosis Radio entropy API.
Drain bytes from the entropy pool.
| Parameter | Type | Default | Description |
|---|---|---|---|
bytes |
int | 32 | Number of bytes to drain (max 4096) |
format |
string | json | json, hex, or raw |
JSON response:
{
"bytes_requested": 8,
"bytes_returned": 8,
"pool_remaining": 3864,
"entropy_hex": "a60d20ee0c940922"
}Server-Sent Events stream. Emits one event per second with accumulated entropy.
data: {"bytes":128,"hex":"a1b2c3d4..."}
{
"pool_bytes": 3200,
"pool_capacity": 4096
}import json, os
from urllib.request import urlopen
def sdr_seed():
"""Seed from SDR entropy, with os.urandom fallback."""
try:
resp = json.loads(
urlopen("http://localhost:9090/api/entropy?bytes=8&format=json", timeout=2).read()
)
return int(resp["entropy_hex"], 16)
except Exception:
return int.from_bytes(os.urandom(8), "big")
import torch
seed = sdr_seed()
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)src/
main.rs CLI dispatcher (local, relay, drain, seed)
capture.rs IQ capture via rtl_sdr + LSB entropy extraction
pool.rs Thread-safe 4KB circular entropy pool
fetch.rs HTTP client for remote entropy sources
server.rs HTTP server (/api/entropy, SSE stream, status)
Entropy extraction algorithm ported from Gnosis Radio pipeline/state.rs:harvest_entropy().
MIT