¿Cómo puedo verificar si una clave bip32 xpub es válida usando python?

Estoy a la caza de algún código de Python que me diga si una cadena es una clave bip32 xpub válida, pero tengo problemas para encontrar alguna.

También me gustaría verificar si una cadena es una dirección de bitcoin válida. Aquí hay un ejemplo que encontré para este propósito, pero no parece funcionar: http://rosettacode.org/wiki/Bitcoin/address_validation#Python

Por favor ayuda :)

Respuestas (1)

El código que vinculaste me funciona en Python 3.4, así que supondré que estás buscando algo para Python 2.7.

Este código es directo de aquí en GitHub :

import base64, hashlib, collections, struct

def int_to_bytes(int_rep, min_length = 0):
    """convert an unsigned integer to a string of bytes (in big-endian order)
    :param int_rep: a non-negative integer
    :type int_rep: long or int
    :param min_length: the minimum output length
    :type min_length: int
    :return: the raw bytes, zero-padded (at the beginning) if necessary
    :rtype: str
    """
    assert int_rep >= 0
    hex_rep = "{:X}".format(int_rep)
    if len(hex_rep) % 2 == 1:    # The hex decoder below requires
        hex_rep = "0" + hex_rep  # exactly 2 chars per byte.
    return base64.b16decode(hex_rep).rjust(min_length, "\0")


dec_digit_to_base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
base58_digit_to_dec = { b58:dec for dec,b58 in enumerate(dec_digit_to_base58) }


def base58check_to_bytes(base58_rep, expected_size):
    """decode a base58check string to its raw bytes
    :param base58_rep: check-code appended base58-encoded string
    :type base58_rep: str
    :param expected_size: the expected number of decoded bytes (excluding the check code)
    :type expected_size: int
    :return: the base58-decoded bytes
    :rtype: str
    """
    base58_stripped = base58_rep.lstrip("1")

    int_rep = 0
    for base58_digit in base58_stripped:
        int_rep *= 58
        int_rep += base58_digit_to_dec[base58_digit]

    # Convert int to raw bytes
    all_bytes  = int_to_bytes(int_rep, expected_size + 4)

    zero_count = next(zeros for zeros,byte in enumerate(all_bytes) if byte != "\0")
    if len(base58_rep) - len(base58_stripped) != zero_count:
        raise ValueError("prepended zeros mismatch")

    if hashlib.sha256(hashlib.sha256(all_bytes[:-4]).digest()).digest()[:4] != all_bytes[-4:]:
        raise ValueError("base58 check code mismatch")

    return all_bytes[:-4]

def base58check_to_hash160(base58_rep):
    """convert from a base58check address to its hash160 form
    :param base58_rep: check-code appended base58-encoded address
    :type base58_rep: str
    :return: the ripemd160(sha256()) hash of the pubkey/redeemScript, then the version byte
    :rtype: (str, str)
    """
    decoded_bytes = base58check_to_bytes(base58_rep, 1 + 20)
    return decoded_bytes[1:], decoded_bytes[0]

BIP32ExtendedKey = collections.namedtuple("BIP32ExtendedKey",
    "version depth fingerprint child_number chaincode key")
#
def base58check_to_bip32(base58_rep):
    """decode a bip32-serialized extended key from its base58check form
    :param base58_rep: check-code appended base58-encoded bip32 extended key
    :type base58_rep: str
    :return: a namedtuple containing: version depth fingerprint child_number chaincode key
    :rtype: BIP32ExtendedKey
    """
    decoded_bytes = base58check_to_bytes(base58_rep, 4 + 1 + 4 + 4 + 32 + 33)
    return BIP32ExtendedKey(decoded_bytes[0:4],  ord(decoded_bytes[ 4:5]), decoded_bytes[ 5:9],
        struct.unpack(">I", decoded_bytes[9:13])[0], decoded_bytes[13:45], decoded_bytes[45:])

En particular, querrá llamar base58check_to_hash160()para verificar una dirección "normal" o base58check_to_bip32()para verificar una dirección extendida BIP-32 (un "xpub" o "xprv"). Devolverán los resultados de descifrar la dirección o aumentarán ValueErrorsi la dirección no es válida.

Está técnicamente licenciado bajo GPLv2 , pero si desea que yo (como el autor original) vuelva a otorgar la licencia bajo algo menos restrictivo para su proyecto, por ejemplo, BSD o MIT , con gusto lo haré. Por favor, házmelo saber en un comentario.

¡Muchas gracias! No es necesario volver a licenciar su código, el método era todo lo que quería. Gracias de nuevo :)