Metadata-Version: 2.4
Name: pqc-scanner
Version: 1.3.2
Summary: Automated timing side-channel scanner for NIST PQC standards ML-KEM and ML-DSA
Author-email: Collective Qubits <disha.p2023@vitstudent.ac.in>
License: MIT License
        
        Copyright (c) 2025 Collective Qubits
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/Disha23112004/pqc-scanner
Project-URL: Repository, https://github.com/Disha23112004/pqc-scanner
Project-URL: Issues, https://github.com/Disha23112004/pqc-scanner/issues
Project-URL: Documentation, https://github.com/Disha23112004/pqc-scanner#readme
Keywords: post-quantum cryptography,side-channel,timing attack,ML-KEM,ML-DSA,FIPS 203,FIPS 204,TVLA,security,cryptography
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Scientific/Engineering
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: POSIX :: Linux
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: kyber-py>=0.5.0
Requires-Dist: dilithium-py>=0.3.0
Requires-Dist: scipy>=1.10.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: click>=8.1.0
Requires-Dist: rich>=13.0.0
Dynamic: license-file

# PQC Side-Channel Scanner

[![PyPI version](https://badge.fury.io/py/pqc-scanner.svg)](https://pypi.org/project/pqc-scanner/)
[![PyPI downloads](https://img.shields.io/pypi/dm/pqc-scanner)](https://pypi.org/project/pqc-scanner/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/)

The first open-source, automated, pip-installable timing side-channel scanner for all four NIST post-quantum cryptography standards — FIPS 203 (ML-KEM), FIPS 204 (ML-DSA), FIPS 205 (SLH-DSA), and FIPS 206 (FN-DSA/FALCON). Scans both liboqs 0.15.0 and OpenSSL+oqs-provider using TVLA statistical methodology at nanosecond precision.

Built by [Disha P](https://github.com/Disha23112004), Technical Director at [Collective Qubits](https://collectivequbits.com).

---

## Why This Exists

NIST finalized the post-quantum cryptography standards in August 2024. Banks, cloud providers, and government agencies are actively deploying ML-KEM, ML-DSA, FALCON, and SLH-DSA to protect against future quantum attacks. But timing side-channel vulnerabilities in cryptographic implementations can leak secret key material even when the underlying algorithm is mathematically secure.

Existing tools like dudect require manual C-level integration, have no PQC-specific targets, and predate the NIST standards. No automated scanner existed for the full NIST PQC suite.

This tool fills that gap.

---

## What It Found

### Finding 1 — ML-KEM Encapsulation (RNG-induced), liboqs 0.15.0

| Algorithm | Operation | t-statistic (WSL2) | t-statistic (bare metal) | Verdict |
| --- | --- | --- | --- | --- |
| ML-KEM-512 | Encapsulation | -4.9 | -8.37 | CRITICAL |
| ML-KEM-512 | Decapsulation | 0.5 | 1.15 | PASS |
| ML-KEM-768 | Encapsulation | 75.5 | -13.68 | CRITICAL |
| ML-KEM-768 | Decapsulation | -3.2 | -0.09 | PASS |
| ML-KEM-1024 | Encapsulation | -12.6 | -51.99 | CRITICAL |
| ML-KEM-1024 | Decapsulation | -0.4 | 3.88 | PASS |

**Root cause confirmed:** `OQS_randombytes()` inside `OQS_KEM_encaps()` has variable timing. Derand confirmation — bypassing RNG with `encaps_derand()` drops both portable C (t=0.66) and AVX2 (t=0.93) to PASS. The cryptographic core is clean. **Fix: use `OQS_KEM_encaps_derand()` with a pre-seeded DRBG.**

**Note:** This finding disappears through OpenSSL+oqs-provider, which uses OpenSSL's `RAND_bytes` instead of `OQS_randombytes`. Enterprises using oqs-provider are not affected by this specific issue.

---

### Finding 2 — FALCON Verify (Algorithmic), liboqs 0.15.0 + OpenSSL+oqs-provider

| Algorithm | Operation | t (liboqs bare metal) | t (OpenSSL bare metal) | Verdict |
| --- | --- | --- | --- | --- |
| FALCON-512 | Sign | 6.38 | — | PASS |
| FALCON-512 | Verify | -217.58 | -192.33 | CRITICAL |
| FALCON-1024 | Sign | 0.77 | — | PASS |
| FALCON-1024 | Verify | -303.05 | -343.24 | CRITICAL |
| FALCON-padded-512 | Verify | -168.63 | -255.66 | CRITICAL |
| FALCON-padded-1024 | Verify | -187.19 | -292.10 | CRITICAL |

**Root cause:** Golomb-Rice signature decompression in `comp_decode()` (`codec.c`). The inner unary decoding loop iterates a variable number of times proportional to coefficient magnitude — producing signature-content dependent timing. Confirmed across both library targets. **No existing fix — a constant-time `comp_decode()` is required.**

Root cause investigation:
- Same message, different signatures → still CRITICAL (t=-53.86) — not message-dependent
- Padded variants with fixed-length signatures → still CRITICAL — not length-dependent
- Verify has no RNG call — cannot be RNG-induced
- No open issue on liboqs GitHub for this finding (as of April 2026)

---

### Finding 3 — ML-DSA Verify (Weak signal), bare metal only

| Algorithm | Operation | t (liboqs bare metal) | t (OpenSSL bare metal) | Verdict |
| --- | --- | --- | --- | --- |
| ML-DSA-44 | Verify | -5.41 | -9.28 | CRITICAL |
| ML-DSA-65 | Verify | -5.66 | -9.04 | CRITICAL |
| ML-DSA-87 | Verify | -4.51 | -10.38 | CRITICAL |
| ML-DSA-44/65/87 | Sign | all PASS | all PASS | PASS |

**Note:** This signal is weak (t ≈ 5-10) and only detectable on bare metal at 100k traces. Not detected on WSL2. Root cause under investigation.

---

### FIPS 205 — SLH-DSA (all parameter sets)

SLH-DSA verify shows variable timing consistent with the inherently variable-time Merkle tree traversal in hash-based signatures. Expected behavior by design — not an implementation vulnerability.

---

### OpenSSL+oqs-provider Summary (bare metal, 100k traces)

| Algorithm | Operation | t-statistic | Verdict |
| --- | --- | --- | --- |
| ML-KEM-512/768/1024 | Encapsulation | ≈ 2-5 | PASS |
| FALCON-512 | Verify | -192.33 | CRITICAL |
| FALCON-1024 | Verify | -343.24 | CRITICAL |
| FALCON-padded-512 | Verify | -255.66 | CRITICAL |
| FALCON-padded-1024 | Verify | -292.10 | CRITICAL |
| ML-DSA-44/65/87 | Verify | -9 to -10 | CRITICAL |

**C-level noise floor (AES-128):** 11.7ns. FALCON verify finding is 500× above noise floor.

---

## How It Works

The scanner implements Test Vector Leakage Assessment (TVLA) as defined in ISO/IEC 17825. For each cryptographic operation:

1. Collects timing measurements for a **fixed input** (same bytes every time)
2. Collects timing measurements for **random inputs** (different bytes every time)
3. Runs **Welch's t-test** on the two distributions
4. Flags as leaking if **|t| > 4.5** — the ISO 17825 threshold

Two measurement layers:
- **Python layer** — targets kyber-py and dilithium-py via `time.perf_counter_ns()`, detects millisecond-level leaks
- **C layer** — targets liboqs and OpenSSL directly with `CLOCK_MONOTONIC_RAW`, detects nanosecond-level leaks

---

## Installation

### Quickstart

```bash
pip install pqc-scanner
```

### Docker (no setup required)

```bash
docker build -t pqc-scanner .
docker run pqc-scanner python3 cli.py liboqs --traces 50000
docker run pqc-scanner python3 cli.py openssl --algorithm falcon --traces 100000
```

No liboqs installation, no gcc, no Python setup required. Everything is bundled.

### From source (recommended for full C harness support)

#### Requirements

- Ubuntu 20.04+ or WSL2 (Ubuntu 24.04 tested)
- Python 3.10+
- gcc and clang
- liboqs (instructions below)
- oqs-provider (for OpenSSL target)

#### 1. Clone and set up

```bash
git clone https://github.com/Disha23112004/pqc-scanner
cd pqc-scanner
python3 -m venv venv
source venv/bin/activate
pip install -e .
pip install kyber-py dilithium-py scipy numpy click rich reportlab
```

#### 2. Install liboqs

```bash
sudo apt install -y cmake ninja-build libssl-dev clang
git clone --depth=1 https://github.com/open-quantum-safe/liboqs ~/liboqs
cmake -S ~/liboqs -B ~/liboqs/build -DBUILD_SHARED_LIBS=ON -GNinja
cmake --build ~/liboqs/build --parallel 4
sudo cmake --build ~/liboqs/build --target install
sudo ldconfig
```

#### 3. Install oqs-provider (for OpenSSL target)

```bash
git clone --depth=1 https://github.com/open-quantum-safe/oqs-provider ~/oqs-provider
cmake -S ~/oqs-provider -B ~/oqs-provider/build \
    -DOPENSSL_ROOT_DIR=/usr \
    -Dliboqs_DIR=/usr/local/lib/cmake/liboqs -GNinja
cmake --build ~/oqs-provider/build --parallel 4
sudo cmake --build ~/oqs-provider/build --target install
```

#### 4. Build C harnesses

```bash
cd harness
gcc -O2 -o ml_kem_harness ml_kem_harness.c -loqs -lm
gcc -O2 -o ml_dsa_harness ml_dsa_harness.c -loqs -lm
gcc -O2 -o baseline_harness baseline_harness.c -lssl -lcrypto
gcc -O2 -o openssl_kem_harness openssl_kem_harness.c -lssl -lcrypto -lm
gcc -O2 -o openssl_sig_harness openssl_sig_harness.c -lssl -lcrypto -lm
cd ..
```

---

## Usage

```bash
source venv/bin/activate
```

### liboqs scan (primary target)

```bash
# ML-KEM-768 production scan
pqc-scanner liboqs --traces 100000

# RNG root cause isolation
pqc-scanner derand --traces 100000
```

### OpenSSL+oqs-provider scan (second target)

```bash
# Scan all algorithms
pqc-scanner openssl --traces 100000

# Scan specific algorithm family
pqc-scanner openssl --algorithm falcon --traces 100000
pqc-scanner openssl --algorithm ml-kem --traces 100000
pqc-scanner openssl --algorithm ml-dsa --traces 100000
```

### Python layer scans

```bash
# Scan ML-KEM and ML-DSA Python implementations
pqc-scanner scan --algorithm both --traces 10000

# Side by side comparison
pqc-scanner compare --traces 10000
```

### Noise floor characterization

```bash
pqc-scanner baseline      # Python layer (SHA-256)
pqc-scanner c-baseline    # C layer (AES-128)
```

### Compiler sweep

```bash
pqc-scanner compiler-sweep --traces 50000 --runs 3
```

---

## Output

Every scan automatically generates three output files:

- **JSON** — structured findings for CI/CD integration (exit code 1 on findings)
- **HTML** — interactive report with timing distribution histograms
- **PDF** — professional compliance report for CISO and auditor review

```bash
pqc-scanner liboqs --traces 100000
# Generates: liboqs.json, liboqs.html, liboqs.pdf

pqc-scanner openssl --algorithm falcon --traces 100000
# Generates: openssl_scan.json, openssl_scan.pdf
```

### SARIF output (GitHub Advanced Security)

```bash
pqc-scanner liboqs --traces 100000 --format sarif --output results
```

---

## CI/CD Integration

```yaml
- name: PQC Timing Scan
  run: pqc-scanner liboqs --traces 50000
  # Pipeline fails automatically if leaks are found
```

Use `--no-exit` to suppress exit code in reporting-only mode.

---

## Methodology

### TVLA (Test Vector Leakage Assessment)

Documented in ISO/IEC 17825. Core principle: a constant-time implementation's execution time must be statistically independent of its input.

### Welch's t-test

Used instead of Student's t-test because it does not assume equal variance. Threshold: |t| > 4.5 indicates statistically significant timing leakage at p < 0.001.

### Derandomization (derand) technique

A novel root-cause isolation method introduced in this tool. By calling `encaps_derand()` directly with a fixed seed, bypassing `OQS_randombytes()` entirely, RNG-induced timing variation is eliminated. Comparing standard TVLA against derand results distinguishes algorithmic from RNG-induced leakage — not present in any prior published tooling.

### Measurement precision

- Python layer — `time.perf_counter_ns()`, noise floor ~100–130ns on WSL2
- C layer — `CLOCK_MONOTONIC_RAW`, noise floor ~10–12ns on WSL2, lower on bare metal

### Noise reduction

- **500-trace warmup** — stabilizes CPU cache, branch predictor, and TLB state
- **5% outlier trimming** — removes OS interrupt spikes and context switches
- **CPU affinity** — pins process to core 0 via `sched_setaffinity`
- **Pre-generated test vectors** — all random inputs generated before the timed window

---

## Project Structure

```
pqc-scanner/
├── cli.py
├── src/pqc_scanner/
│   ├── scanner/
│   │   ├── timing.py           ← TVLA engine, Welch's t-test
│   │   ├── report.py           ← JSON and HTML generation
│   │   ├── pdf_report.py       ← PDF compliance report generation
│   │   └── sarif.py            ← SARIF 2.1.0 output
│   └── targets/
│       ├── ml_kem_target.py    ← ML-KEM Python harness
│       ├── ml_dsa_target.py    ← ML-DSA Python harness
│       ├── baseline_target.py  ← SHA-256 control
│       └── liboqs_target.py    ← liboqs subprocess interface
└── harness/
    ├── ml_kem_harness.c            ← ML-KEM 512/768/1024
    ├── ml_dsa_harness.c            ← ML-DSA + FALCON + SLH-DSA
    ├── ml_kem_harness_derand.c     ← RNG root cause isolation
    ├── baseline_harness.c          ← AES-128 noise floor
    ├── openssl_kem_harness.c       ← OpenSSL EVP KEM harness
    └── openssl_sig_harness.c       ← OpenSSL EVP signature harness
```

---

## Comparison With Existing Tools

| Capability | dudect | Riscure | pqc-scanner |
|------------|--------|---------|-------------|
| Full NIST PQC suite (FIPS 203-206) | ✗ | ✗ | ✓ |
| liboqs integration | ✗ | ✗ | ✓ |
| OpenSSL+oqs-provider target | ✗ | ✗ | ✓ |
| Derand root-cause isolation | ✗ | ✗ | ✓ |
| PDF compliance reports | ✗ | ✓ (hardware) | ✓ |
| CI/CD exit codes + SARIF | ✗ | ✗ | ✓ |
| Docker support | ✗ | ✗ | ✓ |
| No hardware required | ✓ | ✗ | ✓ |
| pip installable | ✗ | ✗ | ✓ |
| Open source | ✓ | ✗ | ✓ |

---

## Related Work

- **dudect** — Reparaz et al. (2016). General-purpose constant-time testing library. No PQC targets.
- **KyberSlash** — Bernstein et al. (2024). Manual timing analysis of Kyber implementations.
- **TVLA** — Cryptography Research Inc. (2011). Leakage assessment methodology, standardized in ISO/IEC 17825.
- **liboqs** — Open Quantum Safe project. C library for post-quantum cryptographic algorithms.

---

## Responsible Disclosure

- **ML-KEM finding** — Disclosed to Open Quantum Safe project (security@openquantumsafe.org), April 2026
- **FALCON verify finding** — Disclosed to PQShield (security@pqshield.com), April 2026

---

## Limitations

- WSL2 hypervisor adds noise. Sub-50ns findings require bare metal Linux for confirmation.
- kyber-py and dilithium-py are non-constant-time reference implementations. Python layer findings are expected and not novel.
- A PASS result does not prove constant-time behavior — it means no significant signal was detected at the given trace count and threshold.
- TVLA detects first-order leakage. Higher-order leakage in masked implementations requires higher-order TVLA extensions not yet implemented.

---

## License

MIT License. See [LICENSE](LICENSE) for details.

---

## Citation

If you use this tool in research, please cite:

```
Disha P, "PQC Side-Channel Scanner: Automated TVLA-based timing analysis for
NIST post-quantum cryptography standards," 2026.
https://github.com/Disha23112004/pqc-scanner
```
