def get_input_peer(entity, allow_self=True, check_hash=True):
    """
    Gets the input peer for the given "entity" (user, chat or channel).

    A ``TypeError`` is raised if the given entity isn't a supported type
    or if ``check_hash is True`` but the entity's ``access_hash is None``.

    Note that ``check_hash`` **is ignored** if an input peer is already
    passed since in that case we assume the user knows what they're doing.
    This is key to getting entities by explicitly passing ``hash = 0``.
    """
    try:
        if entity.SUBCLASS_OF_ID == 0xc91c90b6:  # crc32(b'InputPeer')
            return entity
    except AttributeError:
        # e.g. custom.Dialog (can't cyclic import).
        if allow_self and hasattr(entity, 'input_entity'):
            return entity.input_entity
        elif hasattr(entity, 'entity'):
            return get_input_peer(entity.entity)
        else:
            _raise_cast_fail(entity, 'InputPeer')

    if isinstance(entity, types.User):
        if entity.is_self and allow_self:
            return types.InputPeerSelf()
        elif entity.access_hash is not None or not check_hash:
            return types.InputPeerUser(entity.id, entity.access_hash)
        else:
            raise TypeError('User without access_hash cannot be input')

    if isinstance(entity, (types.Chat, types.ChatEmpty, types.ChatForbidden)):
        return types.InputPeerChat(entity.id)

    if isinstance(entity, (types.Channel, types.ChannelForbidden)):
        if entity.access_hash is not None or not check_hash:
            return types.InputPeerChannel(entity.id, entity.access_hash)
        else:
            raise TypeError('Channel without access_hash cannot be input')

    if isinstance(entity, types.InputUser):
        return types.InputPeerUser(entity.user_id, entity.access_hash)

    if isinstance(entity, types.InputChannel):
        return types.InputPeerChannel(entity.channel_id, entity.access_hash)

    if isinstance(entity, types.InputUserSelf):
        return types.InputPeerSelf()

    if isinstance(entity, types.UserEmpty):
        return types.InputPeerEmpty()

    if isinstance(entity, types.UserFull):
        return get_input_peer(entity.user)

    if isinstance(entity, types.ChatFull):
        return types.InputPeerChat(entity.id)

    if isinstance(entity, types.PeerChat):
        return types.InputPeerChat(entity.chat_id)

    _raise_cast_fail(entity, 'InputPeer')
Gets the input peer for the given "entity" (user, chat or channel).

    A ``TypeError`` is raised if the given entity isn't a supported type
    or if ``check_hash is True`` but the entity's ``access_hash is None``.

    Note that ``check_hash`` **is ignored** if an input peer is already
    passed since in that case we assume the user knows what they're doing.
    This is key to getting entities by explicitly passing ``hash = 0``.