Esempio n. 1
0
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
Esempio n. 2
0
    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)
Esempio n. 3
0
    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()
Esempio n. 4
0
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
Esempio n. 5
0
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")