Ejemplo n.º 1
0
    def dict(self):
        """
        Returns key information as dictionary

        """

        point_x, point_y = self.key.public_point()
        return {
            'private_hex': '' if not self.isprivate else self.private_hex,
            'private_long': '' if not self.isprivate else self.secret,
            'private_wif': '' if not self.isprivate else self.key.wif(),
            'public_hex': self.public_hex,
            'public_hash160': self.key.hash160(),
            'address': self.key.address(),
            'fingerprint': change_base(self.fingerprint(), 256, 16),
            'point_x': point_x,
            'point_y': point_y,
            'key_type': self.key_type,
            'chain_code': change_base(self.chain, 256, 16),
            'child_index': self.child_index,
            'fingerprint_parent': change_base(self.parent_fingerprint, 256,
                                              16),
            'depth': self.depth,
            'extended_wif_public': self.wif_public(),
            'extended_wif_private': self.wif(public=False),
        }
Ejemplo n.º 2
0
 def info(self):
     """
     Prints key information to standard output
     
     """
     if self.isprivate:
         print("SECRET EXPONENT")
         print(" Private Key (hex)           %s" % self.private_hex)
         print(" Private Key (long)          %s" % self.secret)
         print(" Private Key (wif)           %s" % self.key.wif())
         print("")
     print("PUBLIC KEY")
     print(" Public Key (hex)            %s" % self.public_hex)
     print(" Public Key Hash160          %s" % self.key.hash160())
     print(" Address (b58)               %s" % self.key.address())
     print(" Fingerprint (hex)           %s" %
           change_base(self.fingerprint(), 256, 16))
     point_x, point_y = self.key.public_point()
     print(" Point x                     %s" % point_x)
     print(" Point y                     %s" % point_y)
     print("")
     print("EXTENDED KEY INFO")
     print(" Key Type                    %s" % self.key_type)
     print(" Chain code (hex)            %s" %
           change_base(self.chain, 256, 16))
     print(" Child Index                 %s" % self.child_index)
     print(" Parent Fingerprint (hex)    %s" %
           change_base(self.parent_fingerprint, 256, 16))
     print(" Depth                       %s" % self.depth)
     print(" Extended Public Key (wif)   %s" % self.wif_public())
     print(" Extended Private Key (wif)  %s" % self.wif(public=False))
     print("\n")
Ejemplo n.º 3
0
    def child_public(self, index=0):
        """
        Use Child Key Derivation to derive child public key of current HD Key object.

        :param index: Key index number
        :return: HD Key class object
        """
        if index > 0x80000000:
            raise BKeyError("Cannot derive hardened key from public private key. Index must be less then 0x80000000")
        data = self.public().public_byte() + struct.pack('>L', index)
        key, chain = self._key_derivation(data)
        key = change_base(key, 256, 10)
        if key > secp256k1_n:
            raise BKeyError("Key cannot be greater then secp256k1_n. Try another index number.")

        x, y = self.public().public_point()
        Ki = ec_point(key) + ecdsa.ellipticcurve.Point(curve, x, y, secp256k1_n)

        if change_base(Ki.y(), 16, 10) % 2:
            prefix = '03'
        else:
            prefix = '02'
        xhex = change_base(Ki.x(), 10, 16, 64)
        secret = change_base(prefix + xhex, 16, 256)
        return HDKey(key=secret, chain=chain, depth=self._depth+1, parent_fingerprint=self.fingerprint(),
                     child_index=index, isprivate=False)
Ejemplo n.º 4
0
    def to_mnemonic(self, data, add_checksum=True, check_on_curve=True):
        """
        Convert key data entropy to Mnemonic sentence

        >>> Mnemonic().to_mnemonic('28acfc94465fd2f6774759d6897ec122')
        'chunk gun celery million wood kite tackle twenty story episode raccoon dutch'

        :param data: Key data entropy
        :type data: bytes, hexstring
        :param add_checksum: Included a checksum? Default is True
        :type add_checksum: bool
        :param check_on_curve: Check if data integer value is on secp256k1 curve. Should be enabled when not testing and working with crypto
        :type check_on_curve: bool
        
        :return str: Mnemonic passphrase consisting of a space seperated list of words
        """
        data = to_bytes(data)
        data_int = change_base(data, 256, 10)
        if check_on_curve and not 0 < data_int < secp256k1_n:
            raise ValueError(
                "Integer value of data should be in secp256k1 domain between 1 and secp256k1_n-1"
            )
        if add_checksum:
            binresult = change_base(data_int, 10, 2,
                                    len(data) * 8) + self.checksum(data)
            wi = change_base(binresult, 2, 2048)
        else:
            wi = change_base(data_int, 10, 2048,
                             len(data) // 1.375 + len(data) % 1.375 > 0)
        return normalize_string(' '.join([self._wordlist[i] for i in wi]))
Ejemplo n.º 5
0
    def child_public(self, index=0, network=None):
        """
        Use Child Key Derivation to derive child public key of current HD Key object.

        :param index: Key index number
        :type index: int
        
        :return HDKey: HD Key class object
        """
        if network is None:
            network = self.network.network_name
        if index > 0x80000000:
            raise BKeyError("Cannot derive hardened key from public private key. Index must be less then 0x80000000")
        data = self.public_byte + struct.pack('>L', index)
        key, chain = self._key_derivation(data)
        key = change_base(key, 256, 10)
        if key > secp256k1_n:
            raise BKeyError("Key cannot be greater then secp256k1_n. Try another index number.")

        x, y = self.key.public_point()
        Ki = ec_point(key) + ecdsa.ellipticcurve.Point(curve, x, y, secp256k1_n)

        # if change_base(Ki.y(), 16, 10) % 2:
        if Ki.y() % 2:
            prefix = '03'
        else:
            prefix = '02'
        xhex = change_base(Ki.x(), 10, 16, 64)
        secret = binascii.unhexlify(prefix + xhex)
        return HDKey(key=secret, chain=chain, depth=self.depth+1, parent_fingerprint=self.fingerprint(),
                     child_index=index, isprivate=False, network=network)
Ejemplo n.º 6
0
    def child_private(self, index=0, hardened=False):
        """
        Use Child Key Derivation (CDK) to derive child private key of current HD Key object.

        :param index: Key index number
        :param hardened: Specify if key must be hardened (True) or normal (False)
        :return: HD Key class object
        """
        if not self._isprivate:
            raise BKeyError("Need a private key to create child private key")
        if hardened:
            index |= 0x80000000
            data = b'\0' + self._key + struct.pack('>L', index)
        else:
            data = self.public().public_byte() + struct.pack('>L', index)
        key, chain = self._key_derivation(data)

        key = change_base(key, 256, 10)
        if key > secp256k1_n:
            raise BKeyError("Key cannot be greater then secp256k1_n. Try another index number.")
        newkey = (key + self._secret) % secp256k1_n
        if newkey == 0:
            raise BKeyError("Key cannot be zero. Try another index number.")
        newkey = change_base(newkey, 10, 256, 32)

        return HDKey(key=newkey, chain=chain, depth=self._depth+1, parent_fingerprint=self.fingerprint(),
                     child_index=index)
Ejemplo n.º 7
0
    def wif(self, prefix=None):
        """
        Get Private Key in Wallet Import Format, steps:
        # Convert to Binary and add 0x80 hex
        # Calculate Double SHA256 and add as checksum to end of key

        :param prefix: Specify versionbyte prefix in hexstring or bytes. Normally doesn't need to be specified, method uses default prefix from network settings
        :type prefix: str, bytes

        :return str: Base58Check encoded Private Key WIF
        """
        if not self.secret:
            raise KeyError("WIF format not supported for public key")
        if prefix is None:
            versionbyte = self.network.prefix_wif
        else:
            # TODO: Test bytearray
            if not isinstance(prefix, (bytes, bytearray)):
                versionbyte = binascii.unhexlify(prefix)
            else:
                versionbyte = prefix
        key = versionbyte + change_base(self.secret, 10, 256, 32)
        if self.compressed:
            key += b'\1'
        key += hashlib.sha256(hashlib.sha256(key).digest()).digest()[:4]
        return change_base(key, 256, 58)
Ejemplo n.º 8
0
    def child_private(self, index=0, hardened=False, network=None):
        """
        Use Child Key Derivation (CDK) to derive child private key of current HD Key object.

        :param index: Key index number
        :type index: int
        :param hardened: Specify if key must be hardened (True) or normal (False)
        :type hardened: bool
        
        :return HDKey: HD Key class object
        """
        if network is None:
            network = self.network.network_name
        if not self.isprivate:
            raise BKeyError("Need a private key to create child private key")
        if hardened:
            index |= 0x80000000
            data = b'\0' + self.private_byte + struct.pack('>L', index)
        else:
            data = self.public_byte + struct.pack('>L', index)
        key, chain = self._key_derivation(data)

        key = change_base(key, 256, 10)
        if key > secp256k1_n:
            raise BKeyError("Key cannot be greater then secp256k1_n. Try another index number.")
        newkey = (key + self.secret) % secp256k1_n
        if newkey == 0:
            raise BKeyError("Key cannot be zero. Try another index number.")
        newkey = change_base(newkey, 10, 256, 32)

        return HDKey(key=newkey, chain=chain, depth=self.depth+1, parent_fingerprint=self.fingerprint(),
                     child_index=index, network=network)
Ejemplo n.º 9
0
 def to_mnemonic(self, hexdata, add_checksum=True):
     if add_checksum:
         binresult = change_base(hexdata, 16, 2, len(hexdata) * 4) + self.checksum(hexdata)
         wi = change_base(binresult, 2, 2048)
     else:
         wi = change_base(hexdata, 16, 2048)
     return self.normalize_string(' '.join([self._wordlist[i] for i in wi]))
Ejemplo n.º 10
0
 def to_mnemonic(self, data, add_checksum=True, check_on_curve=True):
     """
     Convert key data entropy to Mnemonic sentence
     
     :param data: Key data entropy
     :type data: bytes, hexstring
     :param add_checksum: Included a checksum? Default is True
     :type add_checksum: bool
     :param check_on_curve: Check if data integer value is on secp256k1 curve. Should be enabled when not testing and working with crypto
     :type check_on_curve: bool
     
     :return str: Mnemonic passphrase consisting of a space seperated list of words
     """
     data = to_bytes(data)
     data_int = change_base(data, 256, 10)
     if check_on_curve and not 0 < data_int < secp256k1_n:
         raise ValueError(
             "Integer value of data should be in secp256k1 domain between 1 and secp256k1_n-1"
         )
     if add_checksum:
         binresult = change_base(data_int, 10, 2,
                                 len(data) * 8) + self.checksum(data)
         wi = change_base(binresult, 2, 2048)
     else:
         wi = change_base(data_int, 10, 2048)
     return normalize_string(' '.join([self._wordlist[i] for i in wi]))
Ejemplo n.º 11
0
    def _create_public(self):
        """
        Create public key point and hex repressentation from private key.

        :return:
        """
        if self._secret:
            point = ec_point(self._secret)
            self._x = change_base(int(point.x()), 10, 16, 64)
            self._y = change_base(int(point.y()), 10, 16, 64)
            if point.y() % 2:
                prefix = '03'
            else:
                prefix = '02'
            self._public = prefix + self._x
            self._public_uncompressed = '04' + self._x + self._y
        if hasattr(self, '_x') and hasattr(self, '_y') and self._x and self._y:
            if change_base(self._y, 16, 10) % 2:
                prefix = '03'
            else:
                prefix = '02'
            self._public = prefix + self._x
            self._public_uncompressed = '04' + self._x + self._y
        else:
            raise BKeyError("Key error, no secret key or public key point found.")
Ejemplo n.º 12
0
    def to_entropy(self, words, includes_checksum=True):
        """
        Convert Mnemonic words back to entrophy

        :param words: Mnemonic words as string of list of words
        :param includes_checksum: Boolean to specify if checksum is used
        :return: Hex entrophy string
        """
        words = self.sanitize_mnemonic(words)
        if isinstance(words, (str, unicode if sys.version < '3' else str)):
            words = words.split(' ')
        wi = []
        for word in words:
            wi.append(self._wordlist.index(word))
        ent = change_base(wi, 2048, 16, output_even=0)
        if includes_checksum:
            binresult = change_base(ent, 16, 2, len(ent) * 4)
            ent = change_base(binresult[:-len(binresult) // 33], 2, 16)

            # Check checksum
            checksum = binresult[-len(binresult) // 33:]
            if checksum != self.checksum(ent):
                raise Warning("Invalid checksum %s for entropy %s" % (checksum, ent))

        return ent
Ejemplo n.º 13
0
    def to_entropy(self, words, includes_checksum=True):
        """
        Convert Mnemonic words back to key data entropy

        >>> from bitcoinlib.encoding import to_hexstring
        >>> to_hexstring(Mnemonic().to_entropy('chunk gun celery million wood kite tackle twenty story episode raccoon dutch'))
        '28acfc94465fd2f6774759d6897ec122'


        :param words: Mnemonic words as string of list of words
        :type words: str
        :param includes_checksum: Boolean to specify if checksum is used. Default is True
        :type includes_checksum: bool
        
        :return bytes: Entropy seed
        """
        words = self.sanitize_mnemonic(words)
        if isinstance(words, TYPE_TEXT):
            words = words.split(' ')
        wi = []
        for word in words:
            wi.append(self._wordlist.index(word))
        ent = change_base(wi, 2048, 256, output_even=False)
        if includes_checksum:
            binresult = change_base(ent, 256, 2, len(ent) * 4)
            ent = change_base(binresult[:-len(binresult) // 33], 2, 256)

            # Check checksum
            checksum = binresult[-len(binresult) // 33:]
            if checksum != self.checksum(ent):
                raise ValueError("Invalid checksum %s for entropy %s" %
                                 (checksum, ent))

        return ent
Ejemplo n.º 14
0
    def to_entropy(self, words, includes_checksum=True):
        """
        Convert Mnemonic words back to key data entrophy

        :param words: Mnemonic words as string of list of words
        :type words: str
        :param includes_checksum: Boolean to specify if checksum is used. Default is True
        :type includes_checksum: bool
        
        :return bytes: Entrophy seed
        """
        words = self.sanitize_mnemonic(words)
        if isinstance(words, (str, unicode if sys.version < '3' else str)):
            words = words.split(' ')
        wi = []
        for word in words:
            wi.append(self._wordlist.index(word))
        ent = change_base(wi, 2048, 256, output_even=False)
        if includes_checksum:
            binresult = change_base(ent, 256, 2, len(ent) * 4)
            ent = change_base(binresult[:-len(binresult) // 33], 2, 256)

            # Check checksum
            checksum = binresult[-len(binresult) // 33:]
            if checksum != self.checksum(ent):
                raise Warning("Invalid checksum %s for entropy %s" %
                              (checksum, ent))

        return ent
Ejemplo n.º 15
0
 def address(self, compressed=None):
     if not self._public or not self._public_uncompressed:
         self._create_public()
     if (self._compressed and compressed is None) or compressed:
         key = change_base(self._public, 16, 256)
     else:
         key = change_base(self._public_uncompressed, 16, 256)
     versionbyte = NETWORKS[self._network]['address']
     key = versionbyte + hashlib.new('ripemd160', hashlib.sha256(key).digest()).digest()
     checksum = hashlib.sha256(hashlib.sha256(key).digest()).digest()[:4]
     return change_base(key + checksum, 256, 58)
Ejemplo n.º 16
0
    def checksum(hexdata):
        """
        Calculates checksum for given hexdata key

        :param hexdata: key string as hexadecimal
        :return: Checksum of key as hex
        """
        if len(hexdata) % 8 > 0:
            raise ValueError('Data length in bits should be divisible by 32, but it is not (%d bytes = %d bits).' %
                             (len(hexdata), len(hexdata) * 8))
        # data = self.normalize_string(change_base(hexdata, 16, 256))
        data = change_base(hexdata, 16, 256)
        hashhex = hashlib.sha256(data).hexdigest()
        return change_base(hashhex, 16, 2, 256)[:len(data) * 8 // 32]
Ejemplo n.º 17
0
    def wif(self, public=None, child_index=None, prefix=None):
        """
        Get Extended WIF of current key
        
        :param public: Return public key?
        :type public: bool
        :param child_index: Change child index of output WIF key
        :type child_index: int
        :param prefix: Specify version prefix in hexstring or bytes. Normally doesn't need to be specified, method uses default prefix from network settings
        :type prefix: str, bytes

        :return str: Base58 encoded WIF key 
        """
        rkey = self.private_byte or self.public_byte
        if prefix and not isinstance(prefix, (bytes, bytearray)):
            prefix = binascii.unhexlify(prefix)
        if not self.isprivate and public is False:
            return ''
        if self.isprivate and not public:
            if not prefix:
                prefix = self.network.prefix_hdkey_private
            typebyte = b'\x00'
        else:
            if not prefix:
                prefix = self.network.prefix_hdkey_public
            typebyte = b''
            if public:
                rkey = self.public_byte
        if child_index:
            self.child_index = child_index
        raw = prefix + struct.pack('B', self.depth) + self.parent_fingerprint + \
            struct.pack('>L', self.child_index) + self.chain + typebyte + rkey
        chk = hashlib.sha256(hashlib.sha256(raw).digest()).digest()[:4]
        ret = raw+chk
        return change_base(ret, 256, 58, 111)
Ejemplo n.º 18
0
 def hash160(self):
     if not self._public:
         self._create_public()
     key = change_base(self._public, 16, 256)
     # if sys.version_info > (3,):
     #     key = key.encode('utf-8')
     return hashlib.new('ripemd160', hashlib.sha256(key).digest()).hexdigest()
Ejemplo n.º 19
0
def prefix_search(wif, network=None):
    """
    Extract network, script type and public/private information from WIF prefix.

    :param wif: WIF string or prefix in bytes or hexadecimal string
    :type wif: str, bytes
    :param network: Limit search to specified network
    :type network: str

    :return dict:
    """

    key_hex = change_base(wif, 58, 16)
    if not key_hex:
        key_hex = to_hexstring(wif)
    prefix = key_hex[:8].upper()
    matches = []
    for nw in NETWORK_DEFINITIONS:
        if network is not None and nw != network:
            continue
        data = NETWORK_DEFINITIONS[nw]
        for pf in data['prefixes_wif']:
            if pf[1] == prefix:
                matches.append({
                    'prefix': prefix,
                    'is_private': True if pf[0] == 'private' else False,
                    'prefix_str': pf[2],
                    'network': nw,
                    'script_types': pf[3]
                })
    return matches
Ejemplo n.º 20
0
    def wif(self):
        """
        Get Private Key in Wallet Import Format, steps:
        (1) Convert to Binary and add 0x80 hex
        (2) Calculate Double SHA256 and add as checksum to end of key

        :return: Base58Check encoded Private Key WIF
        """
        if not self._secret:
            return False
        version = NETWORKS[self._network]['wif']
        key = version + change_base(str(self._secret), 10, 256, 32)
        if self._compressed:
            key += b'\1'
        key += hashlib.sha256(hashlib.sha256(key).digest()).digest()[:4]
        return change_base(key, 256, 58)
Ejemplo n.º 21
0
def wif_prefix_search(wif, witness_type=None, multisig=None, network=None):
    """
    Extract network, script type and public/private information from HDKey WIF or WIF prefix.

    Example, get bitcoin 'xprv' info:

    >>> wif_prefix_search('0488ADE4', network='bitcoin', multisig=False)
    [{'prefix': '0488ADE4', 'is_private': True, 'prefix_str': 'xprv', 'network': 'bitcoin', 'witness_type': 'legacy', 'multisig': False, 'script_type': 'p2pkh'}]

    Or retreive info with full WIF string:

    >>> wif_prefix_search('xprv9wTYmMFdV23N21MM6dLNavSQV7Sj7meSPXx6AV5eTdqqGLjycVjb115Ec5LgRAXscPZgy5G4jQ9csyyZLN3PZLxoM1h3BoPuEJzsgeypdKj', network='bitcoin', multisig=False)
    [{'prefix': '0488ADE4', 'is_private': True, 'prefix_str': 'xprv', 'network': 'bitcoin', 'witness_type': 'legacy', 'multisig': False, 'script_type': 'p2pkh'}]

    Can return multiple items if no network is specified:

    >>> [nw['network'] for nw in wif_prefix_search('0488ADE4', multisig=True)]
    ['bitcoin', 'dash']

    :param wif: WIF string or prefix in bytes or hexadecimal string
    :type wif: str, bytes
    :param witness_type: Limit search to specific witness type
    :type witness_type: str
    :param multisig: Limit search to multisig: false, true or None for both. Default is both
    :type multisig: bool
    :param network: Limit search to specified network
    :type network: str

    :return dict:
    """

    key_hex = ''
    if len(wif) > 8:
        try:
            key_hex = change_base(wif, 58, 16)
        except:
            pass
    else:
        key_hex = wif
    if not key_hex:
        key_hex = to_hexstring(wif)
    prefix = key_hex[:8].upper()
    matches = []
    for nw in NETWORK_DEFINITIONS:
        if network is not None and nw != network:
            continue
        data = NETWORK_DEFINITIONS[nw]
        for pf in data['prefixes_wif']:
            if pf[0] == prefix and (multisig is None or pf[3] is None or pf[3] == multisig) and \
                    (witness_type is None or pf[4] is None or pf[4] == witness_type):
                matches.append({
                    'prefix': prefix,
                    'is_private': True if pf[2] == 'private' else False,
                    'prefix_str': pf[1],
                    'network': nw,
                    'witness_type': pf[4],
                    'multisig': pf[3],
                    'script_type': pf[5]
                })
    return matches
Ejemplo n.º 22
0
    def bip38_encrypt(self, passphrase):
        """
        BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted privkey.
        Based on code from https://github.com/nomorecoin/python-bip38-testing

        :param passphrase: Required passphrase for encryption
        :type passphrase: str
        
        :return str: BIP38 passphrase encrypted private key
        """
        if self.compressed:
            flagbyte = b'\xe0'
            addr = self.address()
        else:
            flagbyte = b'\xc0'
            addr = self.address_uncompressed()

        privkey = self.private_hex
        if isinstance(addr, str) and sys.version_info > (3,):
            addr = addr.encode('utf-8')
        addresshash = hashlib.sha256(hashlib.sha256(addr).digest()).digest()[0:4]
        key = scrypt.hash(passphrase, addresshash, 16384, 8, 8)
        derivedhalf1 = key[0:32]
        derivedhalf2 = key[32:64]
        aes = AES.new(derivedhalf2)
        encryptedhalf1 = aes.encrypt(binascii.unhexlify('%0.32x' % (int(privkey[0:32], 16) ^
                                                                    int(binascii.hexlify(derivedhalf1[0:16]), 16))))
        encryptedhalf2 = aes.encrypt(binascii.unhexlify('%0.32x' % (int(privkey[32:64], 16) ^
                                                                    int(binascii.hexlify(derivedhalf1[16:32]), 16))))
        encrypted_privkey = b'\x01\x42' + flagbyte + addresshash + encryptedhalf1 + encryptedhalf2
        encrypted_privkey += hashlib.sha256(hashlib.sha256(encrypted_privkey).digest()).digest()[:4]
        return change_base(encrypted_privkey, 256, 58)
Ejemplo n.º 23
0
 def wif(self, public=None, child_index=None):
     """
     Get Extended WIF of current key
     
     :param public: Return public key?
     :type public: bool
     :param child_index: Change child index of output WIF key
     :type child_index: int
     
     :return str: Base58 encoded WIF key 
     """
     rkey = self.private_byte or self.public_byte
     if not self.isprivate and public is False:
         return ''
     if self.isprivate and not public:
         raw = self.network.prefix_hdkey_private
         typebyte = b'\x00'
     else:
         raw = self.network.prefix_hdkey_public
         typebyte = b''
         if public:
             rkey = self.public_byte
     if child_index:
         self.child_index = child_index
     raw += struct.pack('B', self.depth) + self.parent_fingerprint + \
         struct.pack('>L', self.child_index) + self.chain + typebyte + rkey
     chk = hashlib.sha256(hashlib.sha256(raw).digest()).digest()[:4]
     ret = raw + chk
     return change_base(ret, 256, 58, 111)
Ejemplo n.º 24
0
    def wif(self):
        """
        Get Private Key in Wallet Import Format, steps:
        # Convert to Binary and add 0x80 hex
        # Calculate Double SHA256 and add as checksum to end of key

        :return str: Base58Check encoded Private Key WIF
        """
        if not self.secret:
            raise KeyError("WIF format not supported for public key")
        version = self.network.prefix_wif
        key = version + change_base(self.secret, 10, 256, 32)
        if self.compressed:
            key += b'\1'
        key += hashlib.sha256(hashlib.sha256(key).digest()).digest()[:4]
        return change_base(key, 256, 58)
Ejemplo n.º 25
0
    def bip38_encrypt(self, passphrase):
        """
        BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted privkey.
        Based on code from https://github.com/nomorecoin/python-bip38-testing

        :param passphrase: Required passphrase for encryption
        :return: BIP38 passphrase encrypted private key
        """
        if self._compressed:
            flagbyte = b'\xe0'
            addr = self.address()
        else:
            flagbyte = b'\xc0'
            addr = self.address_uncompressed()

        privkey = self.private_hex()
        if isinstance(addr, str) and sys.version_info > (3,):
            addr = addr.encode('utf-8')
        addresshash = hashlib.sha256(hashlib.sha256(addr).digest()).digest()[0:4]
        key = scrypt.hash(passphrase, addresshash, 16384, 8, 8)
        derivedhalf1 = key[0:32]
        derivedhalf2 = key[32:64]
        aes = AES.new(derivedhalf2)
        encryptedhalf1 = aes.encrypt(binascii.unhexlify('%0.32x' % (int(privkey[0:32], 16) ^
                                                                    int(binascii.hexlify(derivedhalf1[0:16]), 16))))
        encryptedhalf2 = aes.encrypt(binascii.unhexlify('%0.32x' % (int(privkey[32:64], 16) ^
                                                                    int(binascii.hexlify(derivedhalf1[16:32]), 16))))
        encrypted_privkey = b'\x01\x42' + flagbyte + addresshash + encryptedhalf1 + encryptedhalf2
        encrypted_privkey += hashlib.sha256(hashlib.sha256(encrypted_privkey).digest()).digest()[:4]
        return change_base(encrypted_privkey, 256, 58)
Ejemplo n.º 26
0
 def address(self, compressed=None, prefix=None):
     """
     Get address derived from public key
     
     :param compressed: Always return compressed address
     :type compressed: bool
     :param prefix: Specify versionbyte prefix in hexstring or bytes. Normally doesn't need to be specified, method uses default prefix from network settings
     :type prefix: str, bytes
     
     :return str: Base58 encoded address 
     """
     if (self.compressed and compressed is None) or compressed:
         key = self.public_byte
     else:
         key = self.public_uncompressed_byte
     if prefix is None:
         versionbyte = self.network.prefix_address
     else:
         # TODO: Test bytearray
         if not isinstance(prefix, (bytes, bytearray)):
             versionbyte = binascii.unhexlify(prefix)
         else:
             versionbyte = prefix
     key = versionbyte + hashlib.new('ripemd160', hashlib.sha256(key).digest()).digest()
     checksum = hashlib.sha256(hashlib.sha256(key).digest()).digest()[:4]
     return change_base(key + checksum, 256, 58)
Ejemplo n.º 27
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
    }
Ejemplo n.º 28
0
 def to_mnemonic(self, data, add_checksum=True):
     """
     Convert key data entropy to Mnemonic sentence
     
     :param data: Key data entropy
     :type data: bytes, hexstring
     :param add_checksum: Included a checksum? Default is True
     :type add_checksum: bool
     
     :return str: Mnemonic passphrase consisting of a space seperated list of words
     """
     data = to_bytes(data)
     if add_checksum:
         binresult = change_base(data, 256, 2, len(data) * 8) + self.checksum(data)
         wi = change_base(binresult, 2, 2048)
     else:
         wi = change_base(data, 256, 2048)
     return normalize_string(' '.join([self._wordlist[i] for i in wi]))
Ejemplo n.º 29
0
    def _bip38_decrypt(encrypted_privkey, passphrase):
        """
        BIP0038 non-ec-multiply decryption. Returns WIF private key.
        Based on code from https://github.com/nomorecoin/python-bip38-testing
        This method is called by Key class init function when importing BIP0038 key.

        :param encrypted_privkey: Encrypted private key using WIF protected key format
        :type encrypted_privkey: str
        :param passphrase: Required passphrase for decryption
        :type passphrase: str
        
        :return str: Private Key WIF
        """
        # TODO: Also check first 2 bytes
        d = change_base(encrypted_privkey, 58, 256)[2:]
        flagbyte = d[0:1]
        d = d[1:]
        if flagbyte == b'\xc0':
            compressed = False
        elif flagbyte == b'\xe0':
            compressed = True
        else:
            raise Warning(
                "Unrecognised password protected key format. Flagbyte incorrect."
            )
        addresshash = d[0:4]
        d = d[4:-4]
        key = scrypt.hash(passphrase, addresshash, 16384, 8, 8)
        derivedhalf1 = key[0:32]
        derivedhalf2 = key[32:64]
        encryptedhalf1 = d[0:16]
        encryptedhalf2 = d[16:32]
        aes = AES.new(derivedhalf2)
        decryptedhalf2 = aes.decrypt(encryptedhalf2)
        decryptedhalf1 = aes.decrypt(encryptedhalf1)
        priv = decryptedhalf1 + decryptedhalf2
        priv = binascii.unhexlify('%064x' %
                                  (int(binascii.hexlify(priv), 16)
                                   ^ int(binascii.hexlify(derivedhalf1), 16)))
        if compressed:
            # FIXME: This works but does probably not follow the BIP38 standards (was before: priv = b'\0' + priv)
            priv += b'\1'
            key_format = 'wif_compressed'
        else:
            key_format = 'wif'
        k = Key(priv, compressed=compressed)
        wif = k.wif()
        addr = k.address()
        if isinstance(addr, str) and sys.version_info > (3, ):
            addr = addr.encode('utf-8')
        if hashlib.sha256(
                hashlib.sha256(addr).digest()).digest()[0:4] != addresshash:
            print(
                'Addresshash verification failed! Password is likely incorrect.'
            )
        return wif, key_format
Ejemplo n.º 30
0
    def generate(self, strength=128, add_checksum=True):
        """
        Generate a Mnemonic key

        :param strength: Key strenght in number of bits
        :param add_checksum: Boolean to specify if checksum needs to be included
        :return: Mnemonic passphrase
        """
        data = change_base(os.urandom(strength // 8), 256, 16)
        return self.to_mnemonic(data, add_checksum=add_checksum)
Ejemplo n.º 31
0
 def info(self):
     if self._secret:
         print("SECRET EXPONENT")
         print(" Private Key (hex)              %s" % change_base(self._secret, 256, 16))
         print(" Private Key (long)             %s" % change_base(self._secret, 256, 10))
         print(" Private Key (wif)              %s" % self.wif())
     else:
         print("PUBLIC KEY ONLY, NO SECRET EXPONENT")
     print("")
     print(" Compressed                  %s" % self.compressed())
     print("PUBLIC KEY")
     print(" Public Key (hex)            %s" % self.public())
     print(" Public Key uncompr. (hex)   %s" % self.public_uncompressed())
     print(" Address (b58)               %s" % self.address())
     print(" Address uncompressed (b58)  %s" % self.address_uncompressed())
     point_x, point_y = self.public_point()
     print(" Point x                     %s" % point_x)
     print(" Point y                     %s" % point_y)
     print("\n")
Ejemplo n.º 32
0
 def extended_wif(self, public=None, child_index=None):
     rkey = self._key
     if not self._isprivate and public is False:
         return ''
     if self._isprivate and not public:
         raw = NETWORKS[self._network]['hdkey_private']
         typebyte = b'\x00'
     else:
         raw = NETWORKS[self._network]['hdkey_public']
         typebyte = b''
         if public:
             rkey = self.public().public_byte()
     if child_index:
         self._child_index = child_index
     raw += change_base(self._depth, 10, 256, 1) + self._parent_fingerprint + \
         struct.pack('>L', self._child_index) + self._chain + typebyte + rkey
     chk = hashlib.sha256(hashlib.sha256(raw).digest()).digest()[:4]
     ret = raw+chk
     return change_base(ret, 256, 58, 111)
Ejemplo n.º 33
0
    def from_seed(import_seed):
        """
        Used by class init function, import key from seed

        :param import_seed: Hex representation of private key seed
        :return: HDKey class object
        """
        seed = change_base(import_seed, 16, 256)
        I = hmac.new(b"Bitcoin seed", seed, hashlib.sha512).digest()
        key = I[:32]
        chain = I[32:]
        return HDKey(key=key, chain=chain)
Ejemplo n.º 34
0
 def _check_list(self, language, vectors):
     mnemo = Mnemonic(language)
     for v in vectors:
         if v[0]:
             phrase = mnemo.to_mnemonic(v[0])
         else:
             phrase = v[1]
         seed = change_base(mnemo.to_seed(phrase, v[4]), 256, 16)
         print("Test %s => %s" % (v[0], phrase))
         self.assertEqual(v[1], phrase)
         self.assertEqual(v[2], seed)
         k = HDKey.from_seed(seed)
         self.assertEqual(k.extended_wif(), v[3])
Ejemplo n.º 35
0
 def _check_list(self, language, vectors):
     mnemo = Mnemonic(language)
     for v in vectors:
         if v[0]:
             phrase = mnemo.to_mnemonic(v[0])
         else:
             phrase = v[1]
         seed = change_base(mnemo.to_seed(phrase, v[4]), 256, 16)
         print("Test %s => %s" % (v[0], phrase))
         self.assertEqual(v[1], phrase)
         self.assertEqual(v[2], seed)
         k = HDKey.from_seed(seed)
         self.assertEqual(k.wif(), v[3])
Ejemplo n.º 36
0
 def _check_list(self, language, vectors):
     mnemo = Mnemonic(language)
     for v in vectors:
         if v[0]:
             phrase = mnemo.to_mnemonic(v[0], check_on_curve=False)
         else:
             phrase = v[1]
         seed = change_base(mnemo.to_seed(phrase, v[4], validate=False), 256, 16)
         # print("Test %s => %s" % (v[0], phrase))
         self.assertEqual(v[1], phrase)
         self.assertEqual(v[2], seed)
         k = HDKey.from_seed(seed)
         self.assertEqual(k.wif(is_private=True), v[3])
Ejemplo n.º 37
0
    def checksum(data):
        """
        Calculates checksum for given data key

        :param data: key string
        :type data: bytes, hexstring
        
        :return str: Checksum of key in bits
        """
        data = to_bytes(data)
        if len(data) % 4 > 0:
            raise ValueError('Data length in bits should be divisible by 32, but it is not (%d bytes = %d bits).' %
                             (len(data), len(data) * 8))
        tx_hash = hashlib.sha256(data).digest()
        return change_base(tx_hash, 256, 2, 256)[:len(data) * 8 // 32]
Ejemplo n.º 38
0
 def info(self):
     if self._isprivate:
         print("SECRET EXPONENT")
         print(" Private Key (hex)           %s" % change_base(self._key, 256, 16))
         print(" Private Key (long)          %s" % self._secret)
         print(" Private Key (wif)           %s" % self.private().wif())
         print("")
     print("PUBLIC KEY")
     print(" Public Key (hex)            %s" % self.public())
     print(" Address (b58)               %s" % self.public().address())
     print(" Fingerprint (hex)           %s" % change_base(self.fingerprint(), 256, 16))
     point_x, point_y = self.public().public_point()
     print(" Point x                     %s" % point_x)
     print(" Point y                     %s" % point_y)
     print("")
     print("EXTENDED KEY INFO")
     print(" Key Type                    %s" % self.key_type)
     print(" Chain code (hex)            %s" % change_base(self.chain(), 256, 16))
     print(" Child Index                 %s" % self.child_index())
     print(" Parent Fingerprint (hex)    %s" % change_base(self.parent_fingerprint(), 256, 16))
     print(" Depth                       %s" % self.depth())
     print(" Extended Public Key (wif)   %s" % self.extended_wif_public())
     print(" Extended Private Key (wif)  %s" % self.extended_wif(public=False))
     print("\n")
Ejemplo n.º 39
0
 def address(self, compressed=None):
     """
     Get address derived from public key
     
     :param compressed: Always return compressed address
     :type compressed: bool
     
     :return str: Base58 encoded address 
     """
     if (self.compressed and compressed is None) or compressed:
         key = self.public_byte
     else:
         key = self.public_uncompressed_byte
     versionbyte = self.network.prefix_address
     key = versionbyte + hashlib.new('ripemd160', hashlib.sha256(key).digest()).digest()
     checksum = hashlib.sha256(hashlib.sha256(key).digest()).digest()[:4]
     return change_base(key + checksum, 256, 58)
Ejemplo n.º 40
0
    def check_proof_of_work(self):
        """
        Check proof of work for this block. Block hash must be below target.

        This library is not optimised for mining, but you can use this for testing or learning purposes.

        >>> b = Block('0000000000000000000154ba9d02ddd6cee0d71d1ea232753e02c9ac6affd709', version=0x20000000, prev_block='0000000000000000000f9578cda278ae7a2002e50d8e6079d11e2ea1f672b483', merkle_root='20e86f03c24c53c12014264d0e405e014e15a02ad02c174f017ee040750f8d9d', time=1592848036, bits=387044594, nonce=791719079)
        >>> b.check_proof_of_work()
        True

        :return bool:
        """
        if not self.block_hash or not self.bits:
            return False
        if change_base(self.block_hash, 256, 10) < self.target:
            return True
        return False
Ejemplo n.º 41
0
    def _bip38_decrypt(encrypted_privkey, passphrase):
        """
        BIP0038 non-ec-multiply decryption. Returns WIF privkey.
        Based on code from https://github.com/nomorecoin/python-bip38-testing
        This method is called by Key class init function when importing BIP0038 key.

        :param encrypted_privkey: Encrypted Private Key using WIF protected key format
        :param passphrase: Required passphrase for decryption
        :return: Private Key WIF
        """
        d = change_base(encrypted_privkey, 58, 256)[2:]
        flagbyte = d[0:1]
        d = d[1:]
        if flagbyte == b'\xc0':
            compressed = False
        elif flagbyte == b'\xe0':
            compressed = True
        else:
            raise Warning("Unrecognised password protected key format. Flagbyte incorrect.")
        addresshash = d[0:4]
        d = d[4:-4]
        key = scrypt.hash(passphrase, addresshash, 16384, 8, 8)
        derivedhalf1 = key[0:32]
        derivedhalf2 = key[32:64]
        encryptedhalf1 = d[0:16]
        encryptedhalf2 = d[16:32]
        aes = AES.new(derivedhalf2)
        decryptedhalf2 = aes.decrypt(encryptedhalf2)
        decryptedhalf1 = aes.decrypt(encryptedhalf1)
        priv = decryptedhalf1 + decryptedhalf2
        priv = binascii.unhexlify('%064x' % (int(binascii.hexlify(priv), 16) ^ int(binascii.hexlify(derivedhalf1), 16)))
        if compressed:
            priv = b'\0' + priv
            key_format = 'wif_compressed'
        else:
            key_format = 'wif'
        k = Key(priv, compressed=compressed)
        wif = k.wif()
        addr = k.address()
        if isinstance(addr, str) and sys.version_info > (3,):
            addr = addr.encode('utf-8')
        if hashlib.sha256(hashlib.sha256(addr).digest()).digest()[0:4] != addresshash:
            print('Addresshash verification failed! Password is likely incorrect.')
        return wif, key_format
Ejemplo n.º 42
0
 def test_change_base_bin_b58(self):
     self.assertEqual('16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM',
                      change_base("\x00\x01\tfw`\x06\x95=UgC\x9e^9\xf8j\r';\xee\xd6\x19g\xf6", 256, 58))
Ejemplo n.º 43
0
    def __init__(self,
                 import_key=None,
                 key=None,
                 chain=None,
                 depth=0,
                 parent_fingerprint=b'\0\0\0\0',
                 child_index=0,
                 isprivate=True,
                 network=None,
                 key_type='bip32',
                 passphrase='',
                 compressed=True):
        """
        Hierarchical Deterministic Key class init function.
        If no import_key is specified a key will be generated with systems cryptographically random function.
        Import key can be any format normal or HD key (extended key) accepted by get_key_format. 
        If a normal key with no chain part is provided, an chain with only 32 0-bytes will be used.

        :param import_key: HD Key to import in WIF format or as byte with key (32 bytes) and chain (32 bytes)
        :type import_key: str, bytes, int, bytearray
        :param key: Private or public key (length 32)
        :type key: bytes
        :param chain: A chain code (length 32)
        :type chain: bytes
        :param depth: Level of depth in BIP32 key path
        :type depth: int
        :param parent_fingerprint: 4-byte fingerprint of parent
        :type parent_fingerprint: bytes
        :param child_index: Index number of child as integer
        :type child_index: int
        :param isprivate: True for private, False for public key. Default is True
        :type isprivate: bool
        :param network: Network name. Derived from import_key if possible
        :type network: str
        :param key_type: HD BIP32 or normal Private Key. Default is 'bip32'
        :type key_type: str
        
        :return HDKey: 
        """

        self.key_format = None
        if (key and not chain) or (not key and chain):
            raise KeyError(
                "Please specify both key and chain, use import_key attribute "
                "or use simple Key class instead")
        self.compressed = compressed
        self.key = None
        if not (key and chain):
            if not import_key:
                # Generate new Master Key
                seedbits = random.SystemRandom().getrandbits(512)
                seed = change_base(str(seedbits), 10, 256, 64)
                key, chain = self._key_derivation(seed)
            elif isinstance(import_key,
                            (bytearray, bytes if sys.version > '3' else
                             bytearray)) and len(import_key) == 64:
                key = import_key[:32]
                chain = import_key[32:]
            elif isinstance(import_key, Key):
                self.key = import_key
                if not import_key.compressed:
                    _logger.warning(
                        "Uncompressed private keys are not standard for BIP32 keys, use at your own risk!"
                    )
                    self.compressed = False
                chain = b'\0' * 32
                key = self.key.private_byte
                key_type = 'private'
            else:
                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 self.key_format in ['hdkey_private', 'hdkey_public']:
                    bkey = change_base(import_key, 58, 256)
                    # Derive key, chain, depth, child_index and fingerprint part from extended key WIF
                    if ord(bkey[45:46]):
                        isprivate = False
                        key = bkey[45:78]
                    else:
                        key = bkey[46:78]
                    depth = ord(bkey[4:5])
                    parent_fingerprint = bkey[5:9]
                    child_index = int(change_base(bkey[9:13], 256, 10))
                    chain = bkey[13:45]
                    # chk = bkey[78:82]
                else:
                    try:
                        self.key = Key(import_key,
                                       passphrase=passphrase,
                                       network=network)
                        if not self.key.compressed:
                            _logger.warning(
                                "Uncompressed private keys are not standard for BIP32 keys, use at your own risk!"
                            )
                            self.compressed = False
                        # FIXME: Maybe its better to create a random chain?
                        chain = b'\0' * 32
                        key = self.key.private_byte
                        key_type = 'private'
                    except BKeyError as e:
                        raise BKeyError("[BKeyError] %s" % e)

        if not isinstance(key, (bytes, bytearray)) or not (len(key) == 32
                                                           or len(key) == 33):
            raise KeyError(
                "Invalid key specified must be in bytes with length 32. You can use "
                "'import_key' attribute to import keys in other formats")
        self.chain = chain
        if self.key is None:
            self.key = Key(key,
                           passphrase=passphrase,
                           network=network,
                           compressed=compressed)
        self.depth = depth
        self.parent_fingerprint = parent_fingerprint
        self.child_index = child_index
        self.isprivate = isprivate
        if not network:
            network = DEFAULT_NETWORK
        self.network = Network(network)
        self.public_byte = self.key.public_byte
        self.public_hex = self.key.public_hex
        self.secret = None
        self.private_hex = None
        self.private_byte = None
        if isprivate:
            self.secret = self.key.secret
            self.private_hex = self.key.private_hex
            self.private_byte = self.key.private_byte
            self.key_hex = self.private_hex
        else:
            self.key_hex = self.public_hex
        self.key_type = key_type
Ejemplo n.º 44
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)
Ejemplo n.º 45
0
 def test_change_base_hex_bin(self):
     self.assertEqual(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f',
                      change_base("000102030405060708090a0b0c0d0e0f", 16, 256))
Ejemplo n.º 46
0
 def test_change_base_zero_int(self):
     self.assertEqual(0, change_base(b'\0', 256, 10))
Ejemplo n.º 47
0
 def test_change_base32_base3(self):
     self.assertEqual(',   . .. ., .   ,. .,  ,. .., . ,..  .,. ,..,, . . .,.,..  ,...,, ,, .,.,,,.,,,...  . , .,,,'
                      '. ...,, .,.,.  ,,..,,,,.', change_base("Oh what a fun we have !", 256, 3))
Ejemplo n.º 48
0
 def test_change_base_leading_zeros4(self):
     self.assertEqual(b'\x04G\x81', change_base('044781', 16, 256))
Ejemplo n.º 49
0
 def test_change_base_b58_hex(self):
     self.assertEqual('00D77BF7628C19E699010D29787A29AFCF8E92AD5A053D55D7',
                      change_base('1LeNnaRtV52nNtZXvtw6PaGKpk46hU1Xmx', 58, 16).upper())
Ejemplo n.º 50
0
 def test_change_base_encodings_bytes(self):
     self.assertEqual('4c52127a72fb42b82439ab18697dcfcfb96ac63ba8209833b2e29f2302b8993f45e743412d65c7a571da70259d4'
                      'f6795e98af20e6e57603314a662a49c198199',
                      change_base(b'LR\x12zr\xfbB\xb8$9\xab\x18i}\xcf\xcf\xb9j\xc6;\xa8 \x983\xb2\xe2\x9f#\x02\xb8'
                                  b'\x99?E\xe7CA-e\xc7\xa5q\xdap%\x9dOg\x95\xe9\x8a\xf2\x0enW`3\x14\xa6b\xa4\x9c'
                                  b'\x19\x81\x99', 256, 16))
Ejemplo n.º 51
0
 def test_change_base_zero_int(self):
     self.assertEqual(0, change_base(b'\0', 256, 10))
Ejemplo n.º 52
0
 def test_change_base_encodings_utf8(self):
     self.assertEqual('e782ba20e5ae8b20e69ab420e6b2bb20e4bcaf20e58f8a20e7819820e586b620e5bf9920e9808320e6b99820e8'
                      '898720e4be8b20e8ae9320e5bfa0',
                      change_base("為 宋 暴 治 伯 及 灘 冶 忙 逃 湘 艇 例 讓 忠", 256, 16))
Ejemplo n.º 53
0
def bech32_to_hash160(address):
    return change_base(addr_bech32_to_pubkeyhash(address), 256, 16)
Ejemplo n.º 54
0
 def test_change_base_leading_zeros_binascii(self):
     y = 251863285056225027460663457133976813779860093019161001622713253221998044380
     self.assertEqual(64, len(change_base(y, 10, 16, 64)))
Ejemplo n.º 55
0
 def test_change_base_padding(self):
     self.assertEqual('0011', change_base(3, 10, 2, 4))
Ejemplo n.º 56
0
 def test_change_base_leading_zeros3(self):
     self.assertEqual('1L', change_base('013', 16, 58))
Ejemplo n.º 57
0
 def test_change_base_dec_b58(self):
     self.assertEqual('LeNnaRtV52nNtZXvtw6PaGKpk46hU1Xmx',
                      change_base('5283658277747592673868818217239156372404875337009783985623', 10, 58, 33))
Ejemplo n.º 58
0
 def test_change_base_leading_zeros(self):
     self.assertEqual(b'\x00\x00\x03', change_base("000003", 16, 256))
Ejemplo n.º 59
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
        }
Ejemplo n.º 60
0
if __name__ == '__main__':
    #
    # SOME EXAMPLES
    #

    from bitcoinlib.keys import HDKey

    # Convert hexadecimal to mnemonic and back again to hex
    print("\nConvert hexadecimal to mnemonic and back again to hex")
    pk = '7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f'
    words = Mnemonic().to_mnemonic(pk)
    print("Hex                %s" % pk)
    print("Checksum bin       %s" % Mnemonic().checksum(pk))
    print("Mnemonic           %s" % words)
    print(Mnemonic().to_seed(words, 'test'))
    print("Seed for HD Key    %s" % change_base(Mnemonic().to_seed(words, 'test'), 256, 16))
    print("Back to Hex        %s" % Mnemonic().to_entropy(words))

    # Generate a random Mnemonic HD Key
    print("\nGenerate a random Mnemonic HD Key")
    entsize = 128
    words = Mnemonic('english').generate(entsize)
    print("Your Mnemonic is   %s" % words)
    print("  (An avarage of %d tries is needed to brute-force this password)" % ((2 ** entsize) // 2))
    seed = change_base(Mnemonic().to_seed(words), 256, 16)
    hdk = HDKey().from_seed(seed)
    print("Seed for HD Key    %s" % change_base(seed, 256, 16))
    print("HD Key WIF is      %s" % hdk)

    # Generate a key from a Mnemonic sentence
    print("\nGenerate a key from a Mnemonic sentence")