Merge pull request #192 from cygnusv/curvebn-ops

Minor improvements to CurveBN
pull/198/head
Tux 2018-07-17 11:02:25 -06:00 committed by GitHub
commit ef2ff044d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 88 additions and 41 deletions

View File

@ -1,3 +1,4 @@
from cryptography.hazmat.backends.openssl import backend
from umbral.curvebn import CurveBN
@ -9,9 +10,10 @@ def test_mocked_openssl_curvebn_arithmetic(mock_openssl, random_ec_curvebn1, ran
random_ec_curvebn1 ** int(random_ec_curvebn2), # __pow__ (as int)
random_ec_curvebn1 + random_ec_curvebn2, # __add__
random_ec_curvebn1 - random_ec_curvebn2, # __sub__
-random_ec_curvebn1, # __neg__
random_ec_curvebn1 % random_ec_curvebn2, # __mod__
random_ec_curvebn1 % int(random_ec_curvebn2), # __mod__ (as int)
~random_ec_curvebn1, # __invert__
~random_ec_curvebn1, # __invert__
random_ec_curvebn1 / random_ec_curvebn2 # __truediv__
)
@ -21,3 +23,25 @@ def test_mocked_openssl_curvebn_arithmetic(mock_openssl, random_ec_curvebn1, ran
assert operator_result
assert isinstance(operator_result, CurveBN)
order = backend._bn_to_int(random_ec_curvebn1.curve.order)
random_ec_curvebn1 = int(random_ec_curvebn1)
random_ec_curvebn2 = int(random_ec_curvebn2)
# For simplicity, we test these two cases separately
assert (int(operations_that_construct[-2]) * random_ec_curvebn1) % order == 1
assert (int(operations_that_construct[-1]) * random_ec_curvebn2) % order == random_ec_curvebn1
# The remaining cases can be tested in bulk
expected_results = (
(random_ec_curvebn1 * random_ec_curvebn2) % order, # __mul__
pow(random_ec_curvebn1, random_ec_curvebn2, order), # __pow__
pow(random_ec_curvebn1, random_ec_curvebn2, order), # __pow__ (as int)
(random_ec_curvebn1 + random_ec_curvebn2) % order, # __add__
(random_ec_curvebn1 - random_ec_curvebn2) % order, # __sub__
(-random_ec_curvebn1) % order, # __neg__
random_ec_curvebn1 % random_ec_curvebn2, # __mod__
random_ec_curvebn1 % int(random_ec_curvebn2), # __mod__ (as int)
)
for (result, expected) in zip(operations_that_construct[:-2], expected_results):
assert result == expected

View File

@ -1,6 +1,6 @@
from cryptography.hazmat.backends import default_backend
from umbral import openssl
_AVAIL_CURVES = {
'secp256r1': 415,
'secp256k1': 714,
@ -40,6 +40,12 @@ class Curve:
def __repr__(self):
return "<OpenSSL Curve w/ NID {}>".format(self.curve_nid)
def get_field_order_size_in_bytes(self) -> int:
backend = default_backend()
size_in_bits = openssl._get_ec_group_degree(self.ec_group)
return (size_in_bits + 7) // 8
SECP256R1 = Curve(_AVAIL_CURVES['secp256r1'])
SECP256K1 = Curve(_AVAIL_CURVES['secp256k1'])

View File

@ -1,3 +1,5 @@
from typing import Optional, Union
from cryptography.hazmat.backends.openssl import backend
from cryptography.hazmat.primitives import hashes
@ -5,7 +7,6 @@ from umbral import openssl
from umbral.config import default_curve
from umbral.curve import Curve
from umbral.params import UmbralParameters
from umbral.utils import get_field_order_size_in_bytes
class CurveBN(object):
@ -25,16 +26,16 @@ class CurveBN(object):
self.curve = curve
@classmethod
def expected_bytes_length(cls, curve: Curve=None) -> int:
def expected_bytes_length(cls, curve: Optional[Curve] = None) -> int:
"""
Returns the size (in bytes) of a CurveBN given the curve.
If no curve is provided, it uses the default.
"""
curve = curve if curve is not None else default_curve()
return get_field_order_size_in_bytes(curve)
return curve.get_field_order_size_in_bytes()
@classmethod
def gen_rand(cls, curve: Curve=None) -> 'CurveBN':
def gen_rand(cls, curve: Optional[Curve] = None) -> 'CurveBN':
"""
Returns a CurveBN object with a cryptographically secure OpenSSL BIGNUM
based on the given curve.
@ -54,7 +55,7 @@ class CurveBN(object):
return cls(new_rand_bn, curve)
@classmethod
def from_int(cls, num: int, curve: Curve=None) -> 'CurveBN':
def from_int(cls, num: int, curve: Optional[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
@ -99,7 +100,7 @@ class CurveBN(object):
return cls(bignum, params.curve)
@classmethod
def from_bytes(cls, data: bytes, curve: Curve=None) -> 'CurveBN':
def from_bytes(cls, data: bytes, curve: Optional[Curve] = None) -> 'CurveBN':
"""
Returns a CurveBN object from the given byte data that's within the size
of the provided curve's order.
@ -123,7 +124,7 @@ class CurveBN(object):
"""
return backend._bn_to_int(self.bignum)
def __eq__(self, other) -> bool:
def __eq__(self, other : Union[int, 'CurveBN']) -> bool:
"""
Compares the two BIGNUMS or int.
"""
@ -135,7 +136,7 @@ class CurveBN(object):
# -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) -> 'CurveBN':
def __pow__(self, other : Union[int, 'CurveBN']) -> 'CurveBN':
"""
Performs a BN_mod_exp on two BIGNUMS.
@ -171,7 +172,7 @@ class CurveBN(object):
return CurveBN(product, self.curve)
def __truediv__(self, other) -> 'CurveBN':
def __truediv__(self, other : 'CurveBN') -> 'CurveBN':
"""
Performs a BN_div on two BIGNUMs (modulo the order of the curve).
@ -183,6 +184,7 @@ class CurveBN(object):
backend._ffi.NULL, other.bignum, self.curve.order, bn_ctx
)
backend.openssl_assert(inv_other != backend._ffi.NULL)
inv_other = backend._ffi.gc(inv_other, backend._lib.BN_clear_free)
res = backend._lib.BN_mod_mul(
product, self.bignum, inv_other, self.curve.order, bn_ctx
@ -191,10 +193,15 @@ class CurveBN(object):
return CurveBN(product, self.curve)
def __add__(self, other) -> 'CurveBN':
def __add__(self, other : Union[int, 'CurveBN']) -> 'CurveBN':
"""
Performs a BN_mod_add on two BIGNUMs.
"""
if type(other) == int:
other = openssl._int_to_bn(other)
other = CurveBN(other, self.curve)
op_sum = openssl._get_new_BN()
with backend._tmp_bn_ctx() as bn_ctx:
res = backend._lib.BN_mod_add(
@ -204,10 +211,14 @@ class CurveBN(object):
return CurveBN(op_sum, self.curve)
def __sub__(self, other) -> 'CurveBN':
def __sub__(self, other : Union[int, 'CurveBN']) -> 'CurveBN':
"""
Performs a BN_mod_sub on two BIGNUMS.
"""
if type(other) == int:
other = openssl._int_to_bn(other)
other = CurveBN(other, self.curve)
diff = openssl._get_new_BN()
with backend._tmp_bn_ctx() as bn_ctx:
res = backend._lib.BN_mod_sub(
@ -233,7 +244,24 @@ class CurveBN(object):
return CurveBN(inv, self.curve)
def __mod__(self, other) -> 'CurveBN':
def __neg__(self) -> 'CurveBN':
"""
Computes the modular opposite (i.e., additive inverse) of a BIGNUM
"""
zero = backend._int_to_bn(0)
zero = backend._ffi.gc(zero, backend._lib.BN_clear_free)
the_opposite = openssl._get_new_BN()
with backend._tmp_bn_ctx() as bn_ctx:
res = backend._lib.BN_mod_sub(
the_opposite, zero, self.bignum, self.curve.order, bn_ctx
)
backend.openssl_assert(res == 1)
return CurveBN(the_opposite, self.curve)
def __mod__(self, other : Union[int, 'CurveBN']) -> 'CurveBN':
"""
Performs a BN_nnmod on two BIGNUMS.
"""

View File

@ -288,7 +288,7 @@ class UmbralKeyingMaterial(object):
algorithm=hashes.BLAKE2b(64),
length=64,
salt=salt,
info=b"NuCypherKMS/KeyDerivation/"+label,
info=b"NuCypher/KeyDerivation/"+label,
backend=default_backend()
).derive(self.keying_material)

View File

@ -7,15 +7,14 @@ from umbral.curve import Curve
class UmbralParameters(object):
def __init__(self, curve: Curve) -> None:
from umbral.point import Point, unsafe_hash_to_point
from umbral.utils import get_field_order_size_in_bytes
self.curve = curve
self.CURVE_KEY_SIZE_BYTES = get_field_order_size_in_bytes(self.curve)
self.CURVE_KEY_SIZE_BYTES = self.curve.get_field_order_size_in_bytes()
self.g = Point.get_generator_from_curve(curve=curve)
g_bytes = self.g.to_bytes()
parameters_seed = b'NuCypherKMS/UmbralParameters/'
parameters_seed = b'NuCypher/UmbralParameters/'
self.u = unsafe_hash_to_point(g_bytes, self, parameters_seed + b'u')
def __eq__(self, other: 'UmbralParameters') -> bool:

View File

@ -9,7 +9,6 @@ from umbral.config import default_curve
from umbral.curve import Curve
from umbral.curvebn import CurveBN
from umbral.params import UmbralParameters
from umbral.utils import get_field_order_size_in_bytes
class Point(object):
@ -29,12 +28,13 @@ class Point(object):
If no curve is provided, it uses the default curve.
"""
curve = curve if curve is not None else default_curve()
base_size = get_field_order_size_in_bytes(curve)
if not is_compressed:
base_size += get_field_order_size_in_bytes(curve)
coord_size = curve.get_field_order_size_in_bytes()
return base_size + 1
if is_compressed:
return 1 + coord_size
else:
return 1 + 2 * coord_size
@classmethod
def gen_rand(cls, curve: Optional[Curve] = None) -> 'Point':
@ -129,7 +129,7 @@ class Point(object):
if is_compressed is set to True.
"""
affine_x, affine_y = self.to_affine()
key_size = get_field_order_size_in_bytes(self.curve)
key_size = self.curve.get_field_order_size_in_bytes()
if is_compressed:
y_bit = (affine_y & 1) + 2

View File

@ -10,7 +10,6 @@ from umbral.config import default_curve
from umbral.curve import Curve
from umbral.curvebn import CurveBN
from umbral.keys import UmbralPublicKey, UmbralPrivateKey
from umbral.utils import get_field_order_size_in_bytes
_BLAKE2B = hashes.BLAKE2b(64)
@ -32,7 +31,7 @@ class Signature:
@classmethod
def expected_bytes_length(cls, curve: Optional[Curve] = None) -> int:
curve = curve if curve is not None else default_curve()
return get_field_order_size_in_bytes(curve) * 2
return 2 * curve.get_field_order_size_in_bytes()
def verify(self, message: bytes, verifying_key: UmbralPublicKey) -> bool:
"""

View File

@ -4,29 +4,26 @@ from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from umbral import openssl
from umbral.curve import Curve
from umbral.curvebn import CurveBN
def lambda_coeff(id_i: 'CurveBN', selected_ids: List['CurveBN']) -> 'CurveBN':
def lambda_coeff(id_i: CurveBN, selected_ids: List[CurveBN]) -> CurveBN:
ids = [x for x in selected_ids if x != id_i]
if not ids:
return None
div_0 = ~(ids[0] - id_i)
result = ids[0] * div_0
result = ids[0] / (ids[0] - id_i)
for id_j in ids[1:]:
div_j = ~(id_j - id_i)
result = result * (id_j * div_j)
result = result * id_j / (id_j - id_i)
return result
def poly_eval(coeff: List['CurveBN'], x: 'CurveBN') -> 'CurveBN':
def poly_eval(coeff: List[CurveBN], x: CurveBN) -> CurveBN:
result = coeff[-1]
for i in range(-2, -len(coeff) - 1, -1):
result = ((result * x) + coeff[i])
result = (result * x) + coeff[i]
return result
@ -41,9 +38,3 @@ def kdf(ecpoint: 'Point', key_length: int) -> bytes:
info=None,
backend=default_backend()
).derive(data)
def get_field_order_size_in_bytes(curve: Curve) -> int:
backend = default_backend()
size_in_bits = openssl._get_ec_group_degree(curve.ec_group)
return (size_in_bits + 7) // 8