Project renamed to aeg, preparing for PyPI release.

This commit is contained in:
Leo Vasanko
2025-12-23 18:25:03 +00:00
parent a644d27b56
commit 640e812908
23 changed files with 53 additions and 45 deletions
+3 -3
View File
@@ -3,9 +3,9 @@
*.egg-info
/dist
/build
/pyaegis/build
/pyaegis/_aegis*.so
/pyaegis/_aegis*.pyd
/src/aeg/build
/src/aeg/_aegis*.so
/src/aeg/_aegis*.pyd
__pycache__
!.gitignore
!.gitmodules
+7 -7
View File
@@ -1,6 +1,6 @@
# Building pyaegis
# Building aeg
This document contains instructions for developers who want to build pyaegis from source.
This document contains instructions for developers who want to build aeg from source.
## Prerequisites
@@ -11,7 +11,7 @@ This document contains instructions for developers who want to build pyaegis fro
### Installing Zig
pyaegis uses Zig to build the underlying libaegis C library. Install Zig from [ziglang.org/download](https://ziglang.org/download/) or using your package manager:
aeg uses Zig to build the underlying libaegis C library. Install Zig from [ziglang.org/download](https://ziglang.org/download/) or using your package manager:
- **macOS**: `brew install zig`
- **Linux**: See [Zig installation guide](https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager)
@@ -22,8 +22,8 @@ pyaegis uses Zig to build the underlying libaegis C library. Install Zig from [z
Clone the repository with submodules:
```fish
git clone --recursive https://github.com/LeoVasanko/pyaegis.git
cd pyaegis
git clone --recursive https://github.com/LeoVasanko/aeg.git
cd aeg
```
If you already cloned without `--recursive`, initialize submodules:
@@ -74,7 +74,7 @@ This creates files in the `dist/` directory.
## Code Generation
The Python modules and CFFI definitions are generated from C sources and templates. If you modify the core implementation in `pyaegis/aegis256x4.py` or update libaegis headers, regenerate all files:
The Python modules and CFFI definitions are generated from C sources and templates. If you modify the core implementation in `src/aeg/aegis256x4.py` or update libaegis headers, regenerate all files:
```fish
python tools/generate.py
@@ -100,7 +100,7 @@ If you cannot install Zig, you may manually compile in the libaegis folder (Zig,
## Project Structure
- `pyaegis/` - Python package source
- `src/aeg/` - Python package source
- `libaegis/` - C library source (submodule)
- `tests/` - Test suite
- `tools/` - Code generation scripts and `build_backend.py` used to build libaegis
+1 -1
View File
@@ -1,4 +1,4 @@
include pyaegis/aegis_cdef.h
include src/aeg/aegis_cdef.h
include setup.py
include tools/build_backend.py
include BUILD.md
+21 -14
View File
@@ -1,14 +1,16 @@
# pyaegis
# AEGIS Cipher Python Binding
[![PyPI version](https://badge.fury.io/py/pyaegis.svg)](https://badge.fury.io/py/pyaegis)
[![PyPI version](https://badge.fury.io/py/aeg.svg)](https://badge.fury.io/py/aeg)
Safe Python bindings for the AEGIS family of very fast authenticated encryption algorithms (via libaegis).
Safe Python bindings for the AEGIS family of very fast authenticated encryption algorithms via libaegis. The module runs without compilation required on Windows, Mac and Linux (has precompiled wheels). For other platforms compilation is performed at install time.
AEGIS enables extremely fast Encryption, MAC and CSPRNG - many times faster than AES, ChaCha20 or traditional random number generators. Authenticated Encryption with Additional Data is supported with the MAC derived from the cipher state at the end, making it different from other AEADs like AES-GCM and ChaCha20-Poly1305. The whole internal state thus depends on the prior data, and it is neither Encrypt-Then-Mac nor Mac-The-Encrypt scheme when both features are used together.
## Install
Using [uv](https://docs.astral.sh/uv/getting-started/installation/):
```fish
uv pip install git+https://github.com/LeoVasanko/pyaegis.git
uv pip install aeg
```
For development builds, see BUILD.md.
@@ -27,7 +29,7 @@ All submodules expose the same API; pick one for your key/nonce size and platfor
Normal authenticated encryption using the AEGIS-128X4 algorithm:
```python
from pyaegis import aegis128x4 as ciph
from aeg import aegis128x4 as ciph
key = ciph.random_key() # Secret key (stored securely)
nonce = ciph.random_nonce() # Public nonce (recreated for each message)
@@ -123,7 +125,7 @@ Constants (per module): NAME, KEYBYTES, NONCEBYTES, MACBYTES, MACBYTES_LONG, RAT
A cryptographically secure keyed hash is produced. The example uses all zeroes for the nonce to always produce the same hash for the same key:
```python
from pyaegis import aegis256x4 as ciph
from aeg import aegis256x4 as ciph
key, nonce = ciph.random_key(), bytes(ciph.NONCEBYTES)
mac = ciph.mac(key, nonce, b"message", maclen=32)
@@ -146,7 +148,7 @@ b.verify(mac) # Raises ValueError
Keeping the ciphertext, mac and ad separate. The ad represents a file header that needs to be tamper proofed.
```python
from pyaegis import aegis256x4 as ciph
from aeg import aegis256x4 as ciph
key, nonce = ciph.random_key(), ciph.random_nonce()
ct, mac = ciph.encrypt_detached(key, nonce, b"secret", ad=b"header")
@@ -162,7 +164,7 @@ ciph.wipe(pt)
Class-based interface for incremental updates is an alternative to the one-shot functions. Not to be confused with separately verified ciphertext frames (see the next example).
```python
from pyaegis import aegis256x4 as ciph
from aeg import aegis256x4 as ciph
key, nonce = ciph.random_key(), ciph.random_nonce()
enc = ciph.Encryptor(key, nonce, ad=b"header", maclen=16)
@@ -182,7 +184,7 @@ It is often practical to split larger messages into frames that can be individua
```python
# Encryption settings
from pyaegis import aegis128x4 as ciph
from aeg import aegis128x4 as ciph
key = b"sixteenbyte key!" # 16 bytes secret key for aegis128* algorithms
framebytes = 80 # In real applications 1 MiB or more is practical
maclen = ciph.MACBYTES # 16
@@ -202,7 +204,7 @@ with open("encrypted.bin", "wb") as f:
```python
# Decryption needs same values as encryption
from pyaegis import aegis128x4 as ciph
from aeg import aegis128x4 as ciph
key = b"sixteenbyte key!"
framebytes = 80
maclen = ciph.MACBYTES
@@ -223,7 +225,7 @@ with open("encrypted.bin", "rb") as f:
The stream generator is much faster than any traditional random number generator, cryptographically secure and seekable. Use `random_key()` for unpredictable output.
```python
from pyaegis import aegis128x4 as ciph
from aeg import aegis128x4 as ciph
key = b"SeedForReplay001" # A non-random deterministic seed (16 bytes)
nonce = bytearray(ciph.NONCEBYTES) # All-zeroes nonce
@@ -247,7 +249,7 @@ Foreign arrays can be used. This example fills a Numpy array with random integer
```python
import numpy as np
from pyaegis import aegis128x4 as ciph
from aeg import aegis128x4 as ciph
key, nonce = ciph.random_key(), ciph.random_nonce()
arr = np.empty(10, dtype=np.uint64) # Uninitialised integer array
@@ -258,7 +260,7 @@ print(arr)
In-place operations are supported when the input and the output point to the same location in memory. When using attached MAC tag, the input buffer needs to be sliced to correct length:
```python
from pyaegis import aegis256x4 as ciph
from aeg import aegis256x4 as ciph
key, nonce = ciph.random_key(), ciph.random_nonce()
buf = memoryview(bytearray(1000)) # memoryview[:len] is still in the same buffer (no copy)
buf[:7] = b"message"
@@ -279,7 +281,7 @@ Runtime CPU feature detection selects optimized code paths (AES-NI, ARM Crypto,
Benchmarks using the included benchmark module, run on Intel i7-14700, linux, single core (the software is not multithreaded). Note that the results are in megabits per second, not bytes. The CPU lacks AVX-512 that makes the X4 variants faster on AMD hardware.
```fish
$ uv run -m pyaegis.benchmark
$ uv run -m aeg.benchmark
AEGIS-256 103166.24 Mb/s
AEGIS-256X2 184225.50 Mb/s
AEGIS-256X4 194018.26 Mb/s
@@ -310,3 +312,8 @@ AEGIS-256 MAC 116776.62 Mb/s
AEGIS-256X2 MAC 224150.04 Mb/s
AEGIS-256X4 MAC 392088.05 Mb/s
```
## Alternatives
There is also a package named `pyaegis` on PyPI that is unrelated to this module, but that also binds to libaegis C library. Note that there are also a number of modules named `aegis` from different packages not at all related to the encryption algorithm.
+5 -4
View File
@@ -4,7 +4,7 @@ build-backend = "build_backend"
backend-path = ["tools"]
[project]
name = "pyaegis"
name = "aeg"
dynamic = ["version"]
description = "Python bindings for libaegis"
requires-python = ">=3.10"
@@ -20,7 +20,7 @@ dependencies = [
]
[project.urls]
Homepage = "https://github.com/LeoVasanko/pyaegis"
Homepage = "https://github.com/LeoVasanko/aeg"
[dependency-groups]
dev = [
@@ -31,9 +31,10 @@ dev = [
]
[tool.setuptools]
packages = ["pyaegis"]
package-dir = {"" = "src"}
packages = ["aeg"]
[tool.setuptools.package-data]
pyaegis = ["*.h", "*.so", "*.pyd"]
aeg = ["*.h", "*.so", "*.pyd"]
[tool.setuptools_scm]
+3 -3
View File
@@ -1,4 +1,4 @@
"""Setup script for pyaegis - builds CFFI extension with libaegis C library."""
"""Setup script for aeg - builds CFFI extension with libaegis C library."""
import sys
from pathlib import Path
@@ -20,7 +20,7 @@ if not libaegis_include.exists():
include_dirs = [str(libaegis_include)]
# Read the CDEF header
cdef_path = Path(__file__).parent / "pyaegis" / "aegis_cdef.h"
cdef_path = Path(__file__).parent / "src" / "aeg" / "aegis_cdef.h"
cdef_content = cdef_path.read_text(encoding="utf-8")
# Create CFFI builder
@@ -29,7 +29,7 @@ ffibuilder.cdef(cdef_content)
# Set the source
ffibuilder.set_source(
"pyaegis._aegis", # module name
"aeg._aegis", # module name
"""
#include "aegis.h"
#include "aegis128l.h"
+1 -1
View File
@@ -1,6 +1,6 @@
"""Loader for libaegis CFFI extension module."""
from pyaegis._aegis import ffi, lib
from aeg._aegis import ffi, lib
__all__ = ["ffi", "lib"]
@@ -12,7 +12,7 @@ Output format and throughput units mirror the Zig benchmark (Mb/s).
import secrets
import time
from pyaegis import aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4
from aeg import aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4
MSG_LEN = 16384000 # 16 000 KiB
ITERATIONS = 100
+1 -1
View File
@@ -1,4 +1,4 @@
"""Utility helpers for pyaegis.
"""Utility helpers for aeg.
Currently provides Python-side aligned allocation helpers that avoid relying
on libc/posix_memalign. Memory is owned by Python; C code only borrows it.
+1 -1
View File
@@ -3,7 +3,7 @@ from pathlib import Path
import pytest
from pyaegis import aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4
from aeg import aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4
from .util import random_split_bytes
+1 -1
View File
@@ -3,7 +3,7 @@ from pathlib import Path
import pytest
from pyaegis import aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4
from aeg import aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4
from .util import random_split_bytes
+1 -1
View File
@@ -6,7 +6,7 @@ after calling final(), preventing accidental misuse.
import pytest
from pyaegis import aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4
from aeg import aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4
# All AEGIS algorithm modules
ALL_ALGORITHMS = [aegis128l, aegis128x2, aegis128x4, aegis256, aegis256x2, aegis256x4]
+1 -1
View File
@@ -15,7 +15,7 @@ def _check_zig_available():
"\n" + "=" * 70 + "\n"
"ERROR: Zig compiler not found!\n"
"\n"
"Building pyaegis requires the Zig compiler to build the libaegis\n"
"Building aeg requires the Zig compiler to build the libaegis\n"
"static library. Please install Zig before building this package.\n"
"\n"
"Installation instructions:\n"
+1 -1
View File
@@ -277,7 +277,7 @@ def main() -> int:
root = pathlib.Path(__file__).parent.parent
libaegis_src_dir = root / "libaegis" / "src"
include_dir = libaegis_src_dir / "include"
pyaegis_dir = root / "pyaegis"
pyaegis_dir = root / "src" / "aeg"
if not include_dir.exists():
print(f"Include directory not found: {include_dir}", file=sys.stderr)
+5 -5
View File
@@ -112,8 +112,8 @@ def normalize_line_endings(repo_root: Path):
"""Normalize all text files to LF line endings."""
# Patterns for files to normalize
patterns = [
"pyaegis/**/*.py",
"pyaegis/**/*.h",
"src/aeg/**/*.py",
"src/aeg/**/*.h",
"tests/**/*.py",
"tools/**/*.py",
"*.py",
@@ -168,7 +168,7 @@ def main():
# Main header for the packaging process
print(f"\n{'=' * 70}")
print(
f"Packaging pyaegis-{version}"
f"Packaging aeg-{version}"
+ (" for release" if is_release else " (not release)")
)
print(f"Building wheels for Python versions: {', '.join(PYTHON_VERSIONS)}")
@@ -202,7 +202,7 @@ def main():
continue
# Find the wheel for this version
wheel_pattern = f"pyaegis-*-cp{py_version.replace('.', '')}-*.whl"
wheel_pattern = f"aeg-*-cp{py_version.replace('.', '')}-*.whl"
wheels = list(dist_dir.glob(wheel_pattern))
if not wheels:
print(f"✗ Could not find wheel for Python {py_version}", file=sys.stderr)
@@ -241,7 +241,7 @@ def main():
"--with",
str(wheel),
"-m",
"pyaegis.benchmark",
"aeg.benchmark",
]
if not run_command(bench_cmd, f"Running benchmark for Python {py_version}"):
print(f"✗ Benchmark failed for Python {py_version}", file=sys.stderr)