def diffie_hellman(key2)

      lib = BTC::OpenSSL
      lib.autorelease do |pool|

        pk = pool.new_bn(key2.private_key)
        n = lib.group_order

        # Convert pubkey to a EC point
        pubkey_x = pool.new_bn(self.compressed_public_key)
        pubkey_point = pool.new_ec_point
        lib.EC_POINT_bn2point(lib.group, pubkey_x, pubkey_point, pool.bn_ctx)

        # Compute point = pubkey*pk + 0*G
        point = pool.new_ec_point
        # /** Computes r = generator * n + q * m
        #  *  \param  group  underlying EC_GROUP object
        #  *  \param  r      EC_POINT object for the result
        #  *  \param  n      BIGNUM with the multiplier for the group generator (optional)
        #  *  \param  q      EC_POINT object with the first factor of the second summand
        #  *  \param  m      BIGNUM with the second factor of the second summand
        #  *  \param  ctx    BN_CTX object (optional)
        #  *  \return 1 on success and 0 if an error occured
        #  */
        # int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx);
        lib.EC_POINT_mul(lib.group, point, nil, pubkey_point, pk, pool.bn_ctx)

        # Check for invalid derivation.
        if 1 == lib.EC_POINT_is_at_infinity(lib.group, point)
          raise MathError, "Resulting point is at infinity."
        end

        lib.EC_POINT_point2bn(
          lib.group,
          point,
          self.public_key_compressed ?
          BTC::OpenSSL::POINT_CONVERSION_COMPRESSED :
          BTC::OpenSSL::POINT_CONVERSION_UNCOMPRESSED,
          pubkey_x,
          pool.bn_ctx
        )

        result_pubkey = lib.data_from_bn(pubkey_x, required_length: 33)
        return Key.new(public_key: result_pubkey)
      end
    end
def diffie_hellman(key2)

      lib = BTC::OpenSSL
      lib.autorelease do |pool|

        pk = pool.new_bn(key2.private_key)
        n = lib.group_order

        # Convert pubkey to a EC point
        pubkey_x = pool.new_bn(self.compressed_public_key)
        pubkey_point = pool.new_ec_point
        lib.EC_POINT_bn2point(lib.group, pubkey_x, pubkey_point, pool.bn_ctx)

        # Compute point = pubkey*pk + 0*G
        point = pool.new_ec_point
        # /** Computes r = generator * n + q * m
        #  *  \param  group  underlying EC_GROUP object
        #  *  \param  r      EC_POINT object for the result
        #  *  \param  n      BIGNUM with the multiplier for the group generator (optional)
        #  *  \param  q      EC_POINT object with the first factor of the second summand
        #  *  \param  m      BIGNUM with the second factor of the second summand
        #  *  \param  ctx    BN_CTX object (optional)
        #  *  \return 1 on success and 0 if an error occured
        #  */
        # int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx);
        lib.EC_POINT_mul(lib.group, point, nil, pubkey_point, pk, pool.bn_ctx)

        # Check for invalid derivation.
        if 1 == lib.EC_POINT_is_at_infinity(lib.group, point)
          raise MathError, "Resulting point is at infinity."
        end

        lib.EC_POINT_point2bn(
          lib.group,
          point,
          self.public_key_compressed ?
          BTC::OpenSSL::POINT_CONVERSION_COMPRESSED :
          BTC::OpenSSL::POINT_CONVERSION_UNCOMPRESSED,
          pubkey_x,
          pool.bn_ctx
        )

        result_pubkey = lib.data_from_bn(pubkey_x, required_length: 33)
        return Key.new(public_key: result_pubkey)
      end
    end
Multiplies a public key of the receiver with a given private key and
 returns resulting curve point as BTC::Key object (pubkey only).
 Pubkey compression flag is the same as on receiver.