def _is_address_valid(self, address): """Checks is an address string is valid""" digits_58_pattern = r'[^123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]' # check for invalid characters if re.search(digits_58_pattern, address): return False # check for length (26-35 characters) # TODO: need to confirm the possible length! if len(address) < 26 or len(address) > 35: return False # get data, network_prefix and checksum data_checksum = b58decode(address.encode('utf-8')) data = data_checksum[:-4] network_prefix = data_checksum[:1] checksum = data_checksum[-4:] # check correct network (depending on address type) if self.get_type() == P2PKH_ADDRESS: if network_prefix != NETWORK_P2PKH_PREFIXES[get_network()]: return False elif self.get_type() == P2SH_ADDRESS: if network_prefix != NETWORK_P2SH_PREFIXES[get_network()]: return False # check address' checksum data_hash = hashlib.sha256(hashlib.sha256(data).digest()).digest() if data_hash[0:4] != checksum: return False return True
def __init__(self, rpcuser=None, rpcpassword=None, host=None, port=None): """Connects to node using credentials given Parameters ---------- rpcuser : str as defined in bitcoin.conf rpcpassword : str as defined in bitcoin.conf host : str, optional host where the Bitcoin node resides; defaults to 127.0.0.1 port : int, optional port to connect to; uses default ports according to network Raises ------ ValueError if rpcuser and/or rpcpassword are not specified """ if not rpcuser or not rpcpassword: raise ValueError('rpcuser or rpcpassword is missing') if not host: host = '127.0.0.1' if not port: port = NETWORK_DEFAULT_PORTS[get_network()] self.proxy = AuthServiceProxy("http://{}:{}@{}:{}".format(rpcuser, rpcpassword, host, port))
def to_wif(self, compressed=True): """Returns key in WIFC or WIF string | Pseudocode: | network_prefix = (1 byte version number) | data = network_prefix + (32 bytes number/key) [ + 0x01 if compressed ] | data_hash = SHA-256( SHA-256( data ) ) | checksum = (first 4 bytes of data_hash) | wif = Base58CheckEncode( data + checksum ) """ # add network prefix to the key data = NETWORK_WIF_PREFIXES[get_network()] + self.to_bytes() if compressed == True: data += b'\x01' # double hash and get the first 4 bytes for checksum data_hash = hashlib.sha256(hashlib.sha256(data).digest()).digest() checksum = data_hash[0:4] # suffix the key bytes with the checksum and encode to base58check wif = b58encode(data + checksum) return wif.decode('utf-8')
def to_string(self): """Returns as address string Uses a segwit's python reference implementation for now. (TODO) """ # convert hex string hash to int array (required by bech32 lib) hash_bytes = unhexlify( self.witness_hash.encode('utf-8') ) witness_int_array = memoryview(hash_bytes).tolist() return bitcoinutils.bech32.encode(NETWORK_SEGWIT_PREFIXES[get_network()], self.segwit_num_version, witness_int_array)
def to_string(self): """Returns as address string | Pseudocode: | network_prefix = (1 byte version number) | data = network_prefix + hash160_bytes | data_hash = SHA-256( SHA-256( hash160_bytes ) ) | checksum = (first 4 bytes of data_hash) | address_bytes = Base58CheckEncode( data + checksum ) """ hash160_encoded = self.hash160.encode('utf-8') hash160_bytes = unhexlify(hash160_encoded) if self.get_type() == P2PKH_ADDRESS: data = NETWORK_P2PKH_PREFIXES[get_network()] + hash160_bytes elif self.get_type() == P2SH_ADDRESS: data = NETWORK_P2SH_PREFIXES[get_network()] + hash160_bytes data_hash = hashlib.sha256(hashlib.sha256(data).digest()).digest() checksum = data_hash[0:4] address_bytes = b58encode(data + checksum) return address_bytes.decode('utf-8')
def _address_to_hash(self, address): """Converts an address to it's hash equivalent The size of the address determines between P2WPKH and P2WSH. Then Bech32 decodes the address removing network prefix, checksum, witness version. Uses a segwit's python reference implementation for now. (TODO) """ witness_version, witness_int_array = bitcoinutils.bech32.decode( NETWORK_SEGWIT_PREFIXES[get_network()], address) if witness_version == None: raise ValueError("Invalid value for parameter address.") if witness_version != self.segwit_num_version: raise TypeError("Invalid segwit version.") return hexlify(bytes(witness_int_array)).decode('utf-8')
def _from_wif(self, wif): """Creates key from WIFC or WIF format key Check to_wif for the detailed process. From WIF is the reverse. Raises ------ ValueError if the checksum is wrong or if the WIF/WIFC is not from the configured network. """ wif_utf = wif.encode('utf-8') # decode base58check get key bytes plus checksum data_bytes = b58decode(wif_utf) key_bytes = data_bytes[:-4] checksum = data_bytes[-4:] # verify key with checksum data_hash = hashlib.sha256(hashlib.sha256(key_bytes).digest()).digest() if not checksum == data_hash[0:4]: raise ValueError('Checksum is wrong. Possible mistype?') # get network prefix and check with current setup network_prefix = key_bytes[:1] if NETWORK_WIF_PREFIXES[get_network()] != network_prefix: raise ValueError('Using the wrong network!') # remove network prefix key_bytes = key_bytes[1:] # check length of bytes and if > 32 then compressed # use this to instantite an ecdsa key if len(key_bytes) > 32: self.key = SigningKey.from_string(key_bytes[:-1], curve=SECP256k1) else: self.key = SigningKey.from_string(key_bytes, curve=SECP256k1)
def init_network(): if setup.get_network() == None: setup.setup(consts.network)