# pqc-py

Post-quantum cryptography for Python via Rust.

FIPS 203/204/205 implementations (ML-KEM, ML-DSA, SLH-DSA) plus classical primitives (AES-256-GCM, HKDF, HMAC-SHA256), all backed by audited Rust crates with automatic key zeroization.

## Features

| Algorithm | Standard | Purpose |
|-----------|----------|---------|
| ML-KEM (Kyber) | FIPS 203 | Post-quantum key encapsulation |
| ML-DSA (Dilithium) | FIPS 204 | Post-quantum digital signatures |
| SLH-DSA (SPHINCS+) | FIPS 205 | Stateless hash-based signatures |
| AES-256-GCM | NIST SP 800-38D | Authenticated encryption |
| HKDF-SHA256/512 | RFC 5869 | Key derivation |
| HMAC-SHA256 | RFC 2104 | Message authentication |

## Security

- All secret key material is automatically zeroed on drop (`zeroize`)
- Constant-time comparisons where applicable (`subtle`)
- No `unsafe` code in the Rust layer
- Built on audited RustCrypto and pqcrypto libraries

## Installation

### From PyPI (when published)

```bash
pip install pqc-py
```

### From source

Requires Rust 1.70+ and maturin:

```bash
git clone https://github.com/ScrappinR/pqc-py.git
cd pqc-py
pip install maturin
maturin develop --release
```

## Usage

### Post-Quantum Key Exchange (Kyber / ML-KEM)

```python
import pqc_py

# Generate key pair (level1=128bit, level3=192bit, level5=256bit)
pk, sk = pqc_py.kyber_keygen("level3")

# Encapsulate (sender)
ciphertext, shared_secret_sender = pqc_py.kyber_encapsulate(pk)

# Decapsulate (receiver)
shared_secret_receiver = pqc_py.kyber_decapsulate(ciphertext, sk)

assert shared_secret_sender == shared_secret_receiver
```

### Post-Quantum Signatures (Dilithium / ML-DSA)

```python
import pqc_py

pk, sk = pqc_py.dilithium_keygen("level3")
signature = pqc_py.dilithium_sign(sk, b"message to sign")
valid = pqc_py.dilithium_verify(pk, b"message to sign", signature)
assert valid
```

### SPHINCS+ (SLH-DSA) — Conservative Signatures

```python
import pqc_py

# 12 variants: sha2/shake x 128/192/256 x fast/small
pk, sk = pqc_py.sphincs_keygen("sha2-192f")
signature = pqc_py.sphincs_sign(sk, b"message", variant="sha2-192f")
valid = pqc_py.sphincs_verify(pk, b"message", signature, variant="sha2-192f")
```

### Classical Crypto

```python
import pqc_py

# AES-256-GCM
key = pqc_py.random_key()  # 32 bytes
nonce = pqc_py.random_nonce()  # 12 bytes
ciphertext = pqc_py.encrypt_aes_gcm(key, nonce, b"plaintext", b"aad")
plaintext = pqc_py.decrypt_aes_gcm(key, nonce, ciphertext, b"aad")

# HKDF key derivation
derived = pqc_py.derive_key(b"secret", salt=b"salt", info=b"context", length=32)

# HMAC-SHA256
tag = pqc_py.hmac_sha256(key, b"message")
assert pqc_py.verify_hmac(key, b"message", tag)

# SHA-256
digest = pqc_py.sha256(b"data")
hex_digest = pqc_py.sha256_hex(b"data")
```

## Building

```bash
# Rust library only
cargo build --release

# Python wheel
maturin build --release

# Development install
maturin develop --release

# Run Rust tests
cargo test

# Run benchmarks
cargo bench
```

## Benchmarks

Run `cargo bench` for performance numbers. Key operations:

- Kyber keygen + encapsulate + decapsulate
- Dilithium keygen + sign + verify
- SPHINCS+ keygen + sign + verify (all 12 variants)
- AES-256-GCM encrypt/decrypt
- HKDF derivation

## License

Apache 2.0

## Author

Brian James Rutherford — [brianrutherford.dev](https://brianrutherford.dev)
