def validate_address(addr): try: assert len(addr) > 2 if addr[:2].lower() in ['bc', 'tb']: # Regtest special case if addr[:4] == 'bcrt': if btc.bech32addr_decode('bcrt', addr)[1]: return True, 'address validated' return False, 'Invalid bech32 regtest address' #Else, enforce testnet/mainnet per config if get_network() == "testnet": hrpreq = 'tb' else: hrpreq = 'bc' if btc.bech32addr_decode(hrpreq, addr)[1]: return True, 'address validated' return False, 'Invalid bech32 address' #Not bech32; assume b58 from here ver = btc.get_version_byte(addr) except AssertionError: return False, 'Checksum wrong. Typo in address?' except Exception: return False, "Invalid bitcoin address" if ver != get_p2pk_vbyte() and ver != get_p2sh_vbyte(): return False, 'Wrong address version. Testnet/mainnet confused?' if len(btc.b58check_to_bin(addr)) != 20: return False, "Address has correct checksum but wrong length." return True, 'address validated'
def test_wif_privkeys_valid(): with open(os.path.join(testdir, "base58_keys_valid.json"), "r") as f: json_data = f.read() valid_keys_list = json.loads(json_data) for a in valid_keys_list: key, hex_key, prop_dict = a if prop_dict["isPrivkey"]: netval = "testnet" if prop_dict["isTestnet"] else "mainnet" print 'testing this key: ' + key assert chr(btc.get_version_byte( key)) in '\x80\xef', "not valid network byte" comp = prop_dict["isCompressed"] from_wif_key = btc.from_wif_privkey( key, compressed=comp, vbyte=btc.get_version_byte(key) - 128) expected_key = hex_key if comp: expected_key += '01' assert from_wif_key == expected_key, "Incorrect key decoding: " + \ str(from_wif_key) + ", should be: " + str(expected_key)
def wif_to_privkey(cls, wif): raw = btc.b58check_to_bin(wif) vbyte = struct.unpack('B', btc.get_version_byte(wif))[0] if (struct.unpack('B', btc.BTC_P2PK_VBYTE[get_network()])[0] + struct.unpack('B', cls.WIF_PREFIX)[0]) & 0xff == vbyte: key_type = TYPE_P2PKH elif (struct.unpack('B', btc.BTC_P2SH_VBYTE[get_network()])[0] + struct.unpack('B', cls.WIF_PREFIX)[0]) & 0xff == vbyte: key_type = TYPE_P2SH_P2WPKH else: key_type = None return raw, key_type
def test_wif_privkeys_invalid(): #first try to create wif privkey from key of wrong length bad_privs = [b'\x01\x02' * 17] #some silly private key but > 33 bytes #next try to create wif with correct length but wrong compression byte bad_privs.append(b'\x07' * 32 + b'\x02') for priv in bad_privs: with pytest.raises(Exception) as e_info: fake_wif = btc.wif_compressed_privkey( binascii.hexlify(priv).decode('ascii')) #Create a wif with wrong length bad_wif1 = btc.bin_to_b58check(b'\x01\x02' * 34, b'\x80') #Create a wif with wrong compression byte bad_wif2 = btc.bin_to_b58check(b'\x07' * 33, b'\x80') for bw in [bad_wif1, bad_wif2]: with pytest.raises(Exception) as e_info: fake_priv = btc.from_wif_privkey(bw) #Some invalid b58 from bitcoin repo; #none of these are valid as any kind of key or address with open(os.path.join(testdir, "base58_keys_invalid.json"), "r") as f: json_data = f.read() invalid_key_list = json.loads(json_data) for k in invalid_key_list: bad_key = k[0] for netval in ["mainnet", "testnet"]: #if using pytest -s ; sanity check to see what's actually being tested print('testing this key: ' + bad_key) #should throw exception with pytest.raises(Exception) as e_info: from_wif_key = btc.from_wif_privkey( bad_key, btc.get_version_byte(bad_key)) #in case the b58 check encoding is valid, we should #also check if the leading version byte is in the #expected set, and throw an error if not. if chr(btc.get_version_byte(bad_key)) not in b'\x80\xef': raise Exception("Invalid version byte")
def validate_address(addr, nettype): """A mock of jmclient.validate_address """ BTC_P2PK_VBYTE = {"mainnet": b'\x00', "testnet": b'\x6f'} BTC_P2SH_VBYTE = {"mainnet": b'\x05', "testnet": b'\xc4'} try: ver = btc.get_version_byte(addr) except AssertionError as e: return False, 'Checksum wrong. Typo in address?' except Exception as e: return False, "Invalid bitcoin address" if ver not in [BTC_P2PK_VBYTE[nettype], BTC_P2SH_VBYTE[nettype]]: return False, 'Wrong address version. Testnet/mainnet confused?' if len(btc.b58check_to_bin(addr)) != 20: return False, "Address has correct checksum but wrong length." return True, 'address validated'
def wif_to_privkey(cls, wif): raw = btc.b58check_to_bin(wif)[1] # see note to `privkey_to_wif`; same applies here. # We only handle valid private keys, not any byte string. btc.read_privkey(raw) vbyte = struct.unpack('B', btc.get_version_byte(wif))[0] if (struct.unpack('B', btc.BTC_P2PK_VBYTE[get_network()])[0] + \ struct.unpack('B', cls.WIF_PREFIX)[0]) & 0xff == vbyte: key_type = TYPE_P2PKH elif (struct.unpack('B', btc.BTC_P2SH_VBYTE[get_network()])[0] + \ struct.unpack('B', cls.WIF_PREFIX)[0]) & 0xff == vbyte: key_type = TYPE_P2SH_P2WPKH else: key_type = None return raw, key_type
def wif_to_privkey(cls, wif): """ Note July 2020: the `key_type` construction below is custom and is not currently used. Future code should not use this returned `key_type` variable. """ raw = btc.b58check_to_bin(wif)[1] # see note to `privkey_to_wif`; same applies here. # We only handle valid private keys, not any byte string. btc.read_privkey(raw) vbyte = struct.unpack('B', btc.get_version_byte(wif))[0] if (struct.unpack('B', btc.BTC_P2PK_VBYTE[get_network()])[0] + \ struct.unpack('B', cls.WIF_PREFIX)[0]) & 0xff == vbyte: key_type = TYPE_P2PKH elif (struct.unpack('B', btc.BTC_P2SH_VBYTE[get_network()])[0] + \ struct.unpack('B', cls.WIF_PREFIX)[0]) & 0xff == vbyte: key_type = TYPE_P2SH_P2WPKH else: key_type = None return raw, key_type
def test_wif_privkeys_valid(setup_keys): with open(os.path.join(testdir, "base58_keys_valid.json"), "r") as f: json_data = f.read() valid_keys_list = json.loads(json_data) for a in valid_keys_list: key, hex_key, prop_dict = a if prop_dict["isPrivkey"]: netval = "testnet" if prop_dict["isTestnet"] else "mainnet" jm_single().config.set("BLOCKCHAIN", "network", netval) print('testing this key: ' + key) assert btc.get_version_byte( key) in b'\x80\xef', "not valid network byte" comp = prop_dict["isCompressed"] if not comp: # we only handle compressed keys continue from_wif_key, keytype = BTCEngine.wif_to_privkey(key) expected_key = hextobin(hex_key) + b"\x01" assert from_wif_key == expected_key, "Incorrect key decoding: " + \ str(from_wif_key) + ", should be: " + str(expected_key) jm_single().config.set("BLOCKCHAIN", "network", "testnet")