def public_key(self, private_key): """ Returns the public (verifying) key for a given private key. Args: private_key (int): the private key to derive the public key for. Returns: ECPointAffine: The point representing the public key. """ k = ossl.new_key(self.curve_name, private_key) pub_x, pub_y, is_inf = ossl.get_public_key_ints(k) ossl.lc.EC_KEY_free(k) return ECPointAffine(self, pub_x, pub_y, is_inf)
def _sign(self, message, private_key, do_hash=True, secret=None): # This function computes k, kinv and rp before sending into # OpenSSL ECDSA_do_sign_ex() rather than using ECDSA_do_sign() # directly. The reason for this is that as of the commit that # introduces this comment, OpenSSL only supports deterministic # signing nonces (RFC6979) in the master branch and not any # release. As a result, we cannot depend on callers having any # OpenSSL version capable of RFC6979 deterministic nonces. # Nevertheless, computation of kinv (from k) and rp is done # using OpenSSL primitives. ossl.lc.ERR_clear_error() hashed = self.hash_function(message).digest() if do_hash else message r = 0 s = 0 recovery_id = 0 key = ossl.new_key(self.curve_name, private_key) ctx = c_void_p(ossl.lc.BN_CTX_new()) ossl.lc.BN_CTX_start(ctx) order_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) k_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) kinv_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) px_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) r_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) ossl.lc.EC_GROUP_get_order(self.os_group, order_bn, ctx) while r == 0 or s == 0: k = self._nonce_rfc6979(private_key, hashed) if secret is None else secret ossl.int_to_bn(k, k_bn) ossl.lc.BN_mod_inverse(kinv_bn, k_bn, order_bn, ctx) p = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) ossl.lc.EC_POINT_mul(self.os_group, p, k_bn, c_void_p(), c_void_p(), ctx) assert self.h == 1 px, py, _ = ossl.point_get_xy_ints(self.os_group, p) recovery_id = 2 if px > self.n else 0 recovery_id |= (py & 0x1) # Get r ossl.int_to_bn(px, px_bn) ossl.lc.BN_nnmod(r_bn, px_bn, order_bn, ctx) r = ossl.bn_to_int(r_bn) if r == 0: continue hashed_buf = c_char_p(hashed) sig = ossl.lc.ECDSA_do_sign_ex(hashed_buf, len(hashed), kinv_bn, r_bn, key) err = ossl.lc.ERR_peek_error() if err: err_buf = create_string_buffer(120) ossl.lc.ERR_error_string(err, err_buf) raise Exception("Problem when signing: %s" % err_buf.raw.decode()) sig_r = ossl.bn_to_int(sig.contents.r) sig_s = ossl.bn_to_int(sig.contents.s) if sig_r != r: raise ValueError("Didn't get the same r value.") s = sig_s ossl.lc.EC_KEY_free(key) ossl.lc.BN_CTX_end(ctx) ossl.lc.BN_CTX_free(ctx) return (Point(r, s), recovery_id)