Skip to main content

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::ConstantTimeEq and 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 secrecyEphemeralSession class auto-generates keypairs and destroys secrets on close
  • Async supportencrypt_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_std compatibility. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aegisq_pqc-1.1.0.tar.gz (56.1 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

aegisq_pqc-1.1.0-cp311-abi3-win_amd64.whl (175.4 kB view details)

Uploaded CPython 3.11+Windows x86-64

aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (663.8 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (625.8 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ ARM64

aegisq_pqc-1.1.0-cp311-abi3-macosx_11_0_arm64.whl (290.9 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

aegisq_pqc-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl (286.6 kB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

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

Hashes for aegisq_pqc-1.1.0.tar.gz
Algorithm Hash digest
SHA256 c3d92257f27dc83ae2ab2b7e1af53650b3ac9bc2b9466bd9315310c5e3ed31f7
MD5 4dec536a77d4ef826ae0509c9f5b3bef
BLAKE2b-256 e8ae19a2d57ead933f941ea42a236966ae6c16c1d525acddcdac015ef239325f

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisq_pqc-1.1.0.tar.gz:

Publisher: release.yml on AC-Santiago/AegisQ

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for aegisq_pqc-1.1.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 3633de9db691ab8bbf9c70ae5a6e6e932d31dce4165806c2ca34386e6c399b0e
MD5 ad0a22655c1a9be15e469bc4d2cad6e1
BLAKE2b-256 0da4b15f6566236dbebe6ddef5f44a38c743bac33520c845843c9c3211810076

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c63dfed9c6b08f56542c0f6e0748d9a84a907d1231ed1b11eaf41704a79ff27c
MD5 b8bc58d60d48b4642a3a45fa6ccecabd
BLAKE2b-256 1373452d5afd407dd81287427407af0088f7b629b585ad44e08b83a7c98b9387

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for aegisq_pqc-1.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c35a24e523021f4bdd5fe1ca924b577f3a1dd5382884e61c9a679f9bc736ae00
MD5 04ec0327a298d1a03552ceb0c123e61e
BLAKE2b-256 3dc6eca4416d0ee3da8aa2bf26054fab8d982251c94a3cba6883f2bc1ac4a87c

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aegisq_pqc-1.1.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for aegisq_pqc-1.1.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0f9d273128e140740d2f114f209697cf1ea5c5a8b9e1f00635819ec40a126c6b
MD5 65f122d09fa1904c92a679f2c61f4918
BLAKE2b-256 0654f7e9c2557c3eb15ecd9b0e27222c2475b6992edf5885fad6bc67aa9497d6

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aegisq_pqc-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for aegisq_pqc-1.1.0-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 dcda96a4ba61238f63ff1c83626472c184830a3e58b495bc042e86334328d21a
MD5 d3b96fdbcb49400f736c31232cdddaa9
BLAKE2b-256 3e97ad76de756ecbd48ecb165ccb49f2afd9fd91f4cca374c353e7b1c7e897e7

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page