Skip to content

Commit

Permalink
Finish off annotating nacl (#724)
Browse files Browse the repository at this point in the history
* Reorder subpackages above top-level modules

* Annotations for nacl.hash

* Annotations for nacl.hashlib

* annotations for nacl.secret

* annotations for nacl.public

Had some fun merging in the changes from #692 with #706.

I didn't go all-in to make `PrivateKey`'s classmethods take a generic
`cls` parameter. Felt it was easier to keep things simple.

* Annotations for nacl.signing

* Tidy up mypy config

Now that all files are annotated, apply common settings globally so that
the overrides only apply to `nacl.bindings`.

In doing so, account for an `Any`-expression in `scrypt.py`. I must not
have correctly configured mypy for `nacl.pwhash` in #718: I think it
should have been `nacl.pwhash.*` instead of `nacl.pwhash`.

* Include a PEP 561 `py.typed` marker file
  • Loading branch information
DMRobertson committed Dec 21, 2021
1 parent 78b5030 commit b9a14e1
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 111 deletions.
44 changes: 15 additions & 29 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,11 @@ target-version = ["py36"]

[tool.mypy]
show_error_codes = true
check_untyped_defs = true
no_implicit_reexport = true
warn_redundant_casts = true
warn_incomplete_stub = true

files = ["src/nacl"]

[[tool.mypy.overrides]]
module = [
"nacl._sodium",
]
ignore_missing_imports = true

# Most options can be applied across the entire project.
[[tool.mypy.overrides]]
module = [
"nacl.bindings",
"nacl.encoding",
"nacl.exceptions",
"nacl.pwhash",
"nacl.utils",
]
disallow_any_unimported = true
# disallow_any_expr: true outside of `bindings`
disallow_any_expr = true # overridden to `false` inside `nacl.bindings`
disallow_any_decorated = true
disallow_any_explicit = true
disallow_any_generics = true
Expand All @@ -45,19 +26,27 @@ disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
# check_untyped_defs enabled globally
check_untyped_defs = true
disallow_untyped_decorators = true

no_implicit_optional = true

warn_unused_ignores = true
warn_no_return = true
# warn_return_any: true outside of `bindings`
warn_return_any = true # overridden to `false` inside `nacl.bindings`
warn_unreachable = true

# no-implicit-reexport enabled globally
no_implicit_reexport = true
strict_equality = true

files = ["src/nacl"]

[[tool.mypy.overrides]]
module = [
"nacl._sodium",
]
ignore_missing_imports = true

# Within `nacl.bindings`, all of the C functions exposed via cffi in
# nacl._sodium return `Any` as far as mypy is concerned. It's not worth it to
# stub the C functions or cast() their uses. But this means there are more
Expand All @@ -66,11 +55,8 @@ strict_equality = true

[[tool.mypy.overrides]]
module = [
"nacl.encoding",
"nacl.exceptions",
"nacl.utils",
"nacl.pwhash",
"nacl.bindings.*",
]
disallow_any_expr = true
warn_return_any = true
disallow_any_expr = false
warn_return_any = false

1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ def run(self):
tests_require=test_requirements,
package_dir={"": "src"},
packages=["nacl", "nacl.pwhash", "nacl.bindings"],
package_data={"nacl": ["py.typed"]},
ext_package="nacl",
cffi_modules=["src/bindings/build.py:ffi"],
cmdclass={"build_clib": build_clib, "build_ext": build_ext},
Expand Down
34 changes: 23 additions & 11 deletions src/nacl/hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@
_sip_hashx = nacl.bindings.crypto_shorthash_siphashx24


def sha256(message, encoder=nacl.encoding.HexEncoder):
def sha256(
message: bytes, encoder: nacl.encoding.Encoder = nacl.encoding.HexEncoder
) -> bytes:
"""
Hashes ``message`` with SHA256.
Expand All @@ -72,7 +74,9 @@ def sha256(message, encoder=nacl.encoding.HexEncoder):
return encoder.encode(nacl.bindings.crypto_hash_sha256(message))


def sha512(message, encoder=nacl.encoding.HexEncoder):
def sha512(
message: bytes, encoder: nacl.encoding.Encoder = nacl.encoding.HexEncoder
) -> bytes:
"""
Hashes ``message`` with SHA512.
Expand All @@ -86,13 +90,13 @@ def sha512(message, encoder=nacl.encoding.HexEncoder):


def blake2b(
data,
digest_size=BLAKE2B_BYTES,
key=b"",
salt=b"",
person=b"",
encoder=nacl.encoding.HexEncoder,
):
data: bytes,
digest_size: int = BLAKE2B_BYTES,
key: bytes = b"",
salt: bytes = b"",
person: bytes = b"",
encoder: nacl.encoding.Encoder = nacl.encoding.HexEncoder,
) -> bytes:
"""
Hashes ``data`` with blake2b.
Expand Down Expand Up @@ -129,7 +133,11 @@ def blake2b(
generichash = blake2b


def siphash24(message, key=b"", encoder=nacl.encoding.HexEncoder):
def siphash24(
message: bytes,
key: bytes = b"",
encoder: nacl.encoding.Encoder = nacl.encoding.HexEncoder,
) -> bytes:
"""
Computes a keyed MAC of ``message`` using the short-input-optimized
siphash-2-4 construction.
Expand All @@ -149,7 +157,11 @@ def siphash24(message, key=b"", encoder=nacl.encoding.HexEncoder):
shorthash = siphash24


def siphashx24(message, key=b"", encoder=nacl.encoding.HexEncoder):
def siphashx24(
message: bytes,
key: bytes = b"",
encoder: nacl.encoding.Encoder = nacl.encoding.HexEncoder,
) -> bytes:
"""
Computes a keyed MAC of ``message`` using the 128 bit variant of the
siphash-2-4 construction.
Expand Down
34 changes: 24 additions & 10 deletions src/nacl/hashlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@


import binascii
from typing import NoReturn

import nacl.bindings
from nacl.utils import bytes_as_string
Expand Down Expand Up @@ -45,7 +46,12 @@ class blake2b:
SALT_SIZE = SALTBYTES

def __init__(
self, data=b"", digest_size=BYTES, key=b"", salt=b"", person=b""
self,
data: bytes = b"",
digest_size: int = BYTES,
key: bytes = b"",
salt: bytes = b"",
person: bytes = b"",
):
"""
:py:class:`.blake2b` algorithm initializer
Expand Down Expand Up @@ -77,34 +83,34 @@ def __init__(
self.update(data)

@property
def digest_size(self):
def digest_size(self) -> int:
return self._digest_size

@property
def block_size(self):
def block_size(self) -> int:
return 128

@property
def name(self):
def name(self) -> str:
return "blake2b"

def update(self, data):
def update(self, data: bytes) -> None:
_b2b_update(self._state, data)

def digest(self):
def digest(self) -> bytes:
_st = self._state.copy()
return _b2b_final(_st)

def hexdigest(self):
def hexdigest(self) -> str:
return bytes_as_string(binascii.hexlify(self.digest()))

def copy(self):
def copy(self) -> "blake2b":
_cp = type(self)(digest_size=self.digest_size)
_st = self._state.copy()
_cp._state = _st
return _cp

def __reduce__(self):
def __reduce__(self) -> NoReturn:
"""
Raise the same exception as hashlib's blake implementation
on copy.copy()
Expand All @@ -114,7 +120,15 @@ def __reduce__(self):
)


def scrypt(password, salt="", n=2 ** 20, r=8, p=1, maxmem=2 ** 25, dklen=64):
def scrypt(
password: bytes,
salt: bytes = b"",
n: int = 2 ** 20,
r: int = 8,
p: int = 1,
maxmem: int = 2 ** 25,
dklen: int = 64,
) -> bytes:
"""
Derive a cryptographic key using the scrypt KDF.
Expand Down
Loading

0 comments on commit b9a14e1

Please sign in to comment.