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: 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 = openssl._bytes_to_bn(blake2b.finalize()) _1 = backend._lib.BN_value_one() order_minus_1 = openssl._get_new_BN() res = backend._lib.BN_sub(order_minus_1, params.curve.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, params.curve)
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 __add__(self, other) -> 'CurveBN': """ Performs a BN_mod_add on two BIGNUMs. """ op_sum = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod_add(op_sum, self.bignum, other.bignum, self.curve.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(op_sum, self.curve)
def __sub__(self, other): """ Performs a BN_mod_sub on two BIGNUMS. """ 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.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(diff, self.curve_nid, self.group, self.order)
def __mul__(self, other) -> 'CurveBN': """ Performs a BN_mod_mul between two BIGNUMS. """ if type(other) != CurveBN: return NotImplemented product = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod_mul(product, self.bignum, other.bignum, self.curve.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(product, self.curve)
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 __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 hash_to_curvebn(*crypto_items, params: UmbralParameters, customization_string: bytes = b'', hash_class: Type[Hash] = Blake2b) -> CurveBN: customization_string = b'hash_to_curvebn' + customization_string hash_function = hash_class(customization_string=customization_string) for item in crypto_items: try: item_bytes = item.to_bytes() except AttributeError: if isinstance(item, bytes): item_bytes = item else: raise TypeError("Input with type {} not accepted".format( type(item))) hash_function.update(item_bytes) hash_digest = openssl._bytes_to_bn(hash_function.finalize()) one = backend._lib.BN_value_one() order_minus_1 = openssl._get_new_BN() res = backend._lib.BN_sub(order_minus_1, params.curve.order, one) 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, one) backend.openssl_assert(res == 1) return CurveBN(bignum, params.curve)
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 gen_rand(cls, curve: Optional[Curve] = None) -> 'CurveBN': """ Returns a CurveBN object with a cryptographically secure OpenSSL BIGNUM based on the given 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() new_rand_bn = openssl._get_new_BN() rand_res = backend._lib.BN_rand_range(new_rand_bn, curve.order) backend.openssl_assert(rand_res == 1) if not openssl._bn_is_on_curve(new_rand_bn, curve): new_rand_bn = cls.gen_rand(curve=curve) return new_rand_bn return cls(new_rand_bn, curve)
def __truediv__(self, other): """ Performs a BN_div on two BIGNUMs (modulo the order of the curve). WARNING: Only in constant time if BN_FLG_CONSTTIME is set on the BN. """ product = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: inv_other = backend._lib.BN_mod_inverse(backend._ffi.NULL, other.bignum, self.order, bn_ctx) backend.openssl_assert(inv_other != backend._ffi.NULL) res = backend._lib.BN_mod_mul(product, self.bignum, inv_other, self.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(product, self.curve_nid, self.group, self.order)
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 __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 gen_rand(cls, curve: ec.EllipticCurve = None): """ Returns a CurveBN object with a cryptographically secure OpenSSL BIGNUM based on the given 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() curve_nid = backend._elliptic_curve_to_nid(curve) group = openssl._get_ec_group_by_curve_nid(curve_nid) order = openssl._get_ec_order_by_curve_nid(curve_nid) new_rand_bn = openssl._get_new_BN() rand_res = backend._lib.BN_rand_range(new_rand_bn, order) backend.openssl_assert(rand_res == 1) if not openssl._bn_is_on_curve(new_rand_bn, curve_nid): new_rand_bn = cls.gen_rand(curve=curve) return new_rand_bn return cls(new_rand_bn, curve_nid, group, order)