Skip to content

Commit

Permalink
Merge pull request #189 from KPrasch/monkeytype
Browse files Browse the repository at this point in the history
PEP 484 Type Hints for pyUmbral
  • Loading branch information
tuxxy authored Jul 9, 2018
2 parents 062d4d9 + 53ce33e commit 23bc511
Show file tree
Hide file tree
Showing 15 changed files with 290 additions and 185 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,4 @@ pytest.ini
/tests/metrics/.benchmarks/
tests/metrics/histograms/
.circleci/execute_build.sh
/monkeytype.sqlite3
7 changes: 4 additions & 3 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[mypy]
python_version=3.6
verbosity=1
verbosity=0
ignore_missing_imports=True
[mypy-umbral.*]
disallow_untyped_defs=True
disallow_untyped_defs=False
check_untyped_defs=False
disallow_untyped_calls=True
disallow_untyped_calls=False
[mypy-umbral.openssl]
disallow_untyped_defs=False
62 changes: 62 additions & 0 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from collections import namedtuple

import pytest

from umbral import keys
from umbral.curvebn import CurveBN
from umbral.point import Point

MockKeyPair = namedtuple('TestKeyPair', 'priv pub')


parameters = [
# (N, M)
(1, 1),
(6, 1),
(6, 4),
(6, 6),
(50, 30)
]

wrong_parameters = [
# (N, M)
(-1, -1), (-1, 0), (-1, 5),
(0, -1), (0, 0), (0, 5),
(1, -1), (1, 0), (1, 5),
(5, -1), (5, 0), (5, 10)
]


@pytest.fixture(scope='function')
def alices_keys():
delegating_priv = keys.UmbralPrivateKey.gen_key()
signing_priv = keys.UmbralPrivateKey.gen_key()
return delegating_priv, signing_priv


@pytest.fixture(scope='function')
def bobs_keys():
priv = keys.UmbralPrivateKey.gen_key()
pub = priv.get_pubkey()
return MockKeyPair(priv, pub)


@pytest.fixture()
def random_ec_point1():
yield Point.gen_rand()


@pytest.fixture()
def random_ec_point2():
yield Point.gen_rand()


@pytest.fixture()
def random_ec_curvebn1():
yield CurveBN.gen_rand()


@pytest.fixture()
def random_ec_curvebn2():
yield CurveBN.gen_rand()

27 changes: 14 additions & 13 deletions umbral/_pre.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
from typing import Optional

from umbral.curvebn import CurveBN
from umbral.config import default_params
from umbral.keys import UmbralPublicKey
from umbral.params import UmbralParameters


def prove_cfrag_correctness(cfrag: "CapsuleFrag",
kfrag: "KFrag",
capsule: "Capsule",
metadata: bytes = None
) -> "CorrectnessProof":
def prove_cfrag_correctness(cfrag: 'CapsuleFrag',
kfrag: 'KFrag',
capsule: 'Capsule',
metadata: Optional[bytes] = None
) -> 'CorrectnessProof':

params = capsule._umbral_params

rk = kfrag._bn_key
t = CurveBN.gen_rand(params.curve)
####
## Here are the formulaic constituents shared with `assess_cfrag_correctness`.
# Here are the formulaic constituents shared with `assess_cfrag_correctness`.
####
e = capsule._point_e
v = capsule._point_v
Expand Down Expand Up @@ -45,7 +46,7 @@ def prove_cfrag_correctness(cfrag: "CapsuleFrag",
raise capsule.NotValid("Capsule verification failed.")


def assess_cfrag_correctness(cfrag, capsule: "Capsule"):
def assess_cfrag_correctness(cfrag: 'CapsuleFrag', capsule: 'Capsule') -> bool:

correctness_keys = capsule.get_correctness_keys()

Expand All @@ -62,7 +63,7 @@ def assess_cfrag_correctness(cfrag, capsule: "Capsule"):
params = capsule._umbral_params

####
## Here are the formulaic constituents shared with `prove_cfrag_correctness`.
# Here are the formulaic constituents shared with `prove_cfrag_correctness`.
####
e = capsule._point_e
v = capsule._point_v
Expand Down Expand Up @@ -110,11 +111,11 @@ def assess_cfrag_correctness(cfrag, capsule: "Capsule"):
& correct_rk_commitment


def verify_kfrag(kfrag,
def verify_kfrag(kfrag: 'KFrag',
delegating_pubkey: UmbralPublicKey,
signing_pubkey,
signing_pubkey: UmbralPublicKey,
receiving_pubkey: UmbralPublicKey
):
) -> bool:


params = delegating_pubkey.params
Expand Down
14 changes: 8 additions & 6 deletions umbral/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from typing import Optional, Type
from warnings import warn

from umbral.curve import Curve, SECP256K1
from umbral.params import UmbralParameters


class _CONFIG:
Expand All @@ -18,19 +20,19 @@ def __set_curve_by_default(cls):
cls.set_curve(cls.__CURVE_TO_USE_IF_NO_DEFAULT_IS_SET_BY_USER)

@classmethod
def params(cls):
def params(cls) -> UmbralParameters:
if not cls.__params:
cls.__set_curve_by_default()
return cls.__params

@classmethod
def curve(cls):
def curve(cls) -> Type[Curve]:
if not cls.__curve:
cls.__set_curve_by_default()
return cls.__curve

@classmethod
def set_curve(cls, curve: Curve=None):
def set_curve(cls, curve: Optional[Curve] = None) -> None:
if cls.__curve:
raise cls.UmbralConfigurationError(
"You can only set the default curve once. Do it once and then leave it alone.")
Expand All @@ -42,13 +44,13 @@ def set_curve(cls, curve: Curve=None):
cls.__params = UmbralParameters(curve)


def set_default_curve(curve: Curve=None):
def set_default_curve(curve: Optional[Curve] = None) -> None:
return _CONFIG.set_curve(curve)


def default_curve():
def default_curve() -> Type[Curve]:
return _CONFIG.curve()


def default_params():
def default_params() -> UmbralParameters:
return _CONFIG.params()
36 changes: 17 additions & 19 deletions umbral/curvebn.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import os

from cryptography.hazmat.backends.openssl import backend
from cryptography.hazmat.primitives import hashes

from umbral import openssl
from umbral.config import default_curve, default_params
from umbral.config import default_curve
from umbral.curve import Curve
from umbral.utils import get_field_order_size_in_bytes
from umbral.params import UmbralParameters
from umbral.utils import get_field_order_size_in_bytes


class CurveBN(object):
Expand All @@ -27,7 +25,7 @@ def __init__(self, bignum, curve: Curve):
self.curve = curve

@classmethod
def expected_bytes_length(cls, curve: Curve=None):
def expected_bytes_length(cls, curve: Curve=None) -> int:
"""
Returns the size (in bytes) of a CurveBN given the curve.
If no curve is provided, it uses the default.
Expand All @@ -36,7 +34,7 @@ def expected_bytes_length(cls, curve: Curve=None):
return get_field_order_size_in_bytes(curve)

@classmethod
def gen_rand(cls, curve: Curve=None):
def gen_rand(cls, curve: Curve=None) -> 'CurveBN':
"""
Returns a CurveBN object with a cryptographically secure OpenSSL BIGNUM
based on the given curve.
Expand All @@ -56,7 +54,7 @@ def gen_rand(cls, curve: Curve=None):
return cls(new_rand_bn, curve)

@classmethod
def from_int(cls, num, curve: Curve=None):
def from_int(cls, num: int, curve: Curve=None) -> 'CurveBN':
"""
Returns a CurveBN object from a given integer on a curve.
By default, the underlying OpenSSL BIGNUM has BN_FLG_CONSTTIME set for
Expand All @@ -67,7 +65,7 @@ def from_int(cls, num, curve: Curve=None):
return cls(conv_bn, curve)

@classmethod
def hash(cls, *crypto_items, params: UmbralParameters):
def hash(cls, *crypto_items, params: UmbralParameters) -> 'CurveBN':
# TODO: Clean this in an upcoming cleanup of pyUmbral
blake2b = hashes.Hash(hashes.BLAKE2b(64), backend=backend)
for item in crypto_items:
Expand Down Expand Up @@ -101,7 +99,7 @@ def hash(cls, *crypto_items, params: UmbralParameters):
return cls(bignum, params.curve)

@classmethod
def from_bytes(cls, data, curve: Curve=None):
def from_bytes(cls, data: bytes, curve: Curve=None) -> 'CurveBN':
"""
Returns a CurveBN object from the given byte data that's within the size
of the provided curve's order.
Expand All @@ -112,20 +110,20 @@ def from_bytes(cls, data, curve: Curve=None):
num = int.from_bytes(data, 'big')
return cls.from_int(num, curve)

def to_bytes(self):
def to_bytes(self) -> bytes:
"""
Returns the CurveBN as bytes.
"""
size = backend._lib.BN_num_bytes(self.curve.order)
return int.to_bytes(int(self), size, 'big')

def __int__(self):
def __int__(self) -> int:
"""
Converts the CurveBN to a Python int.
"""
return backend._bn_to_int(self.bignum)

def __eq__(self, other):
def __eq__(self, other) -> bool:
"""
Compares the two BIGNUMS or int.
"""
Expand All @@ -137,7 +135,7 @@ def __eq__(self, other):
# -1 less than, 0 is equal to, 1 is greater than
return not bool(backend._lib.BN_cmp(self.bignum, other.bignum))

def __pow__(self, other):
def __pow__(self, other) -> 'CurveBN':
"""
Performs a BN_mod_exp on two BIGNUMS.
Expand All @@ -157,7 +155,7 @@ def __pow__(self, other):

return CurveBN(power, self.curve)

def __mul__(self, other):
def __mul__(self, other) -> 'CurveBN':
"""
Performs a BN_mod_mul between two BIGNUMS.
"""
Expand All @@ -173,7 +171,7 @@ def __mul__(self, other):

return CurveBN(product, self.curve)

def __truediv__(self, other):
def __truediv__(self, other) -> 'CurveBN':
"""
Performs a BN_div on two BIGNUMs (modulo the order of the curve).
Expand All @@ -193,7 +191,7 @@ def __truediv__(self, other):

return CurveBN(product, self.curve)

def __add__(self, other):
def __add__(self, other) -> 'CurveBN':
"""
Performs a BN_mod_add on two BIGNUMs.
"""
Expand All @@ -206,7 +204,7 @@ def __add__(self, other):

return CurveBN(op_sum, self.curve)

def __sub__(self, other):
def __sub__(self, other) -> 'CurveBN':
"""
Performs a BN_mod_sub on two BIGNUMS.
"""
Expand All @@ -219,7 +217,7 @@ def __sub__(self, other):

return CurveBN(diff, self.curve)

def __invert__(self):
def __invert__(self) -> 'CurveBN':
"""
Performs a BN_mod_inverse.
Expand All @@ -235,7 +233,7 @@ def __invert__(self):

return CurveBN(inv, self.curve)

def __mod__(self, other):
def __mod__(self, other) -> 'CurveBN':
"""
Performs a BN_nnmod on two BIGNUMS.
"""
Expand Down
8 changes: 5 additions & 3 deletions umbral/dem.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import os
from typing import Optional

from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305


Expand All @@ -7,7 +9,7 @@


class UmbralDEM(object):
def __init__(self, symm_key: bytes):
def __init__(self, symm_key: bytes) -> None:
"""
Initializes an UmbralDEM object. Requires a key to perform
ChaCha20-Poly1305.
Expand All @@ -19,7 +21,7 @@ def __init__(self, symm_key: bytes):

self.cipher = ChaCha20Poly1305(symm_key)

def encrypt(self, data: bytes, authenticated_data: bytes=None):
def encrypt(self, data: bytes, authenticated_data: Optional[bytes] = None) -> bytes:
"""
Encrypts data using ChaCha20-Poly1305 with optional authenticated data.
"""
Expand All @@ -28,7 +30,7 @@ def encrypt(self, data: bytes, authenticated_data: bytes=None):
# Ciphertext will be a 12 byte nonce, the ciphertext, and a 16 byte tag.
return nonce + enc_data

def decrypt(self, ciphertext: bytes, authenticated_data: bytes=None):
def decrypt(self, ciphertext: bytes, authenticated_data: Optional[bytes] = None) -> bytes:
"""
Decrypts data using ChaCha20-Poly1305 and validates the provided
authenticated data.
Expand Down
Loading

0 comments on commit 23bc511

Please sign in to comment.