# STRIX ### Satellite True Random Information eXtractor [![Arduino MKR Vidor 4000](https://img.shields.io/badge/Arduino-MKR%20Vidor%204000-00878F?logo=arduino&logoColor=white)](https://docs.arduino.cc/hardware/mkr-vidor-4000/) [![Built with Devbox](https://www.jetify.com/img/devbox/shield_galaxy.svg)](https://github.com/jetify-com/devbox/) [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue)](LICENSE) [![AI-DECLARATION: copilot](https://img.shields.io/badge/䷼%20AI--DECLARATION-copilot-fee2e2?labelColor=fee2e2)](https://ai-declaration.md) A portable wireless True Random Number Generator built on an Arduino MKR Vidor 4000. ## Design Entropy comes from FPGA ring oscillators whose sampled timing jitter is XOR-combined into output bits, with no pseudo-random post-processing. A SAMD21 serves the results over USB, over HTTP on its own WiFi access point (stationary mode, on a charger), or over Bluetooth LE (mobile mode, on battery). - 4 independent generators × 90 ring oscillators. Each generator XORs its rings every 120 MHz clock (spatial) and then several consecutive bits (temporal, default 5): about 24 Mbps per generator. - Separate stream per generator, plus a combined stream of all healthy generators - On-device health tests per generator: NIST SP 800-90B repetition count and adaptive proportion, plus a dead-ring monitor - Live statistics per trial: bias, z-score, random walk and lag-1 autocorrelation, with rolling and cumulative windows - Configurable random-walk / majority-vote bias amplifier on a bias path and an autocorrelation path, with sub-trial voting - Von Neumann extractor that can be toggled on the stream, statistics and amplifier paths - Per-second trials in Global Consciousness Project format (200-bit XOR-masked sums per generator, plus full-rate sums), with Stouffer Z and network variance - Raw ring captures and frequency measurement for characterization ```mermaid flowchart LR subgraph FPGA["FPGA: Cyclone 10 LP, 120 MHz from a PLL on the SAMD21's 48 MHz clock"] direction LR subgraph GEN["4 generators"] direction TB RO["90 ring oscillators
3 taps XORed per ring"] --> SMP["2-flip-flop sampling"] SMP --> SX["spatial XOR
of all rings"] SX --> TX["temporal XOR
of 1-8 bits"] end SMP --> HM["health monitors
repetition count, adaptive
proportion, dead rings"] SX --> HM TX --> SEL["healthy generators
g0-g3 and combined XOR"] HM -->|healthy| SEL SEL --> ST["entropy stream
4 KB FIFO"] SEL --> STATS["statistics
per-trial counts"] SEL --> AMP["bias amplifier
2 paths, 3 stages"] SEL --> GCP["GCP trials
per second"] GEN -.-> CAP["raw capture,
frequency counter"] ST & STATS & AMP & GCP & CAP & HM --> REG["SPI registers"] PT["WiFi module
pin pass-through"] end REG <-->|SPI 8 MHz| MCU["SAMD21 firmware"] MCU <--> PT PT <--> NINA["NINA-W102
WiFi and BLE"] MCU --> USB["USB serial"] NINA --> HTTP["HTTP on its own
access point"] NINA --> BLE["BLE GATT service"] ``` The USB, HTTP and BLE API is documented in [arduino/strix/API.md](arduino/strix/API.md). ## Command-line client `tools/strix.py` talks to the device over USB; run it with `devbox run strix ` or `uv run tools/strix.py `. It finds the board by its USB ID (override with `--port` or `STRIX_PORT`). | Command | Does | |---|---| | `id`, `health`, `amp`, `get` | Prints the device's reply | | `stats [--reset]` | Prints the statistics, or restarts them | | `set KEY VALUE` | Changes a setting (keys in the API documentation) | | `entropy N [--out FILE]` | N entropy bytes as hex, or binary into a file | | `watch stats\|amp` | Prints every new trial until Ctrl-C | | `gcp [--log FILE] [--full] [--seconds N]` | Follows the per-second GCP-format trials | | `send LINE` | Sends any command line and prints the reply | `gcp` prints one line per second: UTC time, second number, the four 200-bit sums, Stouffer Z, Z², and the cumulative Z² − 1 with its p = 0.05 envelope (`*` when outside). `--full` tracks the full-rate trials instead. It reconnects after USB dropouts and fills missed seconds from the device's 60-second history. `--log` appends GCP-style CSV rows, `13,,,,,,` (empty for unhealthy generators), after a `12,gmtime,Date/Time,g0,g1,g2,g3` header. ## TODO - WiFi credentials stored on the device instead of compile-time defaults - Battery pack - 3D case --- ## [Development Notes](NOTES.md)