Skip to main content

Implementation of BIP39, BIP32, BIP44, BIP49 and BIP84 for wallet seeds, keys and addresses generation. Supported coins: Bitcoin, Litecoin, Dogecoin, Ethereum.

Project description

BIP utility library

Introduction

This package contains an implementation of some BIP (Bitcoin Improvement Proposal) specifications, allowing to:

  • Generate a mnemonic string from a random entropy
  • Generate a secure seed from the mnemonic string
  • Use the seed to generate the master key of the wallet and derive the children keys, including address encoding

The implemented BIP specifications are the following:

  • BIP-0039 for mnemonic and seed generation
  • BIP-0032 for master key generation (from the secure seed) and children keys derivation
  • BIP-0044, BIP-0049 and BIP-0084 for the hierarchy of deterministic wallets, based on BIP-0032 algorithms

In addition to this, the package allows to:

  • Generate P2PKH addresses (included in BIP-0044)
  • Generate P2SH addresses (included in BIP-0049)
  • Generate P2WPKH addresses (included in BIP-0084)
  • Encode/Decode WIF
  • Encode/Decode base58
  • Encode/Decode bech32

Install the package

The package requires Python 3, it is not compatible with Python 2. To install it:

  • Using setuptools:

      python setup.py install
    
  • Using pip:

      pip install bip_utils
    

To run the unit tests:

python setup.py test

BIP-0039 library

Mnemonic generation

A mnemonic string can be generated by specifying the words number (in this case a random entropy will be used) or directly the entropy bytes. Supported words number: 12, 15, 18, 21, 24 Supported entropy bits: 128, 160, 192, 224, 256

NOTE: only the English words list is supported.

Code example

import binascii
from bip_utils import Bip39MnemonicGenerator

# Generate a random mnemonic string of 15 words
mnemonic = Bip39MnemonicGenerator.FromWordsNumber(15)

# Generate the mnemonic string from entropy bytes:
entropy_bytes_hex = b"00000000000000000000000000000000"
mnemonic = Bip39MnemonicGenerator.FromEntropy(binascii.unhexlify(entropy_bytes_hex))

Mnemonic validation

A mnemonic string can be validated by verifying its checksum. It is also possible to get back the entropy bytes from a mnemonic.

Code example

 from bip_utils import Bip39MnemonicValidator

 # Get back the original entropy from a mnemonic string
 entropy_bytes = Bip39MnemonicValidator(mnemonic).GetEntropy()
 # Validate a mnemonic string by verifying its checksum
 is_valid = Bip39MnemonicValidator(mnemonic).Validate()

Seed generation

A secure 64-byte seed is generated from a mnemonic and can be protected by a passphrase. This seed can be used to contruct a Bip class.

Code example

from bip_utils import Bip39SeedGenerator

# If not specified, the passphrase will be empty
passphrase = "my_passphrase"
seed_bytes = Bip39SeedGenerator(mnemonic).Generate(passphrase)

BIP-0032 library

The BIP-0032 library is wrapped inside the BIP-0044, BIP-0049 and BIP-0084 libraries, so there is no need to use it alone unless you need to derive some non-standard paths.

Construction from a seed

The class can be constructed from a seed. The seed can be specified manually or generated by Bip39SeedGenerator. The constructed class is the master path, so printing the private key will result in printing the master key.

Code example

import binascii
from bip_utils import Bip32

# Seed bytes
seed_bytes = binascii.unhexlify(b"5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4")
# Construct from seed. In case it's a test net, pass True as second parameter. Derivation path returned: m
bip32_ctx = Bip32.FromSeed(seed_bytes)
# Print master key in extended format
print(bip32_ctx.ExtendedPrivateKey())

In addition to a seed, it's also possible to specify a derivation path.

Code example

# Derivation path returned: m/0'/1'/2
bip32_ctx = Bip32.FromSeedAndPath(seed_bytes, "m/0'/1'/2")
# Print private key for derivation path m/0'/1'/2 in extended format
print(bip32_ctx.ExtendedPrivateKey())

Construction from an extended key

Alternatively, the class can be constructed directly from an extended key.
The object returned will be at the same depth of the specified key.

Code example

from bip_utils import Bip32

# Private extended key from derivation path m/0'/1 (depth 2)
key_str = "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"
# Construct from key (return object has depth 2)
bip32_ctx = Bip32.FromExtendedKey(key_str)
# Print keys
print(bip32_ctx.ExtendedPrivateKey())
print(bip32_ctx.ExtendedPublicKey())

# Public extended key from derivation path m/0'/1 (depth 2)
key_str = "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"
# Construct from key (return object has depth 2)
bip32_ctx = Bip32.FromExtendedKey(key_str)
# Print key
print(bip32_ctx.ExtendedPublicKey())
# Private key cannot be printed, since the object has been constructed from a public one

Keys derivation

Each time a key is derived, a new instance of the Bip32 class is returned. This allows to chain the methods call or save a specific key pair for future derivation. The Bip32.HardenIndex method can be used to make an index hardened.

Code example

import binascii
from bip_utils import Bip32

# Seed bytes
seed_bytes = binascii.unhexlify(b"5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4")
# Path: m
bip32_ctx = Bip32.FromSeed(seed_bytes)
# Derivation path: m/0'/1'/2/3
bip32_ctx = bip32_ctx.ChildKey(Bip32.HardenIndex(0)) \
                     .ChildKey(Bip32.HardenIndex(1)) \
                     .ChildKey(2)                    \
                     .ChildKey(3)
# Print keys in extended format
print(bip32_ctx.ExtendedPrivateKey())
print(bip32_ctx.ExtendedPublicKey())

# Alternative: use DerivePath method
bip32_ctx = Bip32.FromSeed(seed_bytes)
bip32_ctx = bip32_ctx.DerivePath("0'/1'/2/3")

# DerivePath derives from the current depth, so it can be split
bip32_ctx = Bip32.FromSeed(seed_bytes)
bip32_ctx = bip32_ctx.DerivePath("0'/1'")   # Derivation path: m/0'/1'
bip32_ctx = bip32_ctx.DerivePath("2/3")     # Derivation path: m/0'/1'/2/3

Parse path

The Bip32 module allows also to parse derivation paths by returning the list of indexes in the path.
In case of error, an empty list is returned.

Code example

from bip_utils import PathParser

# Print: ["m", 2147483648, 2147483649, 2]
print(PathParser.Parse("m/0'/1'/2"))
# Same but skipping the master. Print: [2147483648, 2147483649, 2]
print(PathParser.Parse("0'/1'/2", True))
# Error path: empty list returned. Print: []
print(PathParser.Parse("m/0'/abc/2"))

Bip-0044, BIP-0049, BIP-0084 libraries

These libraries derives all from the same base class, so they are used exactly in the same way. Therefore, the following code examples can be used with the Bip44, Bip49 or Bip84 class.

Construction from a seed

A Bip class can be constructed from a seed, like Bip32. The seed can be specified manually or generated by Bip39SeedGenerator.

Code example

import binascii
from bip_utils import Bip44, Bip44Coins

# Seed bytes
seed_bytes = binascii.unhexlify(b"5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4")
# Derivation path returned: m
# In case it's a test net, pass True as second parameter
bip44_ctx = Bip44.FromSeed(seed_bytes, Bip44Coins.BITCOIN)

Construction from an extended key

Alternatively, a Bip class can be constructed directly from an extended key.
The Bip object returned will be at the same depth of the specified key.

Code example

from bip_utils import Bip44, Bip44Coins

# Private extended key
key_str = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
# Construct from extended key
bip44_ctx = Bip44.FromExtendedKey(key_str, Bip44Coins.BITCOIN)

Keys derivation

Like Bip32, each time a key is derived a new instance of the Bip class is returned.
The keys must be derived with the levels specified by BIP-0044:

m / purpose' / coin_type' / account' / change / address_index

using the correspondent methods. If keys are derived in the wrong level, a RuntimeError will be raised.
The private and public extended keys can be printed at any level.

NOTE: currently only Bitcoin, Litecoin, Dogecoin (and related test nets) and Ethereum are supported, but it can be easily extended with other coins.

Code example

import binascii
from bip_utils import Bip44, Bip44Coins, Bip44Changes

# Seed bytes
seed_bytes = binascii.unhexlify(b"5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4")
# Create from seed
bip44_mst = Bip44.FromSeed(seed_bytes, Bip44Coins.BITCOIN)
# Print master key in extended format (pass False as parameter to get the key bytes instead)
print(bip44_mst.PrivateKey())
# Print the master key in WIF
print(bip44_mst.IsMasterLevel())
print(bip44_mst.WalletImportFormat())

# Derive account 0 for Bitcoin: m/44'/0'/0'
bip44_acc = bip44_mst.Purpose() \
                     .Coin()    \
                     .Account(0)
# Print keys in extended format
print(bip44_acc.IsAccountLevel())
print(bip44_acc.PrivateKey())
print(bip44_acc.PublicKey())

# Derive the external chain: m/44'/0'/0'/0
bip44_change = bip44_acc.Change(Bip44Changes.CHAIN_EXT)
# Print again keys in extended format
print(bip44_change.IsChangeLevel())
print(bip44_change.PrivateKey())
print(bip44_change.PublicKey())

# Derive the first 20 addresses of the external chain: m/44'/0'/0'/0/i
for i in range(20):
    bip44_addr = bip44_change.AddressIndex(i)
    # Print extended keys and address
    print(bip44_addr.PrivateKey())
    print(bip44_addr.PublicKey())
    print(bip44_addr.Address())

In the example above, Bip44 can be substituted with Bip49 or Bip84 without changing the code.

WIF

This library is used internally by the other libraries, but it's available also for external use.

Code example

import binascii
from bip_utils import WifDecoder, WifEncoder

key_bytes = binascii.unhexlify(b'1837c1be8e2995ec11cda2b066151be2cfb48adf9e47b151d46adab3a21cdf67')

# Encode
enc = WifEncoder.Encode(key_bytes)
# Decode
dec = WifDecoder.Decode(enc)

Base58

This library is used internally by the other libraries, but it's available also for external use. It supports both normal encode/decode and check_encode/check_decode.

Code example

import binascii
from bip_utils import Base58Decoder, Base58Encoder

data_bytes = binascii.unhexlify(b"636363")

# Normal encode
enc     = Base58Encoder.Encode(data_bytes)
# Check encode
chk_enc = Base58Encoder.CheckEncode(data_bytes)

# Normal decode
dec     = Base58Decoder.Decode(enc)
# Check decode, RuntimeError is raised if checksum verification fails
chk_dec = Base58Decoder.CheckDecode(chk_enc)

Bech32

This library is used internally by the other libraries, but it's available also for external use.

Code example

import binascii
from bip_utils import Bech32Decoder, Bech32Encoder

data_bytes = binascii.unhexlify(b'9c90f934ea51fa0f6504177043e0908da6929983')

# Encode
enc = Bech32Encoder.EncodeAddr("bc", 0, data_bytes)
# Decode
dec = Bech32Decoder.DecodeAddr("bc", enc)

Complete code example

Example from mnemonic generation to wallet addresses.

import binascii
from bip_utils import Bip39MnemonicGenerator, Bip39SeedGenerator, Bip44, Bip44Coins, Bip44Changes

# Generate random mnemonic
mnemonic = Bip39MnemonicGenerator.FromWordsNumber(12)
print("Mnemonic string: %s" % mnemonic)
# Generate seed from mnemonic
seed_bytes = Bip39SeedGenerator(mnemonic).Generate()

# Generate BIP44 master keys
bip_obj_mst = Bip44.FromSeed(seed_bytes, Bip44Coins.BITCOIN)
# Print master key
print("Master key (bytes): %s" % binascii.hexlify(bip_obj_mst.PrivateKey(False)))
print("Master key (extended): %s" % bip_obj_mst.PrivateKey())
print("Master key (WIF): %s" % bip_obj_mst.WalletImportFormat())

# Generate BIP44 account keys: m/44'/0'/0'
bip_obj_acc = bip_obj_mst.Purpose().Coin().Account(0)
# Generate BIP44 chain keys: m/44'/0'/0'/0
bip_obj_chain = bip_obj_acc.Change(Bip44Changes.CHAIN_EXT)

# Generate the address pool (first 20 addresses): m/44'/0'/0'/0/i
for i in range(20):
    bip_obj_addr = bip_obj_chain.AddressIndex(i)
    print("%d. Address public key (extended): %s" % (i, bip_obj_addr.PublicKey()))
    print("%d. Address private key (extended): %s" % (i, bip_obj_addr.PrivateKey()))
    print("%d. Address: %s" % (i, bip_obj_addr.Address()))

License

This software is available under the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bip_utils-0.3.0a0.tar.gz (35.7 kB view details)

Uploaded Source

Built Distribution

bip_utils-0.3.0a0-py3.8.egg (82.6 kB view details)

Uploaded Source

File details

Details for the file bip_utils-0.3.0a0.tar.gz.

File metadata

  • Download URL: bip_utils-0.3.0a0.tar.gz
  • Upload date:
  • Size: 35.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.2

File hashes

Hashes for bip_utils-0.3.0a0.tar.gz
Algorithm Hash digest
SHA256 722cffcfc1ba5a7e134bfacf37ffee3b9e409184a7f76c0839b5cb6e1344791d
MD5 6e6fb1e6f43d7d84bf9de36cd3741fad
BLAKE2b-256 ce4301df2a5d24a48b6e7f2b605e5810108b65cfcd8ab946b6aa695e486a1491

See more details on using hashes here.

File details

Details for the file bip_utils-0.3.0a0-py3.8.egg.

File metadata

  • Download URL: bip_utils-0.3.0a0-py3.8.egg
  • Upload date:
  • Size: 82.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.2

File hashes

Hashes for bip_utils-0.3.0a0-py3.8.egg
Algorithm Hash digest
SHA256 76ae62741d0af475f0394a69c0aaf6c711baa65e2c84d134c32d319d55dae5d3
MD5 ac198d38f11a0d5464a1990ad37c1e31
BLAKE2b-256 c1a98695b2f337b32de7b853496f033e074c6b231af50ece6efe5144400ef382

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page