import sys
from _typeshed import ReadableBuffer
from collections.abc import Callable
from types import ModuleType
from typing import AnyStr, Protocol, final, overload, type_check_only
from typing_extensions import Self, TypeAlias

_DigestMod: TypeAlias = str | Callable[[], _HashObject] | ModuleType | None

openssl_md_meth_names: frozenset[str]

@type_check_only
class _HashObject(Protocol):
    @property
    def digest_size(self) -> int: ...
    @property
    def block_size(self) -> int: ...
    @property
    def name(self) -> str: ...
    def copy(self) -> Self: ...
    def digest(self) -> bytes: ...
    def hexdigest(self) -> str: ...
    def update(self, obj: ReadableBuffer, /) -> None: ...

class HASH:
    @property
    def digest_size(self) -> int: ...
    @property
    def block_size(self) -> int: ...
    @property
    def name(self) -> str: ...
    def copy(self) -> Self: ...
    def digest(self) -> bytes: ...
    def hexdigest(self) -> str: ...
    def update(self, obj: ReadableBuffer, /) -> None: ...

if sys.version_info >= (3, 10):
    class UnsupportedDigestmodError(ValueError): ...

if sys.version_info >= (3, 9):
    class HASHXOF(HASH):
        def digest(self, length: int) -> bytes: ...  # type: ignore[override]
        def hexdigest(self, length: int) -> str: ...  # type: ignore[override]

    @final
    class HMAC:
        @property
        def digest_size(self) -> int: ...
        @property
        def block_size(self) -> int: ...
        @property
        def name(self) -> str: ...
        def copy(self) -> Self: ...
        def digest(self) -> bytes: ...
        def hexdigest(self) -> str: ...
        def update(self, msg: ReadableBuffer) -> None: ...

    @overload
    def compare_digest(a: ReadableBuffer, b: ReadableBuffer, /) -> bool: ...
    @overload
    def compare_digest(a: AnyStr, b: AnyStr, /) -> bool: ...
    def get_fips_mode() -> int: ...
    def hmac_new(key: bytes | bytearray, msg: ReadableBuffer = b"", digestmod: _DigestMod = None) -> HMAC: ...
    def new(name: str, string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_md5(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha1(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha224(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha384(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha512(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha3_224(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha3_256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha3_384(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_sha3_512(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
    def openssl_shake_128(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASHXOF: ...
    def openssl_shake_256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASHXOF: ...

else:
    def new(name: str, string: ReadableBuffer = b"") -> HASH: ...
    def openssl_md5(string: ReadableBuffer = b"") -> HASH: ...
    def openssl_sha1(string: ReadableBuffer = b"") -> HASH: ...
    def openssl_sha224(string: ReadableBuffer = b"") -> HASH: ...
    def openssl_sha256(string: ReadableBuffer = b"") -> HASH: ...
    def openssl_sha384(string: ReadableBuffer = b"") -> HASH: ...
    def openssl_sha512(string: ReadableBuffer = b"") -> HASH: ...

def hmac_digest(key: bytes | bytearray, msg: ReadableBuffer, digest: str) -> bytes: ...
def pbkdf2_hmac(
    hash_name: str, password: ReadableBuffer, salt: ReadableBuffer, iterations: int, dklen: int | None = None
) -> bytes: ...
def scrypt(
    password: ReadableBuffer, *, salt: ReadableBuffer, n: int, r: int, p: int, maxmem: int = 0, dklen: int = 64
) -> bytes: ...
