Metadata-Version: 2.4
Name: pqchannel
Version: 1.0.0
Summary: A crypto-agile secure-transport library with pluggable cipher suites (classical, hybrid X25519+ML-KEM-768, pure-PQC)
Project-URL: Homepage, https://github.com/Pranay50x/pqchannel
Project-URL: Repository, https://github.com/Pranay50x/pqchannel
Project-URL: Bug Tracker, https://github.com/Pranay50x/pqchannel/issues
Author: pqchannel contributors
License: MIT
Keywords: ML-DSA,ML-KEM,crypto-agility,cryptography,post-quantum,secure-transport
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
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: Programming Language :: Python :: 3.13
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Requires-Dist: cryptography>=42.0
Requires-Dist: liboqs-python>=0.10.0
Provides-Extra: bench
Requires-Dist: matplotlib; extra == 'bench'
Requires-Dist: numpy; extra == 'bench'
Provides-Extra: dev
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: publish
Requires-Dist: build; extra == 'publish'
Requires-Dist: twine; extra == 'publish'
Description-Content-Type: text/markdown

# pqchannel

> A crypto-agile secure-transport library with pluggable cipher suites.

[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://python.org)
[![PyPI version](https://img.shields.io/badge/TestPyPI-1.0.0-brightgreen.svg)](https://test.pypi.org/project/pqchannel/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Status: Alpha](https://img.shields.io/badge/status-alpha-orange.svg)]()

`pqchannel` gives an application a secure TCP connection object
(`connect()` / `send()` / `recv()`) where the cryptography is provided by a
pluggable **cipher suite** — classical, hybrid, or pure post-quantum — swappable
with a single argument.

## The one-line swap

```python
from pqchannel import SecureConnection, HybridSuite, ClassicalSuite

# Quantum-safe today...
conn = SecureConnection.connect(("host", 9000), suite=HybridSuite())

# ...swap to classical with ONE line changed, no other app code touched:
conn = SecureConnection.connect(("host", 9000), suite=ClassicalSuite())
```

That's the whole pitch. The cryptography lives behind an interface — the app
never hard-codes an algorithm.

## Threat model

**Harvest-now-decrypt-later (HNDL):** an adversary recording today's
classical-only traffic can decrypt it retroactively once a
cryptographically-relevant quantum computer exists. The hybrid suite
(X25519 + ML-KEM-768) defends against this: even if ML-KEM is broken by a
future classical attack, X25519 still holds; even if X25519 is broken by a
quantum computer, ML-KEM still holds. **Either primitive alone is enough.**

Authentication (Phase 4) adds MITM protection: the server signs its handshake
material and the client verifies it against a pinned identity key.

## Cipher suites

| Suite | Key exchange | Authentication | AEAD | liboqs? |
|-------|-------------|----------------|------|---------|
| `ClassicalSuite` | X25519 | Ed25519 | AES-256-GCM | no |
| `HybridSuite` | X25519 + ML-KEM-768 | ML-DSA-65 | AES-256-GCM | yes |
| `PQOnlySuite` | ML-KEM-768 | ML-DSA-65 | AES-256-GCM | yes |

## Install

```bash
# From TestPyPI (v1.0.0)
pip install -i https://test.pypi.org/simple/ pqchannel
```

Post-quantum suites (HybridSuite / PQOnlySuite) require `liboqs-python`, which
must be compiled against a native `liboqs` build.  The easiest path is Docker —
see **[SETUP.md](SETUP.md)** for per-OS instructions.

The classical suite (`ClassicalSuite`) works on any host with only `cryptography`.

## Running it (Docker)

The supported, reproducible environment is **Docker** — it compiles `liboqs`
once inside the image so nobody needs a local C toolchain, and it builds
identically on Windows (amd64) and Apple Silicon (arm64). Full setup for both
machines is in **[SETUP.md](SETUP.md)**.

```bash
docker compose build            # first time — compiles liboqs (a few minutes)
docker compose run --rm tests   # run the full test suite (89 tests)
```

The classical parts run natively too (they need only `cryptography`, not
liboqs); the post-quantum tests skip off-Docker. See [SETUP.md](SETUP.md).

## Quick start (library usage)

```python
# server.py
from pqchannel import SecureListener, HybridSuite

with SecureListener(("0.0.0.0", 9000), suite=HybridSuite()) as listener:
    conn = listener.accept()
    print(conn.recv())
    conn.send(b"pong")

# client.py
from pqchannel import SecureConnection, HybridSuite

conn = SecureConnection.connect(("localhost", 9000), suite=HybridSuite())
conn.send(b"ping")
print(conn.recv())
```

### Authenticated handshake

```python
from pqchannel import SecureConnection, HybridSuite, AuthenticationError

# The client pins the server's identity public key (distributed out-of-band).
conn = SecureConnection.connect(
    ("host", 9000), suite=HybridSuite(), server_pubkey=pinned_pk
)
# AuthenticationError is raised — before any session key is derived — if a
# man-in-the-middle tampered with the server's handshake material.
```

## Examples

Three runnable examples, each using only the public API. Exact two-terminal
commands are in **[SETUP.md → Running the examples](SETUP.md#running-the-examples-manual-tests)**.

- **`examples/chat.py`** — an encrypted chat. Swap the suite live with
  `--suite classical|hybrid|pqonly` — this *is* the crypto-agility story.
- **`examples/filetransfer.py`** — send a file with an end-to-end SHA-256
  integrity check.
- **`examples/mitm.py`** — proves the authenticated handshake catches a
  man-in-the-middle (raises `AuthenticationError`).

## Benchmarks

`benchmarks/bench.py` times each suite (keygen / kex / sign / verify / full
authenticated handshake) and measures handshake **bytes-on-the-wire**:

```bash
docker compose run --rm dev python benchmarks/bench.py
```

| Suite | handshake latency\* | handshake bytes on the wire |
|-------|--------------------|-----------------------------|
| Classical | ~0.21 ms | **176 B** |
| Hybrid | ~0.22 ms | **7,617 B** |
| PQOnly | ~0.14 ms | **7,553 B** |

\* Crypto only (no TCP), measured in Docker — hardware-specific and noisy, so
compare suites *relative* to each other, not as absolute figures. The wire
sizes are exact.

**Takeaway:** post-quantum security here is *fast but large* — the PQC
handshakes are ~43× the size of the classical one on the wire, at comparable
CPU cost (the cost of ML-KEM/ML-DSA is bandwidth, not compute). The table, a raw
CSV, and charts are written to [`benchmarks/results/`](benchmarks/results/).

![Handshake size by suite](benchmarks/results/handshake_bytes.png)

## Architecture

```
Application code
      │  suite=HybridSuite()
      ▼
SecureConnection / SecureListener   ← channel.py  (public API + AEAD records)
      │
      ▼
Handshake (suite-agnostic)          ← handshake.py (KEX + auth, no algo names)
      │
      ├─▶ CipherSuite interface     ← suites.py   (abstract contract)
      │       │
      │       ├─ ClassicalSuite     (X25519 + Ed25519)
      │       ├─ HybridSuite        (X25519 + ML-KEM-768 + ML-DSA-65)
      │       └─ PQOnlySuite        (ML-KEM-768  + ML-DSA-65)
      │
      └─▶ Framing layer             ← framing.py  (4-byte length prefix)
```

## Limitations ⚠️

This is a **prototyping-grade** library for learning and demonstration, not a
production security product.

- **liboqs is not production-vetted** — it is for experimentation.
- **Demo-grade authentication.** The server's identity key is generated
  in-process and pinned by the client from that same process — there is no real
  PKI or out-of-band key distribution. The server signs only its own KEX
  material (not the full transcript), and there is no mutual (client) auth.
- **Counter-based nonces.** A direction-partitioned counter drives the AES-GCM
  nonce — safe for demo scale; a production library would harden this.
- **Example-scale.** The listener handles one blocking connection at a time
  (no concurrency model, no data-phase timeouts) — fine for the demos, not a
  server.
- **Benchmark latencies are indicative only** (see the note above); the wire
  sizes are exact.

## Building on vetted primitives

This library **never implements cryptographic primitives**. All crypto comes from:

- **[liboqs-python](https://github.com/open-quantum-safe/liboqs-python)** — ML-KEM-768, ML-DSA-65
- **[cryptography](https://cryptography.io)** — X25519, Ed25519, HKDF-SHA256, AES-256-GCM

## Development

```bash
docker compose run --rm tests                          # full test suite (89)
docker compose run --rm dev mypy src/                  # type check (strict)
docker compose run --rm dev python benchmarks/bench.py # benchmarks + charts
```

See [SETUP.md](SETUP.md) for the native (non-Docker) path and per-OS notes.

## References

- [NIST FIPS 203 (ML-KEM)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf)
- [NIST FIPS 204 (ML-DSA)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf)
- [NCCoE Migration to Post-Quantum Cryptography](https://www.nccoe.nist.gov/crypto-agility-considerations-migrating-post-quantum-cryptographic-algorithms)
- [Open Quantum Safe](https://openquantumsafe.org)

## Changelog

### v1.0.0 (2026-07-04)

- Full crypto-agility story complete: `ClassicalSuite`, `HybridSuite`, `PQOnlySuite`
  all implement the same `CipherSuite` interface; swap with one argument.
- Authenticated handshake with ML-DSA-65 / Ed25519; MITM example (`mitm.py`).
- `examples/chat.py` and `examples/filetransfer.py` use only the public API.
- `benchmarks/bench.py` quantifies handshake size and latency across all three suites.
- Published to TestPyPI: `pip install -i https://test.pypi.org/simple/ pqchannel`
- 91+ pytest tests; `mypy --strict src/` clean.
