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+)

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

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

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.0.0.tar.gz (48.9 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.0.0-cp311-abi3-win_amd64.whl (173.2 kB view details)

Uploaded CPython 3.11+Windows x86-64

aegisq_pqc-1.0.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (667.8 kB view details)

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

aegisq_pqc-1.0.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (643.7 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ ARM64

aegisq_pqc-1.0.0-cp311-abi3-macosx_11_0_arm64.whl (291.7 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

aegisq_pqc-1.0.0-cp311-abi3-macosx_10_12_x86_64.whl (286.0 kB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

Details for the file aegisq_pqc-1.0.0.tar.gz.

File metadata

  • Download URL: aegisq_pqc-1.0.0.tar.gz
  • Upload date:
  • Size: 48.9 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.0.0.tar.gz
Algorithm Hash digest
SHA256 df8018ed4a4b616b79a98d529b0c54dd3dd53091da0cade9dd4ebcaa3933f806
MD5 fb6c2eb23c35f6583a4e0177b70a9666
BLAKE2b-256 94abfe0f810dd521482e999a35ccaa7505333c4fe1db1a01928d012b5dd30401

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisq_pqc-1.0.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.0.0-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: aegisq_pqc-1.0.0-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 173.2 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.0.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 60d332ebb0a059efdfc6d9f1341e20b42f81188c5f89b089add3cc84e9513591
MD5 44cbd3f35e631a216db6d8e305a4dd5b
BLAKE2b-256 9ad5c1ea2906cb5f9081ad9599d23f666b39f97b995d418e86dc5eb7d1f0c180

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisq_pqc-1.0.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.0.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for aegisq_pqc-1.0.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1e781ba86e111fd0dac0d1ab3ecf15915696d7fc79588a24f8aa7cdd49c774fb
MD5 76effdee6ed7516ca73e42459e9cf75b
BLAKE2b-256 7d2947a3339c4e85503ce3ffabff69d0b1df3e15ca5fe1e5487bdd9bd772ed02

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisq_pqc-1.0.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.0.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for aegisq_pqc-1.0.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 93d417341372f28ea1e950434b1d06aaf26f0ea84328e10aebaea66eb69fbc0d
MD5 fe77df6c54279d43c7eeeed9ea6b5e9f
BLAKE2b-256 883d835c71aa295481358b58c933b4c00cf646be72c4864966fb59e1f87cb2ab

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisq_pqc-1.0.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.0.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for aegisq_pqc-1.0.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 62eab422bb9071222d0037eb4c6105fda021ade34b0bddbc8cae79525834000e
MD5 5d6a0b37e7f479764a55d137ae27d2d3
BLAKE2b-256 a4359b33522ed65c01ae1cb39f5d64e60e1ed561421f968fa65629fa40be2f1b

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisq_pqc-1.0.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.0.0-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for aegisq_pqc-1.0.0-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 522649bce101cb6d2cedf118c650bc976c250472743fe658a0ed7c2f5be79400
MD5 0355138886f335fdc393073dbc3239d0
BLAKE2b-256 22152252231829fc082e56f1a8ac2dd9b2e182968003dab6f60b2dff898ffcf7

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisq_pqc-1.0.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