python-bitcoin-utils

repository·master·Indexed 18 days ago

https://github.com/karask/python-bitcoin-utils

A pure-Python educational library for building, parsing, and signing Bitcoin data structures. It provides low-level tools for key management, address generation (P2PKH, P2SH, P2WPKH, P2WSH, P2TR), complex transaction construction including SegWit and Taproot, HD derivation via HDWallet, and Bitcoin Core RPC interaction through NodeProxy. Note: Private-key implementations are intended for educational purposes and testing only, as they lack side-channel protection.

Tokens
9.6K
Snippets
43
Records
56
Agent score
62%

What's inside python-bitcoin-utils

  1. Overview of python-bitcoin-utils

    master

    python-bitcoin-utils is a pure-Python educational library designed for building, parsing, and signing Bitcoin data structures. It provides low-level access to Bitcoin primitives, allowing developers to work directly with objects for keys, addresses, scripts, transactions, PSBTs, blocks, HD derivation, and Bitcoin Core RPC calls.

    The library follows a primitive-first approach: you typically construct objects, inspect their internal fields, serialize them, and pass them to subsequent processes.

  2. Supported Bitcoin features and capabilities

    master

    The library (v0.8.4) provides low-level utilities for:

    • Keys and Addresses: Private/public keys, all address types (Legacy, Segwit v0, Taproot/Segwit v1), and HD keys (BIP-32/BIP-39).
    • Transactions: Creation of any transaction type including Legacy (P2PKH, P2SH), Segwit, Timelock (CSV), and Taproot. Supports all SIGHASH types.
    • Scripting: All script opcodes are included. Supports output descriptors (e.g., wpkh(KEY), tr(KEY)) via bitcoinutils.descriptors.
    • Advanced Features: PSBT (BIP-174) support, block parsing, and NodeProxy for programmatic Bitcoin CLI calls.
  3. Core Transaction Objects in python-bitcoin-utils

    master

    The bitcoinutils.transactions module provides the following low-level objects for building and manipulating Bitcoin transactions:

    • TxInput: References a previous transaction output (UTXO).
    • TxOutput: Represents an output containing an amount (in satoshis) and a locking script.
    • TxWitnessInput: Stores the witness stack for SegWit transactions.
    • Transaction: The primary object used to serialize, parse, hash, and build signing digests for a full transaction.
    • Sequence: Used to construct input sequence values, including relative timelocks and Replace-By-Fee (RBF) settings.
    • Locktime: Used to construct transaction-level locktime values.
  4. Use the PSBT module for BIP-174 workflows

    master

    The bitcoinutils.psbt module provides implementations for BIP-174 Partially Signed Bitcoin Transactions (PSBT) workflows. The PSBT class serves multiple roles in a transaction lifecycle:

    • Creator: Wrap an unsigned Transaction object.
    • Updater: Attach UTXO and script metadata using update_input.
    • Signer: Sign inputs using sign_input with a PrivateKey.
    • Combiner: Merge compatible PSBTs using combine.
    • Finalizer: Prepare the transaction for extraction using finalize or finalize_input.
    • Extractor: Retrieve the final transaction using extract_transaction.
  5. Handle integers and data pushes in Scripts

    master

    When constructing a Script object:

    • Small integers: Values from 0 through 16 are automatically converted to their corresponding opcodes (OP_0 through OP_16).
    • Large integers: Values larger than 16 are encoded as script numbers.
    • Hex strings: Hexadecimal strings are automatically encoded using the smallest valid pushdata opcode.

    Example:

    from bitcoinutils.script import Script
    
    # 2 becomes OP_2, hex strings are pushed as data
    script = Script([2, "aa" * 33, "bb" * 33, 2, "OP_CHECKMULTISIG"])
    Script([2, "aa" * 33, "bb" * 33, 2, "OP_CHECKMULTISIG"])
  6. How BIP-174 PSBTs coordinate multisig spending

    master

    BIP-174 (Partially Signed Bitcoin Transactions) allows multiple independent signers to coordinate a transaction without needing to share private keys or understand the full transaction context. In a 2-of-3 multisig scenario, the process follows a specific lifecycle of roles:

    1. Creator/Updater: Builds the unsigned transaction and attaches necessary metadata like the redeem_script and non_witness_utxo (the full previous transaction) so signers can verify the amount being spent.
    2. Signer: Parses the PSBT, verifies the UTXO data, and adds a partial_sig using their private key.
    3. Combiner: Merges multiple PSBTs (each containing different partial signatures) into a single PSBT containing all signatures.
    4. Finalizer: Constructs the final scriptSig (e.g., OP_0 <sig_1> <sig_2> <redeemScript>) and clears metadata.
    5. Extractor: Pulls the fully signed, valid Bitcoin transaction out of the finalized PSBT for broadcasting.

    Signers can work in parallel (creating separate signed PSBTs and then using combine()) or sequentially (passing the same PSBT from one signer to the next).

    # Parallel workflow example
    # Signer 1
    psbt.sign_input(0, sk1)
    # Signer 2
    psbt_unsigned.sign_input(0, sk2)
    # Combiner
    combined = psbt_signed1.combine(psbt_unsigned)
    # Finalizer
    combined.finalize()
    # Extractor
    final_tx = combined.extract_transaction()
  7. Security Model and usage warnings

    master

    The library's private-key implementation is written in pure Python and is intended for educational purposes, testing, testnet, and offline experimentation only.

    Critical Security Warnings:

    • No Side-Channel Protection: ECDSA signing and Taproot/Schnorr signing are not side-channel hardened.
    • Risk of Fund Loss: Do not use this library to protect real funds in timing-observable environments.
    • Mainnet Warnings: On mainnet, the library will emit a one-time warning when private-key operations are performed. No warnings are emitted on testnet, testnet4, signet, or regtest.
  8. Handle Multiple Script Paths in Taproot trees

    master

    Taproot supports complex spending conditions using trees with multiple leaves. The library supports constructing and spending from two-, three-, and four-leaf Taproot trees. For multi-leaf trees, ensure the correct script and control block are used for the specific path being exercised.

    # Example usage for sending to P2TR with multiple scripts
    # (Referencing the logic described in the documentation)
    # see examples/send_to_p2tr_with_three_scripts.py
  9. Security model and private-key warnings

    master

    This library is intended for educational purposes and is written in pure Python. It is not side-channel hardened. Private-key operations (ECDSA, Taproot/Schnorr signing) may be vulnerable to timing attacks.

    Warning Management: Private-key warnings are enabled by default on mainnet. They are disabled by default on testnet, testnet4, signet, and regtest. To manually disable warnings, use:

    bitcoinutils.setup.set_security_warnings(False)

    Recommendation: Use production wallets, hardware signers, or hardened native cryptographic libraries for real funds. Use this library for learning, testing, and transaction construction.

  10. Use NodeProxy to interact with Bitcoin Core RPC

    master

    The NodeProxy class acts as a wrapper around the Bitcoin Core JSON-RPC interface. It allows you to dynamically call Bitcoin Core RPC methods as if they were native Python methods on the proxy instance. This is particularly useful for querying local node state (like block counts) or broadcasting raw transactions within your scripts.

    from bitcoinutils.proxy import NodeProxy
    
    # Initialize the proxy with your node credentials
    proxy = NodeProxy("bitcoinrpc", "password", host="127.0.0.1", port=18443)
    
    # RPC methods are exposed dynamically. 
    # Calling proxy.getblockcount() maps to the Bitcoin Core RPC method 'getblockcount'
    block_count = proxy.getblockcount()
    print(block_count)
  11. Derive keys from a mnemonic using HDWallet

    master

    You can initialize an HDWallet from a BIP-39 mnemonic phrase. Once initialized, use from_path() to navigate to a specific derivation path and get_private_key() to retrieve the resulting PrivateKey object. This allows you to derive specific addresses (like SegWit) from a seed phrase.

    from bitcoinutils.hdwallet import HDWallet
    
    mnemonic = "addict weather world sense idle purity rich wagon ankle fall cheese spatial"
    wallet = HDWallet.from_mnemonic(mnemonic)
    wallet.from_path("m/84'/1'/0'/0/0")
    
    private_key = wallet.get_private_key()
    print(private_key.get_public_key().get_segwit_address().to_string())