Skip to content

Improve documentation #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a10dd27
Add type annotations to _compat.py
tekktrik Mar 25, 2022
9651119
Add type annotations to common.py
tekktrik Mar 25, 2022
c34d9c0
Add type annotations to core.py
tekktrik Mar 25, 2022
08f5020
Add tpe annotations for key.py
tekktrik Mar 25, 2022
9bc7377
Add type annotations to machine_size.py
tekktrik Mar 25, 2022
75c5e5f
Add type annotations to pem.py
tekktrik Mar 25, 2022
257441f
Add type annotations to pkcs1.py
tekktrik Mar 25, 2022
c33547c
Add type annotations for prime.py
tekktrik Mar 25, 2022
421d4a8
Add type annotations to randnum.py
tekktrik Mar 25, 2022
4956f38
Add type annotations to transform.py
tekktrik Mar 25, 2022
b1c4be3
Require Blinka >= 7.0.0 for Protocol
tekktrik Mar 25, 2022
7a98b65
Add pyasn1 as dependency
tekktrik Mar 30, 2022
b818b42
Update module docstrings
tekktrik Mar 30, 2022
3e13a78
Update method and class docstrings
tekktrik Mar 30, 2022
6f2a1cf
Add missing modules from api.rst
tekktrik Mar 30, 2022
98d64d4
Change :returns: to :return:
tekktrik Mar 30, 2022
0b5074d
Updated to new version of black
tekktrik Mar 30, 2022
5281aa0
Ran new version of black via pre-commit
tekktrik Mar 30, 2022
df66778
Merge branch 'adafruit:main' into doc/add-typing
tekktrik Mar 30, 2022
3f67aa1
Actually add pyasn1 to requirements.txt
tekktrik Mar 30, 2022
dfc52d0
Update module docstrings
tekktrik Mar 30, 2022
2faabe8
Update method and class docstrings
tekktrik Mar 30, 2022
44cac6f
Add missing modules from api.rst
tekktrik Mar 30, 2022
f89e0c8
Change :returns: to :return:
tekktrik Mar 30, 2022
e964710
Update Black to latest.
kattni Mar 28, 2022
0e80f9d
Ran new version of black via pre-commit
tekktrik Mar 30, 2022
c23a85a
Merge branch 'doc/add-typing' of https://github.com/tekktrik/Adafruit…
tekktrik Apr 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This driver depends on:

* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
* `Adafruit CircuitPython Logger Module <https://github.com/adafruit/Adafruit_CircuitPython_Logger>`_
* `pyasn1 Module <https://github.com/etingof/pyasn1>`_

Please ensure all dependencies are available on the CircuitPython filesystem.
This is easily achieved by downloading
Expand Down
6 changes: 4 additions & 2 deletions adafruit_rsa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
#
# SPDX-License-Identifier: Apache-2.0

"""RSA module
"""
RSA module
====================================================

Module for calculating large primes, and RSA encryption, decryption, signing
and verification. Includes generating public and private keys.

WARNING: this implementation does not use compression of the cleartext input to
**WARNING:** This implementation does not use compression of the cleartext input to
prevent repetitions, or other common security improvements. Use with care.

"""
Expand Down
63 changes: 36 additions & 27 deletions adafruit_rsa/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@
#
# SPDX-License-Identifier: Apache-2.0

"""Python compatibility wrappers."""
"""
`adafruit_rsa._compat`
====================================================

Python compatibility wrappers.
"""

import sys
from struct import pack

try:
from typing import Any, Literal, Tuple
except ImportError:
pass

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RSA.git"

Expand All @@ -31,87 +41,86 @@
INTEGER_TYPES = (int,)


def write_to_stdout(data):
def write_to_stdout(data: bytes) -> None:
"""Writes bytes to stdout

:type data: bytes
:param bytes data: Data to write
"""
# On Py3 we must use the buffer interface to write bytes.
sys.stdout.buffer.write(data)


def is_bytes(obj):
def is_bytes(obj: Any) -> bool:
"""
Determines whether the given value is a byte string.

:param obj:
The value to test.
:returns:
``True`` if ``value`` is a byte string; ``False`` otherwise.
:return:
``True`` if ``obj`` is a byte string; ``False`` otherwise.
"""
return isinstance(obj, bytes)


def is_integer(obj):
def is_integer(obj: Any) -> bool:
"""
Determines whether the given value is an integer.

:param obj:
The value to test.
:returns:
``True`` if ``value`` is an integer; ``False`` otherwise.
:return:
``True`` if ``obj`` is an integer; ``False`` otherwise.
"""
return isinstance(obj, INTEGER_TYPES)


def byte(num):
def byte(num: int) -> bytes:
"""
Converts a number between 0 and 255 (both inclusive) to a base-256 (byte)
representation.

Use it as a replacement for ``chr`` where you are expecting a byte
because this will work on all current versions of Python::

:param num:
An unsigned integer between 0 and 255 (both inclusive).
:returns:
A single byte.
:param int num: An unsigned integer between 0 and 255 (both inclusive).
:return: A single byte.
"""
return pack("B", num)


def xor_bytes(bytes_1, bytes_2):
def xor_bytes(bytes_1: bytes, bytes_2: bytes) -> bytes:
"""
Returns the bitwise XOR result between two bytes objects, bytes_1 ^ bytes_2.

Bitwise XOR operation is commutative, so order of parameters doesn't
generate different results. If parameters have different length, extra
length of the largest one is ignored.

:param bytes_1:
First bytes object.
:param bytes_2:
Second bytes object.
:returns:
Bytes object, result of XOR operation.
:param bytes bytes_1: First bytes object.
:param bytes_2: Second bytes object.
:return: Bytes object, result of XOR operation.
"""
return bytes(x ^ y for x, y in zip(bytes_1, bytes_2))


def get_word_alignment(num, force_arch=64, _machine_word_size=MACHINE_WORD_SIZE):
def get_word_alignment(
num: int,
force_arch: int = 64,
_machine_word_size: Literal[64, 32] = MACHINE_WORD_SIZE,
) -> Tuple[int, int, int, str]:
"""
Returns alignment details for the given number based on the platform
Python is running on.

:param num:
Unsigned integral number.
:param force_arch:
:param int num:
Unsigned integer number.
:param int force_arch:
If you don't want to use 64-bit unsigned chunks, set this to
anything other than 64. 32-bit chunks will be preferred then.
Default 64 will be used when on a 64-bit machine.
:param _machine_word_size:
:param int _machine_word_size:
(Internal) The machine word size used for alignment.
:returns:
:return:
4-tuple::

(word_bits, word_bytes,
Expand Down
6 changes: 5 additions & 1 deletion adafruit_rsa/asn1.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
#
# SPDX-License-Identifier: Apache-2.0

"""ASN.1 definitions.
"""
`adafruit_rsa.asn1`
====================================================

ASN.1 definitions.

Not all ASN.1-handling code use these definitions, but when it does, they should be here.
"""
Expand Down
59 changes: 35 additions & 24 deletions adafruit_rsa/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,31 @@
#
# SPDX-License-Identifier: Apache-2.0

"""Common functionality shared by several modules."""
"""
`adafruit_rsa.common`
====================================================

Common functionality shared by several modules.
"""

# pylint: disable=invalid-name

try:
from typing import Optional, Tuple, Sequence
except ImportError:
pass

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RSA.git"


def bit_length(int_type):
def bit_length(int_type: int) -> int:
"""Return the number of bits necessary to represent an integer in binary,
excluding the sign and leading zeros"""
excluding the sign and leading zeros

:param int int_type: The integer to check
"""

length = 0
while int_type:
int_type >>= 1
Expand All @@ -24,7 +38,7 @@ def bit_length(int_type):
class NotRelativePrimeError(ValueError):
"""Raises if provided a and b not relatively prime."""

def __init__(self, a, b, d, msg=None):
def __init__(self, a: int, b: int, d: int, msg: Optional[str] = None):
super().__init__(
msg or "%d and %d are not relatively prime, divider=%i" % (a, b, d)
)
Expand All @@ -33,7 +47,7 @@ def __init__(self, a, b, d, msg=None):
self.d = d


def bit_size(num):
def bit_size(num: int) -> int:
"""
Number of bits needed to represent a integer excluding any prefix
0 bits.
Expand All @@ -47,11 +61,11 @@ def bit_size(num):
>>> bit_size(1025)
11

:param num:
:param int num:
Integer value. If num is 0, returns 0. Only the absolute value of the
number is considered. Therefore, signed integers will be abs(num)
before the number's bit length is determined.
:returns:
:return:
Returns the number of bits in the integer.
"""

Expand All @@ -63,7 +77,7 @@ def bit_size(num):
) from err


def byte_size(number):
def byte_size(number: int) -> int:
"""
Returns the number of bytes required to hold a specific long number.

Expand All @@ -78,21 +92,19 @@ def byte_size(number):
>>> byte_size(1 << 1024)
129

:param number:
An unsigned integer
:returns:
The number of bytes required to hold a specific long number.
:param int number: An unsigned integer
:return: The number of bytes required to hold a specific long number.
"""
if number == 0:
return 1
return ceil_div(bit_size(number), 8)


def ceil_div(num, div):
def ceil_div(num: int, div: int) -> int:
"""
Returns the ceiling function of a division between `num` and `div`.
Returns the ceiling function of a division between ``num`` and ``div``.

Usage::
Usage:

>>> ceil_div(100, 7)
15
Expand All @@ -101,9 +113,8 @@ def ceil_div(num, div):
>>> ceil_div(1, 4)
1

:param num: Division's numerator, a number
:param div: Division's divisor, a number

:param int num: Division's numerator, a number
:param int div: Division's divisor, a number
:return: Rounded up result of the division between the parameters.
"""
quanta, mod = divmod(num, div)
Expand All @@ -112,7 +123,7 @@ def ceil_div(num, div):
return quanta


def extended_gcd(a, b):
def extended_gcd(a: int, b: int) -> Tuple[int, int, int]:
"""Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb"""
# r = gcd(a,b) i = multiplicitive inverse of a mod b
# or j = multiplicitive inverse of b mod a
Expand All @@ -136,7 +147,7 @@ def extended_gcd(a, b):
return a, lx, ly # Return only positive values


def inverse(x, n):
def inverse(x: int, n: int) -> int:
"""Returns the inverse of x % n under multiplication, a.k.a x^-1 (mod n)

>>> inverse(7, 4)
Expand All @@ -153,14 +164,14 @@ def inverse(x, n):
return inv


def crt(a_values, modulo_values):
def crt(a_values: Sequence[int], modulo_values: Sequence[int]) -> int:
"""Chinese Remainder Theorem.

Calculates x such that x = a[i] (mod m[i]) for each i.

:param a_values: the a-values of the above equation
:param modulo_values: the m-values of the above equation
:returns: x such that x = a[i] (mod m[i]) for each i
:param Sequence[int] a_values: the a-values of the above equation
:param Sequence[int] modulo_values: the m-values of the above equation
:return: x such that x = a[i] (mod m[i]) for each i


>>> crt([2, 3], [3, 5])
Expand Down
20 changes: 15 additions & 5 deletions adafruit_rsa/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
#
# SPDX-License-Identifier: Apache-2.0

"""Core mathematical operations.
"""
`adafruit_rsa.core`
====================================================

Core mathematical operations.

This is the actual core RSA implementation, which is only defined
mathematically on integers.
Expand All @@ -12,12 +16,18 @@
# pylint: disable=invalid-name
from adafruit_rsa._compat import is_integer

try:
from typing import Any
except ImportError:
pass

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RSA.git"


def fast_pow(x, e, m):
def fast_pow(x: int, e: int, m: int) -> int:
"""Performs fast modular exponentiation, saves RAM on small CPUs/micros.

:param int x: Base
:param int y: Exponent
:param int e: Second exponent
Expand All @@ -35,15 +45,15 @@ def fast_pow(x, e, m):
return Y


def assert_int(var, name):
def assert_int(var: Any, name: str) -> None:
"""Asserts provided variable is an integer."""
if is_integer(var):
return

raise TypeError("%s should be an integer, not %s" % (name, var.__class__))


def encrypt_int(message, ekey, n):
def encrypt_int(message: int, ekey: int, n: int) -> int:
"""Encrypts a message using encryption key 'ekey', working modulo n"""

assert_int(message, "message")
Expand All @@ -61,7 +71,7 @@ def encrypt_int(message, ekey, n):
return fast_pow(message, ekey, n)


def decrypt_int(cyphertext, dkey, n):
def decrypt_int(cyphertext: int, dkey: int, n: int) -> int:
"""Decrypts a cypher text using the decryption key 'dkey', working modulo n"""

assert_int(cyphertext, "cyphertext")
Expand Down
Loading