import re
import base64
import hashlib


def validate_onion_v3_address(onion_address):
    """Validates a given Onion v3 address (whole domain including the ".onion" TLD) based on the
    Tor Rendezvous Specification Version 3
    (https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt#n2135).

    Args:
        onion_address: Tor Onion address to validate as string.

    Returns:
        True if the given string is a valid Onion v3 address, False if not.
    """

    if onion_address is not None:
        search = re.compile(r'^[a-z2-7]{56}.onion$').search
        if bool(search(onion_address)):
            # onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
            b32_decoded = base64.b32decode(onion_address.upper()[:-6])  # -6 -> cut .onion
            pubkey, checksum, version = b32_decoded[:32], b32_decoded[32:34], b32_decoded[34:]

            # VERSION is an one byte version field (default value '\x03')
            if version != b"\x03":
                return False

            # CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2]
            target_checksum = \
                hashlib.sha3_256(b".onion checksum" + pubkey + version).digest()[:2]

            if checksum == target_checksum:
                return True
    return False