def from_affine(cls, coords, curve: ec.EllipticCurve = None): """ Returns a Point object from the given affine coordinates in a tuple in the format of (x, y) and a given curve. """ curve = curve if curve is not None else default_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 = openssl._int_to_bn(affine_x) if type(affine_y) == int: affine_y = openssl._int_to_bn(affine_y) group = openssl._get_ec_group_by_curve_nid(curve_nid) ec_point = openssl._get_EC_POINT_via_affine(affine_x, affine_y, ec_group=group) return cls(ec_point, curve_nid, group)
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 constant time operations. """ curve = curve if curve is not None else default_curve() conv_bn = openssl._int_to_bn(num, curve) return cls(conv_bn, curve)
def from_affine(cls, coords: Tuple[int, int], curve: Optional[Curve] = None) -> 'Point': """ Returns a Point object from the given affine coordinates in a tuple in the format of (x, y) and a given curve. """ curve = curve if curve is not None else default_curve() affine_x, affine_y = coords if type(affine_x) == int: affine_x = openssl._int_to_bn(affine_x, curve=curve) if type(affine_y) == int: affine_y = openssl._int_to_bn(affine_y, curve=curve) ec_point = openssl._get_EC_POINT_via_affine(affine_x, affine_y, curve) return cls(ec_point, curve)
def __eq__(self, other): """ Compares the two BIGNUMS or int. """ if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, None, None, None) # -1 less than, 0 is equal to, 1 is greater than return not bool(backend._lib.BN_cmp(self.bignum, other.bignum))
def __eq__(self, other) -> bool: """ Compares the two BIGNUMS or int. """ # TODO: Should this stay in or not? if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, self.curve) # -1 less than, 0 is equal to, 1 is greater than return not bool(backend._lib.BN_cmp(self.bignum, other.bignum))
def __mod__(self, other): """ Performs a BN_nnmod on two BIGNUMS. """ if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, None, None, None) rem = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_nnmod(rem, self.bignum, other.bignum, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(rem, self.curve_nid, self.group, self.order)
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(diff, self.bignum, other.bignum, self.curve.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(diff, self.curve)
def __mod__(self, other: Union[int, 'CurveBN']) -> 'CurveBN': """ Performs a BN_nnmod on two BIGNUMS. """ if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, self.curve) other = cast('CurveBN', other) # This is just for mypy rem = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_nnmod(rem, self.bignum, other.bignum, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(rem, self.curve)
def __pow__(self, other): """ Performs a BN_mod_exp on two BIGNUMS. WARNING: Only in constant time if BN_FLG_CONSTTIME is set on the BN. """ if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, None, None, None) power = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx, openssl._tmp_bn_mont_ctx(self.order) as bn_mont_ctx: res = backend._lib.BN_mod_exp_mont( power, self.bignum, other.bignum, self.order, bn_ctx, bn_mont_ctx ) backend.openssl_assert(res == 1) return CurveBN(power, self.curve_nid, self.group, self.order)
def hash(cls, *crypto_items, params=None): params = params if params is not None else default_params() curve_nid = backend._elliptic_curve_to_nid(params.curve) order = openssl._get_ec_order_by_curve_nid(curve_nid) group = openssl._get_ec_group_by_curve_nid(curve_nid) # TODO: Clean this in an upcoming cleanup of pyUmbral blake2b = hashes.Hash(hashes.BLAKE2b(64), backend=backend) for item in crypto_items: try: item_bytes = item.to_bytes() except AttributeError: if isinstance(item, bytes): item_bytes = item else: raise TypeError( "{} is not acceptable type, received {}".format( item, type(item))) blake2b.update(item_bytes) hash_digest = blake2b.finalize() hash_digest = int.from_bytes(hash_digest, byteorder='big', signed=False) hash_digest = openssl._int_to_bn(hash_digest) _1 = backend._lib.BN_value_one() order_minus_1 = openssl._get_new_BN() res = backend._lib.BN_sub(order_minus_1, order, _1) backend.openssl_assert(res == 1) bignum = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod(bignum, hash_digest, order_minus_1, bn_ctx) backend.openssl_assert(res == 1) res = backend._lib.BN_add(bignum, bignum, _1) backend.openssl_assert(res == 1) return cls(bignum, curve_nid, group, order)
def from_int(cls, num, curve: ec.EllipticCurve = None): """ Returns a CurveBN object from a given integer on a curve. By default, the underlying OpenSSL BIGNUM has BN_FLG_CONSTTIME set for constant time operations. """ curve = curve if curve is not None else default_curve() try: curve_nid = backend._elliptic_curve_to_nid(curve) except AttributeError: # Presume that the user passed in the curve_nid curve_nid = curve group = openssl._get_ec_group_by_curve_nid(curve_nid) order = openssl._get_ec_order_by_curve_nid(curve_nid) conv_bn = openssl._int_to_bn(num, curve_nid) return cls(conv_bn, curve_nid, group, order)
def __pow__(self, other : Union[int, 'CurveBN']) -> 'CurveBN': """ Performs a BN_mod_exp on two BIGNUMS. WARNING: Only in constant time if BN_FLG_CONSTTIME is set on the BN. """ # TODO: Should this stay in or not? if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, self.curve) power = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx, openssl._tmp_bn_mont_ctx(self.curve.order) as bn_mont_ctx: res = backend._lib.BN_mod_exp_mont( power, self.bignum, other.bignum, self.curve.order, bn_ctx, bn_mont_ctx ) backend.openssl_assert(res == 1) return CurveBN(power, self.curve)
def from_bytes(cls, data: bytes, curve: Optional[Curve] = None) -> 'Point': """ Returns a Point object from the given byte data on the curve provided. """ curve = curve if curve is not None else default_curve() compressed_size = cls.expected_bytes_length(curve) # Check if compressed if data[0] in [2, 3]: if len(data) != compressed_size: raise ValueError("X coordinate too large for curve.") affine_x = int.from_bytes(data[1:], 'big') affine_x = openssl._int_to_bn(affine_x, curve=None) type_y = data[0] - 2 ec_point = openssl._get_new_EC_POINT(curve) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_set_compressed_coordinates_GFp( curve.ec_group, ec_point, affine_x, type_y, bn_ctx) backend.openssl_assert(res == 1) return cls(ec_point, curve) # Handle uncompressed point # TODO: Give better error messages elif data[0] == 4: coord_size = compressed_size - 1 uncompressed_size = 1 + (2 * coord_size) if len(data) != uncompressed_size: raise ValueError( "Uncompressed point does not have right size.") affine_x = int.from_bytes(data[1:coord_size + 1], 'big') affine_y = int.from_bytes(data[1 + coord_size:], 'big') return cls.from_affine((affine_x, affine_y), curve) else: raise ValueError("Invalid point serialization.")