btclib.bip32 package¶
Submodules¶
btclib.bip32.bip32 module¶
BIP32 hierarchical deterministic wallet functions.
https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
A deterministic wallet derives every key pair from a single root, the one element requiring backup; BIP32 makes the derivation a tree, so a branch of keys can be shared without the rest, and public derivation computes child public keys with no private key at hand.
A BIP32 extended key is 78 bytes:
[ : 4] version
[ 4: 5] depth in the derivation path
[ 5: 9] parent fingerprint
[ 9:13] index
[13:45] chain code
[45:78] compressed pub_key or [0x00][prv_key]
- btclib.bip32.bip32.BIP32Key = btclib.bip32.bip32.BIP32KeyData | bytes | str | bytearray | memoryview¶
A BIP32KeyData, or the base58 text – xprv or xpub – it encodes.
- class btclib.bip32.bip32.BIP32KeyData(version: bytes | str | bytearray | memoryview, depth: int, parent_fingerprint: bytes | str | bytearray | memoryview, index: int, chain_code: bytes | str | bytearray | memoryview, key: bytes | str | bytearray | memoryview, *, check_validity: bool = True)[source]¶
Bases:
objectA BIP32 extended key, decoded into its six fields.
What one xprv/xpub string holds: version, depth, parent fingerprint, index, chain code and the 33-byte key, private keys carrying their 0x00 prefix. The wire form is the 78-byte serialize and parse; b58encode and b58decode add the customary Base58Check spelling. repr masks the key material of a private one.
Frozen, so that a public function handed one can trust it rather than revalidate it: check_validity=False says “not checked yet”, and a mutable field would let that stay true forever, one attribute write after the check that never came (issue 727). _BIP32KeyData below is where derivation still needs to mutate one field at a time – a sibling struct now, and not a subclass, frozen and non-frozen dataclasses refusing to mix in one inheritance chain.
- assert_valid() None[source]¶
Refuse what no valid extended key can hold.
Field types and sizes, a depth consistent with index and parent fingerprint, a known version, and a key that parses – as a scalar in 1..n-1 or as a point of the curve, whichever the version demands.
- classmethod b58decode(address: bytes | str | bytearray | memoryview, *, check_validity: bool = True) BIP32KeyData[source]¶
Build a BIP32KeyData from its xprv/xpub Base58Check text.
The type is asked here rather than left to base58.decode, which does ask it: the cache in front of that call keys on the argument, so anything unhashable – a list, or a mutable buffer – would leave a complaint about hashing instead of the refusal decoding would have given.
- b58encode(*, check_validity: bool = True) str[source]¶
Return the Base58Check text, the xprv/xpub spelling.
- classmethod parse(xkey_bin: BytesIO | bytes | str | bytearray | memoryview, *, check_validity: bool = True) BIP32KeyData[source]¶
Return a BIP32KeyData by parsing 78 bytes from binary data.
- btclib.bip32.bip32.crack_prv_key_var(parent_xpub: BIP32KeyData | bytes | str | bytearray | memoryview, child_xprv: BIP32KeyData | bytes | str | bytearray | memoryview) str[source]¶
Return the parent xprv from a parent xpub and a non-hardened child.
The known break BIP32 warns about: a non-hardened child’s private key minus the derivation offset – computable from the xpub – is the parent’s, so leaking one child xprv beside the account xpub leaks the account. A hardened child is refused, its offset not being computable.
- btclib.bip32.bip32.derive(xkey: BIP32KeyData | bytes | str | bytearray | memoryview, der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, forced_version: bytes | str | bytearray | memoryview | None = None) str[source]¶
Derive a BIP32 key across a path spanning multiple depth levels.
Valid DerPath examples:
string like “m/44h/0’/1H/0/10”
iterable integer indexes
one single integer index
bytes, bytearray or memoryview in multiples of the 4-bytes index
DerPath is case/blank/extra-slash insensitive (e.g. “M /44h / 0’ /1H // 0/ 10 / “).
- btclib.bip32.bip32.derive_(xkey: BIP32KeyData | bytes | str | bytearray | memoryview, der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, forced_version: bytes | str | bytearray | memoryview | None = None) BIP32KeyData[source]¶
Derive a BIP32 key across a path, answering the extended key itself.
derive below is this with the Base58Check encoding on top; the trailing underscore is rootxprv_from_seed_’s, and says the same thing. It is the one of the four object spellings the measurement of issue 886 is about: a caller deriving from a key it holds pays neither the decoding of the argument nor the encoding of the answer, where the xprv text it would have built is a string the next call decodes again.
The path and the version are derive’s, and so is what they accept.
- btclib.bip32.bip32.derive_from_account(mxkey: BIP32KeyData | bytes | str | bytearray | memoryview, branch: int, address_index: int, branches_0_1_only: bool = True, max_index: int = 65535) str[source]¶
Derive a key with public derivation at the given branch and index.
It also ensures that the master key is hardened, that the branch is a standard receive or change, and that the index is not arbitrarily high.
- btclib.bip32.bip32.derive_from_account_(mxkey: BIP32KeyData | bytes | str | bytearray | memoryview, branch: int, address_index: int, branches_0_1_only: bool = True, max_index: int = 65535) BIP32KeyData[source]¶
Derive at the given branch and index, answering the extended key.
derive_from_account below is this with the Base58Check encoding on top; the trailing underscore is rootxprv_from_seed_’s, and says the same thing. Which is the spelling a wallet wants: key_wallet and script_wallet derive one of these per address, and an address is built from the key rather than from its text.
- btclib.bip32.bip32.derive_from_account_range(mxkey: BIP32KeyData | bytes | str | bytearray | memoryview, branch: int, address_indexes: Sequence[int], branches_0_1_only: bool = True, max_index: int = 65535) list[str][source]¶
Derive many addresses of one branch, as Base58Check text.
- btclib.bip32.bip32.derive_from_account_range_(mxkey: BIP32KeyData | bytes | str | bytearray | memoryview, branch: int, address_indexes: Sequence[int], branches_0_1_only: bool = True, max_index: int = 65535) list[BIP32KeyData][source]¶
Derive many addresses of one branch, walking to it once.
derive_from_account_ above answers one, and a wallet asks for many: a gap-limit scan, a ranged descriptor, an account being enumerated. Asked one at a time, each of those walks m/branch/index from the account key, so the branch level – which every sibling shares – is derived again for every one of them, hmac and tweak and all. Here it is derived once and each index is one level on top of it, at a little over half the cost per address, measured over a thousand.
Which is the larger half of what issue 918 asked about, and not the half it named. The parse of the account key is one per path and not one per level – _PubKeyTweakChain holds the point across the levels of a walk, so the branch key is never parsed from octets – so what a range saves there is six percent of an address, which is not worth an entry point. The level is worth one.
A sequence rather than a first and a count, so that a scan resuming at a gap, or a descriptor’s own list, is the argument itself. One address is a loss – the branch walked and nothing to amortize it over – and two already pay, so a caller with exactly one still wants derive_from_account_.
Every index is refused by the rules derive_from_account_ refuses it by, before any of them is walked: a list half derived would leave the caller holding the addresses before the bad index and no answer for the rest. The branch is refused whatever the list, an empty one included – a branch that is no branch is a bad call and not a question nobody asked – and is walked only where there is an index to put on it.
- btclib.bip32.bip32.fingerprint(xkey: BIP32KeyData | bytes | str | bytearray | memoryview) bytes[source]¶
Return the four octets BIP32 identifies an extended key by.
The first four of the HASH160 of the compressed public key, which is what BIP32 defines the fingerprint as and what a BIP32KeyOrigin names its master with.
Here and not in a converter, because it is bip32’s own idea: nothing outside this module’s formats has a fingerprint (issue #1188). Every reader of the four octets is this module’s or sits above it – derive below writes a parent’s into each child it makes, crack_prv_key_var reads one back to tell whether a parent and a child are that pair, and psbt’s origins carry one to name a master.
An xprv answers with its xpub’s, the fingerprint being the public key’s: a pair that gave two would identify one key twice. The neutering is _xpub_from_xprv’s, so the two spellings share the derivation rather than agreeing by coincidence.
- btclib.bip32.bip32.pub_key_derivation_tweaks(pub_key: bytes | str | bytearray | memoryview, chain_code: bytes | str | bytearray | memoryview, der_path: str | Sequence[int] | int | bytes | bytearray | memoryview) list[bytes][source]¶
Return the 32-byte tweak each step of a public derivation adds.
A public child is the parent point plus IL*G, so a whole path is a list of scalars that can be applied wherever the point itself is not available to derive from. That is what a BIP327 MuSig2 aggregate key needs: the group has no private key, so BIP328 derivation reaches the signers as plain tweaks of the aggregate key, and BIP373 carries a psbt signed under a key derived that way.
Hardened indexes are refused before any step is walked, as __pub_key_path_derivation refuses them: they need a private key that by construction does not exist.
- btclib.bip32.bip32.rootxprv_from_seed(seed: bytes | str | bytearray | memoryview, version: bytes | str | bytearray | memoryview = b'\x04\x88\xad\xe4') str[source]¶
Return BIP32 root master extended private key from seed.
- btclib.bip32.bip32.rootxprv_from_seed_(seed: bytes | str | bytearray | memoryview, version: bytes | str | bytearray | memoryview = b'\x04\x88\xad\xe4') BIP32KeyData[source]¶
Return the BIP32 root master extended private key of a seed.
rootxprv_from_seed below is this with the Base58Check encoding on top, and the trailing underscore says which of the two this is: as in ecc.dsa, it marks the spelling for a caller holding the prepared form – there a message already hashed, here the extended key itself rather than its xprv text.
Which is what the four object spellings of this module are for. A caller deriving a child public key from a seed had btclib build Base58Check text and read it back at every hop, three encodings and three decodings of a spelling that never left the module: seed to m/0h/1 and neutered costs about twice what the same three calls over BIP32KeyData do over distinct seeds, and not much less where one seed repeats and _cached_base58_decode answers (issue 886). The text is what rootxprv_from_seed is for, and nothing here stops answering it.
- btclib.bip32.bip32.xpub_from_xprv(xprv: BIP32KeyData | bytes | str | bytearray | memoryview) str[source]¶
Neutered Derivation (ND).
Derivation of the extended public key corresponding to an extended private key (“neutered” as it removes the ability to sign transactions).
- btclib.bip32.bip32.xpub_from_xprv_(xprv: BIP32KeyData | bytes | str | bytearray | memoryview) BIP32KeyData[source]¶
Neutered Derivation (ND), answering the extended key itself.
xpub_from_xprv below is this with the Base58Check encoding on top; the trailing underscore is rootxprv_from_seed_’s, and says the same thing.
btclib.bip32.der_path module¶
BIP32 derivation path and key origin.
DerPath names the representations a derivation path is accepted in.
Three hardening symbols are read and two are written, which is not an oversight: BIP32 spells its own test vectors “m/0H/1/2H”, while BIP380 lists “[deadbeef/0H/0H/0H]” among its invalid hardened indicators, beside “0f” and “-0”. So a path is read leniently, and bip380_enforced is the stricter reading a descriptor needs – the two symbols it allows, and the number spelled the one way it spells it.
- btclib.bip32.der_path.DerPath = str | collections.abc.Sequence[int] | int | bytes | bytearray | memoryview¶
An “m/44h/0’/1H/0/10” string, a sequence of int indexes (a single int included), or bytes, bytearray or memoryview, each a multiple of a 4-byte index.
- btclib.bip32.der_path.bytes_from_der_path(der_path: str | Sequence[int] | int | bytes | bytearray | memoryview) bytes[source]¶
Return the path as bytes: each index in 4 bytes, little-endian.
- btclib.bip32.der_path.hardenings_from_der_path(der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, *, bip380_enforced: bool = False) list[str][source]¶
Return the hardening symbol each step of the path was spelled with.
One entry per index, and “” where the step is unhardened or the path is not text. What it is for is writing the path out as it came in: “0h” and “0’” are one index and two strings, and a descriptor is the string – BIP380’s own valid vectors include the mixed “[deadbeef/0’/0h/0’]”.
- btclib.bip32.der_path.indexes_from_der_path(der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, *, bip380_enforced: bool = False) list[int][source]¶
Return the path as a list of indexes, whatever spelling it came in.
The DerPath spellings of the module docstring are all read: a string with or without the leading m, a single int, the 4-byte little-endian concatenation, or any iterable of ints. bip380_enforced is the stricter reading of a string, and says nothing about the spellings that are not text.
- btclib.bip32.der_path.int_from_index_str(s: str, *, bip380_enforced: bool = False) int[source]¶
Return one path step as its index: “0h” is 0x80000000.
Any of the three hardening symbols is read, uppercase “H” included, which is how BIP32 spells its own vectors. bip380_enforced reads the two a descriptor may hold instead, and holds the number to decimal digits; see the module docstring for why the two readings differ. An index at or above the hardened offset must be spelled with a symbol, not as the number.
- btclib.bip32.der_path.str_from_der_path(der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, master_fingerprint: bytes | str | bytearray | memoryview | None = None, hardening: str = 'h') str[source]¶
Return the path as text, led by m or by the master fingerprint.
With a fingerprint this is the key-origin spelling a descriptor brackets; without, the m/ path BIP32 writes.
- btclib.bip32.der_path.str_from_index_int(i: int, hardening: str = 'h') str[source]¶
Return one index as a path step, the chosen symbol for hardened.
Two symbols, where the reader above takes three: an uppercase “H” is a hardened indicator BIP380 lists as invalid and Bitcoin Core’s parsers refuse, so this writes no path a descriptor cannot hold.
btclib.bip32.key_origin module¶
The BIP32KeyOrigin dataclass and the bip32_derivs codecs.
- class btclib.bip32.key_origin.BIP32KeyOrigin(master_fingerprint: bytes | str | bytearray | memoryview, der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, *, check_validity: bool = True)[source]¶
Bases:
objectWhere a key comes from: master fingerprint and derivation path.
What BIP174’s bip32_derivs and a descriptor’s [fingerprint/path] prefix carry; the path is held as indexes, hardened ones offset by 0x80000000. The wire form is serialize and parse, the bracketed text form description and from_description.
- assert_valid() None[source]¶
Refuse a fingerprint not of 4 bytes, a path too long or out of range.
Btclib bounds a BIP32 path at 255 indexes; each serialized index occupies 4 bytes.
- classmethod from_description(data: str, *, check_validity: bool = True) BIP32KeyOrigin[source]¶
Build a BIP32KeyOrigin from its fingerprint/path spelling.
- classmethod from_dict(dict_: Mapping[str, str], *, check_validity: bool = True) BIP32KeyOrigin[source]¶
Build a BIP32KeyOrigin from the dict shape to_dict writes.
- classmethod parse(data: bytes | str | bytearray | memoryview, *, check_validity: bool = True) BIP32KeyOrigin[source]¶
Return a BIP32KeyOrigin by parsing binary data.
The four fingerprint octets are the encoding’s boundary and not an opinion about what it means, so they are required whatever check_validity says: a slice of a shorter buffer answers with whatever is there, and the object serializes back longer than what it was parsed from. The other half of the same boundary is already unconditional – indexes_from_der_path refuses a remainder that is not a whole number of 4-octet indexes.
- btclib.bip32.key_origin.assert_valid_hd_key_paths(hd_key_paths: Mapping[bytes, BIP32KeyOrigin]) None[source]¶
Raise an exception if the dataclass element is not valid.
- btclib.bip32.key_origin.decode_from_bip32_derivs(bip32_derivs: Sequence[Mapping[str, str]], *, check_validity: bool = True) MutableMapping[bytes, BIP32KeyOrigin][source]¶
Return the dataclass element from its json representation.
- btclib.bip32.key_origin.decode_hd_key_paths(map_: Mapping[bytes | str | bytearray | memoryview, BIP32KeyOrigin] | None) MutableMapping[bytes, BIP32KeyOrigin][source]¶
Return the dataclass element from its json representation.
Module contents¶
BIP32 extended keys, derivation, and key origins.
- class btclib.bip32.BIP32KeyData(version: bytes | str | bytearray | memoryview, depth: int, parent_fingerprint: bytes | str | bytearray | memoryview, index: int, chain_code: bytes | str | bytearray | memoryview, key: bytes | str | bytearray | memoryview, *, check_validity: bool = True)[source]¶
Bases:
objectA BIP32 extended key, decoded into its six fields.
What one xprv/xpub string holds: version, depth, parent fingerprint, index, chain code and the 33-byte key, private keys carrying their 0x00 prefix. The wire form is the 78-byte serialize and parse; b58encode and b58decode add the customary Base58Check spelling. repr masks the key material of a private one.
Frozen, so that a public function handed one can trust it rather than revalidate it: check_validity=False says “not checked yet”, and a mutable field would let that stay true forever, one attribute write after the check that never came (issue 727). _BIP32KeyData below is where derivation still needs to mutate one field at a time – a sibling struct now, and not a subclass, frozen and non-frozen dataclasses refusing to mix in one inheritance chain.
- assert_valid() None[source]¶
Refuse what no valid extended key can hold.
Field types and sizes, a depth consistent with index and parent fingerprint, a known version, and a key that parses – as a scalar in 1..n-1 or as a point of the curve, whichever the version demands.
- classmethod b58decode(address: bytes | str | bytearray | memoryview, *, check_validity: bool = True) BIP32KeyData[source]¶
Build a BIP32KeyData from its xprv/xpub Base58Check text.
The type is asked here rather than left to base58.decode, which does ask it: the cache in front of that call keys on the argument, so anything unhashable – a list, or a mutable buffer – would leave a complaint about hashing instead of the refusal decoding would have given.
- b58encode(*, check_validity: bool = True) str[source]¶
Return the Base58Check text, the xprv/xpub spelling.
- classmethod parse(xkey_bin: BytesIO | bytes | str | bytearray | memoryview, *, check_validity: bool = True) BIP32KeyData[source]¶
Return a BIP32KeyData by parsing 78 bytes from binary data.
- class btclib.bip32.BIP32KeyOrigin(master_fingerprint: bytes | str | bytearray | memoryview, der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, *, check_validity: bool = True)[source]¶
Bases:
objectWhere a key comes from: master fingerprint and derivation path.
What BIP174’s bip32_derivs and a descriptor’s [fingerprint/path] prefix carry; the path is held as indexes, hardened ones offset by 0x80000000. The wire form is serialize and parse, the bracketed text form description and from_description.
- assert_valid() None[source]¶
Refuse a fingerprint not of 4 bytes, a path too long or out of range.
Btclib bounds a BIP32 path at 255 indexes; each serialized index occupies 4 bytes.
- classmethod from_description(data: str, *, check_validity: bool = True) BIP32KeyOrigin[source]¶
Build a BIP32KeyOrigin from its fingerprint/path spelling.
- classmethod from_dict(dict_: Mapping[str, str], *, check_validity: bool = True) BIP32KeyOrigin[source]¶
Build a BIP32KeyOrigin from the dict shape to_dict writes.
- classmethod parse(data: bytes | str | bytearray | memoryview, *, check_validity: bool = True) BIP32KeyOrigin[source]¶
Return a BIP32KeyOrigin by parsing binary data.
The four fingerprint octets are the encoding’s boundary and not an opinion about what it means, so they are required whatever check_validity says: a slice of a shorter buffer answers with whatever is there, and the object serializes back longer than what it was parsed from. The other half of the same boundary is already unconditional – indexes_from_der_path refuses a remainder that is not a whole number of 4-octet indexes.
- btclib.bip32.assert_valid_hd_key_paths(hd_key_paths: Mapping[bytes, BIP32KeyOrigin]) None[source]¶
Raise an exception if the dataclass element is not valid.
- btclib.bip32.bytes_from_der_path(der_path: str | Sequence[int] | int | bytes | bytearray | memoryview) bytes[source]¶
Return the path as bytes: each index in 4 bytes, little-endian.
- btclib.bip32.crack_prv_key_var(parent_xpub: BIP32KeyData | bytes | str | bytearray | memoryview, child_xprv: BIP32KeyData | bytes | str | bytearray | memoryview) str[source]¶
Return the parent xprv from a parent xpub and a non-hardened child.
The known break BIP32 warns about: a non-hardened child’s private key minus the derivation offset – computable from the xpub – is the parent’s, so leaking one child xprv beside the account xpub leaks the account. A hardened child is refused, its offset not being computable.
- btclib.bip32.decode_from_bip32_derivs(bip32_derivs: Sequence[Mapping[str, str]], *, check_validity: bool = True) MutableMapping[bytes, BIP32KeyOrigin][source]¶
Return the dataclass element from its json representation.
- btclib.bip32.decode_hd_key_paths(map_: Mapping[bytes | str | bytearray | memoryview, BIP32KeyOrigin] | None) MutableMapping[bytes, BIP32KeyOrigin][source]¶
Return the dataclass element from its json representation.
- btclib.bip32.derive(xkey: BIP32KeyData | bytes | str | bytearray | memoryview, der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, forced_version: bytes | str | bytearray | memoryview | None = None) str[source]¶
Derive a BIP32 key across a path spanning multiple depth levels.
Valid DerPath examples:
string like “m/44h/0’/1H/0/10”
iterable integer indexes
one single integer index
bytes, bytearray or memoryview in multiples of the 4-bytes index
DerPath is case/blank/extra-slash insensitive (e.g. “M /44h / 0’ /1H // 0/ 10 / “).
- btclib.bip32.derive_(xkey: BIP32KeyData | bytes | str | bytearray | memoryview, der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, forced_version: bytes | str | bytearray | memoryview | None = None) BIP32KeyData[source]¶
Derive a BIP32 key across a path, answering the extended key itself.
derive below is this with the Base58Check encoding on top; the trailing underscore is rootxprv_from_seed_’s, and says the same thing. It is the one of the four object spellings the measurement of issue 886 is about: a caller deriving from a key it holds pays neither the decoding of the argument nor the encoding of the answer, where the xprv text it would have built is a string the next call decodes again.
The path and the version are derive’s, and so is what they accept.
- btclib.bip32.derive_from_account(mxkey: BIP32KeyData | bytes | str | bytearray | memoryview, branch: int, address_index: int, branches_0_1_only: bool = True, max_index: int = 65535) str[source]¶
Derive a key with public derivation at the given branch and index.
It also ensures that the master key is hardened, that the branch is a standard receive or change, and that the index is not arbitrarily high.
- btclib.bip32.derive_from_account_(mxkey: BIP32KeyData | bytes | str | bytearray | memoryview, branch: int, address_index: int, branches_0_1_only: bool = True, max_index: int = 65535) BIP32KeyData[source]¶
Derive at the given branch and index, answering the extended key.
derive_from_account below is this with the Base58Check encoding on top; the trailing underscore is rootxprv_from_seed_’s, and says the same thing. Which is the spelling a wallet wants: key_wallet and script_wallet derive one of these per address, and an address is built from the key rather than from its text.
- btclib.bip32.derive_from_account_range(mxkey: BIP32KeyData | bytes | str | bytearray | memoryview, branch: int, address_indexes: Sequence[int], branches_0_1_only: bool = True, max_index: int = 65535) list[str][source]¶
Derive many addresses of one branch, as Base58Check text.
- btclib.bip32.derive_from_account_range_(mxkey: BIP32KeyData | bytes | str | bytearray | memoryview, branch: int, address_indexes: Sequence[int], branches_0_1_only: bool = True, max_index: int = 65535) list[BIP32KeyData][source]¶
Derive many addresses of one branch, walking to it once.
derive_from_account_ above answers one, and a wallet asks for many: a gap-limit scan, a ranged descriptor, an account being enumerated. Asked one at a time, each of those walks m/branch/index from the account key, so the branch level – which every sibling shares – is derived again for every one of them, hmac and tweak and all. Here it is derived once and each index is one level on top of it, at a little over half the cost per address, measured over a thousand.
Which is the larger half of what issue 918 asked about, and not the half it named. The parse of the account key is one per path and not one per level – _PubKeyTweakChain holds the point across the levels of a walk, so the branch key is never parsed from octets – so what a range saves there is six percent of an address, which is not worth an entry point. The level is worth one.
A sequence rather than a first and a count, so that a scan resuming at a gap, or a descriptor’s own list, is the argument itself. One address is a loss – the branch walked and nothing to amortize it over – and two already pay, so a caller with exactly one still wants derive_from_account_.
Every index is refused by the rules derive_from_account_ refuses it by, before any of them is walked: a list half derived would leave the caller holding the addresses before the bad index and no answer for the rest. The branch is refused whatever the list, an empty one included – a branch that is no branch is a bad call and not a question nobody asked – and is walked only where there is an index to put on it.
- btclib.bip32.encode_to_bip32_derivs(hd_key_paths: Mapping[bytes, BIP32KeyOrigin]) list[Mapping[str, str]][source]¶
Return the json representation of the dataclass element.
- btclib.bip32.fingerprint(xkey: BIP32KeyData | bytes | str | bytearray | memoryview) bytes[source]¶
Return the four octets BIP32 identifies an extended key by.
The first four of the HASH160 of the compressed public key, which is what BIP32 defines the fingerprint as and what a BIP32KeyOrigin names its master with.
Here and not in a converter, because it is bip32’s own idea: nothing outside this module’s formats has a fingerprint (issue #1188). Every reader of the four octets is this module’s or sits above it – derive below writes a parent’s into each child it makes, crack_prv_key_var reads one back to tell whether a parent and a child are that pair, and psbt’s origins carry one to name a master.
An xprv answers with its xpub’s, the fingerprint being the public key’s: a pair that gave two would identify one key twice. The neutering is _xpub_from_xprv’s, so the two spellings share the derivation rather than agreeing by coincidence.
- btclib.bip32.hardenings_from_der_path(der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, *, bip380_enforced: bool = False) list[str][source]¶
Return the hardening symbol each step of the path was spelled with.
One entry per index, and “” where the step is unhardened or the path is not text. What it is for is writing the path out as it came in: “0h” and “0’” are one index and two strings, and a descriptor is the string – BIP380’s own valid vectors include the mixed “[deadbeef/0’/0h/0’]”.
- btclib.bip32.indexes_from_der_path(der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, *, bip380_enforced: bool = False) list[int][source]¶
Return the path as a list of indexes, whatever spelling it came in.
The DerPath spellings of the module docstring are all read: a string with or without the leading m, a single int, the 4-byte little-endian concatenation, or any iterable of ints. bip380_enforced is the stricter reading of a string, and says nothing about the spellings that are not text.
- btclib.bip32.int_from_index_str(s: str, *, bip380_enforced: bool = False) int[source]¶
Return one path step as its index: “0h” is 0x80000000.
Any of the three hardening symbols is read, uppercase “H” included, which is how BIP32 spells its own vectors. bip380_enforced reads the two a descriptor may hold instead, and holds the number to decimal digits; see the module docstring for why the two readings differ. An index at or above the hardened offset must be spelled with a symbol, not as the number.
- btclib.bip32.pub_key_derivation_tweaks(pub_key: bytes | str | bytearray | memoryview, chain_code: bytes | str | bytearray | memoryview, der_path: str | Sequence[int] | int | bytes | bytearray | memoryview) list[bytes][source]¶
Return the 32-byte tweak each step of a public derivation adds.
A public child is the parent point plus IL*G, so a whole path is a list of scalars that can be applied wherever the point itself is not available to derive from. That is what a BIP327 MuSig2 aggregate key needs: the group has no private key, so BIP328 derivation reaches the signers as plain tweaks of the aggregate key, and BIP373 carries a psbt signed under a key derived that way.
Hardened indexes are refused before any step is walked, as __pub_key_path_derivation refuses them: they need a private key that by construction does not exist.
- btclib.bip32.rootxprv_from_seed(seed: bytes | str | bytearray | memoryview, version: bytes | str | bytearray | memoryview = b'\x04\x88\xad\xe4') str[source]¶
Return BIP32 root master extended private key from seed.
- btclib.bip32.rootxprv_from_seed_(seed: bytes | str | bytearray | memoryview, version: bytes | str | bytearray | memoryview = b'\x04\x88\xad\xe4') BIP32KeyData[source]¶
Return the BIP32 root master extended private key of a seed.
rootxprv_from_seed below is this with the Base58Check encoding on top, and the trailing underscore says which of the two this is: as in ecc.dsa, it marks the spelling for a caller holding the prepared form – there a message already hashed, here the extended key itself rather than its xprv text.
Which is what the four object spellings of this module are for. A caller deriving a child public key from a seed had btclib build Base58Check text and read it back at every hop, three encodings and three decodings of a spelling that never left the module: seed to m/0h/1 and neutered costs about twice what the same three calls over BIP32KeyData do over distinct seeds, and not much less where one seed repeats and _cached_base58_decode answers (issue 886). The text is what rootxprv_from_seed is for, and nothing here stops answering it.
- btclib.bip32.str_from_der_path(der_path: str | Sequence[int] | int | bytes | bytearray | memoryview, master_fingerprint: bytes | str | bytearray | memoryview | None = None, hardening: str = 'h') str[source]¶
Return the path as text, led by m or by the master fingerprint.
With a fingerprint this is the key-origin spelling a descriptor brackets; without, the m/ path BIP32 writes.
- btclib.bip32.str_from_index_int(i: int, hardening: str = 'h') str[source]¶
Return one index as a path step, the chosen symbol for hardened.
Two symbols, where the reader above takes three: an uppercase “H” is a hardened indicator BIP380 lists as invalid and Bitcoin Core’s parsers refuse, so this writes no path a descriptor cannot hold.
- btclib.bip32.xpub_from_xprv(xprv: BIP32KeyData | bytes | str | bytearray | memoryview) str[source]¶
Neutered Derivation (ND).
Derivation of the extended public key corresponding to an extended private key (“neutered” as it removes the ability to sign transactions).
- btclib.bip32.xpub_from_xprv_(xprv: BIP32KeyData | bytes | str | bytearray | memoryview) BIP32KeyData[source]¶
Neutered Derivation (ND), answering the extended key itself.
xpub_from_xprv below is this with the Base58Check encoding on top; the trailing underscore is rootxprv_from_seed_’s, and says the same thing.