btclib

Logo

A Python library for 'bitcoin cryptography'

View the Project on GitHub btclib-org/btclib

A Python library for ‘bitcoin cryptography’

PyPI version downloads development status license supported Python versions

test workflow status lint workflow status pre-commit.ci status documentation build

GitHub repository: btclib-org/btclib slack: btclib_dev


btclib is a Python3 type annotated library for teaching, learning and using bitcoin, focused on elliptic curve cryptography and bitcoin’s blockchain. It started as a teaching tool for Ferdinando Ametrano’s Bitcoin and Blockchain Technology course, it is used in production today (still marked as beta because it is often refactored for improved clarity).

The test suite covers virtually the whole code base, a floor the build enforces, and it answers to vectors their authors publish: the BIPs’ and the SLIPs’ own, Bitcoin Core’s script, transaction, sighash and key-encoding files, HWI’s, trezor’s for BIP39 and SLIP39, and Appendix A.2 of RFC 6979. tests/_data/README.md pins each vendored file to the upstream commit it was copied from, and says whether the two still match — including the few vectors that are btclib’s own, having no upstream.

The library is not limited to secp256k1, and for that curve it always calls btclib_libsecp256k1, FFI bindings to Bitcoin Core’s optimized C library libsecp256k1. They are a required dependency and not an optional accelerator, so installing btclib needs one of their wheels or a C toolchain. The Python arithmetic serves every other curve, and the suite validates it against the bindings: libsecp256k1 says what the right answer is, being what bitcoin consensus relies on.

Included features are:


Module layout

Three pairs of modules are one idea split in two, and each split runs one way only:

the codec / the arithmetic the bitcoin semantics on top
btclib.curvesCurve, mult btclib.eccdsa, ssa, bms
btclib.base58 — the encoding btclib.b58 — WIF, p2pkh, p2sh
btclib.bech32 — the encoding btclib.b32 — p2wpkh, p2wsh, p2tr

The right column imports the left one; the left never imports the right.

So from btclib.ecc import dsa for a signature, from btclib.curves import mult for a point multiplication, btclib.b58 for an address, btclib.base58 for the encoding on its own. Each of the six modules says the same in its own docstring.

The rest, roughly bottom-up. alias holds the types the public API accepts, much of it taking anything convertible rather than one type, and exceptions the errors it raises. to_prv_key and to_pub_key accept any key representation and hand back one. bip32 and mnemonic derive keys. script, tx, block and psbt build and validate what goes on the chain, and script.engine runs a transaction against the consensus rules.

Above them, bip44 composes bip32, script.taproot and both address encodings into an address from an extended key and a derivation path, and descriptors reads the BIP380 grammar and hands back the scripts a descriptor names. psbt_signer is the contract an external signer answers; hwi is that contract over Bitcoin Core’s HWI.

Nothing in the library imports bip21, slip132, fee, keystore, hwi or fetch: they are the top of the stack, and fetch is the only one that goes out to the network. keystore remembers which addresses bip44 has handed out and signs for one with ecc.bms.

The rpc client fetch speaks through is not in that stack: it is bitcoin-core-rpc, a package of its own that btclib depends on — one file, standard library only, installable or copyable, and usable by anyone who wants a node client and no bitcoin library. btclib.fetch turns its answers into Tx and TxOut, and checks the chain the node reports against the network those are labelled for.

The dependency stops at btclib/fetch/. bitcoin-core-rpc declares its own FetchError, importing nothing of btclib’s being what lets its file be vendored, and btclib.fetch.fetcher.client_errors re-raises it as btclib.exceptions’ own, with the status and the code carried across: an except FetchError written against btclib catches what a fetcher raises, and no module outside that package loads urllib.request. Constructing a client opens no socket; the first call does.


To install, or upgrade:

python -m pip install --upgrade btclib

In a virtual environment:

python -m venv venv_btclib
source venv_btclib/bin/activate
python -m pip install --upgrade btclib

On Windows the second line is venv_btclib\Scripts\activate in CMD and PowerShell, source venv_btclib/Scripts/activate in Git bash.

CONTRIBUTING is for development, SECURITY for reporting a vulnerability.