Esempio n. 1
0
def deserialize_address(address):
    """
    Deserialize cryptocurrency address. Calculate public key hash and try to determine script type and network.

    If one and only one network is found the 'network' dictionary item with contain this network. Same applies for the script type.

    If more networks and or script types are found you can find these in 'networks_p2sh' and 'networks_p2pkh'.

    :param address: A base-58 encoded address
    :type address: str

    :return dict: with information about this address
    """
    try:
        address_bytes = change_base(address, 58, 256, 25)
    except EncodingError as err:
        raise EncodingError("Invalid address %s: %s" % (address, err))
    check = address_bytes[-4:]
    key_hash = address_bytes[:-4]
    checksum = hashlib.sha256(hashlib.sha256(key_hash).digest()).digest()[0:4]
    assert (check == checksum), "Invalid address, checksum incorrect"
    address_prefix = key_hash[0:1]
    networks_p2pkh = network_by_value('prefix_address', address_prefix)
    networks_p2sh = network_by_value('prefix_address_p2sh', address_prefix)
    public_key_hash = key_hash[1:]
    script_type = ''
    network = ''
    if networks_p2pkh and not networks_p2sh:
        script_type = 'p2pkh'
        if len(networks_p2pkh) == 1:
            network = networks_p2pkh[0]
    elif networks_p2sh and not networks_p2pkh:
        script_type = 'p2sh'
        if len(networks_p2sh) == 1:
            network = networks_p2sh[0]

    return {
        'address': address,
        'public_key_hash': change_base(public_key_hash, 256, 16),
        'public_key_hash_bytes': public_key_hash,
        'prefix': address_prefix,
        'network': network,
        'script_type': script_type,
        'networks_p2sh': networks_p2sh,
        'networks_p2pkh': networks_p2pkh
    }
Esempio n. 2
0
def get_key_format(key, isprivate=None):
    """
    Determins the type (private or public), format and network key.
    
    This method does not validate if a key is valid.

    :param key: Any private or public key
    :type key: str, int, bytes, bytearray
    :param isprivate: Is key private or not?
    :type isprivate: bool
    
    :return dict: Dictionary with format, network and isprivate
    """
    if not key:
        raise BKeyError("Key empty, please specify a valid key")
    key_format = ""
    networks = None

    if isinstance(key, (bytes, bytearray)) and len(key) in [128, 130]:
        key = to_hexstring(key)

    if not (isprivate is None or isinstance(isprivate, bool)):
        raise BKeyError("Attribute 'is_private' must be False or True")
    elif isinstance(key, numbers.Number):
        key_format = 'decimal'
        isprivate = True
    elif isinstance(key, (bytes, bytearray)) and len(key) in [
            33, 65
    ] and key[:1] in [b'\2', b'\3']:
        key_format = 'bin_compressed'
        isprivate = False
    elif isinstance(key, (bytes, bytearray)) and (len(key) in [33, 65]
                                                  and key[:1] == b'\4'):
        key_format = 'bin'
        isprivate = False
    elif isinstance(
            key, (bytes, bytearray)) and len(key) == 33 and key[-1:] == b'\1':
        key_format = 'bin_compressed'
        isprivate = True
    elif isinstance(key, (bytes, bytearray)) and len(key) == 32:
        key_format = 'bin'
        isprivate = True
    elif len(key) == 130 and key[:2] == '04' and not isprivate:
        key_format = 'public_uncompressed'
        isprivate = False
    elif len(key) == 128:
        key_format = 'hex'
        if isprivate is None:
            isprivate = True
    elif len(key) == 66 and key[:2] in ['02', '03'] and not isprivate:
        key_format = 'public'
        isprivate = False
    elif len(key) == 64:
        key_format = 'hex'
        if isprivate is None:
            isprivate = True
    elif len(key) == 66 and key[-2:] in ['01'] and not (isprivate is False):
        key_format = 'hex_compressed'
        isprivate = True
    elif len(key) == 58 and key[:2] == '6P':
        key_format = 'wif_protected'
        isprivate = True
    else:
        try:
            key_hex = change_base(key, 58, 16)
            networks = network_by_value('prefix_wif', key_hex[:2])
            if networks:
                if key_hex[-10:-8] == '01':
                    key_format = 'wif_compressed'
                else:
                    key_format = 'wif'
                isprivate = True
            else:
                networks = network_by_value('prefix_hdkey_private',
                                            key_hex[:8])
                if networks:
                    key_format = 'hdkey_private'
                    isprivate = True
                else:
                    networks = network_by_value('prefix_hdkey_public',
                                                key_hex[:8])
                    if networks:
                        key_format = 'hdkey_public'
                        isprivate = False
                    # TODO: Recognise address key and implement in Key en HDKey classs
                    # else:
                    #     networks = network_by_value('prefix_address_p2sh', key_hex[:2]) + \
                    #                network_by_value('prefix_address', key_hex[:2])
                    #     if networks:
                    #         key_format = 'address'
                    #         isprivate = False

        except (TypeError, EncodingError):
            pass
    if not key_format:
        try:
            int(key)
            if 70 < len(key) < 78:
                key_format = 'decimal'
                isprivate = True
        except (TypeError, ValueError):
            pass
    if not key_format:
        raise BKeyError("Key: %s. Unrecognised key format" % key)
    else:
        return {
            "format": key_format,
            "networks": networks,
            "isprivate": isprivate
        }
Esempio n. 3
0
    def __init__(self,
                 import_key=None,
                 network=None,
                 compressed=True,
                 passphrase=''):
        """
        Initialize a Key object. Import key can be in WIF, bytes, hexstring, etc.
        If a private key is imported a public key will be derived. If a public is imported the private key data will
        be empty.
        
        Both compressed and uncompressed key version is available, the Key.compressed boolean attribute tells if the
        original imported key was compressed or not.

        :param import_key: If specified import given private or public key. If not specified a new private key is generated.
        :type import_key: str, int, bytes, bytearray
        :param network: Bitcoin, testnet, litecoin or other network
        :type network: str
        :param compressed: Is key compressed or not, default is True
        :type compressed: bool
        :param passphrase: Optional passphrase if imported key is password protected
        :type passphrase: str
        
        :return: Key object
        """
        self.public_hex = None
        self.public_uncompressed_hex = None
        self.public_compressed_hex = None
        self.public_byte = None
        self.public_uncompressed_byte = None
        self.public_compressed_byte = None
        self.private_byte = None
        self.private_hex = None
        self._x = None
        self._y = None
        self.secret = None
        self.compressed = compressed
        if not import_key:
            import_key = random.SystemRandom().randint(0, secp256k1_n)
        kf = get_key_format(import_key)
        self.key_format = kf["format"]
        network = check_network_and_key(import_key, network, kf["networks"])
        self.network = Network(network)
        if kf['isprivate']:
            self.isprivate = True
        elif kf['isprivate'] is None:
            raise KeyError("Could not determine if key is private or public")
        else:
            self.isprivate = False

        if self.key_format == "wif_protected":
            # TODO: return key as byte to make more efficient
            import_key, self.key_format = self._bip38_decrypt(
                import_key, passphrase)

        if not self.isprivate:
            self.secret = None
            pub_key = to_hexstring(import_key)
            if len(pub_key) == 130:
                self.public_uncompressed_hex = pub_key
                self._x = pub_key[2:66]
                self._y = pub_key[66:130]
                self.compressed = False
                if int(self._y, 16) % 2:
                    prefix = '03'
                else:
                    prefix = '02'
                self.public_hex = prefix + self._x
                self.public_compressed_hex = prefix + self._x
            else:
                self.public_hex = pub_key
                self._x = pub_key[2:66]
                self.compressed = True
                # Calculate y from x with y=x^3 + 7 function
                sign = pub_key[:2] == '03'
                x = int(self._x, 16)
                ys = (x**3 + 7) % secp256k1_p
                y = ecdsa.numbertheory.square_root_mod_prime(ys, secp256k1_p)
                if y & 1 != sign:
                    y = secp256k1_p - y
                self._y = change_base(y, 10, 16, 64)
                self.public_uncompressed_hex = '04' + self._x + self._y
                self.public_compressed_hex = pub_key
            self.public_compressed_byte = binascii.unhexlify(self.public_hex)
            self.public_uncompressed_byte = binascii.unhexlify(
                self.public_uncompressed_hex)
            if self.compressed:
                self.public_byte = self.public_compressed_byte
            else:
                self.public_byte = self.public_uncompressed_byte
        elif self.isprivate and self.key_format == 'decimal':
            self.secret = import_key
            self.private_hex = change_base(import_key, 10, 16, 64)
            self.private_byte = binascii.unhexlify(self.private_hex)
        elif self.isprivate:
            if self.key_format == 'hex':
                key_hex = import_key
                key_byte = binascii.unhexlify(key_hex)
            elif self.key_format == 'hex_compressed':
                key_hex = import_key[:-2]
                key_byte = binascii.unhexlify(key_hex)
                self.compressed = True
            elif self.key_format == 'bin':
                key_byte = import_key
                key_hex = to_hexstring(key_byte)
            elif self.key_format == 'bin_compressed':
                key_byte = import_key[:-1]
                key_hex = to_hexstring(key_byte)
                self.compressed = True
            elif self.isprivate and self.key_format in [
                    'wif', 'wif_compressed'
            ]:
                # Check and remove Checksum, prefix and postfix tags
                key = change_base(import_key, 58, 256)
                checksum = key[-4:]
                key = key[:-4]
                if checksum != hashlib.sha256(
                        hashlib.sha256(key).digest()).digest()[:4]:
                    raise BKeyError("Invalid checksum, not a valid WIF key")
                found_networks = network_by_value('prefix_wif', key[0:1])
                if not len(found_networks):
                    raise BKeyError(
                        "Unrecognised WIF private key, version byte unknown. Versionbyte: %s"
                        % key[0:1])
                if self.network.network_name not in found_networks:
                    if len(found_networks) > 1:
                        raise BKeyError(
                            "More then one network found with this versionbyte, please specify network. "
                            "Networks found: %s" % found_networks)
                    else:
                        _logger.warning(
                            "Current network %s is different then the one found in key: %s"
                            % (network, found_networks[0]))
                        self.network = Network(found_networks[0])
                if key[-1:] == b'\x01':
                    self.compressed = True
                    key = key[:-1]
                else:
                    self.compressed = False
                key_byte = key[1:]
                key_hex = to_hexstring(key_byte)
            else:
                raise KeyError("Unknown key format %s" % self.key_format)

            if not (key_byte or key_hex):
                raise KeyError("Cannot format key in hex or byte format")
            self.private_hex = key_hex
            self.private_byte = key_byte
            self.secret = int(key_hex, 16)
        else:
            raise KeyError("Cannot import key. Public key format unknown")

        if self.isprivate and not (self.public_byte or self.public_hex):
            if not self.isprivate:
                raise KeyError("Private key has no known secret number")
            point = ec_point(self.secret)
            self._x = change_base(point.x(), 10, 16, 64)
            self._y = change_base(point.y(), 10, 16, 64)
            if point.y() % 2:
                prefix = '03'
            else:
                prefix = '02'

            self.public_compressed_hex = prefix + self._x
            self.public_uncompressed_hex = '04' + self._x + self._y
            self.public_hex = self.public_compressed_hex if self.compressed else self.public_uncompressed_hex

            self.public_byte = binascii.unhexlify(self.public_hex)
            self.public_compressed_byte = binascii.unhexlify(
                self.public_compressed_hex)
            self.public_uncompressed_byte = binascii.unhexlify(
                self.public_uncompressed_hex)
Esempio n. 4
0
from bitcoinlib.networks import Network, network_by_value, network_values_for, wif_prefix_search

#
# Network examples
#

network = Network('bitcoin')
print("\n=== Get all WIF prefixes ===")
print("WIF Prefixes: %s" % network_values_for('prefix_wif'))

print("\n=== Get all HDkey private prefixes ===")
print("HDkey private prefixes: %s" % network_values_for('prefix_wif'))

print("\n=== Get network(s) for WIF prefix B0 ===")
print("WIF Prefixes: %s" % network_by_value('prefix_wif', 'B0'))

print("\n=== Get HD key private prefix for current network ===")
print("self.prefix_hdkey_private: %s" % network.wif_prefix())

print("\n=== Network parameters ===")
for k in network.__dir__():
    if k[:1] != '_':
        v = eval('network.%s' % k)
        if not callable(v):
            print("%25s: %s" % (k, v))

wif = 'Zpub74CSuvLPQxWkdW7bivQAhomXZTzbE8quAakKRg1C3x7uDcCCeh7zPp1tZrtJrscihJRASZWjZQ7nPQj1SHTn8gkzAHPZL3dC' \
      'MbMQLFwMKVV'
print("\n=== Search for WIF prefix ===")
print("WIF: %s" % wif)
Esempio n. 5
0
 def test_networks_prefix_bech32_network_by_value_sorted(self):
     self.assertEqual(network_by_value('prefix_bech32', 'ltc'),
                      ['litecoin', 'litecoin_legacy'])
Esempio n. 6
0
 def test_networks_prefix_bech32_network_by_value(self):
     self.assertEqual(network_by_value('prefix_bech32', 'tb'), ['testnet'])
Esempio n. 7
0
 def test_networks_prefix_wif_network_by_value(self):
     self.assertEqual(network_by_value('prefix_wif', '80')[:1], ['bitcoin'])
     self.assertEqual(network_by_value('prefix_wif', 10), [])