mirror of https://github.com/nucypher/pyUmbral.git
211 lines
7.1 KiB
Python
211 lines
7.1 KiB
Python
from umbral.bignum import BigNum
|
|
from cryptography.hazmat.backends.openssl import backend
|
|
|
|
|
|
class Point(object):
|
|
"""
|
|
Represents an OpenSSL EC_POINT except more Pythonic
|
|
"""
|
|
|
|
def __init__(self, ec_point, curve_nid, group):
|
|
self.ec_point = ec_point
|
|
self.curve_nid = curve_nid
|
|
self.group = group
|
|
|
|
@classmethod
|
|
def gen_rand(cls, curve):
|
|
"""
|
|
Returns a Point object with a cryptographically secure EC_POINT based
|
|
on the provided curve.
|
|
"""
|
|
curve_nid = backend._elliptic_curve_to_nid(curve)
|
|
|
|
group = backend._lib.EC_GROUP_new_by_curve_name(curve_nid)
|
|
backend.openssl_assert(group != backend._ffi.NULL)
|
|
|
|
generator = backend._lib.EC_GROUP_get0_generator(group)
|
|
backend.openssl_assert(generator != backend._ffi.NULL)
|
|
|
|
rand_point = backend._lib.EC_POINT_new(group)
|
|
backend.openssl_assert(rand_point != backend._ffi.NULL)
|
|
rand_point = backend._ffi.gc(rand_point, backend._lib.EC_POINT_free)
|
|
|
|
rand_bn = BigNum.gen_rand(curve).bignum
|
|
|
|
with backend._tmp_bn_ctx() as bn_ctx:
|
|
res = backend._lib.EC_POINT_mul(
|
|
group, rand_point, backend._ffi.NULL, generator, rand_bn, bn_ctx
|
|
)
|
|
backend.openssl_assert(res == 1)
|
|
|
|
return Point(rand_point, curve_nid, group)
|
|
|
|
@classmethod
|
|
def from_affine(cls, coords, curve):
|
|
"""
|
|
Returns a Point object from the given affine coordinates in a tuple in
|
|
the format of (x, y) and a given curve.
|
|
"""
|
|
try:
|
|
curve_nid = backend._elliptic_curve_to_nid(curve)
|
|
except AttributeError:
|
|
# Presume that the user passed in the curve_nid
|
|
curve_nid = curve
|
|
|
|
affine_x, affine_y = coords
|
|
if type(affine_x) == int:
|
|
affine_x = backend._int_to_bn(affine_x)
|
|
affine_x = backend._ffi.gc(affine_x, backend._lib.BN_free)
|
|
|
|
if type(affine_y) == int:
|
|
affine_y = backend._int_to_bn(affine_y)
|
|
affine_y = backend._ffi.gc(affine_y, backend._lib.BN_free)
|
|
|
|
group = backend._lib.EC_GROUP_new_by_curve_name(curve_nid)
|
|
backend.openssl_assert(group != backend._ffi.NULL)
|
|
|
|
ec_point = backend._lib.EC_POINT_new(group)
|
|
backend.openssl_assert(ec_point != backend._ffi.NULL)
|
|
|
|
with backend._tmp_bn_ctx() as bn_ctx:
|
|
res = backend._lib.EC_POINT_set_affine_coordinates_GFp(
|
|
group, ec_point, affine_x, affine_y, bn_ctx
|
|
)
|
|
backend.openssl_assert(res == 1)
|
|
|
|
return Point(ec_point, curve_nid, group)
|
|
|
|
@classmethod
|
|
def get_generator_from_curve(cls, curve):
|
|
"""
|
|
Returns the generator Point from the given curve as a Point object.
|
|
"""
|
|
try:
|
|
curve_nid = backend._elliptic_curve_to_nid(curve)
|
|
except AttributeError:
|
|
# Presume that the user passed in the curve_nid
|
|
curve_nid = curve
|
|
|
|
group = backend._lib.EC_GROUP_new_by_curve_name(curve_nid)
|
|
backend.openssl_assert(group != backend._ffi.NULL)
|
|
|
|
generator = backend._lib.EC_GROUP_get0_generator(group)
|
|
backend.openssl_assert(generator != backend._ffi.NULL)
|
|
|
|
return Point(generator, curve_nid, group)
|
|
|
|
@classmethod
|
|
def get_order_from_curve(cls, curve):
|
|
"""
|
|
Returns the order from the given curve as a BigNum.
|
|
"""
|
|
try:
|
|
curve_nid = backend._elliptic_curve_to_nid(curve)
|
|
except AttributeError:
|
|
# Presume that the user passed in the curve_nid
|
|
curve_nid = curve
|
|
|
|
group = backend._lib.EC_GROUP_new_by_curve_name(curve_nid)
|
|
backend.openssl_assert(group != backend._ffi.NULL)
|
|
|
|
order = backend._lib.BN_new()
|
|
backend.openssl_assert(order != backend._ffi.NULL)
|
|
order = backend._ffi.gc(order, backend._lib.BN_free)
|
|
|
|
with backend._tmp_bn_ctx() as bn_ctx:
|
|
res = backend._lib.EC_GROUP_get_order(group, order, bn_ctx)
|
|
backend.openssl_assert(res == 1)
|
|
|
|
return BigNum(order, curve_nid, group, order)
|
|
|
|
def __eq__(self, other):
|
|
"""
|
|
Compares two EC_POINTS for equality.
|
|
"""
|
|
with backend._tmp_bn_ctx() as bn_ctx:
|
|
is_equal = backend._lib.EC_POINT_cmp(
|
|
self.group, self.ec_point, other.ec_point, bn_ctx
|
|
)
|
|
backend.openssl_assert(is_equal != -1)
|
|
|
|
# 1 is not-equal, 0 is equal, -1 is error
|
|
return not bool(is_equal)
|
|
|
|
def __mul__(self, other):
|
|
"""
|
|
Performs an EC_POINT_mul on an EC_POINT and a BIGNUM.
|
|
"""
|
|
prod = backend._lib.EC_POINT_new(self.group)
|
|
backend.openssl_assert(prod != backend._ffi.NULL)
|
|
prod = backend._ffi.gc(prod, backend._lib.EC_POINT_free)
|
|
|
|
with backend._tmp_bn_ctx() as bn_ctx:
|
|
res = backend._lib.EC_POINT_mul(
|
|
self.group, prod, backend._ffi.NULL, self.ec_point,
|
|
other.bignum, bn_ctx
|
|
)
|
|
backend.openssl_assert(res == 1)
|
|
|
|
return Point(prod, self.curve_nid, self.group)
|
|
|
|
def __add__(self, other):
|
|
"""
|
|
Performs an EC_POINT_add on two EC_POINTS.
|
|
"""
|
|
sum = backend._lib.EC_POINT_new(self.group)
|
|
backend.openssl_assert(sum != backend._ffi.NULL)
|
|
sum = backend._ffi.gc(sum, backend._lib.EC_POINT_free)
|
|
|
|
with backend._tmp_bn_ctx() as bn_ctx:
|
|
res = backend._lib.EC_POINT_add(
|
|
self.group, sum, self.ec_point, other.ec_point, bn_ctx
|
|
)
|
|
backend.openssl_assert(res == 1)
|
|
|
|
return Point(sum, self.curve_nid, self.group)
|
|
|
|
def __sub__(self, other):
|
|
"""
|
|
Performs subtraction by adding the inverse of the `other` to the point.
|
|
"""
|
|
return (self + (~other))
|
|
|
|
def __invert__(self):
|
|
"""
|
|
Performs an EC_POINT_invert on itself.
|
|
"""
|
|
inv = backend._lib.EC_POINT_dup(self.ec_point, self.group)
|
|
backend.openssl_assert(inv != backend._ffi.NULL)
|
|
inv = backend._ffi.gc(inv, backend._lib.EC_POINT_free)
|
|
|
|
with backend._tmp_bn_ctx() as bn_ctx:
|
|
res = backend._lib.EC_POINT_invert(
|
|
self.group, inv, bn_ctx
|
|
)
|
|
backend.openssl_assert(res == 1)
|
|
|
|
return Point(inv, self.curve_nid, self.group)
|
|
|
|
def to_affine(self):
|
|
"""
|
|
Returns a tuple of Python ints in the format of (x, y) that represents the point in the curve
|
|
"""
|
|
x = backend._lib.BN_new()
|
|
backend.openssl_assert(x != backend._ffi.NULL)
|
|
x = backend._ffi.gc(x, backend._lib.BN_free)
|
|
|
|
y = backend._lib.BN_new()
|
|
backend.openssl_assert(y != backend._ffi.NULL)
|
|
y = backend._ffi.gc(y, backend._lib.BN_free)
|
|
|
|
with backend._tmp_bn_ctx() as bn_ctx:
|
|
backend._lib.EC_POINT_get_affine_coordinates_GFp(
|
|
self.group, self.ec_point, x, y, bn_ctx)
|
|
return (backend._bn_to_int(x), backend._bn_to_int(y))
|
|
|
|
def to_bytes(self):
|
|
(x,y) = self.to_affine()
|
|
data = x.to_bytes(32, byteorder='big')
|
|
data = data + y.to_bytes(32, byteorder='big')
|
|
return data
|