camera-trng/TECHNICAL.md

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.

  1. Cover the lens: Use the lens cap, opaque tape, or place the camera in a light-proof enclosure
  2. Verify darkness: The camera should capture pure black frames
  3. 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:

  1. Opens the camera and maximizes gain/brightness settings
  2. Captures frames of pure sensor noise (no light = no scene data)
  3. Extracts the 2 LSBs from each pixel (highest entropy density)
  4. Hashes the LSBs with SHA-256 to condition the output
  5. 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
  • 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 latest and <commit-sha>
  • On version tag: Tags <version> and latest

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