Skip to main content

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.

PQC Migration: MODERATE License: Apache 2.0 Python 3.9+ Zero Telemetry

🔒 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

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 Migration: MODERATE](https://img.shields.io/...)

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


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)

Source distribution for pqc-sandbox 0.1.0
File Size Uploaded
pqc_sandbox-0.1.0.tar.gz 75.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pqc-sandbox 0.1.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page