Post-quantum cryptography engine — Hybrid ML-KEM + AES-256-GCM (FIPS 203)
Project description
AegisQ
Post-Quantum Cryptography Engine for Python
AegisQ is a hybrid cryptographic library that combines ML-KEM (FIPS 203) for quantum-resistant key encapsulation with AES-256-GCM for authenticated symmetric encryption. The cryptographic core is written in Rust for performance and security guarantees, exposed to Python via PyO3.
from aegisq import AegisCipher, SecurityLevel
cipher = AegisCipher(level=SecurityLevel.ML_KEM_768)
keypair = cipher.generate_keypair()
# Encrypt
package = cipher.encrypt(b"Secret data", keypair.public_key)
# Decrypt
plaintext = cipher.decrypt(package, keypair.secret_key)
Features
- Quantum-safe key exchange — ML-KEM (Module Lattice-based KEM), standardized as NIST FIPS 203
- Authenticated encryption — AES-256-GCM provides confidentiality and integrity in a single operation
- Three security levels — ML-KEM-512 (NIST Level 1), ML-KEM-768 (Level 3, default), ML-KEM-1024 (Level 5)
- Rust core, Python API — Cryptographic operations run in optimized Rust; Python developers get an ergonomic 3-line API
- Constant-time operations — Timing-attack resistant via
subtle::ConstantTimeEqand Barrett reduction - Memory zeroization — All secret keys and shared secrets are securely erased after use via
zeroize - Zero-copy FFI — Data passes between Python and Rust without unnecessary copies
- GIL release — Rust crypto operations release the Python GIL via
py.detach(), enabling true parallelism - Type-safe — Full PEP 561 type stubs with IDE autocompletion support
- Python 3.11+ — Built with PyO3 abi3 stable ABI for broad compatibility (3.11 through 3.13+)
- Ephemeral sessions with forward secrecy —
EphemeralSessionclass auto-generates keypairs and destroys secrets on close - Async support —
encrypt_async()/decrypt_async()methods for non-blocking cryptographic operations
Installation
From source (requires Rust toolchain)
# Prerequisites: Rust (via rustup), Python >= 3.11, maturin
pip install maturin
# Clone and build
git clone <repository-url>
cd aegisq
maturin develop --release
Development build (debug, faster compilation)
maturin develop
Quick Start
Encrypt and Decrypt (Recommended API)
The AegisCipher class handles the entire hybrid KEM-DEM flow — ML-KEM key encapsulation followed by AES-256-GCM encryption — in a single .encrypt() call.
from aegisq import AegisCipher, SecurityLevel
# 1. Receiver generates a keypair
cipher_bob = AegisCipher(level=SecurityLevel.ML_KEM_768)
keypair = cipher_bob.generate_keypair()
# keypair.public_key → 1184 bytes (share openly)
# keypair.secret_key → 2400 bytes (keep private)
# 2. Sender encrypts with the receiver's public key
cipher_alice = AegisCipher(level=SecurityLevel.ML_KEM_768)
encrypted_package = cipher_alice.encrypt(
plaintext=b"Top secret medical records",
recipient_public_key=keypair.public_key,
)
# encrypted_package is a single bytes object:
# [ ML-KEM Capsule (1088 B) | Nonce (12 B) | Auth Tag (16 B) | Ciphertext ]
# 3. Receiver decrypts
decrypted = cipher_bob.decrypt(
encrypted_package=encrypted_package,
secret_key=keypair.secret_key,
)
assert decrypted == b"Top secret medical records"
Raw KEM Operations (Advanced)
The MlKem class exposes low-level ML-KEM operations for users building custom protocols:
from aegisq import MlKem, SecurityLevel
kem = MlKem(level=SecurityLevel.ML_KEM_768)
keypair = kem.generate_keypair()
# Encapsulate: produces a capsule + 32-byte shared secret
capsule, shared_secret = kem.encapsulate(keypair.public_key)
# Decapsulate: recovers the same 32-byte shared secret
recovered = kem.decapsulate(capsule, keypair.secret_key)
assert shared_secret == recovered
Security Levels
| Level | Enum Value | NIST Level | Public Key | Secret Key | Capsule | Package Overhead |
|---|---|---|---|---|---|---|
| ML-KEM-512 | SecurityLevel.ML_KEM_512 |
1 | 800 B | 1632 B | 768 B | 796 B |
| ML-KEM-768 | SecurityLevel.ML_KEM_768 |
3 (default) | 1184 B | 2400 B | 1088 B | 1116 B |
| ML-KEM-1024 | SecurityLevel.ML_KEM_1024 |
5 | 1568 B | 3168 B | 1568 B | 1596 B |
Package overhead = capsule + AES nonce (12 B) + AES auth tag (16 B). The total encrypted package size is overhead + plaintext length.
API Reference
AegisCipher (recommended for most users)
class AegisCipher:
def __init__(self, level: SecurityLevel = SecurityLevel.ML_KEM_768) -> None
def generate_keypair(self) -> KeyPair
def encrypt(self, plaintext: bytes, recipient_public_key: bytes) -> bytes
def decrypt(self, encrypted_package: bytes, secret_key: bytes) -> bytes
async def encrypt_async(self, plaintext: bytes, recipient_public_key: bytes) -> bytes
async def decrypt_async(self, encrypted_package: bytes, secret_key: bytes) -> bytes
EphemeralSession (forward secrecy)
class EphemeralSession:
def __init__(self, level: SecurityLevel = SecurityLevel.ML_KEM_768) -> None
def public_key(self) -> bytes # Read-only, secret key never exposed
def encrypt(self, plaintext: bytes, recipient_public_key: bytes) -> bytes
def decrypt(self, encrypted_package: bytes) -> bytes
def close(self) -> None
# Also supports context manager: `with EphemeralSession() as s: ...`
MlKem (advanced, raw KEM operations)
class MlKem:
def __init__(self, level: SecurityLevel = SecurityLevel.ML_KEM_768) -> None
def generate_keypair(self) -> KeyPair
def encapsulate(self, public_key: bytes) -> tuple[bytes, bytes]
def decapsulate(self, capsule: bytes, secret_key: bytes) -> bytes
KeyPair
class KeyPair:
public_key: bytes # Encryption key (share openly)
secret_key: bytes # Decapsulation key (keep private)
level: SecurityLevel
Exceptions
AegisQError(Exception) Base exception
├── DecapsulationError(AegisQError) ML-KEM structural error (wrong buffer size)
├── DecryptionError(AegisQError) AES-GCM auth tag failed (tampered or wrong key)
├── InvalidParameterError(AegisQError, ValueError) Incorrect parameter sizes
├── RngError(AegisQError) OS CSPRNG unavailable
└── SessionExpiredError(AegisQError) Attempted operation on closed EphemeralSession
All exceptions can be imported from the top-level package:
from aegisq import AegisQError, DecryptionError
Architecture
AegisQ is structured in three hermetic layers. Each layer only depends on the one below it:
┌─────────────────────────────────────────────────────────────┐
│ Layer 3: Python API (aegisq/) │
│ AegisCipher, MlKem, SecurityLevel, exception hierarchy │
│ Type hints, docstrings, developer-facing abstractions │
├─────────────────────────────────────────────────────────────┤
│ Layer 2: FFI Bridge (crates/aegisq-pyo3/) │
│ PyO3 bindings, GIL release, zero-copy data passing │
│ No cryptographic logic — pure translation layer │
├─────────────────────────────────────────────────────────────┤
│ Layer 1: Rust Core (crates/aegisq-core/) │
│ ML-KEM (FIPS 203), AES-256-GCM, Transit Package assembly │
│ #![no_std] compatible, constant-time, zeroize │
└─────────────────────────────────────────────────────────────┘
- Layer 1 implements all cryptographic math in pure Rust with
no_stdcompatibility. It has no knowledge of Python. - Layer 2 translates Rust types to Python types via PyO3 and releases the GIL during expensive operations.
- Layer 3 provides the ergonomic Python classes that end users interact with.
Development
Build
maturin develop # Debug build (fast compilation)
maturin develop --release # Release build (optimized)
Test
# Rust tests (unit + integration, all crates)
cargo test --workspace
# Python tests
pytest tests/python/ -v
# Specific test suites
cargo test -p aegisq-core # Core crypto only
pytest tests/python/test_cipher_api.py # AegisCipher end-to-end
pytest tests/python/test_hybrid_bindings.py # Hybrid bridge
pytest tests/python/test_kem_bindings.py # KEM bridge
pytest tests/python/test_kem_api.py # MlKem API
Code Quality
cargo clippy --workspace -- -D warnings # Rust linter (warnings are errors)
cargo fmt --all # Rust formatting
ruff check aegisq/ # Python type checking
Security
Guarantees
| Property | Mechanism |
|---|---|
| IND-CCA2 security | Implicit rejection in ML-KEM Decaps (FIPS 203 §7.3) |
| Quantum resistance | M-LWE hardness assumption (ML-KEM) |
| Data confidentiality + integrity | AES-256-GCM authenticated encryption |
| Timing attack immunity | subtle::ConstantTimeEq, Barrett reduction |
| Memory scrubbing | zeroize::Zeroize on all secrets |
| Nonce uniqueness | Fresh 96-bit random nonce via OsRng per encrypt call |
| Integer overflow protection | overflow-checks = true in release profile |
Important Notes
- No forward secrecy by default. If a secret key is compromised, all payloads encrypted to that key are compromised. Mitigation: Use ephemeral keypairs — generate a new keypair per session and discard the secret key after decryption.
- ML-KEM Decaps never raises an error for invalid capsules (implicit rejection). Instead, it returns a pseudorandom key, which causes AES-GCM to fail with
DecryptionError. This prevents chosen-ciphertext oracle attacks. - AES-GCM tag failure always raises
DecryptionError. Unlike ML-KEM's silent rejection, a failed auth tag means the payload was tampered with or the wrong key was used.
Standards Compliance
| Standard | Description |
|---|---|
| FIPS 203 | ML-KEM — Module-Lattice-Based Key-Encapsulation Mechanism (NIST, 2024) |
| NIST SP 800-38D | AES-GCM — Galois/Counter Mode specification |
Dependencies
| Crate | Purpose |
|---|---|
aes-gcm 0.10 |
AES-256-GCM authenticated encryption (no_std, hardware AES-NI) |
sha3 0.10 |
SHAKE-128/256 and SHA3-256/512 for ML-KEM (no_std) |
zeroize 1.8 |
Secure memory erasure of secrets |
subtle 2.6 |
Constant-time comparisons |
rand_core 0.6 |
OS-level CSPRNG via OsRng (no_std) |
pyo3 0.28 |
Rust-Python FFI bindings (abi3-py311) |
For complete technical documentation including the mathematical foundation, algorithm specifications, and security model details, see DOCUMENTATION.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aegisq_pqc-1.1.0.tar.gz.
File metadata
- Download URL: aegisq_pqc-1.1.0.tar.gz
- Upload date:
- Size: 56.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3d92257f27dc83ae2ab2b7e1af53650b3ac9bc2b9466bd9315310c5e3ed31f7
|
|
| MD5 |
4dec536a77d4ef826ae0509c9f5b3bef
|
|
| BLAKE2b-256 |
e8ae19a2d57ead933f941ea42a236966ae6c16c1d525acddcdac015ef239325f
|
Provenance
The following attestation bundles were made for aegisq_pqc-1.1.0.tar.gz:
Publisher:
release.yml on AC-Santiago/AegisQ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aegisq_pqc-1.1.0.tar.gz -
Subject digest:
c3d92257f27dc83ae2ab2b7e1af53650b3ac9bc2b9466bd9315310c5e3ed31f7 - Sigstore transparency entry: 1409777199
- Sigstore integration time:
-
Permalink:
AC-Santiago/AegisQ@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/AC-Santiago
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aegisq_pqc-1.1.0-cp311-abi3-win_amd64.whl.
File metadata
- Download URL: aegisq_pqc-1.1.0-cp311-abi3-win_amd64.whl
- Upload date:
- Size: 175.4 kB
- Tags: CPython 3.11+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3633de9db691ab8bbf9c70ae5a6e6e932d31dce4165806c2ca34386e6c399b0e
|
|
| MD5 |
ad0a22655c1a9be15e469bc4d2cad6e1
|
|
| BLAKE2b-256 |
0da4b15f6566236dbebe6ddef5f44a38c743bac33520c845843c9c3211810076
|
Provenance
The following attestation bundles were made for aegisq_pqc-1.1.0-cp311-abi3-win_amd64.whl:
Publisher:
release.yml on AC-Santiago/AegisQ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aegisq_pqc-1.1.0-cp311-abi3-win_amd64.whl -
Subject digest:
3633de9db691ab8bbf9c70ae5a6e6e932d31dce4165806c2ca34386e6c399b0e - Sigstore transparency entry: 1409777211
- Sigstore integration time:
-
Permalink:
AC-Santiago/AegisQ@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/AC-Santiago
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 663.8 kB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c63dfed9c6b08f56542c0f6e0748d9a84a907d1231ed1b11eaf41704a79ff27c
|
|
| MD5 |
b8bc58d60d48b4642a3a45fa6ccecabd
|
|
| BLAKE2b-256 |
1373452d5afd407dd81287427407af0088f7b629b585ad44e08b83a7c98b9387
|
Provenance
The following attestation bundles were made for aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on AC-Santiago/AegisQ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
c63dfed9c6b08f56542c0f6e0748d9a84a907d1231ed1b11eaf41704a79ff27c - Sigstore transparency entry: 1409777218
- Sigstore integration time:
-
Permalink:
AC-Santiago/AegisQ@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/AC-Santiago
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 625.8 kB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c35a24e523021f4bdd5fe1ca924b577f3a1dd5382884e61c9a679f9bc736ae00
|
|
| MD5 |
04ec0327a298d1a03552ceb0c123e61e
|
|
| BLAKE2b-256 |
3dc6eca4416d0ee3da8aa2bf26054fab8d982251c94a3cba6883f2bc1ac4a87c
|
Provenance
The following attestation bundles were made for aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on AC-Santiago/AegisQ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
c35a24e523021f4bdd5fe1ca924b577f3a1dd5382884e61c9a679f9bc736ae00 - Sigstore transparency entry: 1409777203
- Sigstore integration time:
-
Permalink:
AC-Santiago/AegisQ@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/AC-Santiago
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aegisq_pqc-1.1.0-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: aegisq_pqc-1.1.0-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 290.9 kB
- Tags: CPython 3.11+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f9d273128e140740d2f114f209697cf1ea5c5a8b9e1f00635819ec40a126c6b
|
|
| MD5 |
65f122d09fa1904c92a679f2c61f4918
|
|
| BLAKE2b-256 |
0654f7e9c2557c3eb15ecd9b0e27222c2475b6992edf5885fad6bc67aa9497d6
|
Provenance
The following attestation bundles were made for aegisq_pqc-1.1.0-cp311-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on AC-Santiago/AegisQ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aegisq_pqc-1.1.0-cp311-abi3-macosx_11_0_arm64.whl -
Subject digest:
0f9d273128e140740d2f114f209697cf1ea5c5a8b9e1f00635819ec40a126c6b - Sigstore transparency entry: 1409777222
- Sigstore integration time:
-
Permalink:
AC-Santiago/AegisQ@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/AC-Santiago
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aegisq_pqc-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: aegisq_pqc-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 286.6 kB
- Tags: CPython 3.11+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dcda96a4ba61238f63ff1c83626472c184830a3e58b495bc042e86334328d21a
|
|
| MD5 |
d3b96fdbcb49400f736c31232cdddaa9
|
|
| BLAKE2b-256 |
3e97ad76de756ecbd48ecb165ccb49f2afd9fd91f4cca374c353e7b1c7e897e7
|
Provenance
The following attestation bundles were made for aegisq_pqc-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl:
Publisher:
release.yml on AC-Santiago/AegisQ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aegisq_pqc-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl -
Subject digest:
dcda96a4ba61238f63ff1c83626472c184830a3e58b495bc042e86334328d21a - Sigstore transparency entry: 1409777206
- Sigstore integration time:
-
Permalink:
AC-Santiago/AegisQ@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/AC-Santiago
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5df8a45d793f7c5f7779283e6d5bf1858ed16c1 -
Trigger Event:
push
-
Statement type: