def _decode_from_bip32_deriv( bip32_deriv: Mapping[str, str]) -> Tuple[bytes, BIP32KeyOrigin]: # FIXME remove size checks to allow # the instantiation of invalid master_fingerprint and pub_key master_fingerprint = bytes_from_octets(bip32_deriv["master_fingerprint"], 4) der_path = indexes_from_bip32_path(bip32_deriv["path"]) key_origin = BIP32KeyOrigin(master_fingerprint, der_path) return bytes_from_octets(bip32_deriv["pub_key"]), key_origin
def parse(cls: Type["BIP32KeyOrigin"], data: Octets, check_validity: bool = True) -> "BIP32KeyOrigin": "Return a BIP32KeyOrigin by parsing binary data." data = bytes_from_octets(data) master_fingerprint = data[:4] der_path = indexes_from_bip32_path(data[4:]) return cls(master_fingerprint, der_path, check_validity)
def __init__( self, master_fingerprint: Octets, der_path: BIP32DerPath, check_validity: bool = True, ) -> None: object.__setattr__(self, "master_fingerprint", bytes_from_octets(master_fingerprint)) object.__setattr__(self, "der_path", indexes_from_bip32_path(der_path)) if check_validity: self.assert_valid()
def _derive( xkey: BIP32Key, der_path: BIP32DerPath, forced_version: Optional[Octets] = None ) -> BIP32KeyData: if not isinstance(xkey, BIP32KeyData): xkey = BIP32KeyData.b58decode(xkey) indexes = indexes_from_bip32_path(der_path) final_depth = xkey.depth + len(indexes) if final_depth > 255: err_msg = f"final depth greater than 255: {final_depth}" raise BTClibValueError(err_msg) xkey = _ExtendedBIP32KeyData( version=xkey.version, depth=xkey.depth, parent_fingerprint=xkey.parent_fingerprint, index=xkey.index, chain_code=xkey.chain_code, key=xkey.key, ) for index in indexes: __ckd(xkey, index) if forced_version: if xkey.version in XPRV_VERSIONS_ALL: allowed_versions = XPRV_VERSIONS_ALL else: allowed_versions = XPUB_VERSIONS_ALL fversion = bytes_from_octets(forced_version, 4) if fversion not in allowed_versions: err_msg = "invalid version forced on the extended key" err_msg += f"{hex_string(fversion)}" raise BTClibValueError(err_msg) xkey.version = fversion return xkey
def test_from_bip32_path_str() -> None: test_reg_str_vectors = [ # account 0, external branch, address_index 463 ("m/0" + _HARDENING + "/0/463", [0x80000000, 0, 463]), # account 0, internal branch, address_index 267 ("m/0" + _HARDENING + "/1/267", [0x80000000, 1, 267]), ] for bip32_path_str, bip32_path_ints in test_reg_str_vectors: # recover ints from str assert bip32_path_ints == _indexes_from_bip32_path_str(bip32_path_str) assert bip32_path_ints == indexes_from_bip32_path(bip32_path_str) # recover ints from ints assert bip32_path_ints == indexes_from_bip32_path(bip32_path_ints) # recover str from str assert bip32_path_str == str_from_bip32_path(bip32_path_str) # recover str from ints assert bip32_path_str == str_from_bip32_path(bip32_path_ints) # ensure bytes from ints == bytes from str bip32_path_bytes = bytes_from_bip32_path(bip32_path_ints) assert bip32_path_bytes == bytes_from_bip32_path(bip32_path_str) # recover ints from bytes assert bip32_path_ints == indexes_from_bip32_path(bip32_path_bytes) # recover str from bytes assert bip32_path_str == str_from_bip32_path(bip32_path_bytes) test_irregular_str_vectors = [ # account 0, external branch, address_index 463 ("m / 0 h / 0 / 463", [0x80000000, 0, 463]), ("m / 0 H / 0 / 463", [0x80000000, 0, 463]), ("m // 0' / 0 / 463", [0x80000000, 0, 463]), # account 0, internal branch, address_index 267 ("m / 0 h / 1 / 267", [0x80000000, 1, 267]), ("m / 0 H / 1 / 267", [0x80000000, 1, 267]), ("m // 0' / 1 / 267", [0x80000000, 1, 267]), ] for bip32_path_str, bip32_path_ints in test_irregular_str_vectors: # recover ints from str assert bip32_path_ints == _indexes_from_bip32_path_str(bip32_path_str) assert bip32_path_ints == indexes_from_bip32_path(bip32_path_str) # recover ints from ints assert bip32_path_ints == indexes_from_bip32_path(bip32_path_ints) # irregular str != normalized str assert bip32_path_str != str_from_bip32_path(bip32_path_str) # irregular str != normalized str from ints assert bip32_path_str != str_from_bip32_path(bip32_path_ints) # ensure bytes from ints == bytes from str bip32_path_bytes = bytes_from_bip32_path(bip32_path_ints) assert bip32_path_bytes == bytes_from_bip32_path(bip32_path_str) # recover ints from bytes assert bip32_path_ints == indexes_from_bip32_path(bip32_path_bytes) # irregular str != normalized str from bytes assert bip32_path_str != str_from_bip32_path(bip32_path_bytes) with pytest.raises(BTClibValueError, match="invalid index: "): _indexes_from_bip32_path_str("m/1/2/-3h/4") with pytest.raises(BTClibValueError, match="invalid index: "): _indexes_from_bip32_path_str("m/1/2/-3/4") i = 0x80000000 with pytest.raises(BTClibValueError, match="invalid index: "): _indexes_from_bip32_path_str(f"m/1/2/{i}/4") with pytest.raises(BTClibValueError, match="invalid index: "): _indexes_from_bip32_path_str(f"m/1/2/{i}h/4")