9.7 KiB
Camera TRNG
Read the Research & Science Behind This — A deep dive into the physics, academic literature, and the LavaRnd approach.
A true random number generator that extracts entropy from camera sensor thermal noise, following the LavaRnd methodology.
Setup Requirements
Important: Cover the camera lens for optimal operation.
- Cover the lens: Use the lens cap, opaque tape, or place the camera in a light-proof enclosure
- Verify darkness: The camera should capture pure black frames
- Run the service: Gain and brightness are automatically maximized
This approach (pioneered by the LavaRnd project) isolates pure thermal noise from the sensor, eliminating any scene-correlated data and providing a simpler security model.
How It Works
With the lens covered, camera sensors produce noise from thermal electron activity and dark current. This service:
- Opens the camera and maximizes gain/brightness settings
- Captures frames of pure sensor noise (no light = no scene data)
- Extracts the 2 LSBs from each pixel (highest entropy density)
- Hashes the LSBs with SHA-256 to condition the output
- Mixes in timing entropy for additional randomness
Build
cargo build --release
Run
./target/release/camera-trng
# Or set a custom port
PORT=9000 ./target/release/camera-trng
Use the camera at **max resolution** (and highest frame rate):
```bash
CAMERA_MAX_RESOLUTION=1 cargo run
macOS — camera in use ("Lock Rejected")? Run once to release the webcam, then start the server:
./scripts/release-camera.sh # may prompt for sudo password
cargo run
Streaming random (multiple terminals)
To see a stream of random in the terminal and verify each stream is unique:
- One stream:
./scripts/stream-random.sh 0(infinite; Ctrl+C to stop) - Several streams in different terminals (each gets different random; never the same):
- Terminal 1:
./scripts/stream-random.sh "Stream-1" 0 - Terminal 2:
./scripts/stream-random.sh "Stream-2" 0 - Terminal 3:
./scripts/stream-random.sh "Stream-3" 0
- Terminal 1:
- Quick demo (3 streams, 5 lines each, verify no duplicates):
./scripts/stream-demo.sh 5
Docker
Pull the pre-built image:
docker pull git.nixc.us/colin/camera-trng:latest
Run with camera access (Linux with V4L2):
docker run -d \
--name camera-trng \
--device /dev/video0:/dev/video0 \
-p 8787:8787 \
git.nixc.us/colin/camera-trng:latest
Note: Ensure the camera lens is covered before starting the container.
Available Tags
| Tag | Description |
|---|---|
latest |
Latest build from master branch |
<commit-sha> |
Specific commit (first 8 chars) |
<version> |
Semantic version tags (e.g., v1.0.0) |
API
GET /random
Returns random bytes from camera thermal noise.
Query Parameters:
bytes- Number of bytes to return (default: 32, max: 1024)hex- Return as hex string instead of raw bytes (default: false)
Examples:
# Get 32 random bytes as hex
curl "http://localhost:8787/random?hex=true"
# Get 64 raw random bytes
curl "http://localhost:8787/random?bytes=64" -o random.bin
# Get 256 bytes as hex
curl "http://localhost:8787/random?bytes=256&hex=true"
GET /health
Returns ok if the server is running.
Rate Limiting
- Maximum 4 concurrent requests
- Maximum 1024 bytes per request
- Returns 429 Too Many Requests when overloaded
Cross-Platform Support
Uses nokhwa for camera access, supporting:
- macOS (AVFoundation)
- Windows (Media Foundation)
- Linux (V4L2)
Randomness Validation
A built-in test suite validates the statistical quality of generated random data.
Quick Test
# Test against running server (fetches 1MB)
./scripts/test-randomness.py --server http://127.0.0.1:8787
# Test a file
./scripts/test-randomness.py /path/to/random.bin
# Test from stdin
curl -s http://127.0.0.1:8787/random?bytes=1048576 | ./scripts/test-randomness.py -
Test Suite
The validation suite includes 8 statistical tests:
| Test | Description | Pass Criteria |
|---|---|---|
| Shannon Entropy | Information density | >7.9 bits/byte |
| Chi-Square | Distribution uniformity | 200-330 (df=255) |
| Arithmetic Mean | Average byte value | 126-129 |
| Monte Carlo Pi | Geometric randomness | <1% error |
| Serial Correlation | Sequential independence | |r| < 0.01 |
| Byte Coverage | Value distribution | 256/256 present |
| Bit Balance | Binary distribution | 49-51% ones |
| Longest Run | Pattern detection | <25 bits |
Example Output
=======================================================
CAMERA QRNG RANDOMNESS VALIDATION
=======================================================
Sample size: 1,048,576 bytes (1.00 MB)
1. Shannon Entropy: 7.999796 bits/byte [PASS]
2. Chi-Square Test: 297.12 [PASS]
3. Arithmetic Mean: 127.5829 [PASS]
4. Monte Carlo Pi: 3.155151 [PASS]
5. Serial Correlation: 0.000235 [PASS]
6. Byte Coverage: 256/256 [PASS]
7. Bit Balance: 50.00% ones [PASS]
8. Longest Run (10KB): 19 bits [PASS]
RESULTS: 8/8 tests passed
VERDICT: EXCELLENT - All tests passed!
External Test Suites
For more rigorous validation, the output also passes industry-standard test suites:
- NIST SP 800-22: 15 statistical tests (official NIST standard)
- Dieharder: 100+ statistical tests
- TestU01: Academic test library (BigCrush)
- ENT: Entropy analysis tool
# Using dieharder (if installed)
curl -s http://127.0.0.1:8787/random?bytes=10485760 | dieharder -a -g 200
# Using rngtest
curl -s http://127.0.0.1:8787/random?bytes=2500000 | rngtest
CI/CD Pipeline
This project uses Woodpecker CI to automatically build, test, and deploy.
Pipeline Overview
┌─────────────────────────────────────────────────────────────────┐
│ Woodpecker CI │
├─────────────────────────────────────────────────────────────────┤
│ │
│ On Push/PR to master: │
│ ┌─────────┐ │
│ │ test │──┬──> build-linux-x86_64 ──> binary artifact │
│ └─────────┘ │ │
│ ├──> build-linux-aarch64 ──> binary artifact │
│ │ │
│ └──> build-image ──┬──> trivy-image (scan) │
│ └──> sbom-image (SBOM) │
│ │
│ Parallel checks: cargo-audit, trivy-fs, clippy, fmt-check │
│ │
└─────────────────────────────────────────────────────────────────┘
Build Artifacts
| Artifact | Architecture | Description |
|---|---|---|
camera-trng-linux-x86_64 |
x86_64 | Linux AMD64 binary |
camera-trng-linux-aarch64 |
aarch64 | Linux ARM64 binary (best-effort) |
| Docker Image | linux/amd64 | Container image |
Docker Image Registry
Images are pushed to: git.nixc.us/colin/camera-trng
- On push to master: Tags
latestand<commit-sha> - On version tag: Tags
<version>andlatest
Required Secrets
Configure these secrets in Woodpecker:
| Secret | Description |
|---|---|
REGISTRY_USER |
Username for git.nixc.us registry |
REGISTRY_PASSWORD |
Password/token for git.nixc.us registry |
DOCKER_REGISTRY_USER |
Docker Hub username (for base images) |
DOCKER_REGISTRY_PASSWORD |
Docker Hub password/token |
Security Scanning
The pipeline includes:
- cargo-audit: Scans Rust dependencies for known vulnerabilities
- trivy-fs: Scans filesystem and Cargo.lock for vulnerabilities
- trivy-image: Scans the built Docker image
- SBOM generation: Creates SPDX and CycloneDX SBOMs for dependencies
Cross-Compilation Notes
Linux x86_64: Fully supported, built natively on CI runners.
Linux aarch64: Best-effort cross-compilation. May fail due to native camera library dependencies (libv4l). For production ARM64 builds, consider using native ARM64 runners.
macOS/Windows: Not built in CI due to native camera library requirements. Build locally:
# macOS
cargo build --release
# Windows (requires MSVC toolchain)
cargo build --release
Local Docker Build
# Build locally
docker build -t camera-trng:local .
# Test locally (requires camera device with lens covered)
docker run --rm --device /dev/video0 -p 8787:8787 camera-trng:local
Security Notes
This implementation follows the LavaRnd approach for thermal noise extraction:
- Cover the lens: Required for the intended security model
- Gain maximized: Software automatically configures camera for maximum noise amplification
- No scene data: With lens covered, there is no side-channel information leakage
- SHA-256 conditioning: Removes any bias and ensures uniform distribution
For high-security cryptographic applications, consider:
- Using dedicated hardware RNGs (HSMs)
- Mixing with system entropy (
/dev/urandom) - Verifying the camera is properly covered before deployment