Keys

Bit assumes the easiest way to reason about Bitcoin is in the basic unit of a private key and, therefore, all functionality (viewing balance, making transactions, etc.) is wrapped up in this class for convenience. You shouldn’t have to use anything else.

What is a private key?

A private key is a derived point on an elliptic curve. Bitcoin and other cryptocurrencies use the SEC defined curve secp256k1 due to its properties that allow for particularly fast computation. The secret part of a private key is essentially just a sequence of randomly generated bytes (32 max); nothing special by itself. The features come when you derive a point on the curve from that value.

This value must be kept secret or you risk losing your funds permanently!

Types

Bit defines 2 kinds of private keys: PrivateKey, aliased as simply Key, and PrivateKeyTestnet. Both classes have the exact same functionality.

>>> from bit import Key, PrivateKey, PrivateKeyTestnet
>>>
>>> Key == PrivateKey
True
>>>
>>> dir(Key) == dir(PrivateKeyTestnet)
True

The only difference is the network operations for PrivateKeyTestnet will use Bitcoin’s test network where coins have no value. As such, the derived address will also be different.

Further, there are 2 kinds of multisignature keys: MultiSig and MultiSigTestnet. They incorporate a private key class from above into a multisignature contract.

Creation

Creation of a new private key is as simple as:

>>> from bit import Key
>>> key = Key()

To create a multisignature key a PrivateKey (or PrivateKeyTestnet) must be provided in addition to a list or set of public keys and the number of required signatures for the contract. The public keys may be presented as strings in hex format or bytes.

The following code produces a multisignature contract requiring signatures from both key1 and key2 to spend from:

>>> from bit import Key, MultiSig
>>> key1 = Key()
>>> key2 = Key()
>>> multisig = MultiSig(key1, {key1.public_key, key2.public_key}, 2)

IMPORTANT:

When providing as argument public keys with a set such as above, then Bit will sort the public keys internally in lexicographical order similar to how Electrum behaves. If the public keys are provided with a list, then the ordering of the public keys of that list are used, similar to how Bitcoin Core behaves. Calling public_keys() will always return a list with the public keys in the order they are being used by in the multisignature contract.

Public Point

Each unique value applied to the curve will yield a unique point. As this is a one-way function, there is no known way to derive the private value from the point.

You can see it like this:

>>> key.public_point
Point(x=97142194878787224003202190607135598251247304976930950188466413219499502457410, y=43606604972619611673144670688496329906728122067438546662512577612023859619611)

You will never use this directly.

Public Key

A public key is a public point serialized to bytes. By default all keys will use the compressed version unless you explicitly need otherwise. This reduces the size of each transaction and thus fees.

Access it like so:

>>> key.public_key
b'\x03\xd6\xc4\x88\xab[S\x1d_\xb1H\x12\xbe\x19C\x08\x16\x90~@\x9fv-\x95\xf0w\x87\xfdB\x81\xa3\xd2B'

You will also never use this directly. This value is only used internally to derive your address and is needed in the construction of every transaction.

Addresses

All keys possess a address() property which is derived from your public key:

>>> key.address
'1KF3Vas28f5tnt3rj2fWyR89V9MPw51xhX'

This is what you share with others to receive payments.

Bit also allows to use nested Segwit addresses, which can be displayed with the segwit_address() property:

>>> key.segwit_address
'3DYf8JL9F6Lmz98gpvYMH5qVMXAEazSEEn'

The address of a multisignature key can be displayed in similar manner using the same properties address() and segwit_address():

>>> multisig.address
'328k6RPdgRTLJZe9JUZUanNnJPtWB8tkvM'
>>> multisig.segwit_address
'3AkJkY9XESnPPuX2ZMFotyGggbytxfNRVZ'

Formats

WIF

The wallet import format is the primary way of representing private keys. This format stores the secret value as well as some metadata such as whether or not the public key should be compressed.

To import a private key you can pass a key in wallet import format directly to the initializer:

>>> key = Key('L3jsepcttyuJK3HKezD4qqRKGtwc8d2d1Nw6vsoPDX9cMcUxqqMv')
>>> key.address
'1ExJJsNLQDNVVM1s1sdyt1o5P3GC5r32UG'

Export:

>>> key = Key()
>>> key.to_wif()
'KxVhypbvS3hEYPAP3pYuH1LtcfbdEUcugiqg7fNFUUnmEfWVXJV4'

If you don’t know what kind of private key your WIF represents, and you don’t want to force the use of a particular class, you can do this:

>>> from bit import wif_to_key
>>>
>>> key = wif_to_key('cU6s7jckL3bZUUkb3Q2CD9vNu8F1o58K5R5a3JFtidoccMbhEGKZ')
>>> print(key)
<PrivateKeyTestnet: muUFbvTKDEokGTVUjScMhw1QF2rtv5hxCz>

Hex

Import:

>>> key = Key.from_hex('c28a9f80738f770d527803a566cf6fc3edf6cea586c4fc4a5223a5ad797e1ac3')
>>> key.address
'1ExJJsNLQDNVVM1s1sdyt1o5P3GC5r32UG'

Export:

>>> key = Key()
>>> key.to_hex()
'738fc299281ba8d29f54cbc6b064f9b468e064a02fe6807af8367cbb25b20673'

Integer

Import:

>>> key = Key.from_int(87993618360805341115891506172036624893404292644470266399436498750715784469187)
>>> key.address
'1ExJJsNLQDNVVM1s1sdyt1o5P3GC5r32UG'

Export:

>>> key = Key()
>>> key.to_int()
100038680087491563809217308525458351872289809954309021777847614847412668376286

PEM

Import:

>>> key = Key.from_pem(...)
>>> key.address
'1ExJJsNLQDNVVM1s1sdyt1o5P3GC5r32UG'

Export:

>>> key = Key()
>>> key.to_pem()
b'-----BEGIN PRIVATE KEY-----\nMIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQg93tloWnF8UvDLeK2n0OE\nyf/Si6O73rm33ctZHVhTIBGhRANCAARG3vtgCf5SGfIkwcvuAxNvO/tdy8HnWqS3\nUM+KrWUPpPnHeysZbO6zrG4tN/VBeV2p3whYU6dUhSueOXUPB2Oo\n-----END PRIVATE KEY-----\n'

DER

Import:

>>> key = Key.from_der(...)
>>> key.address
'1ExJJsNLQDNVVM1s1sdyt1o5P3GC5r32UG'

Export:

>>> key = Key()
>>> key.to_der()
b'0\x81\x84\x02\x01\x000\x10\x06\x07*\x86H\xce=\x02\x01\x06\x05+\x81\x04\x00\n\x04m0k\x02\x01\x01\x04 ld\x8f\xd4\xc0\x19\xbd^\xa1\xf7f\xee\x8b9j\x1c\xd3ZX\x89\x1b\x04\x13|e\xe7|g\x84:\xcf\xab\xa1D\x03B\x00\x04\xb6\x1a\x9bQ\x0c?\xe3\xb7\x80\x05,\xcf7\x01{\xf9,"\xb6\xdf\xe5\xbb\x0b+\x9b\xc5\x07@2\xa1\x8a\x01R<\x86\t\x1c\x02\x0fd\x8d\x90\xb5\x99w\xc5\x84(#\xfdr>^\xd3\xb5|\x9d1\xa1\x9c/\x04\xf5\xdd'