From 5fa614f2b38d366551ebe65bb269ca00d2f486c3 Mon Sep 17 00:00:00 2001 From: M-AlNoaimi <26318936+M-AlNoaimi@users.noreply.github.com> Date: Fri, 23 May 2025 01:05:32 +0100 Subject: [PATCH 1/2] Add PEP 561 type stubs for oqs package The following files have been added: - oqs/py.typed: Marker file for PEP 561 compliance. - oqs/__init__.pyi: Stub for the main package entry point. - oqs/oqs.pyi: Stubs for core OQS functionalities (KeyEncapsulation, Signature, related functions, and exceptions). - oqs/rand.pyi: Stubs for random number generation functions. Signed-off-by: M-AlNoaimi <26318936+M-AlNoaimi@users.noreply.github.com> --- oqs/__init__.pyi | 20 +++++++++++ oqs/oqs.pyi | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ oqs/py.typed | 0 oqs/rand.pyi | 2 ++ 4 files changed, 116 insertions(+) create mode 100644 oqs/__init__.pyi create mode 100644 oqs/oqs.pyi create mode 100644 oqs/py.typed create mode 100644 oqs/rand.pyi diff --git a/oqs/__init__.pyi b/oqs/__init__.pyi new file mode 100644 index 0000000..9b219b6 --- /dev/null +++ b/oqs/__init__.pyi @@ -0,0 +1,20 @@ +# Re-export symbols from oqs/__init__.py for type hinting +from .oqs import ( + KeyEncapsulation, + MechanismNotEnabledError, + MechanismNotSupportedError, + OQS_SUCCESS, + OQS_VERSION, + Signature, + get_enabled_kem_mechanisms, + get_enabled_sig_mechanisms, + get_supported_kem_mechanisms, + get_supported_sig_mechanisms, + is_kem_enabled, + is_sig_enabled, + native, + oqs_python_version, + oqs_version, +) + +__all__: tuple[str, ...] \ No newline at end of file diff --git a/oqs/oqs.pyi b/oqs/oqs.pyi new file mode 100644 index 0000000..4b2fb2f --- /dev/null +++ b/oqs/oqs.pyi @@ -0,0 +1,94 @@ +import ctypes +from types import TracebackType +from typing import Final, TypeVar + +_TKeyEncapsulation = TypeVar("_TKeyEncapsulation", bound="KeyEncapsulation") +_TSignature = TypeVar("_TSignature", bound="Signature") + +OQS_SUCCESS: Final[int] +OQS_ERROR: Final[int] +OQS_VERSION: str | None + +def oqs_python_version() -> str | None: ... +def native() -> ctypes.CDLL: ... +def oqs_version() -> str: ... + +class MechanismNotSupportedError(Exception): + alg_name: str + message: str + def __init__(self, alg_name: str) -> None: ... + +class MechanismNotEnabledError(MechanismNotSupportedError): + # alg_name and message are inherited from MechanismNotSupportedError + def __init__(self, alg_name: str) -> None: ... + +class KeyEncapsulation: + # Attributes from the underlying ctypes.Structure, exposed with Python types + method_name: bytes + alg_version: bytes + claimed_nist_level: int + ind_cca: int + length_public_key: int + length_secret_key: int + length_ciphertext: int + length_shared_secret: int + + # Custom attributes set during initialization + alg_name: str + details: dict[str, str | int | bool] + + def __init__(self, alg_name: str, secret_key: int | bytes | None = None) -> None: ... + def __enter__(self: _TKeyEncapsulation) -> _TKeyEncapsulation: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: ... + def generate_keypair(self) -> bytes: ... + def export_secret_key(self) -> bytes: ... + def encap_secret(self, public_key: int | bytes) -> tuple[bytes, bytes]: ... + def decap_secret(self, ciphertext: int | bytes) -> bytes: ... + def free(self) -> None: ... + def __repr__(self) -> str: ... + +class Signature: + # Attributes from the underlying ctypes.Structure, exposed with Python types + method_name: bytes + alg_version: bytes + claimed_nist_level: int + euf_cma: int + sig_with_ctx_support: int + length_public_key: int + length_secret_key: int + length_signature: int + + # Custom attributes set during initialization + alg_name: str + details: dict[str, str | int | bool] + + def __init__(self, alg_name: str, secret_key: int | bytes | None = None) -> None: ... + def __enter__(self: _TSignature) -> _TSignature: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: ... + def generate_keypair(self) -> bytes: ... + def export_secret_key(self) -> bytes: ... + def sign(self, message: bytes) -> bytes: ... + def verify(self, message: bytes, signature: bytes, public_key: bytes) -> bool: ... + def sign_with_ctx_str(self, message: bytes, context: bytes) -> bytes: ... + def verify_with_ctx_str( + self, message: bytes, signature: bytes, context: bytes, public_key: bytes + ) -> bool: ... + def free(self) -> None: ... + def __repr__(self) -> str: ... + +def is_kem_enabled(alg_name: str) -> bool: ... +def get_enabled_kem_mechanisms() -> tuple[str, ...]: ... +def get_supported_kem_mechanisms() -> tuple[str, ...]: ... +def is_sig_enabled(alg_name: str) -> bool: ... +def get_enabled_sig_mechanisms() -> tuple[str, ...]: ... +def get_supported_sig_mechanisms() -> tuple[str, ...]: ... \ No newline at end of file diff --git a/oqs/py.typed b/oqs/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/oqs/rand.pyi b/oqs/rand.pyi new file mode 100644 index 0000000..f3350f9 --- /dev/null +++ b/oqs/rand.pyi @@ -0,0 +1,2 @@ +def randombytes(bytes_to_read: int) -> bytes: ... +def randombytes_switch_algorithm(alg_name: str) -> None: ... \ No newline at end of file From 43d1c0e99b39b92e543698d559cbfa694c096fea Mon Sep 17 00:00:00 2001 From: M-AlNoaimi <26318936+M-AlNoaimi@users.noreply.github.com> Date: Fri, 23 May 2025 02:08:30 +0100 Subject: [PATCH 2/2] Improved oqs stub to use @final for classes and TypedDict for details attributes & Removed init stub to be more flexible (when making edits directly down the line). Signed-off-by: M-AlNoaimi <26318936+M-AlNoaimi@users.noreply.github.com> --- oqs/__init__.pyi | 20 -------------------- oqs/oqs.pyi | 30 ++++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 24 deletions(-) delete mode 100644 oqs/__init__.pyi diff --git a/oqs/__init__.pyi b/oqs/__init__.pyi deleted file mode 100644 index 9b219b6..0000000 --- a/oqs/__init__.pyi +++ /dev/null @@ -1,20 +0,0 @@ -# Re-export symbols from oqs/__init__.py for type hinting -from .oqs import ( - KeyEncapsulation, - MechanismNotEnabledError, - MechanismNotSupportedError, - OQS_SUCCESS, - OQS_VERSION, - Signature, - get_enabled_kem_mechanisms, - get_enabled_sig_mechanisms, - get_supported_kem_mechanisms, - get_supported_sig_mechanisms, - is_kem_enabled, - is_sig_enabled, - native, - oqs_python_version, - oqs_version, -) - -__all__: tuple[str, ...] \ No newline at end of file diff --git a/oqs/oqs.pyi b/oqs/oqs.pyi index 4b2fb2f..9315858 100644 --- a/oqs/oqs.pyi +++ b/oqs/oqs.pyi @@ -1,6 +1,6 @@ import ctypes from types import TracebackType -from typing import Final, TypeVar +from typing import Final, TypeVar, final, TypedDict _TKeyEncapsulation = TypeVar("_TKeyEncapsulation", bound="KeyEncapsulation") _TSignature = TypeVar("_TSignature", bound="Signature") @@ -22,6 +22,17 @@ class MechanismNotEnabledError(MechanismNotSupportedError): # alg_name and message are inherited from MechanismNotSupportedError def __init__(self, alg_name: str) -> None: ... +class KeyEncapsulationDetails(TypedDict): + name: str + version: str + claimed_nist_level: int + is_ind_cca: bool + length_public_key: int + length_secret_key: int + length_ciphertext: int + length_shared_secret: int + +@final class KeyEncapsulation: # Attributes from the underlying ctypes.Structure, exposed with Python types method_name: bytes @@ -35,7 +46,7 @@ class KeyEncapsulation: # Custom attributes set during initialization alg_name: str - details: dict[str, str | int | bool] + details: KeyEncapsulationDetails def __init__(self, alg_name: str, secret_key: int | bytes | None = None) -> None: ... def __enter__(self: _TKeyEncapsulation) -> _TKeyEncapsulation: ... @@ -52,6 +63,17 @@ class KeyEncapsulation: def free(self) -> None: ... def __repr__(self) -> str: ... +class SignatureDetails(TypedDict): + name: str + version: str + claimed_nist_level: int + is_euf_cma: bool + sig_with_ctx_support: bool + length_public_key: int + length_secret_key: int + length_signature: int + +@final class Signature: # Attributes from the underlying ctypes.Structure, exposed with Python types method_name: bytes @@ -65,7 +87,7 @@ class Signature: # Custom attributes set during initialization alg_name: str - details: dict[str, str | int | bool] + details: SignatureDetails def __init__(self, alg_name: str, secret_key: int | bytes | None = None) -> None: ... def __enter__(self: _TSignature) -> _TSignature: ... @@ -91,4 +113,4 @@ def get_enabled_kem_mechanisms() -> tuple[str, ...]: ... def get_supported_kem_mechanisms() -> tuple[str, ...]: ... def is_sig_enabled(alg_name: str) -> bool: ... def get_enabled_sig_mechanisms() -> tuple[str, ...]: ... -def get_supported_sig_mechanisms() -> tuple[str, ...]: ... \ No newline at end of file +def get_supported_sig_mechanisms() -> tuple[str, ...]: ...