pqc-sandbox
See exactly what happens to your latency, payload size, CPU, and compatibility when you switch to ML-KEM / ML-DSA / SLH-DSA — in 60 seconds, without changing a line of production code.
🔒 Zero cloud. Zero telemetry. Runs entirely on your machine.
The 60-second demo
pip install pqc-sandbox
pqc-sandbox demo
No NIST keys. No API calls. No account required. All analysis is local. All benchmarks run on your hardware.
The demo simulates migrating a web API server from ECDSA-P256 → ML-DSA-44 (NIST FIPS 204) and ECDH-P256 → ML-KEM-768 (NIST FIPS 203), showing you the real cost before you touch a single config file.
What it does
pqc-sandbox is the missing second half of the PQC migration toolchain. Crypto discovery tools (Semgrep, CodeQL, Cryptosense) tell you what to change. pqc-sandbox tells you what happens when you do.
┌─────────────────────────────────────────────────────────────────────┐
│ Discovery tools (CBOM/SARIF) pqc-sandbox │
│ ───────────────────────── ────────────────────────────────────── │
│ "You use ECDSA-P256 here" → "Here's what ML-DSA-44 costs you: │
│ +33× signature size │
│ +1.8× signing time │
│ CAUTION: cert spans 2 MTU packets │
│ Score: MODERATE (38/100)" │
└─────────────────────────────────────────────────────────────────────┘
Core output per migration
| Output | Description |
|---|---|
| Benchmark table | Side-by-side latency, key sizes, artifact sizes: classical vs. PQC |
| Hybrid simulation | Classical + PQC in tandem — the recommended transitional approach |
| Compatibility oracle | Flags what will break: MTU limits, TLS version, RAM, DNSSEC, JWTs, HSMs |
| Migration Difficulty Score | 0–100, badge-ready: EASY / MODERATE / HARD / CRITICAL |
| Config diff | Copy-paste ready: OpenSSL, nginx, sshd, Go TLS, Python |
| HTML report | Self-contained, screenshot-friendly, shareable |
| JSON output | CI/CD pipeline integration with exit codes |
Installation
# Basic (simulation mode — no native deps)
pip install pqc-sandbox
# With real benchmarks via liboqs
pip install pqc-sandbox[oqs]
# Requires liboqs to be installed: https://github.com/open-quantum-safe/liboqs
liboqs (optional but recommended)
When liboqs-python is installed, pqc-sandbox runs real NIST reference implementations instead of simulated timings. In simulation mode, timings are derived from published NIST benchmarks with ±5% jitter — accurate for planning, but not a substitute for hardware measurement.
# macOS
brew install liboqs
pip install liboqs-python
# Ubuntu/Debian
sudo apt-get install liboqs-dev
pip install liboqs-python
Usage
pqc-sandbox demo — Start here
# Default: web API server scenario (ECDH-P256 → ML-KEM-768, ECDSA-P256 → ML-DSA-44)
pqc-sandbox demo
# IoT device with 256 KB RAM
pqc-sandbox demo --scenario 1
# Legacy TLS 1.2 endpoint
pqc-sandbox demo --scenario 2
# Save reports
pqc-sandbox demo --html report.html --json report.json
pqc-sandbox compare — Compare any two algorithms
# Auto-select PQC replacement
pqc-sandbox compare --classical "ECDH-P256"
# Explicit pairing
pqc-sandbox compare --classical "ECDSA-P256" --pqc "ML-DSA-65"
# With system constraints
pqc-sandbox compare \
--classical "ECDSA-P256" --pqc "ML-DSA-44" \
--mtu 1500 \
--tls-version 1.3 \
--protocol tls \
--ram-kb 256 \
--tag embedded --tag iot
# Generate all outputs
pqc-sandbox compare \
--classical "ECDH-P256" --pqc "ML-KEM-768" \
--html report.html \
--json report.json \
--diff openssl.conf.patch \
--diff-format openssl
# CI/CD mode (exit code: 0=GO, 1=CAUTION, 2=BLOCKED)
pqc-sandbox compare --classical "ECDH-P256" --ci
pqc-sandbox scan tls — Probe a live endpoint
# Detect current algorithms and simulate migration
pqc-sandbox scan tls example.com
pqc-sandbox scan tls api.mycompany.com --port 8443 --html tls_report.html
pqc-sandbox scan cbom — Integrate with CBOM scanners
# Accept CycloneDX CBOM JSON (from Dependency-Track, Cryptosense, etc.)
pqc-sandbox scan cbom cryptographic-bill-of-materials.json
# Sample CBOM included
pqc-sandbox scan cbom assets/sample.cbom.json
pqc-sandbox scan sarif — Integrate with SARIF crypto scanners
# Accept SARIF 2.1.0 output (from Semgrep, CodeQL, etc.)
pqc-sandbox scan sarif crypto-findings.sarif
# Sample SARIF included
pqc-sandbox scan sarif assets/sample.sarif.json
pqc-sandbox diff — Config diff only
pqc-sandbox diff --classical "ECDH-P256" --format nginx
pqc-sandbox diff --classical "ECDSA-P256" --pqc "ML-DSA-65" --format go-tls
pqc-sandbox diff --classical "ECDH-P256" --format sshd --output sshd_config.patch
Supported formats: openssl, nginx, sshd, go-tls, python
pqc-sandbox badge — Generate README badge
pqc-sandbox badge --classical "ECDSA-P256"
# Output:
# Score: 38/100 — MODERATE
# 
pqc-sandbox list — Show all algorithms
pqc-sandbox list
pqc-sandbox list --pqc-only
pqc-sandbox list --classical-only --category kem
Supported algorithms
PQC (NIST standards)
| Algorithm | Standard | Category | Security Level |
|---|---|---|---|
| ML-KEM-512 | NIST FIPS 203 | KEM | 1 |
| ML-KEM-768 ⭐ | NIST FIPS 203 | KEM | 3 |
| ML-KEM-1024 | NIST FIPS 203 | KEM | 5 |
| ML-DSA-44 | NIST FIPS 204 | Signature | 2 |
| ML-DSA-65 ⭐ | NIST FIPS 204 | Signature | 3 |
| ML-DSA-87 | NIST FIPS 204 | Signature | 5 |
| SLH-DSA-SHA2-128s | NIST FIPS 205 | Signature | 1 |
| SLH-DSA-SHA2-128f | NIST FIPS 205 | Signature | 1 |
| SLH-DSA-SHA2-256s | NIST FIPS 205 | Signature | 5 |
⭐ = recommended for most deployments
Classical (for comparison)
ECDH-P256, ECDH-P384, RSA-2048, ECDSA-P256, ECDSA-P384, RSA-2048 PKCS#1 v1.5, RSA-4096 PKCS#1 v1.5, Ed25519
The size problem (why this tool exists)
The PQC migration is not like past algorithm transitions. The size increases are structural:
Public key Signature/Ciphertext
ECDSA-P256 65 B 72 B
ML-DSA-44 1,312 B 2,420 B ← 33× larger
ML-DSA-65 1,952 B 3,293 B ← 45× larger
SLH-DSA-SHA2-128s 32 B 7,856 B ← 109× larger
SLH-DSA-SHA2-256s 64 B 29,792 B ← 413× larger
ECDH-P256 ciphertext: 65 B
ML-KEM-768 ciphertext: 1,088 B ← 17× larger
A TLS handshake that fit in a single 1500-byte MTU packet will fragment. DNSSEC records that fit in a single UDP packet will require TCP fallback. JWT tokens will overflow HTTP header limits. pqc-sandbox finds these issues before they find you in production.
Compatibility oracle checks
| Category | What's checked |
|---|---|
| MTU / fragmentation | Does the ML-KEM ClientHello + TLS overhead exceed your MTU? |
| TLS version | TLS 1.0/1.1 cannot support hybrid PQC key exchange |
| Memory (embedded) | Does your RAM support SLH-DSA's ~256 KB stack requirement? |
| DNSSEC | ML-DSA signatures exceed DNS UDP limits — TCP fallback required |
| JWT / HTTP | Large PQC signatures overflow default header size limits |
| CMS / S/MIME | Parser buffer limits for large PQC-signed content |
| HSM support | HSMs typically lag 12-24 months — flags if vendor support is unclear |
| Legacy TLS stacks | OpenSSL < 3.x has no PQC support |
CI/CD integration
# GitHub Actions example
- name: PQC Migration Check
run: |
pip install pqc-sandbox
pqc-sandbox compare \
--classical "ECDH-P256" \
--pqc "ML-KEM-768" \
--json pqc-report.json \
--ci # exit 1 on CAUTION, exit 2 on BLOCKED
- name: Upload PQC Report
uses: actions/upload-artifact@v3
with:
name: pqc-migration-report
path: pqc-report.json
The JSON output includes a ci.exit_code field:
0= GO (migration looks clean)1= CAUTION (issues to review, but not blocking)2= BLOCKED (hard blockers detected)
Using as a library
from pqc_sandbox.benchmarks import run_comparison
from pqc_sandbox.compat import run_compat_check, SystemConstraints
from pqc_sandbox.hybrid import simulate_hybrid
from pqc_sandbox.scoring import compute_score
from pqc_sandbox.algorithms import ALL_ALGORITHMS
from pqc_sandbox.report import print_report, generate_html, generate_json
# Benchmark comparison
cmp = run_comparison("ECDH-P256", "ML-KEM-768", iterations=100)
print(f"Ciphertext size ratio: {cmp.artifact_ratio:.1f}×")
print(f"KeyGen slowdown: {cmp.keygen_slowdown:.1f}×")
# Compatibility check
constraints = SystemConstraints(
mtu_bytes=1500,
tls_version="1.3",
ram_kb=None, # unconstrained
protocol="tls",
tags=["hsm"],
)
compat = run_compat_check(ALL_ALGORITHMS["ML-KEM-768"], constraints)
print(f"Verdict: {compat.verdict}")
for issue in compat.issues:
print(f" {issue.severity.value}: {issue.title}")
# Hybrid simulation
hybrid = simulate_hybrid("ECDH-P256", "ML-KEM-768")
print(f"Hybrid wire overhead: +{hybrid.wire_overhead_bytes:,} bytes")
# Migration difficulty score
score = compute_score(comparison=cmp, compat=compat, hybrid=hybrid)
print(f"Migration difficulty: {score.score}/100 ({score.label})")
print(f"Badge: {score.badge_markdown}")
# Generate reports
generate_html(cmp, compat, hybrid, score, output_path="report.html")
generate_json(cmp, compat, hybrid, score, output_path="report.json")
Architecture
pqc_sandbox/
├── algorithms.py # Algorithm catalogue: sizes, perf baselines, migration map
├── cli.py # Click CLI (demo, compare, scan, list, diff, badge)
├── scoring.py # Migration Difficulty Score (0-100) + badge generator
├── benchmarks/
│ └── runner.py # liboqs runner + NIST-baseline simulation fallback
├── compat/
│ └── oracle.py # Compatibility checks: MTU, TLS version, RAM, protocol
├── hybrid/
│ └── simulator.py # Hybrid (classical+PQC) key exchange simulation
├── inputs/
│ ├── tls_probe.py # Live TLS endpoint probing via stdlib ssl
│ ├── cbom.py # CycloneDX CBOM parser
│ └── sarif.py # SARIF 2.1.0 parser
├── report/
│ ├── terminal.py # Rich terminal renderer
│ ├── html_gen.py # Self-contained HTML report (no CDN)
│ ├── json_out.py # JSON output for CI/CD
│ └── config_diff.py # Copy-paste config diffs (OpenSSL, nginx, sshd, Go, Python)
└── demo/
└── runner.py # 60-second bundled demo scenarios
Dependencies: click, rich, psutil, cryptography, jinja2, requests
Optional: liboqs-python (for real NIST reference implementation benchmarks)
Out of scope (by design)
pqc-sandbox does not scan your codebase for crypto usage — excellent tools already do that:
Feed their CBOM or SARIF output directly to pqc-sandbox scan cbom / pqc-sandbox scan sarif.
Privacy & trust
🔒 ZERO CLOUD — All benchmarks run on your hardware.
🔒 ZERO TELEMETRY — No data leaves your machine. Ever.
🔒 ZERO ACCOUNTS — No sign-up, no API keys.
🔒 OPEN SOURCE — Apache 2.0. Audit everything.
Enterprise security teams: every byte this tool processes stays on your machine. The HTML report is generated locally from an embedded template — no external stylesheets, no CDN, no fonts loaded from the internet.
Contributing
git clone https://github.com/Deaksh/pqc-sandbox
cd pqc-sandbox
pip install -e ".[dev]"
python -m pytest tests/ -v
Pull requests welcome. Priority areas:
- Real liboqs integration tests (need liboqs installed in CI)
- Additional protocol compat checks (WireGuard, Signal Protocol, S/MIME)
- More config diff formats (HAProxy, Apache, Kubernetes TLS secrets)
- Hardware benchmark profiles (ARM Cortex-M, RISC-V, Apple Silicon)
References
- NIST FIPS 203 — ML-KEM
- NIST FIPS 204 — ML-DSA
- NIST FIPS 205 — SLH-DSA
- Open Quantum Safe (liboqs)
- IETF TLS Hybrid Key Exchange (draft-ietf-tls-hybrid-design)
- CNSA 2.0 — NSA Commercial National Security Algorithm Suite 2.0
- CycloneDX CBOM specification
License
Apache 2.0 — see LICENSE.
Release files for pqc-sandbox 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pqc_sandbox-0.1.0.tar.gz | 75.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pqc_sandbox-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 155.0 kB
Release files / pqc_sandbox-0.1.0.tar.gz
| Download URL | pqc_sandbox-0.1.0.tar.gz |
|---|---|
| Size | 75.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a8ef7ee29c481e51724638bf81184b598966fa6009ae2d0b9522786f79c7e91a
|
|
BLAKE2b-256 checksum How to use checksums |
950b3e11e36b3026ac538d4c1fc895b8767a5166236d57e5f8085cf62fce258f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|
Release files / pqc_sandbox-0.1.0-py3-none-any.whl
| Download URL | pqc_sandbox-0.1.0-py3-none-any.whl |
|---|---|
| Size | 79.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
18d0dd74afd50189e1c6c8d893e3b302be26f4a1c02a541debc11bea465c2c51
|
|
BLAKE2b-256 checksum How to use checksums |
1ea05dc2d4eb55c8198d3481c6f9d1bfd8b33993569c8f1d3b526ec3059faae6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|