Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1bfeb2434 | ||
|
|
a26ce6a9fb | ||
|
|
7e6a5bf52a | ||
|
|
8018e68274 | ||
|
|
ccccfd7918 | ||
|
|
4de66b6bc6 | ||
|
|
66338ef416 | ||
|
|
509898ac73 | ||
|
|
67ec091bc5 | ||
|
|
4977a7e79d | ||
|
|
d7acf7a315 | ||
|
|
7f01de8327 | ||
|
|
9294fba86d | ||
|
|
348812e750 | ||
|
|
22dff32b22 | ||
|
|
178b689a35 | ||
|
|
bd8b183e32 | ||
|
|
daba717ebb | ||
|
|
5b74bcb683 | ||
|
|
d9a18f43d5 | ||
|
|
98ee4ab7b3 | ||
|
|
c6148806dd | ||
|
|
6e6bc49466 | ||
|
|
c2ac2e2790 | ||
|
|
c6e77cac66 | ||
|
|
df1acadb1f | ||
|
|
cb0f9956c3 | ||
|
|
a29405455a | ||
|
|
0d63844201 | ||
|
|
7682d5bc8b | ||
|
|
26b883ecbc | ||
|
|
87d9a07868 | ||
|
|
eed36e2463 | ||
|
|
46bc05f547 | ||
|
|
56d304a82e | ||
|
|
28ee0e1314 | ||
|
|
1f506806d4 | ||
|
|
17fba3c2f2 | ||
|
|
d04c593766 | ||
|
|
fce6324ae5 | ||
|
|
b35dc75513 | ||
|
|
1da3000a22 | ||
|
|
f983cbe4c5 | ||
|
|
f0b4373c0e | ||
|
|
0efc2595d8 | ||
|
|
a78f5c4ea3 | ||
|
|
fc1025f56d | ||
|
|
3d75cc7e55 | ||
|
|
5b49422cb7 | ||
|
|
cca78f4224 | ||
|
|
2e460b5796 | ||
|
|
407cedc7a9 | ||
|
|
b5b939cffe | ||
|
|
5c04940525 | ||
|
|
e644f1b2ca | ||
|
|
56b451ac0c | ||
|
|
93bdbc26a2 | ||
|
|
2612dc8187 | ||
|
|
302429b7a4 | ||
|
|
b83120187c | ||
|
|
e3508025f5 | ||
|
|
3767b34e2c | ||
|
|
0ae8752666 | ||
|
|
d51736f5ba | ||
|
|
df6b1b2832 | ||
|
|
c16e785203 | ||
|
|
2ffe7b6c0e | ||
|
|
618d9e0967 | ||
|
|
299586e6ee | ||
|
|
22299a1676 |
@@ -17,19 +17,6 @@ Or add to your project using [UV](https://docs.astral.sh/uv/getting-started/inst
|
|||||||
uv add aeg
|
uv add aeg
|
||||||
```
|
```
|
||||||
|
|
||||||
## Variants
|
|
||||||
|
|
||||||
All submodules expose the same API; pick one for your needs. The 256 bit variants offer maximal security and use larger key and nonce, while the 128 bit variants run slightly faster and use smaller key and nonce while still providing strong security. The MAC length does not depend on the variant. Note that the x2 and x4 variants are typically the fastest (depending on CPU) by utilizing SIMD multi-lane processing for the highest throughput.
|
|
||||||
|
|
||||||
| Variant | Key/Nonce Bytes | Notes |
|
|
||||||
|----------------|----------------:|-------------------------|
|
|
||||||
| **aegis128l** | 16 | |
|
|
||||||
| **aegis128x2** | 16 | Fastest on Intel Core |
|
|
||||||
| **aegis128x4** | 16 | Fastest on AMD and Xeon |
|
|
||||||
| **aegis256** | 32 | |
|
|
||||||
| **aegis256x2** | 32 | Fast on Intel Core |
|
|
||||||
| **aegis256x4** | 32 | Fast on AMD and Xeon |
|
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
Normal authenticated encryption using the AEGIS-128X4 algorithm:
|
Normal authenticated encryption using the AEGIS-128X4 algorithm:
|
||||||
@@ -46,6 +33,27 @@ pt = ciph.decrypt(key, nonce, ct) # Raises ValueError if anything was tampered
|
|||||||
assert pt == msg
|
assert pt == msg
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Variants
|
||||||
|
|
||||||
|
All submodules expose the same API; pick one for your needs. The 256 bit variants offer maximal security and use larger key and nonce, while the 128 bit variants run slightly faster and use smaller key and nonce while still providing strong security. The MAC length does not depend on the variant. Note that the x2 and x4 variants are typically the fastest (depending on CPU) by utilizing SIMD multi-lane processing for the highest throughput.
|
||||||
|
|
||||||
|
| Variant | Key/Nonce Bytes | Notes |
|
||||||
|
|----------------|----------------:|-------------------------|
|
||||||
|
| **aegis128l** | 16 | |
|
||||||
|
| **aegis128x2** | 16 | Fastest on Intel Core |
|
||||||
|
| **aegis128x4** | 16 | Fastest on AMD and Xeon |
|
||||||
|
| **aegis256** | 32 | |
|
||||||
|
| **aegis256x2** | 32 | Fast on Intel Core |
|
||||||
|
| **aegis256x4** | 32 | Fast on AMD and Xeon |
|
||||||
|
|
||||||
|
Instead of importing the submodules, you can obtain one by its name string:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import aeg
|
||||||
|
|
||||||
|
ciph = aeg.cipher("AEGIS-128X2") # Also accepts "aegis128x2" and other forms
|
||||||
|
```
|
||||||
|
|
||||||
## API overview
|
## API overview
|
||||||
|
|
||||||
Common parameters and returns (applies to all items below):
|
Common parameters and returns (applies to all items below):
|
||||||
|
|||||||
+1
-1
Submodule libaegis updated: 4a234009c9...7b667dd883
+2
-1
@@ -10,6 +10,7 @@ description = "AEGIS encryption easy to use Python binding. Wheels for major pla
|
|||||||
readme = {file = "README.md", content-type = "text/markdown"}
|
readme = {file = "README.md", content-type = "text/markdown"}
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
"Topic :: Security :: Cryptography",
|
"Topic :: Security :: Cryptography",
|
||||||
@@ -36,6 +37,6 @@ package-dir = {"" = "src"}
|
|||||||
packages = ["aeg"]
|
packages = ["aeg"]
|
||||||
|
|
||||||
[tool.setuptools.package-data]
|
[tool.setuptools.package-data]
|
||||||
aeg = ["*.h", "*.so", "*.pyd"]
|
aeg = ["*.h"]
|
||||||
|
|
||||||
[tool.setuptools_scm]
|
[tool.setuptools_scm]
|
||||||
|
|||||||
@@ -1,35 +1,24 @@
|
|||||||
"""Setup script for aeg - builds CFFI extension with libaegis C library."""
|
"""Setup script for aeg - builds CFFI extension with libaegis C library."""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import sysconfig
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from cffi import FFI
|
from cffi import FFI
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
# Locate the static library (built by build_backend.py before this runs)
|
libaegis_static = Path("libaegis/zig-out/lib") / (
|
||||||
lib_name = "aegis.lib" if sys.platform == "win32" else "libaegis.a"
|
"aegis.lib" if sys.platform == "win32" else "libaegis.a"
|
||||||
libaegis_static = Path("libaegis/zig-out/lib") / lib_name
|
)
|
||||||
if not libaegis_static.exists():
|
|
||||||
raise RuntimeError(f"libaegis static library not found at {libaegis_static}")
|
|
||||||
libaegis_static = str(libaegis_static.resolve())
|
|
||||||
|
|
||||||
# Include directory for headers
|
|
||||||
libaegis_include = Path("libaegis/src/include")
|
|
||||||
if not libaegis_include.exists():
|
|
||||||
raise RuntimeError(f"libaegis include directory not found at {libaegis_include}")
|
|
||||||
include_dirs = [str(libaegis_include)]
|
|
||||||
|
|
||||||
# Read the CDEF header
|
|
||||||
cdef_path = Path(__file__).parent / "src" / "aeg" / "aegis_cdef.h"
|
|
||||||
cdef_content = cdef_path.read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
# Create CFFI builder
|
|
||||||
ffibuilder = FFI()
|
ffibuilder = FFI()
|
||||||
ffibuilder.cdef(cdef_content)
|
ffibuilder.cdef((Path(__file__).parent / "src/aeg/aegis_cdef.h").read_text())
|
||||||
|
|
||||||
|
# Free-threaded Python does not support Limited API (abi3)
|
||||||
|
is_free_threaded = sysconfig.get_config_var("Py_GIL_DISABLED")
|
||||||
|
|
||||||
# Set the source
|
|
||||||
ffibuilder.set_source(
|
ffibuilder.set_source(
|
||||||
"aeg._aegis", # module name
|
"aeg._aegis",
|
||||||
"""
|
"""
|
||||||
#include "aegis.h"
|
#include "aegis.h"
|
||||||
#include "aegis128l.h"
|
#include "aegis128l.h"
|
||||||
@@ -39,11 +28,15 @@ ffibuilder.set_source(
|
|||||||
#include "aegis256x2.h"
|
#include "aegis256x2.h"
|
||||||
#include "aegis256x4.h"
|
#include "aegis256x4.h"
|
||||||
""",
|
""",
|
||||||
include_dirs=include_dirs,
|
include_dirs=["libaegis/src/include"],
|
||||||
extra_objects=[libaegis_static],
|
extra_objects=[str(libaegis_static.resolve())],
|
||||||
|
py_limited_api=not is_free_threaded,
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
setup(
|
setup(
|
||||||
cffi_modules=["setup.py:ffibuilder"],
|
cffi_modules=["setup.py:ffibuilder"],
|
||||||
|
options=(
|
||||||
|
{"bdist_wheel": {"py_limited_api": "cp310"}} if not is_free_threaded else {}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import importlib
|
||||||
|
|
||||||
|
from ._ciphers import CIPHERS, CipherName
|
||||||
|
from ._typing import Cipher
|
||||||
|
|
||||||
|
__all__ = ["cipher", "CIPHERS", "Cipher", "CipherName"]
|
||||||
|
|
||||||
|
|
||||||
|
def cipher(alg: CipherName) -> Cipher:
|
||||||
|
"""Acquire a cipher module by name."""
|
||||||
|
name = alg.lower().replace("-", "")
|
||||||
|
if name == "aegis128":
|
||||||
|
name = "aegis128l" # AEGIS-128 is dead, the user meant AEGIS-128L
|
||||||
|
if not name.startswith("aegis"):
|
||||||
|
name = "aegis" + name
|
||||||
|
if name in CIPHERS.values():
|
||||||
|
return importlib.import_module(f".{name}", __package__) # type: ignore[return-value]
|
||||||
|
raise ValueError(f"Unknown algorithm {alg!r}. Valid options: {', '.join(CIPHERS)}")
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# This file is generated by tools/generate.py. Do not edit.
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
|
CipherName = Literal[
|
||||||
|
"AEGIS-128L",
|
||||||
|
"AEGIS-128X2",
|
||||||
|
"AEGIS-128X4",
|
||||||
|
"AEGIS-256",
|
||||||
|
"AEGIS-256X2",
|
||||||
|
"AEGIS-256X4",
|
||||||
|
]
|
||||||
|
|
||||||
|
CIPHERS: dict[CipherName, str] = {
|
||||||
|
"AEGIS-128L": "aegis128l",
|
||||||
|
"AEGIS-128X2": "aegis128x2",
|
||||||
|
"AEGIS-128X4": "aegis128x4",
|
||||||
|
"AEGIS-256": "aegis256",
|
||||||
|
"AEGIS-256X2": "aegis256x2",
|
||||||
|
"AEGIS-256X4": "aegis256x4",
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
from typing import TYPE_CHECKING, Protocol
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .util import Buffer
|
||||||
|
|
||||||
|
__all__ = ["Cipher"]
|
||||||
|
|
||||||
|
|
||||||
|
class _Mac(Protocol):
|
||||||
|
def reset(self) -> None: ...
|
||||||
|
def clone(self) -> "_Mac": ...
|
||||||
|
def update(self, data: "Buffer") -> None: ...
|
||||||
|
def final(self, into: "Buffer | None" = None) -> bytearray | memoryview: ...
|
||||||
|
def digest(self) -> bytes: ...
|
||||||
|
def hexdigest(self) -> str: ...
|
||||||
|
def verify(self, mac: "Buffer") -> None: ...
|
||||||
|
|
||||||
|
|
||||||
|
class _Encryptor(Protocol):
|
||||||
|
def update(
|
||||||
|
self, message: "Buffer", into: "Buffer | None" = None
|
||||||
|
) -> bytearray | memoryview: ...
|
||||||
|
def final(self, into: "Buffer | None" = None) -> bytearray | memoryview: ...
|
||||||
|
|
||||||
|
|
||||||
|
class _Decryptor(Protocol):
|
||||||
|
def update(
|
||||||
|
self, ct: "Buffer", into: "Buffer | None" = None
|
||||||
|
) -> bytearray | memoryview: ...
|
||||||
|
def final(self, mac: "Buffer") -> None: ...
|
||||||
|
|
||||||
|
|
||||||
|
class Cipher(Protocol):
|
||||||
|
NAME: str
|
||||||
|
KEYBYTES: int
|
||||||
|
NONCEBYTES: int
|
||||||
|
MACBYTES: int
|
||||||
|
MACBYTES_LONG: int
|
||||||
|
ALIGNMENT: int
|
||||||
|
RATE: int
|
||||||
|
|
||||||
|
Mac: type[_Mac]
|
||||||
|
Encryptor: type[_Encryptor]
|
||||||
|
Decryptor: type[_Decryptor]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def random_key() -> bytearray: ...
|
||||||
|
@staticmethod
|
||||||
|
def random_nonce() -> bytearray: ...
|
||||||
|
@staticmethod
|
||||||
|
def encrypt_detached(
|
||||||
|
key: "Buffer",
|
||||||
|
nonce: "Buffer",
|
||||||
|
message: "Buffer",
|
||||||
|
ad: "Buffer | None" = None,
|
||||||
|
*,
|
||||||
|
maclen: int = ...,
|
||||||
|
ct_into: "Buffer | None" = None,
|
||||||
|
mac_into: "Buffer | None" = None,
|
||||||
|
) -> tuple[bytearray | memoryview, bytearray | memoryview]: ...
|
||||||
|
@staticmethod
|
||||||
|
def decrypt_detached(
|
||||||
|
key: "Buffer",
|
||||||
|
nonce: "Buffer",
|
||||||
|
ct: "Buffer",
|
||||||
|
mac: "Buffer",
|
||||||
|
ad: "Buffer | None" = None,
|
||||||
|
*,
|
||||||
|
into: "Buffer | None" = None,
|
||||||
|
) -> bytearray | memoryview: ...
|
||||||
|
@staticmethod
|
||||||
|
def encrypt(
|
||||||
|
key: "Buffer",
|
||||||
|
nonce: "Buffer",
|
||||||
|
message: "Buffer",
|
||||||
|
ad: "Buffer | None" = None,
|
||||||
|
*,
|
||||||
|
maclen: int = ...,
|
||||||
|
into: "Buffer | None" = None,
|
||||||
|
) -> bytearray | memoryview: ...
|
||||||
|
@staticmethod
|
||||||
|
def decrypt(
|
||||||
|
key: "Buffer",
|
||||||
|
nonce: "Buffer",
|
||||||
|
ct: "Buffer",
|
||||||
|
ad: "Buffer | None" = None,
|
||||||
|
*,
|
||||||
|
maclen: int = ...,
|
||||||
|
into: "Buffer | None" = None,
|
||||||
|
) -> bytearray | memoryview: ...
|
||||||
|
@staticmethod
|
||||||
|
def stream(
|
||||||
|
key: "Buffer",
|
||||||
|
nonce: "Buffer | None",
|
||||||
|
length: int | None = None,
|
||||||
|
*,
|
||||||
|
into: "Buffer | None" = None,
|
||||||
|
) -> "bytearray | Buffer": ...
|
||||||
|
@staticmethod
|
||||||
|
def encrypt_unauthenticated(
|
||||||
|
key: "Buffer",
|
||||||
|
nonce: "Buffer",
|
||||||
|
message: "Buffer",
|
||||||
|
*,
|
||||||
|
into: "Buffer | None" = None,
|
||||||
|
) -> bytearray | memoryview: ...
|
||||||
|
@staticmethod
|
||||||
|
def decrypt_unauthenticated(
|
||||||
|
key: "Buffer",
|
||||||
|
nonce: "Buffer",
|
||||||
|
ct: "Buffer",
|
||||||
|
*,
|
||||||
|
into: "Buffer | None" = None,
|
||||||
|
) -> bytearray | memoryview: ...
|
||||||
|
@staticmethod
|
||||||
|
def mac(
|
||||||
|
key: "Buffer",
|
||||||
|
nonce: "Buffer",
|
||||||
|
data: "Buffer",
|
||||||
|
maclen: int = ...,
|
||||||
|
into: "Buffer | None" = None,
|
||||||
|
) -> bytearray | memoryview: ...
|
||||||
|
@staticmethod
|
||||||
|
def nonce_increment(nonce: "Buffer") -> None: ...
|
||||||
|
@staticmethod
|
||||||
|
def wipe(buffer: "Buffer") -> None: ...
|
||||||
+6
-29
@@ -708,24 +708,17 @@ class Encryptor:
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"into length must be >= expected output size for this update"
|
"into length must be >= expected output size for this update"
|
||||||
)
|
)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis128l_state_encrypt_update(
|
rc = _lib.aegis128l_state_encrypt_update(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(message),
|
_ptr(message),
|
||||||
message.nbytes,
|
message.nbytes,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"state encrypt update failed: {err_name}")
|
||||||
f"state encrypt update failed: {err_name} written {written[0]}"
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
)
|
|
||||||
w = int(written[0])
|
|
||||||
assert w == expected_out
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
||||||
"""Finalize encryption and return the authentication tag.
|
"""Finalize encryption and return the authentication tag.
|
||||||
@@ -746,24 +739,17 @@ class Encryptor:
|
|||||||
if into is not None:
|
if into is not None:
|
||||||
into = memoryview(into)
|
into = memoryview(into)
|
||||||
out = into if into is not None else bytearray(maclen)
|
out = into if into is not None else bytearray(maclen)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis128l_state_encrypt_final(
|
rc = _lib.aegis128l_state_encrypt_final(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out),
|
ffi.from_buffer(out),
|
||||||
memoryview(out).nbytes,
|
|
||||||
written,
|
|
||||||
maclen,
|
maclen,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
||||||
w = int(written[0])
|
|
||||||
if into is None:
|
|
||||||
# Only the tag bytes are returned when we allocate the buffer
|
|
||||||
assert w == maclen
|
|
||||||
self._state = None
|
self._state = None
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
return out if into is None else memoryview(out)[:maclen] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Decryptor:
|
class Decryptor:
|
||||||
@@ -837,12 +823,9 @@ class Decryptor:
|
|||||||
out_mv = memoryview(out)
|
out_mv = memoryview(out)
|
||||||
if out_mv.nbytes < expected_out:
|
if out_mv.nbytes < expected_out:
|
||||||
raise TypeError("into length must be >= required capacity for this update")
|
raise TypeError("into length must be >= required capacity for this update")
|
||||||
written = ffi.new("size_t *")
|
rc = _lib.aegis128l_state_decrypt_update(
|
||||||
rc = _lib.aegis128l_state_decrypt_detached_update(
|
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(ct),
|
_ptr(ct),
|
||||||
ct.nbytes,
|
ct.nbytes,
|
||||||
)
|
)
|
||||||
@@ -850,11 +833,7 @@ class Decryptor:
|
|||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
||||||
w = int(written[0])
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
assert w == expected_out, (
|
|
||||||
f"got {w}, expected {expected_out}, ct.nbytes={ct.nbytes}"
|
|
||||||
)
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, mac: Buffer) -> None:
|
def final(self, mac: Buffer) -> None:
|
||||||
"""Finalize decryption by verifying the MAC tag.
|
"""Finalize decryption by verifying the MAC tag.
|
||||||
@@ -873,9 +852,7 @@ class Decryptor:
|
|||||||
mac = memoryview(mac)
|
mac = memoryview(mac)
|
||||||
if mac.nbytes != maclen:
|
if mac.nbytes != maclen:
|
||||||
raise TypeError(f"mac length must be {maclen}")
|
raise TypeError(f"mac length must be {maclen}")
|
||||||
rc = _lib.aegis128l_state_decrypt_detached_final(
|
rc = _lib.aegis128l_state_decrypt_final(self._state.ptr, _ptr(mac), maclen)
|
||||||
self._state.ptr, ffi.NULL, 0, ffi.NULL, _ptr(mac), maclen
|
|
||||||
)
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise ValueError("authentication failed")
|
raise ValueError("authentication failed")
|
||||||
self._state = None
|
self._state = None
|
||||||
|
|||||||
+6
-29
@@ -708,24 +708,17 @@ class Encryptor:
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"into length must be >= expected output size for this update"
|
"into length must be >= expected output size for this update"
|
||||||
)
|
)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis128x2_state_encrypt_update(
|
rc = _lib.aegis128x2_state_encrypt_update(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(message),
|
_ptr(message),
|
||||||
message.nbytes,
|
message.nbytes,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"state encrypt update failed: {err_name}")
|
||||||
f"state encrypt update failed: {err_name} written {written[0]}"
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
)
|
|
||||||
w = int(written[0])
|
|
||||||
assert w == expected_out
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
||||||
"""Finalize encryption and return the authentication tag.
|
"""Finalize encryption and return the authentication tag.
|
||||||
@@ -746,24 +739,17 @@ class Encryptor:
|
|||||||
if into is not None:
|
if into is not None:
|
||||||
into = memoryview(into)
|
into = memoryview(into)
|
||||||
out = into if into is not None else bytearray(maclen)
|
out = into if into is not None else bytearray(maclen)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis128x2_state_encrypt_final(
|
rc = _lib.aegis128x2_state_encrypt_final(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out),
|
ffi.from_buffer(out),
|
||||||
memoryview(out).nbytes,
|
|
||||||
written,
|
|
||||||
maclen,
|
maclen,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
||||||
w = int(written[0])
|
|
||||||
if into is None:
|
|
||||||
# Only the tag bytes are returned when we allocate the buffer
|
|
||||||
assert w == maclen
|
|
||||||
self._state = None
|
self._state = None
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
return out if into is None else memoryview(out)[:maclen] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Decryptor:
|
class Decryptor:
|
||||||
@@ -837,12 +823,9 @@ class Decryptor:
|
|||||||
out_mv = memoryview(out)
|
out_mv = memoryview(out)
|
||||||
if out_mv.nbytes < expected_out:
|
if out_mv.nbytes < expected_out:
|
||||||
raise TypeError("into length must be >= required capacity for this update")
|
raise TypeError("into length must be >= required capacity for this update")
|
||||||
written = ffi.new("size_t *")
|
rc = _lib.aegis128x2_state_decrypt_update(
|
||||||
rc = _lib.aegis128x2_state_decrypt_detached_update(
|
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(ct),
|
_ptr(ct),
|
||||||
ct.nbytes,
|
ct.nbytes,
|
||||||
)
|
)
|
||||||
@@ -850,11 +833,7 @@ class Decryptor:
|
|||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
||||||
w = int(written[0])
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
assert w == expected_out, (
|
|
||||||
f"got {w}, expected {expected_out}, ct.nbytes={ct.nbytes}"
|
|
||||||
)
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, mac: Buffer) -> None:
|
def final(self, mac: Buffer) -> None:
|
||||||
"""Finalize decryption by verifying the MAC tag.
|
"""Finalize decryption by verifying the MAC tag.
|
||||||
@@ -873,9 +852,7 @@ class Decryptor:
|
|||||||
mac = memoryview(mac)
|
mac = memoryview(mac)
|
||||||
if mac.nbytes != maclen:
|
if mac.nbytes != maclen:
|
||||||
raise TypeError(f"mac length must be {maclen}")
|
raise TypeError(f"mac length must be {maclen}")
|
||||||
rc = _lib.aegis128x2_state_decrypt_detached_final(
|
rc = _lib.aegis128x2_state_decrypt_final(self._state.ptr, _ptr(mac), maclen)
|
||||||
self._state.ptr, ffi.NULL, 0, ffi.NULL, _ptr(mac), maclen
|
|
||||||
)
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise ValueError("authentication failed")
|
raise ValueError("authentication failed")
|
||||||
self._state = None
|
self._state = None
|
||||||
|
|||||||
+6
-29
@@ -708,24 +708,17 @@ class Encryptor:
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"into length must be >= expected output size for this update"
|
"into length must be >= expected output size for this update"
|
||||||
)
|
)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis128x4_state_encrypt_update(
|
rc = _lib.aegis128x4_state_encrypt_update(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(message),
|
_ptr(message),
|
||||||
message.nbytes,
|
message.nbytes,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"state encrypt update failed: {err_name}")
|
||||||
f"state encrypt update failed: {err_name} written {written[0]}"
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
)
|
|
||||||
w = int(written[0])
|
|
||||||
assert w == expected_out
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
||||||
"""Finalize encryption and return the authentication tag.
|
"""Finalize encryption and return the authentication tag.
|
||||||
@@ -746,24 +739,17 @@ class Encryptor:
|
|||||||
if into is not None:
|
if into is not None:
|
||||||
into = memoryview(into)
|
into = memoryview(into)
|
||||||
out = into if into is not None else bytearray(maclen)
|
out = into if into is not None else bytearray(maclen)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis128x4_state_encrypt_final(
|
rc = _lib.aegis128x4_state_encrypt_final(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out),
|
ffi.from_buffer(out),
|
||||||
memoryview(out).nbytes,
|
|
||||||
written,
|
|
||||||
maclen,
|
maclen,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
||||||
w = int(written[0])
|
|
||||||
if into is None:
|
|
||||||
# Only the tag bytes are returned when we allocate the buffer
|
|
||||||
assert w == maclen
|
|
||||||
self._state = None
|
self._state = None
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
return out if into is None else memoryview(out)[:maclen] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Decryptor:
|
class Decryptor:
|
||||||
@@ -837,12 +823,9 @@ class Decryptor:
|
|||||||
out_mv = memoryview(out)
|
out_mv = memoryview(out)
|
||||||
if out_mv.nbytes < expected_out:
|
if out_mv.nbytes < expected_out:
|
||||||
raise TypeError("into length must be >= required capacity for this update")
|
raise TypeError("into length must be >= required capacity for this update")
|
||||||
written = ffi.new("size_t *")
|
rc = _lib.aegis128x4_state_decrypt_update(
|
||||||
rc = _lib.aegis128x4_state_decrypt_detached_update(
|
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(ct),
|
_ptr(ct),
|
||||||
ct.nbytes,
|
ct.nbytes,
|
||||||
)
|
)
|
||||||
@@ -850,11 +833,7 @@ class Decryptor:
|
|||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
||||||
w = int(written[0])
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
assert w == expected_out, (
|
|
||||||
f"got {w}, expected {expected_out}, ct.nbytes={ct.nbytes}"
|
|
||||||
)
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, mac: Buffer) -> None:
|
def final(self, mac: Buffer) -> None:
|
||||||
"""Finalize decryption by verifying the MAC tag.
|
"""Finalize decryption by verifying the MAC tag.
|
||||||
@@ -873,9 +852,7 @@ class Decryptor:
|
|||||||
mac = memoryview(mac)
|
mac = memoryview(mac)
|
||||||
if mac.nbytes != maclen:
|
if mac.nbytes != maclen:
|
||||||
raise TypeError(f"mac length must be {maclen}")
|
raise TypeError(f"mac length must be {maclen}")
|
||||||
rc = _lib.aegis128x4_state_decrypt_detached_final(
|
rc = _lib.aegis128x4_state_decrypt_final(self._state.ptr, _ptr(mac), maclen)
|
||||||
self._state.ptr, ffi.NULL, 0, ffi.NULL, _ptr(mac), maclen
|
|
||||||
)
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise ValueError("authentication failed")
|
raise ValueError("authentication failed")
|
||||||
self._state = None
|
self._state = None
|
||||||
|
|||||||
+6
-29
@@ -708,24 +708,17 @@ class Encryptor:
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"into length must be >= expected output size for this update"
|
"into length must be >= expected output size for this update"
|
||||||
)
|
)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis256_state_encrypt_update(
|
rc = _lib.aegis256_state_encrypt_update(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(message),
|
_ptr(message),
|
||||||
message.nbytes,
|
message.nbytes,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"state encrypt update failed: {err_name}")
|
||||||
f"state encrypt update failed: {err_name} written {written[0]}"
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
)
|
|
||||||
w = int(written[0])
|
|
||||||
assert w == expected_out
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
||||||
"""Finalize encryption and return the authentication tag.
|
"""Finalize encryption and return the authentication tag.
|
||||||
@@ -746,24 +739,17 @@ class Encryptor:
|
|||||||
if into is not None:
|
if into is not None:
|
||||||
into = memoryview(into)
|
into = memoryview(into)
|
||||||
out = into if into is not None else bytearray(maclen)
|
out = into if into is not None else bytearray(maclen)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis256_state_encrypt_final(
|
rc = _lib.aegis256_state_encrypt_final(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out),
|
ffi.from_buffer(out),
|
||||||
memoryview(out).nbytes,
|
|
||||||
written,
|
|
||||||
maclen,
|
maclen,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
||||||
w = int(written[0])
|
|
||||||
if into is None:
|
|
||||||
# Only the tag bytes are returned when we allocate the buffer
|
|
||||||
assert w == maclen
|
|
||||||
self._state = None
|
self._state = None
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
return out if into is None else memoryview(out)[:maclen] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Decryptor:
|
class Decryptor:
|
||||||
@@ -837,12 +823,9 @@ class Decryptor:
|
|||||||
out_mv = memoryview(out)
|
out_mv = memoryview(out)
|
||||||
if out_mv.nbytes < expected_out:
|
if out_mv.nbytes < expected_out:
|
||||||
raise TypeError("into length must be >= required capacity for this update")
|
raise TypeError("into length must be >= required capacity for this update")
|
||||||
written = ffi.new("size_t *")
|
rc = _lib.aegis256_state_decrypt_update(
|
||||||
rc = _lib.aegis256_state_decrypt_detached_update(
|
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(ct),
|
_ptr(ct),
|
||||||
ct.nbytes,
|
ct.nbytes,
|
||||||
)
|
)
|
||||||
@@ -850,11 +833,7 @@ class Decryptor:
|
|||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
||||||
w = int(written[0])
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
assert w == expected_out, (
|
|
||||||
f"got {w}, expected {expected_out}, ct.nbytes={ct.nbytes}"
|
|
||||||
)
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, mac: Buffer) -> None:
|
def final(self, mac: Buffer) -> None:
|
||||||
"""Finalize decryption by verifying the MAC tag.
|
"""Finalize decryption by verifying the MAC tag.
|
||||||
@@ -873,9 +852,7 @@ class Decryptor:
|
|||||||
mac = memoryview(mac)
|
mac = memoryview(mac)
|
||||||
if mac.nbytes != maclen:
|
if mac.nbytes != maclen:
|
||||||
raise TypeError(f"mac length must be {maclen}")
|
raise TypeError(f"mac length must be {maclen}")
|
||||||
rc = _lib.aegis256_state_decrypt_detached_final(
|
rc = _lib.aegis256_state_decrypt_final(self._state.ptr, _ptr(mac), maclen)
|
||||||
self._state.ptr, ffi.NULL, 0, ffi.NULL, _ptr(mac), maclen
|
|
||||||
)
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise ValueError("authentication failed")
|
raise ValueError("authentication failed")
|
||||||
self._state = None
|
self._state = None
|
||||||
|
|||||||
+6
-29
@@ -708,24 +708,17 @@ class Encryptor:
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"into length must be >= expected output size for this update"
|
"into length must be >= expected output size for this update"
|
||||||
)
|
)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis256x2_state_encrypt_update(
|
rc = _lib.aegis256x2_state_encrypt_update(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(message),
|
_ptr(message),
|
||||||
message.nbytes,
|
message.nbytes,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"state encrypt update failed: {err_name}")
|
||||||
f"state encrypt update failed: {err_name} written {written[0]}"
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
)
|
|
||||||
w = int(written[0])
|
|
||||||
assert w == expected_out
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
||||||
"""Finalize encryption and return the authentication tag.
|
"""Finalize encryption and return the authentication tag.
|
||||||
@@ -746,24 +739,17 @@ class Encryptor:
|
|||||||
if into is not None:
|
if into is not None:
|
||||||
into = memoryview(into)
|
into = memoryview(into)
|
||||||
out = into if into is not None else bytearray(maclen)
|
out = into if into is not None else bytearray(maclen)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis256x2_state_encrypt_final(
|
rc = _lib.aegis256x2_state_encrypt_final(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out),
|
ffi.from_buffer(out),
|
||||||
memoryview(out).nbytes,
|
|
||||||
written,
|
|
||||||
maclen,
|
maclen,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
||||||
w = int(written[0])
|
|
||||||
if into is None:
|
|
||||||
# Only the tag bytes are returned when we allocate the buffer
|
|
||||||
assert w == maclen
|
|
||||||
self._state = None
|
self._state = None
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
return out if into is None else memoryview(out)[:maclen] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Decryptor:
|
class Decryptor:
|
||||||
@@ -837,12 +823,9 @@ class Decryptor:
|
|||||||
out_mv = memoryview(out)
|
out_mv = memoryview(out)
|
||||||
if out_mv.nbytes < expected_out:
|
if out_mv.nbytes < expected_out:
|
||||||
raise TypeError("into length must be >= required capacity for this update")
|
raise TypeError("into length must be >= required capacity for this update")
|
||||||
written = ffi.new("size_t *")
|
rc = _lib.aegis256x2_state_decrypt_update(
|
||||||
rc = _lib.aegis256x2_state_decrypt_detached_update(
|
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(ct),
|
_ptr(ct),
|
||||||
ct.nbytes,
|
ct.nbytes,
|
||||||
)
|
)
|
||||||
@@ -850,11 +833,7 @@ class Decryptor:
|
|||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
||||||
w = int(written[0])
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
assert w == expected_out, (
|
|
||||||
f"got {w}, expected {expected_out}, ct.nbytes={ct.nbytes}"
|
|
||||||
)
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, mac: Buffer) -> None:
|
def final(self, mac: Buffer) -> None:
|
||||||
"""Finalize decryption by verifying the MAC tag.
|
"""Finalize decryption by verifying the MAC tag.
|
||||||
@@ -873,9 +852,7 @@ class Decryptor:
|
|||||||
mac = memoryview(mac)
|
mac = memoryview(mac)
|
||||||
if mac.nbytes != maclen:
|
if mac.nbytes != maclen:
|
||||||
raise TypeError(f"mac length must be {maclen}")
|
raise TypeError(f"mac length must be {maclen}")
|
||||||
rc = _lib.aegis256x2_state_decrypt_detached_final(
|
rc = _lib.aegis256x2_state_decrypt_final(self._state.ptr, _ptr(mac), maclen)
|
||||||
self._state.ptr, ffi.NULL, 0, ffi.NULL, _ptr(mac), maclen
|
|
||||||
)
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise ValueError("authentication failed")
|
raise ValueError("authentication failed")
|
||||||
self._state = None
|
self._state = None
|
||||||
|
|||||||
+6
-29
@@ -708,24 +708,17 @@ class Encryptor:
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"into length must be >= expected output size for this update"
|
"into length must be >= expected output size for this update"
|
||||||
)
|
)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis256x4_state_encrypt_update(
|
rc = _lib.aegis256x4_state_encrypt_update(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(message),
|
_ptr(message),
|
||||||
message.nbytes,
|
message.nbytes,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"state encrypt update failed: {err_name}")
|
||||||
f"state encrypt update failed: {err_name} written {written[0]}"
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
)
|
|
||||||
w = int(written[0])
|
|
||||||
assert w == expected_out
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
def final(self, into: Buffer | None = None) -> bytearray | memoryview:
|
||||||
"""Finalize encryption and return the authentication tag.
|
"""Finalize encryption and return the authentication tag.
|
||||||
@@ -746,24 +739,17 @@ class Encryptor:
|
|||||||
if into is not None:
|
if into is not None:
|
||||||
into = memoryview(into)
|
into = memoryview(into)
|
||||||
out = into if into is not None else bytearray(maclen)
|
out = into if into is not None else bytearray(maclen)
|
||||||
written = ffi.new("size_t *")
|
|
||||||
rc = _lib.aegis256x4_state_encrypt_final(
|
rc = _lib.aegis256x4_state_encrypt_final(
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out),
|
ffi.from_buffer(out),
|
||||||
memoryview(out).nbytes,
|
|
||||||
written,
|
|
||||||
maclen,
|
maclen,
|
||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
raise RuntimeError(f"state encrypt final failed: {err_name}")
|
||||||
w = int(written[0])
|
|
||||||
if into is None:
|
|
||||||
# Only the tag bytes are returned when we allocate the buffer
|
|
||||||
assert w == maclen
|
|
||||||
self._state = None
|
self._state = None
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
return out if into is None else memoryview(out)[:maclen] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Decryptor:
|
class Decryptor:
|
||||||
@@ -837,12 +823,9 @@ class Decryptor:
|
|||||||
out_mv = memoryview(out)
|
out_mv = memoryview(out)
|
||||||
if out_mv.nbytes < expected_out:
|
if out_mv.nbytes < expected_out:
|
||||||
raise TypeError("into length must be >= required capacity for this update")
|
raise TypeError("into length must be >= required capacity for this update")
|
||||||
written = ffi.new("size_t *")
|
rc = _lib.aegis256x4_state_decrypt_update(
|
||||||
rc = _lib.aegis256x4_state_decrypt_detached_update(
|
|
||||||
self._state.ptr,
|
self._state.ptr,
|
||||||
ffi.from_buffer(out_mv),
|
ffi.from_buffer(out_mv),
|
||||||
out_mv.nbytes,
|
|
||||||
written,
|
|
||||||
_ptr(ct),
|
_ptr(ct),
|
||||||
ct.nbytes,
|
ct.nbytes,
|
||||||
)
|
)
|
||||||
@@ -850,11 +833,7 @@ class Decryptor:
|
|||||||
err_num = ffi.errno
|
err_num = ffi.errno
|
||||||
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
err_name = errno.errorcode.get(err_num, f"errno_{err_num}")
|
||||||
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
raise RuntimeError(f"state decrypt update failed: {err_name}")
|
||||||
w = int(written[0])
|
return out if into is None else memoryview(out)[:expected_out] # type: ignore
|
||||||
assert w == expected_out, (
|
|
||||||
f"got {w}, expected {expected_out}, ct.nbytes={ct.nbytes}"
|
|
||||||
)
|
|
||||||
return out if into is None else memoryview(out)[:w] # type: ignore
|
|
||||||
|
|
||||||
def final(self, mac: Buffer) -> None:
|
def final(self, mac: Buffer) -> None:
|
||||||
"""Finalize decryption by verifying the MAC tag.
|
"""Finalize decryption by verifying the MAC tag.
|
||||||
@@ -873,9 +852,7 @@ class Decryptor:
|
|||||||
mac = memoryview(mac)
|
mac = memoryview(mac)
|
||||||
if mac.nbytes != maclen:
|
if mac.nbytes != maclen:
|
||||||
raise TypeError(f"mac length must be {maclen}")
|
raise TypeError(f"mac length must be {maclen}")
|
||||||
rc = _lib.aegis256x4_state_decrypt_detached_final(
|
rc = _lib.aegis256x4_state_decrypt_final(self._state.ptr, _ptr(mac), maclen)
|
||||||
self._state.ptr, ffi.NULL, 0, ffi.NULL, _ptr(mac), maclen
|
|
||||||
)
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise ValueError("authentication failed")
|
raise ValueError("authentication failed")
|
||||||
self._state = None
|
self._state = None
|
||||||
|
|||||||
+32
-158
@@ -55,35 +55,10 @@ void aegis128l_state_init(aegis128l_state *st_,
|
|||||||
size_t adlen,
|
size_t adlen,
|
||||||
const uint8_t *npub,
|
const uint8_t *npub,
|
||||||
const uint8_t *k);
|
const uint8_t *k);
|
||||||
int aegis128l_state_encrypt_update(aegis128l_state *st_,
|
int aegis128l_state_encrypt_update(aegis128l_state *st_, uint8_t *c, const uint8_t *m, size_t mlen);
|
||||||
uint8_t *c,
|
int aegis128l_state_encrypt_final(aegis128l_state *st_, uint8_t *mac, size_t maclen);
|
||||||
size_t clen_max,
|
int aegis128l_state_decrypt_update(aegis128l_state *st_, uint8_t *m, const uint8_t *c, size_t clen) ;
|
||||||
size_t *written,
|
int aegis128l_state_decrypt_final(aegis128l_state *st_, const uint8_t *mac, size_t maclen) ;
|
||||||
const uint8_t *m,
|
|
||||||
size_t mlen);
|
|
||||||
int aegis128l_state_encrypt_detached_final(aegis128l_state *st_,
|
|
||||||
uint8_t *c,
|
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
uint8_t *mac,
|
|
||||||
size_t maclen);
|
|
||||||
int aegis128l_state_encrypt_final(aegis128l_state *st_,
|
|
||||||
uint8_t *c,
|
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
size_t maclen);
|
|
||||||
int aegis128l_state_decrypt_detached_update(aegis128l_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *c,
|
|
||||||
size_t clen) ;
|
|
||||||
int aegis128l_state_decrypt_detached_final(aegis128l_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *mac,
|
|
||||||
size_t maclen) ;
|
|
||||||
void aegis128l_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
void aegis128l_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
||||||
void aegis128l_encrypt_unauthenticated(uint8_t *c,
|
void aegis128l_encrypt_unauthenticated(uint8_t *c,
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
@@ -151,33 +126,14 @@ void aegis128x2_state_init(aegis128x2_state *st_,
|
|||||||
const uint8_t *k);
|
const uint8_t *k);
|
||||||
int aegis128x2_state_encrypt_update(aegis128x2_state *st_,
|
int aegis128x2_state_encrypt_update(aegis128x2_state *st_,
|
||||||
uint8_t *c,
|
uint8_t *c,
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
size_t mlen);
|
size_t mlen);
|
||||||
int aegis128x2_state_encrypt_detached_final(aegis128x2_state *st_,
|
int aegis128x2_state_encrypt_final(aegis128x2_state *st_, uint8_t *mac, size_t maclen);
|
||||||
uint8_t *c,
|
int aegis128x2_state_decrypt_update(aegis128x2_state *st_,
|
||||||
size_t clen_max,
|
uint8_t *m,
|
||||||
size_t *written,
|
const uint8_t *c,
|
||||||
uint8_t *mac,
|
size_t clen) ;
|
||||||
size_t maclen);
|
int aegis128x2_state_decrypt_final(aegis128x2_state *st_, const uint8_t *mac, size_t maclen) ;
|
||||||
int aegis128x2_state_encrypt_final(aegis128x2_state *st_,
|
|
||||||
uint8_t *c,
|
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
size_t maclen);
|
|
||||||
int aegis128x2_state_decrypt_detached_update(aegis128x2_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *c,
|
|
||||||
size_t clen) ;
|
|
||||||
int aegis128x2_state_decrypt_detached_final(aegis128x2_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *mac,
|
|
||||||
size_t maclen) ;
|
|
||||||
void aegis128x2_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
void aegis128x2_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
||||||
void aegis128x2_encrypt_unauthenticated(uint8_t *c,
|
void aegis128x2_encrypt_unauthenticated(uint8_t *c,
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
@@ -245,33 +201,14 @@ void aegis128x4_state_init(aegis128x4_state *st_,
|
|||||||
const uint8_t *k);
|
const uint8_t *k);
|
||||||
int aegis128x4_state_encrypt_update(aegis128x4_state *st_,
|
int aegis128x4_state_encrypt_update(aegis128x4_state *st_,
|
||||||
uint8_t *c,
|
uint8_t *c,
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
size_t mlen);
|
size_t mlen);
|
||||||
int aegis128x4_state_encrypt_detached_final(aegis128x4_state *st_,
|
int aegis128x4_state_encrypt_final(aegis128x4_state *st_, uint8_t *mac, size_t maclen);
|
||||||
uint8_t *c,
|
int aegis128x4_state_decrypt_update(aegis128x4_state *st_,
|
||||||
size_t clen_max,
|
uint8_t *m,
|
||||||
size_t *written,
|
const uint8_t *c,
|
||||||
uint8_t *mac,
|
size_t clen) ;
|
||||||
size_t maclen);
|
int aegis128x4_state_decrypt_final(aegis128x4_state *st_, const uint8_t *mac, size_t maclen) ;
|
||||||
int aegis128x4_state_encrypt_final(aegis128x4_state *st_,
|
|
||||||
uint8_t *c,
|
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
size_t maclen);
|
|
||||||
int aegis128x4_state_decrypt_detached_update(aegis128x4_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *c,
|
|
||||||
size_t clen) ;
|
|
||||||
int aegis128x4_state_decrypt_detached_final(aegis128x4_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *mac,
|
|
||||||
size_t maclen) ;
|
|
||||||
void aegis128x4_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
void aegis128x4_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
||||||
void aegis128x4_encrypt_unauthenticated(uint8_t *c,
|
void aegis128x4_encrypt_unauthenticated(uint8_t *c,
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
@@ -337,35 +274,10 @@ void aegis256_state_init(aegis256_state *st_,
|
|||||||
size_t adlen,
|
size_t adlen,
|
||||||
const uint8_t *npub,
|
const uint8_t *npub,
|
||||||
const uint8_t *k);
|
const uint8_t *k);
|
||||||
int aegis256_state_encrypt_update(aegis256_state *st_,
|
int aegis256_state_encrypt_update(aegis256_state *st_, uint8_t *c, const uint8_t *m, size_t mlen);
|
||||||
uint8_t *c,
|
int aegis256_state_encrypt_final(aegis256_state *st_, uint8_t *mac, size_t maclen);
|
||||||
size_t clen_max,
|
int aegis256_state_decrypt_update(aegis256_state *st_, uint8_t *m, const uint8_t *c, size_t clen) ;
|
||||||
size_t *written,
|
int aegis256_state_decrypt_final(aegis256_state *st_, const uint8_t *mac, size_t maclen) ;
|
||||||
const uint8_t *m,
|
|
||||||
size_t mlen);
|
|
||||||
int aegis256_state_encrypt_detached_final(aegis256_state *st_,
|
|
||||||
uint8_t *c,
|
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
uint8_t *mac,
|
|
||||||
size_t maclen);
|
|
||||||
int aegis256_state_encrypt_final(aegis256_state *st_,
|
|
||||||
uint8_t *c,
|
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
size_t maclen);
|
|
||||||
int aegis256_state_decrypt_detached_update(aegis256_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *c,
|
|
||||||
size_t clen) ;
|
|
||||||
int aegis256_state_decrypt_detached_final(aegis256_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *mac,
|
|
||||||
size_t maclen) ;
|
|
||||||
void aegis256_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
void aegis256_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
||||||
void aegis256_encrypt_unauthenticated(uint8_t *c,
|
void aegis256_encrypt_unauthenticated(uint8_t *c,
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
@@ -433,33 +345,14 @@ void aegis256x2_state_init(aegis256x2_state *st_,
|
|||||||
const uint8_t *k);
|
const uint8_t *k);
|
||||||
int aegis256x2_state_encrypt_update(aegis256x2_state *st_,
|
int aegis256x2_state_encrypt_update(aegis256x2_state *st_,
|
||||||
uint8_t *c,
|
uint8_t *c,
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
size_t mlen);
|
size_t mlen);
|
||||||
int aegis256x2_state_encrypt_detached_final(aegis256x2_state *st_,
|
int aegis256x2_state_encrypt_final(aegis256x2_state *st_, uint8_t *mac, size_t maclen);
|
||||||
uint8_t *c,
|
int aegis256x2_state_decrypt_update(aegis256x2_state *st_,
|
||||||
size_t clen_max,
|
uint8_t *m,
|
||||||
size_t *written,
|
const uint8_t *c,
|
||||||
uint8_t *mac,
|
size_t clen) ;
|
||||||
size_t maclen);
|
int aegis256x2_state_decrypt_final(aegis256x2_state *st_, const uint8_t *mac, size_t maclen) ;
|
||||||
int aegis256x2_state_encrypt_final(aegis256x2_state *st_,
|
|
||||||
uint8_t *c,
|
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
size_t maclen);
|
|
||||||
int aegis256x2_state_decrypt_detached_update(aegis256x2_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *c,
|
|
||||||
size_t clen) ;
|
|
||||||
int aegis256x2_state_decrypt_detached_final(aegis256x2_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *mac,
|
|
||||||
size_t maclen) ;
|
|
||||||
void aegis256x2_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
void aegis256x2_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
||||||
void aegis256x2_encrypt_unauthenticated(uint8_t *c,
|
void aegis256x2_encrypt_unauthenticated(uint8_t *c,
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
@@ -527,33 +420,14 @@ void aegis256x4_state_init(aegis256x4_state *st_,
|
|||||||
const uint8_t *k);
|
const uint8_t *k);
|
||||||
int aegis256x4_state_encrypt_update(aegis256x4_state *st_,
|
int aegis256x4_state_encrypt_update(aegis256x4_state *st_,
|
||||||
uint8_t *c,
|
uint8_t *c,
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
size_t mlen);
|
size_t mlen);
|
||||||
int aegis256x4_state_encrypt_detached_final(aegis256x4_state *st_,
|
int aegis256x4_state_encrypt_final(aegis256x4_state *st_, uint8_t *mac, size_t maclen);
|
||||||
uint8_t *c,
|
int aegis256x4_state_decrypt_update(aegis256x4_state *st_,
|
||||||
size_t clen_max,
|
uint8_t *m,
|
||||||
size_t *written,
|
const uint8_t *c,
|
||||||
uint8_t *mac,
|
size_t clen) ;
|
||||||
size_t maclen);
|
int aegis256x4_state_decrypt_final(aegis256x4_state *st_, const uint8_t *mac, size_t maclen) ;
|
||||||
int aegis256x4_state_encrypt_final(aegis256x4_state *st_,
|
|
||||||
uint8_t *c,
|
|
||||||
size_t clen_max,
|
|
||||||
size_t *written,
|
|
||||||
size_t maclen);
|
|
||||||
int aegis256x4_state_decrypt_detached_update(aegis256x4_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *c,
|
|
||||||
size_t clen) ;
|
|
||||||
int aegis256x4_state_decrypt_detached_final(aegis256x4_state *st_,
|
|
||||||
uint8_t *m,
|
|
||||||
size_t mlen_max,
|
|
||||||
size_t *written,
|
|
||||||
const uint8_t *mac,
|
|
||||||
size_t maclen) ;
|
|
||||||
void aegis256x4_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
void aegis256x4_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k);
|
||||||
void aegis256x4_encrypt_unauthenticated(uint8_t *c,
|
void aegis256x4_encrypt_unauthenticated(uint8_t *c,
|
||||||
const uint8_t *m,
|
const uint8_t *m,
|
||||||
|
|||||||
+46
-78
@@ -1,100 +1,68 @@
|
|||||||
"""Custom build backend that builds libaegis with Zig before building the Python package."""
|
"""Custom build backend that builds libaegis with Zig before building the Python package."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from setuptools import build_meta as _orig
|
from setuptools import build_meta
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"build_sdist",
|
||||||
|
"build_wheel",
|
||||||
|
"build_editable",
|
||||||
|
"get_requires_for_build_sdist",
|
||||||
|
"get_requires_for_build_wheel",
|
||||||
|
"prepare_metadata_for_build_wheel",
|
||||||
|
]
|
||||||
|
|
||||||
|
_MACOS_TARGET = "11.0"
|
||||||
|
_prepared = False
|
||||||
|
|
||||||
|
|
||||||
def _check_zig_available():
|
def _prepare():
|
||||||
"""Check if Zig is installed and available."""
|
"""Prepare the build environment and build libaegis."""
|
||||||
|
global _prepared
|
||||||
|
if _prepared:
|
||||||
|
return
|
||||||
|
_prepared = True
|
||||||
|
|
||||||
|
# Set macOS deployment target
|
||||||
|
if sys.platform == "darwin" and "MACOSX_DEPLOYMENT_TARGET" not in os.environ:
|
||||||
|
os.environ["MACOSX_DEPLOYMENT_TARGET"] = _MACOS_TARGET
|
||||||
|
|
||||||
|
# Check Zig is available
|
||||||
if shutil.which("zig") is None:
|
if shutil.which("zig") is None:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"\n" + "=" * 70 + "\n"
|
"Zig compiler not found. Install from https://ziglang.org/download/"
|
||||||
"ERROR: Zig compiler not found!\n"
|
|
||||||
"\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"
|
|
||||||
" - Visit: https://ziglang.org/download/\n"
|
|
||||||
" - Or use a package manager:\n"
|
|
||||||
" * macOS: brew install zig\n"
|
|
||||||
" * Linux: See https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager\n"
|
|
||||||
" * Windows: choco install zig or scoop install zig\n"
|
|
||||||
"\n"
|
|
||||||
"After installing Zig, please try building again.\n" + "=" * 70 + "\n"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Build libaegis
|
||||||
def _build_libaegis():
|
|
||||||
"""Build libaegis static library with Zig."""
|
|
||||||
# Check Zig availability first
|
|
||||||
_check_zig_available()
|
|
||||||
|
|
||||||
libaegis_dir = Path(__file__).parent.parent / "libaegis"
|
libaegis_dir = Path(__file__).parent.parent / "libaegis"
|
||||||
if not libaegis_dir.exists():
|
cmd = ["zig", "build", "-Drelease"]
|
||||||
raise FileNotFoundError(
|
if sys.platform == "darwin":
|
||||||
f"libaegis directory not found at {libaegis_dir}. "
|
arch = {"arm64": "aarch64", "x86_64": "x86_64"}.get(platform.machine())
|
||||||
"Cannot build static library."
|
if arch:
|
||||||
)
|
cmd.append(f"-Dtarget={arch}-macos.{_MACOS_TARGET}")
|
||||||
|
subprocess.run(cmd, cwd=libaegis_dir, check=True)
|
||||||
print("Building libaegis static library with Zig...")
|
|
||||||
try:
|
|
||||||
subprocess.run(
|
|
||||||
["zig", "build", "-Drelease"],
|
|
||||||
cwd=libaegis_dir,
|
|
||||||
check=True,
|
|
||||||
capture_output=False,
|
|
||||||
)
|
|
||||||
print("Successfully built libaegis static library")
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(
|
|
||||||
f"\nError: Zig build failed with exit code {e.returncode}\n"
|
|
||||||
f"Command: {' '.join(e.cmd)}\n",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
# Expose all the standard build backend hooks
|
build_sdist = build_meta.build_sdist
|
||||||
def get_requires_for_build_wheel(config_settings=None):
|
get_requires_for_build_sdist = build_meta.get_requires_for_build_sdist
|
||||||
"""Return build requirements and ensure libaegis is built first."""
|
get_requires_for_build_wheel = build_meta.get_requires_for_build_wheel
|
||||||
_build_libaegis()
|
prepare_metadata_for_build_wheel = build_meta.prepare_metadata_for_build_wheel
|
||||||
return _orig.get_requires_for_build_wheel(config_settings)
|
|
||||||
|
|
||||||
|
|
||||||
def get_requires_for_build_sdist(config_settings=None):
|
|
||||||
"""Return build requirements for sdist and ensure libaegis is built first."""
|
|
||||||
_build_libaegis()
|
|
||||||
return _orig.get_requires_for_build_sdist(config_settings)
|
|
||||||
|
|
||||||
|
|
||||||
_orig_prepare_metadata_for_build_wheel = _orig.prepare_metadata_for_build_wheel
|
|
||||||
_orig_build_sdist = _orig.build_sdist
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
|
|
||||||
"""Prepare metadata and ensure libaegis is built (some frontends call this early)."""
|
|
||||||
_build_libaegis()
|
|
||||||
return _orig_prepare_metadata_for_build_wheel(metadata_directory, config_settings)
|
|
||||||
|
|
||||||
|
|
||||||
def build_sdist(sdist_directory, config_settings=None):
|
|
||||||
"""Build sdist, building libaegis first so the sdist can include built artifacts if needed."""
|
|
||||||
_build_libaegis()
|
|
||||||
return _orig_build_sdist(sdist_directory, config_settings)
|
|
||||||
|
|
||||||
|
|
||||||
|
# Wheel build hooks - need libaegis built first
|
||||||
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
||||||
"""Build wheel with libaegis built first."""
|
_prepare()
|
||||||
_build_libaegis()
|
return build_meta.build_wheel(wheel_directory, config_settings, metadata_directory)
|
||||||
return _orig.build_wheel(wheel_directory, config_settings, metadata_directory)
|
|
||||||
|
|
||||||
|
|
||||||
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
|
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
|
||||||
"""Build editable install with libaegis built first."""
|
_prepare()
|
||||||
_build_libaegis()
|
return build_meta.build_editable(
|
||||||
return _orig.build_editable(wheel_directory, config_settings, metadata_directory)
|
wheel_directory, config_settings, metadata_directory
|
||||||
|
)
|
||||||
|
|||||||
Regular → Executable
+32
-1
@@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env -S uv run
|
||||||
"""Generate CFFI cdef and Python modules from libaegis C sources."""
|
"""Generate CFFI cdef and Python modules from libaegis C sources."""
|
||||||
|
|
||||||
import pathlib
|
import pathlib
|
||||||
@@ -273,6 +274,23 @@ def generate_python_modules(
|
|||||||
return updated, unchanged
|
return updated, unchanged
|
||||||
|
|
||||||
|
|
||||||
|
def generate_ciphers_module(constants: Dict[str, Dict[str, int]]) -> str:
|
||||||
|
labels = [algo_label(variant) for variant in constants]
|
||||||
|
literal_items = ", ".join(f'"{label}"' for label in labels)
|
||||||
|
lines = [
|
||||||
|
"# This file is generated by tools/generate.py. Do not edit.",
|
||||||
|
"from typing import Literal",
|
||||||
|
"",
|
||||||
|
f"CipherName = Literal[{literal_items}]",
|
||||||
|
"",
|
||||||
|
"CIPHERS: dict[CipherName, str] = {",
|
||||||
|
]
|
||||||
|
for variant in constants:
|
||||||
|
lines.append(f' "{algo_label(variant)}": "{variant}",')
|
||||||
|
lines.append("}")
|
||||||
|
return "\n".join(lines) + "\n"
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
root = pathlib.Path(__file__).parent.parent
|
root = pathlib.Path(__file__).parent.parent
|
||||||
libaegis_src_dir = root / "libaegis" / "src"
|
libaegis_src_dir = root / "libaegis" / "src"
|
||||||
@@ -304,7 +322,20 @@ def main() -> int:
|
|||||||
cdef_path.write_bytes(cdef_content.encode())
|
cdef_path.write_bytes(cdef_content.encode())
|
||||||
print(f" - Updated {cdef_path}", file=sys.stderr)
|
print(f" - Updated {cdef_path}", file=sys.stderr)
|
||||||
|
|
||||||
print("Step 3: Generating Python modules...", file=sys.stderr)
|
print("Step 3: Generating _ciphers.py...", file=sys.stderr)
|
||||||
|
ciphers_path = pyaegis_dir / "_ciphers.py"
|
||||||
|
ciphers_content = generate_ciphers_module(constants)
|
||||||
|
|
||||||
|
if (
|
||||||
|
ciphers_path.exists()
|
||||||
|
and ciphers_path.read_text(encoding="utf-8") == ciphers_content
|
||||||
|
):
|
||||||
|
print(f" - No changes to {ciphers_path.name}", file=sys.stderr)
|
||||||
|
else:
|
||||||
|
ciphers_path.write_bytes(ciphers_content.encode())
|
||||||
|
print(f" - Updated {ciphers_path.name}", file=sys.stderr)
|
||||||
|
|
||||||
|
print("Step 4: Generating Python modules...", file=sys.stderr)
|
||||||
try:
|
try:
|
||||||
updated, unchanged = generate_python_modules(
|
updated, unchanged = generate_python_modules(
|
||||||
pyaegis_dir / "aegis256x4.py", pyaegis_dir, constants
|
pyaegis_dir / "aegis256x4.py", pyaegis_dir, constants
|
||||||
|
|||||||
Regular → Executable
+269
-124
@@ -1,28 +1,46 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env -S uv run
|
||||||
"""Build wheels for all supported Python versions using uv."""
|
"""Build wheels for all supported Python versions using uv."""
|
||||||
|
|
||||||
|
import os
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import tomllib
|
|
||||||
from packaging.specifiers import SpecifierSet
|
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
|
|
||||||
# Import generate module from same directory
|
# Import generate module from same directory
|
||||||
sys.path.insert(0, str(Path(__file__).parent))
|
sys.path.insert(0, str(Path(__file__).parent))
|
||||||
import generate
|
import generate
|
||||||
|
|
||||||
|
# Minimum macOS deployment target for compatibility
|
||||||
|
MACOS_DEPLOYMENT_TARGET = "11.0"
|
||||||
|
|
||||||
def get_python_versions():
|
# ABI3 wheel: built once, works for all GIL-enabled Python versions
|
||||||
"""Get supported Python versions."""
|
# We use a recent Python to build since it doesn't affect the wheel compatibility
|
||||||
pyproject_toml = Path(__file__).parent.parent / "pyproject.toml"
|
ABI3_BUILD_VERSION = "3.14+gil"
|
||||||
data = tomllib.loads(pyproject_toml.read_text(encoding="utf-8"))
|
|
||||||
spec = SpecifierSet(data["project"]["requires-python"])
|
# All GIL-enabled Python versions covered by the ABI3 wheel
|
||||||
# Generate versions that match the specifier (up to Python 3.14)
|
ABI3_COVERED_VERSIONS = [
|
||||||
return [f"3.{minor}" for minor in range(10, 15) if f"3.{minor}" in spec]
|
"3.10",
|
||||||
|
"3.11",
|
||||||
|
"3.12",
|
||||||
|
"3.13+gil",
|
||||||
|
"3.14+gil",
|
||||||
|
"3.15+gil",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Non-ABI3 wheels: each needs its own build (free-threaded and PyPy)
|
||||||
|
NON_ABI3_VERSIONS = [
|
||||||
|
"3.14t",
|
||||||
|
"3.15t",
|
||||||
|
"pypy3.10",
|
||||||
|
"pypy3.11",
|
||||||
|
]
|
||||||
|
|
||||||
|
# All versions for testing and benchmarking
|
||||||
|
ALL_PYTHON_VERSIONS = ABI3_COVERED_VERSIONS + NON_ABI3_VERSIONS
|
||||||
|
|
||||||
|
|
||||||
def get_version_from_scm():
|
def get_version_from_scm():
|
||||||
@@ -92,24 +110,29 @@ def make_release_message(version):
|
|||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
PYTHON_VERSIONS = get_python_versions()
|
def run_command(cmd, description=None, env=None):
|
||||||
|
"""Run a command and handle errors. If description is None, only print the command."""
|
||||||
|
if description:
|
||||||
def run_command(cmd, description):
|
print(f"\n{'=' * 70}")
|
||||||
"""Run a command and handle errors."""
|
print(f"{description}")
|
||||||
print(f"\n{'=' * 70}")
|
print(f"{'=' * 70}")
|
||||||
print(f"{description}")
|
|
||||||
print(f"{'=' * 70}")
|
|
||||||
print(f">>> {' '.join(cmd)}")
|
print(f">>> {' '.join(cmd)}")
|
||||||
try:
|
try:
|
||||||
subprocess.run(cmd, check=True)
|
subprocess.run(cmd, check=True, env=env)
|
||||||
print(f"✓ {description} completed successfully")
|
|
||||||
return True
|
return True
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print(f"✗ {description} failed with exit code {e.returncode}", file=sys.stderr)
|
print(f"✗ Command failed with exit code {e.returncode}", file=sys.stderr)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_build_env():
|
||||||
|
"""Get environment variables for building wheels."""
|
||||||
|
env = os.environ.copy()
|
||||||
|
if platform.system() == "Darwin":
|
||||||
|
env["MACOSX_DEPLOYMENT_TARGET"] = MACOS_DEPLOYMENT_TARGET
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
def normalize_line_endings(repo_root: Path):
|
def normalize_line_endings(repo_root: Path):
|
||||||
"""Normalize all text files to LF line endings."""
|
"""Normalize all text files to LF line endings."""
|
||||||
# Patterns for files to normalize
|
# Patterns for files to normalize
|
||||||
@@ -133,6 +156,160 @@ def normalize_line_endings(repo_root: Path):
|
|||||||
file_path.write_bytes(content)
|
file_path.write_bytes(content)
|
||||||
|
|
||||||
|
|
||||||
|
def get_wheel_pattern(py_version: str, abi3: bool = False) -> str:
|
||||||
|
"""Get the glob pattern for finding a wheel file."""
|
||||||
|
if abi3:
|
||||||
|
# ABI3 wheels always use cp310-abi3 tag (minimum supported version)
|
||||||
|
# regardless of which Python version was used to build
|
||||||
|
return "aeg-*-cp310-abi3-*.whl"
|
||||||
|
elif py_version.startswith("pypy"):
|
||||||
|
# PyPy wheels use pp3XX format
|
||||||
|
return f"aeg-*-pp{py_version.replace('pypy', '').replace('.', '')}-*.whl"
|
||||||
|
elif py_version.endswith("t"):
|
||||||
|
# Free-threaded Python wheels use cpXXX-cpXXXt format (e.g., cp314-cp314t)
|
||||||
|
base_version = py_version.replace(".", "").replace("t", "")
|
||||||
|
return f"aeg-*-cp{base_version}-cp{base_version}t-*.whl"
|
||||||
|
else:
|
||||||
|
# Regular CPython wheels use cpXXX-cpXXX format
|
||||||
|
# Strip +gil suffix used to force non-free-threaded build
|
||||||
|
base_version = py_version.replace(".", "").replace("+gil", "")
|
||||||
|
return f"aeg-*-cp{base_version}-cp{base_version}-*.whl"
|
||||||
|
|
||||||
|
|
||||||
|
def build_abi3_wheel(dist_dir: Path, py_version: str) -> Path | None:
|
||||||
|
"""Build the ABI3 wheel using the specified Python version."""
|
||||||
|
cmd = ["uv", "build", "--python", py_version, "--wheel", "--quiet"]
|
||||||
|
|
||||||
|
if not run_command(cmd, env=get_build_env()):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Find the ABI3 wheel (always tagged cp310-abi3 regardless of build Python version)
|
||||||
|
wheel_pattern = get_wheel_pattern(py_version, abi3=True)
|
||||||
|
wheels = list(dist_dir.glob(wheel_pattern))
|
||||||
|
if not wheels:
|
||||||
|
print(f"✗ Could not find ABI3 wheel matching {wheel_pattern}", file=sys.stderr)
|
||||||
|
return None
|
||||||
|
|
||||||
|
wheel = wheels[0]
|
||||||
|
|
||||||
|
# Repair wheel with auditwheel for manylinux compatibility (Linux only)
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
wheel = repair_wheel_linux(dist_dir, wheel, py_version, abi3=True)
|
||||||
|
if not wheel:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return wheel
|
||||||
|
|
||||||
|
|
||||||
|
def build_wheel_for_version(dist_dir: Path, py_version: str) -> Path | None:
|
||||||
|
"""Build a wheel for a specific Python version (non-ABI3)."""
|
||||||
|
cmd = ["uv", "build", "--python", py_version, "--wheel", "--quiet"]
|
||||||
|
|
||||||
|
if not run_command(cmd, env=get_build_env()):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Find the wheel for this version
|
||||||
|
wheel_pattern = get_wheel_pattern(py_version, abi3=False)
|
||||||
|
wheels = list(dist_dir.glob(wheel_pattern))
|
||||||
|
if not wheels:
|
||||||
|
print(f"✗ Could not find wheel for Python {py_version}", file=sys.stderr)
|
||||||
|
return None
|
||||||
|
|
||||||
|
wheel = wheels[0]
|
||||||
|
|
||||||
|
# Repair wheel with auditwheel for manylinux compatibility (Linux only)
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
wheel = repair_wheel_linux(dist_dir, wheel, py_version, abi3=False)
|
||||||
|
if not wheel:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return wheel
|
||||||
|
|
||||||
|
|
||||||
|
def repair_wheel_linux(
|
||||||
|
dist_dir: Path, wheel: Path, py_version: str, abi3: bool
|
||||||
|
) -> Path | None:
|
||||||
|
"""Repair a wheel with auditwheel for manylinux compatibility (Linux only)."""
|
||||||
|
repair_cmd = [
|
||||||
|
"uv",
|
||||||
|
"run",
|
||||||
|
"auditwheel",
|
||||||
|
"repair",
|
||||||
|
str(wheel),
|
||||||
|
"-w",
|
||||||
|
str(dist_dir),
|
||||||
|
]
|
||||||
|
if not run_command(repair_cmd):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Find the repaired wheel (it will have a different name)
|
||||||
|
wheel_pattern = get_wheel_pattern(py_version, abi3=abi3)
|
||||||
|
all_wheels = list(dist_dir.glob(wheel_pattern))
|
||||||
|
repaired_wheels = [w for w in all_wheels if "linux_x86_64" not in str(w)]
|
||||||
|
if not repaired_wheels:
|
||||||
|
print(
|
||||||
|
f"✗ Could not find repaired (manylinux) wheel for Python {py_version}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
repaired_wheel = repaired_wheels[0]
|
||||||
|
|
||||||
|
# Remove the unrepaired linux_x86_64 wheels
|
||||||
|
for w in all_wheels:
|
||||||
|
if "linux_x86_64" in str(w):
|
||||||
|
w.unlink()
|
||||||
|
|
||||||
|
return repaired_wheel
|
||||||
|
|
||||||
|
|
||||||
|
def test_wheel(wheel: Path, py_version: str) -> bool:
|
||||||
|
"""Test a wheel with pytest."""
|
||||||
|
# --isolated: avoid .venv conflicts
|
||||||
|
# --no-project: don't build from source in current directory, use the wheel
|
||||||
|
# --refresh-package: force uv to not use cached old versions
|
||||||
|
test_cmd = [
|
||||||
|
"uv",
|
||||||
|
"run",
|
||||||
|
"--isolated",
|
||||||
|
"--no-project",
|
||||||
|
"--refresh-package",
|
||||||
|
"aeg",
|
||||||
|
"--python",
|
||||||
|
py_version,
|
||||||
|
"--with",
|
||||||
|
str(wheel),
|
||||||
|
"--with",
|
||||||
|
"pytest",
|
||||||
|
"pytest",
|
||||||
|
"tests/",
|
||||||
|
]
|
||||||
|
return run_command(test_cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def run_benchmark(wheel: Path, py_version: str) -> bool:
|
||||||
|
"""Run benchmark for a wheel."""
|
||||||
|
# --isolated: avoid .venv conflicts
|
||||||
|
# --no-project: don't build from source in current directory, use the wheel
|
||||||
|
# --refresh-package: force uv to not use cached old versions
|
||||||
|
bench_cmd = [
|
||||||
|
"uv",
|
||||||
|
"run",
|
||||||
|
"--isolated",
|
||||||
|
"--no-project",
|
||||||
|
"--refresh-package",
|
||||||
|
"aeg",
|
||||||
|
"--python",
|
||||||
|
py_version,
|
||||||
|
"--with",
|
||||||
|
str(wheel),
|
||||||
|
"-m",
|
||||||
|
"aeg.benchmark",
|
||||||
|
]
|
||||||
|
return run_command(bench_cmd)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Build wheels for all supported Python versions."""
|
"""Build wheels for all supported Python versions."""
|
||||||
repo_root = Path(__file__).parent.parent
|
repo_root = Path(__file__).parent.parent
|
||||||
@@ -147,14 +324,15 @@ def main():
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Run ruff to check and fix any issues
|
# Run ruff to check and fix any issues
|
||||||
if not run_command(
|
print(f"\n{'=' * 70}")
|
||||||
["uv", "run", "ruff", "check", "--fix", "."], "Running ruff check --fix"
|
print("Linting and formatting")
|
||||||
):
|
print(f"{'=' * 70}")
|
||||||
|
if not run_command(["uv", "run", "ruff", "check", "--fix", "."]):
|
||||||
print("✗ Ruff check failed", file=sys.stderr)
|
print("✗ Ruff check failed", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Run ruff format
|
# Run ruff format
|
||||||
if not run_command(["uv", "run", "ruff", "format", "."], "Running ruff format"):
|
if not run_command(["uv", "run", "ruff", "format", "."]):
|
||||||
print("✗ Ruff format failed", file=sys.stderr)
|
print("✗ Ruff format failed", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@@ -173,7 +351,11 @@ def main():
|
|||||||
f"Packaging aeg-{version}"
|
f"Packaging aeg-{version}"
|
||||||
+ (" for release" if is_release else " (not release)")
|
+ (" for release" if is_release else " (not release)")
|
||||||
)
|
)
|
||||||
print(f"Building wheels for Python versions: {', '.join(PYTHON_VERSIONS)}")
|
print(f"Building: 1 ABI3 wheel (for Python {', '.join(ABI3_COVERED_VERSIONS)})")
|
||||||
|
print(
|
||||||
|
f" + {len(NON_ABI3_VERSIONS)} non-ABI3 wheels ({', '.join(NON_ABI3_VERSIONS)})"
|
||||||
|
)
|
||||||
|
print(f"Testing/benchmarking: {len(ALL_PYTHON_VERSIONS)} Python versions")
|
||||||
print(f"Output directory: {dist_dir}", end=" ")
|
print(f"Output directory: {dist_dir}", end=" ")
|
||||||
|
|
||||||
# Clean dist directory
|
# Clean dist directory
|
||||||
@@ -182,129 +364,89 @@ def main():
|
|||||||
shutil.rmtree(dist_dir)
|
shutil.rmtree(dist_dir)
|
||||||
else:
|
else:
|
||||||
print("(created)")
|
print("(created)")
|
||||||
|
|
||||||
|
# Clean build directory to remove stale CFFI-generated C code and .so files
|
||||||
|
build_dir = repo_root / "build"
|
||||||
|
if build_dir.exists():
|
||||||
|
print(f"Cleaning build directory: {build_dir}")
|
||||||
|
shutil.rmtree(build_dir)
|
||||||
|
|
||||||
|
# Build distributions
|
||||||
|
print(f"\n{'=' * 70}")
|
||||||
|
print("Building distributions")
|
||||||
print(f"{'=' * 70}")
|
print(f"{'=' * 70}")
|
||||||
|
|
||||||
# Build source distribution first
|
# Build source distribution first
|
||||||
if not run_command(
|
if not run_command(["uv", "build", "--sdist", "--quiet"], env=get_build_env()):
|
||||||
["uv", "build", "--sdist", "--quiet"], "Building source distribution"
|
|
||||||
):
|
|
||||||
print("✗ Source distribution build failed", file=sys.stderr)
|
print("✗ Source distribution build failed", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
failed_builds = []
|
failed_builds = []
|
||||||
|
failed_tests = []
|
||||||
successful_wheels = []
|
successful_wheels = []
|
||||||
|
wheel_for_version = {} # Map Python version to wheel path
|
||||||
|
|
||||||
for py_version in PYTHON_VERSIONS:
|
# Build ABI3 wheel (once, works for all GIL-enabled versions)
|
||||||
# Build wheel
|
abi3_wheel = build_abi3_wheel(dist_dir, ABI3_BUILD_VERSION)
|
||||||
description = f"Building wheel for Python {py_version}"
|
if abi3_wheel:
|
||||||
cmd = ["uv", "build", "--python", py_version, "--wheel", "--quiet"]
|
successful_wheels.append(abi3_wheel)
|
||||||
|
# This wheel works for all ABI3-covered versions
|
||||||
|
for py_version in ABI3_COVERED_VERSIONS:
|
||||||
|
wheel_for_version[py_version] = abi3_wheel
|
||||||
|
else:
|
||||||
|
failed_builds.append(f"abi3 (built with {ABI3_BUILD_VERSION})")
|
||||||
|
|
||||||
if not run_command(cmd, description):
|
# Build non-ABI3 wheels (free-threaded and PyPy)
|
||||||
|
for py_version in NON_ABI3_VERSIONS:
|
||||||
|
wheel = build_wheel_for_version(dist_dir, py_version)
|
||||||
|
if wheel:
|
||||||
|
successful_wheels.append(wheel)
|
||||||
|
wheel_for_version[py_version] = wheel
|
||||||
|
else:
|
||||||
failed_builds.append(py_version)
|
failed_builds.append(py_version)
|
||||||
|
|
||||||
|
# Test and benchmark each Python version with its appropriate wheel
|
||||||
|
print(f"\n{'=' * 70}")
|
||||||
|
print("Testing and benchmarking")
|
||||||
|
print(f"{'=' * 70}")
|
||||||
|
|
||||||
|
for py_version in ALL_PYTHON_VERSIONS:
|
||||||
|
wheel = wheel_for_version.get(py_version)
|
||||||
|
if not wheel:
|
||||||
|
# No wheel available for this version (build failed)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Find the wheel for this version
|
# Test the wheel with pytest
|
||||||
wheel_pattern = f"aeg-*-cp{py_version.replace('.', '')}-*.whl"
|
if not test_wheel(wheel, py_version):
|
||||||
wheels = list(dist_dir.glob(wheel_pattern))
|
failed_tests.append(py_version)
|
||||||
if not wheels:
|
|
||||||
print(f"✗ Could not find wheel for Python {py_version}", file=sys.stderr)
|
|
||||||
failed_builds.append(py_version)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
wheel = wheels[0]
|
# Run benchmark
|
||||||
|
if not run_benchmark(wheel, py_version):
|
||||||
# Repair wheel with auditwheel for manylinux compatibility (Linux only)
|
failed_tests.append(py_version)
|
||||||
if platform.system() == "Linux":
|
|
||||||
repair_cmd = [
|
|
||||||
"uv",
|
|
||||||
"run",
|
|
||||||
"auditwheel",
|
|
||||||
"repair",
|
|
||||||
str(wheel),
|
|
||||||
"-w",
|
|
||||||
str(dist_dir),
|
|
||||||
]
|
|
||||||
if not run_command(
|
|
||||||
repair_cmd, f"Repairing wheel for Python {py_version} with auditwheel"
|
|
||||||
):
|
|
||||||
print(
|
|
||||||
f"✗ Auditwheel repair failed for Python {py_version}",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
failed_builds.append(py_version)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Find the repaired wheel (it will have a different name)
|
|
||||||
all_wheels = list(
|
|
||||||
dist_dir.glob(f"aeg-*-cp{py_version.replace('.', '')}-*.whl")
|
|
||||||
)
|
|
||||||
repaired_wheels = [w for w in all_wheels if "linux_x86_64" not in str(w)]
|
|
||||||
if not repaired_wheels:
|
|
||||||
print(
|
|
||||||
f"✗ Could not find repaired (manylinux) wheel for Python {py_version}",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
failed_builds.append(py_version)
|
|
||||||
continue
|
|
||||||
|
|
||||||
wheel = repaired_wheels[0] # Use the repaired wheel for testing
|
|
||||||
|
|
||||||
# Remove the unrepaired linux_x86_64 wheels
|
|
||||||
for w in all_wheels:
|
|
||||||
if "linux_x86_64" in str(w):
|
|
||||||
w.unlink()
|
|
||||||
|
|
||||||
# Test the wheel with pytest (use --isolated to avoid .venv conflicts)
|
|
||||||
test_cmd = [
|
|
||||||
"uv",
|
|
||||||
"run",
|
|
||||||
"--isolated",
|
|
||||||
"--python",
|
|
||||||
py_version,
|
|
||||||
"--with",
|
|
||||||
str(wheel),
|
|
||||||
"--with",
|
|
||||||
"pytest",
|
|
||||||
"pytest",
|
|
||||||
]
|
|
||||||
if not run_command(
|
|
||||||
test_cmd, f"Testing wheel for Python {py_version} with pytest"
|
|
||||||
):
|
|
||||||
print(f"✗ Tests failed for Python {py_version}", file=sys.stderr)
|
|
||||||
failed_builds.append(py_version)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Run benchmark (use --isolated to avoid .venv conflicts)
|
|
||||||
bench_cmd = [
|
|
||||||
"uv",
|
|
||||||
"run",
|
|
||||||
"--isolated",
|
|
||||||
"--python",
|
|
||||||
py_version,
|
|
||||||
"--with",
|
|
||||||
str(wheel),
|
|
||||||
"-m",
|
|
||||||
"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)
|
|
||||||
failed_builds.append(py_version)
|
|
||||||
continue
|
|
||||||
|
|
||||||
successful_wheels.append(wheel)
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
print(f"\n{'=' * 70}")
|
print(f"\n{'=' * 70}")
|
||||||
print("BUILD SUMMARY")
|
print("BUILD SUMMARY")
|
||||||
print(f"{'=' * 70}")
|
print(f"{'=' * 70}")
|
||||||
print(
|
print(
|
||||||
f"Successful builds: sdist and {len(successful_wheels)}/{len(PYTHON_VERSIONS)} wheels"
|
f"Successful builds: sdist and {len(successful_wheels)} wheels "
|
||||||
|
f"(1 abi3 + {len(NON_ABI3_VERSIONS)} non-abi3)"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"Tests/benchmarks passed: {len(ALL_PYTHON_VERSIONS) - len(failed_tests) - len(failed_builds)}/{len(ALL_PYTHON_VERSIONS)} Python versions"
|
||||||
)
|
)
|
||||||
|
|
||||||
if failed_builds:
|
if failed_builds:
|
||||||
print(f"\nFailed builds: {len(failed_builds)}")
|
print(f"\nFailed builds: {len(failed_builds)}")
|
||||||
for version in failed_builds:
|
for failed_version in failed_builds:
|
||||||
print(f" ✗ Python {version}")
|
print(f" ✗ {failed_version}")
|
||||||
|
|
||||||
|
if failed_tests:
|
||||||
|
print(f"\nFailed tests/benchmarks: {len(failed_tests)}")
|
||||||
|
for failed_version in failed_tests:
|
||||||
|
print(f" ✗ Python {failed_version}")
|
||||||
|
|
||||||
if not successful_wheels:
|
if not successful_wheels:
|
||||||
print("\n✗ No successful wheels to upload")
|
print("\n✗ No successful wheels to upload")
|
||||||
@@ -336,4 +478,7 @@ def main():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main())
|
try:
|
||||||
|
sys.exit(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user