The Python Quants

Bitcoin Mining with Python

Dr. Yves J. Hilpisch

team@tpq.io | http://tpq.io

The Python Quants GmbH

Some Hashing Examples

The Basics with MD5

From https://en.wikipedia.org/wiki/Hash_function:

A hash function is any function that can be used to map data of arbitrary size to data of fixed size. The values returned by a hash function are called hash values, hash codes, hash sums, or simply hashes.

First, importing Python's hashing function library.

In [1]:
import hashlib

The first MD5 hash codes (cf. https://en.wikipedia.org/wiki/MD5).

In [2]:
md5_1 = hashlib.md5('yves').hexdigest()
md5_1
Out[2]:
'afe3bd960b4c46a68580c4e564cca24e'
In [3]:
md5_2 = hashlib.md5('yves2').hexdigest()
md5_2
Out[3]:
'664d839e06bada38ce04f7208896efdf'
In [4]:
hashlib.md5('Dr. Yves Johannes Hilpisch').hexdigest()
Out[4]:
'642394f6d25fd9fe4b88e359c8aaf051'

Brute Force Hash (Password) Cracking

We define first a character set of lower case letters only.

In [5]:
import string
charset = string.ascii_lowercase
charset
Out[5]:
'abcdefghijklmnopqrstuvwxyz'

Hash codes for all single characters in charset.

In [6]:
from itertools import permutations
In [7]:
pm = permutations(charset, 1)
for comb in pm:
    comb = ''.join(comb)
    md5 = hashlib.md5(comb)
    print comb, md5.hexdigest()
a 0cc175b9c0f1b6a831c399e269772661
b 92eb5ffee6ae2fec3ad71c777531578f
c 4a8a08f09d37b73795649038408b5f33
d 8277e0910d750195b448797616e091ad
e e1671797c52e15f763380b45e841ec32
f 8fa14cdd754f91cc6554c9e71929cce7
g b2f5ff47436671b6e533d8dc3614845d
h 2510c39011c5be704182423e3a695e91
i 865c0c0b4ab0e063e5caa3387c1a8741
j 363b122c528f54df4a0446b6bab05515
k 8ce4b16b22b58894aa86c421e8759df3
l 2db95e8e1a9267b7a1188556b2013b33
m 6f8f57715090da2632453988d9a1501b
n 7b8b965ad4bca0e41ab51de7b31363a1
o d95679752134a2d9eb61dbd7b91c4bcc
p 83878c91171338902e0fe0fb97a8c47a
q 7694f4a66316e53c8cdd9d9954bd611d
r 4b43b0aee35624cd95b910189b3dc231
s 03c7c0ace395d80182db07ae2c30f034
t e358efa489f58062f10dd7316b65649e
u 7b774effe4a349c6dd82ad4f4f21d34c
v 9e3669d19b675bd57058fd4664205d2a
w f1290186a5d0b1ceab27f4e77c0c5d68
x 9dd4e461268c8034f5c8564e155c67a6
y 415290769594460e2e485922904f345d
z fbade9e36a3f36d3d676c1b808451dd7

Now doing brute force hash code cracking — 'knowing' that the relevant word has a maximum of 4 characters.

In [8]:
%%time
for i in range(1, 5):
    print '%d CHARATERS USED NOW' % i
    pm = permutations(charset, i)
    for comb in pm:
        comb = ''.join(comb)
        md5 = hashlib.md5(comb).hexdigest()
        if md5 == md5_1:
            print 'SUCCESS'
            print comb, md5
            break
1 CHARATERS USED NOW
2 CHARATERS USED NOW
3 CHARATERS USED NOW
4 CHARATERS USED NOW
SUCCESS
yves afe3bd960b4c46a68580c4e564cca24e
CPU times: user 375 ms, sys: 40 ms, total: 415 ms
Wall time: 359 ms

Let us enlarge the character set to include digits as well.

In [9]:
charset2 = string.lowercase + string.digits
charset2
Out[9]:
'abcdefghijklmnopqrstuvwxyz0123456789'

Time to crack the second hash code increases due to greater word length and bigger character set.

In [10]:
%%time
for i in range(1, 6):
    print '%d CHARATERS USED NOW' % i
    pm = permutations(charset2, i)
    for comb in pm:
        comb = ''.join(comb)
        md5 = hashlib.md5(comb).hexdigest()
        if md5 == md5_2:
            print 'SUCCESS'
            print comb, md5
            break
1 CHARATERS USED NOW
2 CHARATERS USED NOW
3 CHARATERS USED NOW
4 CHARATERS USED NOW
5 CHARATERS USED NOW
SUCCESS
yves2 664d839e06bada38ce04f7208896efdf
CPU times: user 30 s, sys: 75 ms, total: 30.1 s
Wall time: 29.9 s

Basic Idea Behind Mining

Bitcoin mining is based on SHA256 hash codes (cf. https://en.wikipedia.org/wiki/SHA-2)

In [11]:
md5 = hashlib.sha256('yves')
md5.hexdigest()
Out[11]:
'9195c7b9bb56d375948ba058cddea1982b49864e12c700de58d69c5c72dbd075'

The idea behind mining is to find a hash code that is 'small enough', i.e. lies below a certain target level (mainly defined by 'leading zeros' in the target hex value).

In [12]:
target = '%064x' % (1000000000 << 200)
target
Out[12]:
'0000003b9aca0000000000000000000000000000000000000000000000000000'
In [13]:
target = target.decode('hex')
target
Out[13]:
'\x00\x00\x00;\x9a\xca\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

The original hash code for 'yves' is not small enough.

In [14]:
md5.digest() < target
Out[14]:
False

However, adding (a) certain number(s) to the string, yields a hash code small enough.

In [15]:
hashlib.sha256('%dyves' % 23240167).hexdigest()
Out[15]:
'00000003b04fad4b30a527760fea6ee5beec8035ef636316c2bf2577b2789611'

The following code simulates a mining procedure.

In [16]:
%%time
i = 0
while True:
    md5 = hashlib.sha256('%d' % i + 'yves')
    if md5.digest() < target:
        print 'SUCCESS'
        print i, md5.hexdigest()
        # break
    if i % 2500000 == 0:
        print i
    i += 1
    if i > 55000000:
        break
0
2500000
5000000
7500000
10000000
12500000
15000000
17500000
20000000
22500000
SUCCESS
23240167 00000003b04fad4b30a527760fea6ee5beec8035ef636316c2bf2577b2789611
25000000
SUCCESS
27090678 00000007a53f0b5163e1cb7ade64881e4eb3e06f9c102ad72a19c942223ba82b
27500000
30000000
32500000
35000000
37500000
40000000
42500000
45000000
47500000
50000000
SUCCESS
50427211 000000099f6760417f3b2161a9ba9e989c62da1745d949267d5b648edaa21496
52500000
55000000
CPU times: user 1min 10s, sys: 153 ms, total: 1min 10s
Wall time: 1min 10s

The time to find a suitable hash code depends on the input string.

In [17]:
%%time
i = 0
while True:
    md5 = hashlib.sha256('%d' % i + 'yveshilpisch')
    if md5.digest() < target:
        print 'SUCCESS'
        print i, md5.hexdigest()
        # break
    if i % 2500000 == 0:
        print i
    i += 1
    if i > 55000000:
        break
0
2500000
5000000
7500000
10000000
12500000
15000000
17500000
20000000
22500000
25000000
27500000
30000000
32500000
35000000
37500000
40000000
42500000
45000000
47500000
50000000
52500000
55000000
CPU times: user 1min 10s, sys: 157 ms, total: 1min 10s
Wall time: 1min 10s

Mining a Bitcoin Block

The following example is from http://www.righto.com/2014/02/bitcoin-mining-hard-way-algorithms.html and is about a 'real' bitcoin block and how to mine it wih Python.

In [18]:
import struct

The basic elements of a bitcoin block.

The elements translated into Python code.

In [19]:
ver = 2
prev_block = "000000000000000117c80378b8da0e33559b5997f2ad55e2f7d18ec1975b9717"
mrkl_root = "871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a"
time_ = 0x53058b35  # 2014-02-20 04:57:25
bits = 0x19015f53  # difficulty
bits
Out[19]:
419520339

The derivation of the target value which is the upper limit for a successful hash code.

In [20]:
# https://en.bitcoin.it/wiki/Difficulty
exp = bits >> 24
exp
Out[20]:
25
In [21]:
mant = bits & 0xffffff
mant
Out[21]:
89939
In [22]:
hex(mant)
Out[22]:
'0x15f53'
In [23]:
8 * (exp - 3)
Out[23]:
176

The concrete values.

In [24]:
target_hexstr = '%064x' % (mant * (1 << (8 * (exp - 3))))
target_hexstr
Out[24]:
'00000000000000015f5300000000000000000000000000000000000000000000'
In [25]:
target_str = target_hexstr.decode('hex')
target_str  # C struct
Out[25]:
'\x00\x00\x00\x00\x00\x00\x00\x01_S\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

The Python module struct can be used to convert Python values to C structs represented as Python strings and vice versa.

In [26]:
pa = struct.pack('LLL', 1, 20, 300)  # packing data
pa
Out[26]:
'\x01\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00,\x01\x00\x00\x00\x00\x00\x00'
In [27]:
struct.unpack('LLL', pa)  # unpacking data
Out[27]:
(1, 20, 300)

The nonce is the value which is to be added to the other block elements during the hash code generation. One looks for the nonce that gives a hash code smaller than the target level.

In [28]:
nonce = 850000000

Finally, the Python code to do the mining activitiy. Basically, the nonce values gets increased by 1 during the look, a new hash code is generated and compared to the target level.

In [29]:
%%time
while nonce < 0x100000000:
    header = (struct.pack("<L", ver)
            + prev_block.decode('hex')[::-1]
            + mrkl_root.decode('hex')[::-1]
            + struct.pack("<LLL", time_, bits, nonce))
    hash = hashlib.sha256(hashlib.sha256(header).digest()).digest()
    if nonce % 100000 == 0:
        print nonce, hash[::-1].encode('hex')
    if hash[::-1] < target_str:
        print nonce, hash[::-1].encode('hex')
        print 'success'
        break
    nonce += 1
850000000 2d06d5717ef51ce987ec0f0e4823620f8d9d2d6556174103297a6099900a04c0
850100000 d426ab32784c7bf5b24b93e9e83d4f685abf21d1b8117c69dfcc644ed8b59f4d
850200000 879860b11769268f1e5ca7df9a763a7daf63911d2e25eb599db5bd295eba15ee
850300000 639bb2d2d53ad9923c1aea1da51d20d716754086a47605bf51a474e0f8751d2e
850400000 b00da7ec454b36fd7f7f96fd973361e56c8f19d252b95b4ada21d49dc6751001
850500000 124ceef6fa93474bfbaa91dc1428d2d5801a6b3e8e19c4edbb87c17995757030
850600000 ed546943a811deed9a2e37a74fda8a66b60d93f80db8f98d02fac8209c116862
850700000 53a8be9b39b0320a8d52eb02a53ca868fbdf550e90eacfafcc06b421afde2abd
850800000 275944cb52b35cc3993bd286e3861afbc246c7de7ed274da917cc22d05cd2bf5
850900000 3f39d1b4f2296ff6511f163484d121b12b2e4393026dddae7fd21940193c4959
851000000 2caff003e29dfc2ec7130a20d84118580a48d81627e0a766a6450a14404aa030
851100000 38532290165437742d889e1aca06d8547cf5e212ab6a201ce0aa18a7178bde93
851200000 5328e4e15f9143668ee761fcd6703b4bbb491962d18d0198acb036eaddec27d4
851300000 84b6093aabe15d54875d6507ff4101e9fab1f19281cf02d66b0535dc8ef3c540
851400000 961beb37d43cb3e9ec00b12ad6999e7599f2671dc9bd0529cbb4825e045ef6ad
851500000 b6d5c3b36ba77f5216eb8ce0cd0d7ee35ca24794d519d689637cb331a83cd531
851600000 58c3abc58a3fcccda18f205cc124bcfce61d244b46bb70161da040e346429b61
851700000 a96d86bf20b939b6013fd8e30fe6dba47a449d66bebf4010ae04d56a3706ba76
851800000 4e0bc5299ef60ee2e542b3db8c17a1fc37b423d7d04a90b8afdca7d637a58879
851900000 00676bec9bef56ada1a43471bf99d314d32c5722997e91026b517602eafc0768
852000000 47c01a53e024c253601f54332790483091888c463d8b8647c8d6f7e078eafb9b
852100000 c6a6127d8c781f9094c285487f3524395d14add01d1a78705d2e6c95525a588b
852200000 53c762141e8c9d615dc50b9f3dbc7923d770e8909b1e9a2d3a07e4bb5bc4cbe1
852300000 1367247fa37ba19a1f4f7611a660dd7d20ee3e0966fed015aba43c260c1a6ed6
852400000 1bd5babc0d87efd848b56e09cf7cc46c95923864cc2924aa2a1c5fc71835ec21
852500000 e49a890d18918861d8b3a70ee4db417884ff44940e0a05aa282bc5af5d2cf8df
852600000 1906382ef5f88e718a0a3f511300278828b9e066f0f17538bb0a004789ce03f1
852700000 e2019b137817605eabe86e477fb701a939704d0ea6a0edbde551add2398d9712
852800000 b9cd34c3e42796b3acfdbade72f80f58d6d25210dd69bd7e2e07a1b1f11dcb44
852900000 7b9ee4365e34663f53f6f2839782c6742874d1df9a26d9d5849b4f7ab44e1d22
853000000 4691fb160b2d339e2a54e95f81b891d46acd7f68754b0bd1f4b6942ca0c804ca
853100000 0f8f14bbce8a3130c77c9c1e16350b6e355dd1ed02e609e2c27317733c0b3961
853200000 61988103dd17e23ded0344340f3b0f264cb8d96132730cf48ebc34b06377a75b
853300000 5fe85a9f29709cb866065cf82c45c0d16b8c9f59cf548dad131a8b07805597b9
853400000 ee63a5132d8126c255f73d48e02eec5c7b3d3fb91c447a74aa13b9c982dbbbf6
853500000 d042c47176ab86bca4b9b2f85c2bd88ba755006e7edccfed7f0c701dc4d33fc9
853600000 6cac0791a530a9e3b8b53d72cbaa2fb46c14c5e65d843e08ab656444bea9a9ea
853700000 d79092388a07d7e9267e286bc947c01c54dffca661f8f80bf6800be46d742369
853800000 75ebeafea5b28c3121000dcf48e023aa829a2a2644afbe530d2b631ed8906bdf
853900000 dfbd31c5596f8face76616084d962d0ff2736a36b8171166d11de5fe2624fa33
854000000 b261dbf2a4d3178730c06c7d37b3d3f104b9b0c8266cc0bf8ddcffb88ee3e620
854100000 b8fa2bdc41f553695f1dbd368b924569b4fa4cb59b7bbb16a8d8e78efa6bb43e
854200000 4e7174dc8891c4cf1e6e97dc62166961a289f88206bdd383ba0c31a027610e4f
854300000 e80a0ac318574b7bebba1ec3aaec37ed173b4e143997eb66cf5118daf68e020b
854400000 0da8de618a00dd0aa71af0ff3350cd78435f10b160a06dee0578caf5bcab38b9
854500000 f0759c38ce0c7772ac8c4722937bed08140f8ce159725643dc2e96c335cc7c23
854600000 20e6560f3b64596d9632005d9464d83a3125eb2faef9e34349fd7409869fef51
854700000 c3c28a756b90252a0798a4fb318dece2f66671c142c79094ee04143284c00cfe
854800000 e1f78c86fb5afb69ade79f1ba6a0b2f059fd04c1826b74dc7dd99f1ce1148c39
854900000 7a4267e76008a80ffe34241f9fdcd829017fc41ec26af8446f7a2d1c736563a5
855000000 c56c40696263177bce80ee786c31f5d488d5bab570efb4abee25acb004088645
855100000 f365ea084e95a6a45ea48e957c188d3639db4aa7d8e91f246a5e69004033b79f
855200000 96519548a733cc53746e0b07b62f7c0ebb1389a6c4cb8d30309b1f24d78eff26
855300000 08a9120bb5b207c95ee9d9437c53224024fd7da2c38ef03988ba952eccb85910
855400000 18379a22c13f193c9cdb0d5e6eccc2745bc0c95402162ca9721c0dc286c8d61d
855500000 3c2d6d680516d5d430dbf787e9158799676277a6e419595dbbf4fe42f43120a9
855600000 0233a14315cf2b61fce61b534d530c6087e805731bf52fd8f273a24c0806024c
855700000 27a1c3fe9e19f964bcc172598705a1a9bf4e705cb6846765ea1cef856d009cd9
855800000 b0603f071da6f70c98dd66d59be05bc9da7e5a144a7cd4088eac3fccf85f2579
855900000 55046172647ff3a4a8b3928816f4f05bf24a08e1ddfde212ba4d83ece5749bb7
856000000 634192b589ea881333b5e566873ecbaaf8addc5d7ef4240f8e8c1325c29c4c7a
856100000 c2fbb25c7dcca8a41e5b305e9ba0c0c9fcb80b16877029349b65358a7d7b7ce0
856192328 0000000000000000e067a478024addfecdc93628978aa52d91fabd4292982a50
success
CPU times: user 25.1 s, sys: 78 ms, total: 25.2 s
Wall time: 25 s

Merkle Hash

The following are the hard-coded transaction hashes for the Bitcoin block under consideration (http://www.righto.com/2014/02/bitcoin-mining-hard-way-algorithms.html).

In [30]:
# https://blockexplorer.com/rawblock/0000000000000000e067a478024addfecdc93628978aa52d91fabd4292982a50
txHashes = [
  "00baf6626abc2df808da36a518c69f09b0d2ed0a79421ccfde4f559d2e42128b",
  "91c5e9f288437262f218c60f986e8bc10fb35ab3b9f6de477ff0eb554da89dea",
  "46685c94b82b84fa05b6a0f36de6ff46475520113d5cb8c6fb060e043a0dbc5c",
  "ba7ed2544c78ad793ef5bb0ebe0b1c62e8eb9404691165ffcb08662d1733d7a8",
  "b8dc1b7b7ed847c3595e7b02dbd7372aa221756b718c5f2943c75654faf48589",
  "25074ef168a061fcc8663b4554a31b617683abc33b72d2e2834f9329c93f8214",
  "0fb8e311bffffadc6dc4928d7da9e142951d3ba726c8bde2cf1489b62fb9ebc5",
  "c67c79204e681c8bb453195db8ca7d61d4692f0098514ca198ccfd1b59dbcee3",
  "bd27570a6cbd8ad026bfdb8909fdae9321788f0643dea195f39cd84a60a1901b",
  "41a06e53ffc5108358ddcec05b029763d714ae9f33c5403735e8dee78027fe74",
  "cc2696b44cb07612c316f24c07092956f7d8b6e0d48f758572e0d611d1da6fb9",
  "8fc508772c60ace7bfeb3f5f3a507659285ea6f351ac0474a0a9710c7673d4fd",
  "62fed508c095446d971580099f976428fc069f32e966a40a991953b798b28684",
  "928eadbc39196b95147416eedf6f635dcff818916da65419904df8fde977d5db",
  "b137e685df7c1dffe031fb966a0923bb5d0e56f381e730bc01c6d5244cfe47c1",
  "b92207cee1f9e0bfbd797b05a738fab9de9c799b74f54f6b922f20bd5ec23dd6",
  "29d6f37ada0481375b6903c6480a81f8deaf2dcdba03411ed9e8d3e5684d02dd",
  "48158deb116e4fd0429fbbbae61e8e68cb6d0e0c4465ff9a6a990037f88c489c",
  "be64ea86960864cc0a0236bbb11f232faf5b19ae6e2c85518628f5fae37ec1ca",
  "081363552e9fff7461f1fc6663e1abd0fb2dd1c54931e177479a18c4c26260e8",
  "eb87c25dd2b2537b1ff3dbabc420e422e2a801f1bededa6fa49ef7980feaef70",
  "339e16fcc11deb61ccb548239270af43f5ad34c321416bada4b8d66467b1c697",
  "4ad6417a3a04179482ed2e4b7251c396e38841c6fba8d2ce9543337ab7c93c02",
  "c28a45cded020bf424b400ffc9cb6f2f85601934f18c34a4f78283247192056a",
  "882037cc9e3ee6ddc2d3eba86b7ca163533b5d3cbb16eaa38696bb0a2ea1137e",
  "179bb936305b46bb0a9df330f8701984c725a60e063ad5892fa97461570b5c04",
  "9517c585d1578cb327b7988f38e1a15c663955ea288a2292b40d27f232fbb980",
  "2c7e07d0cf42e5520bcbfe2f5ef63761a9ab9d7ccb00ea346195eae030f3b86f",
  "534f631fc42ae2d309670e01c7a0890e4bfb65bae798522ca14df09c81b09734",
  "104643385619adb848593eb668a8066d1f32650edf35e74b0fc3306cb6719448",
  "87ac990808239c768182a752f4f71cd98558397072883c7e137efb49d22b9231",
  "9b3e2f1c47d59a444e9b6dc725f0ac6baf160d22f3a9d399434e5e65b14eccb0",
  "fbe123066ae5add633a542f151663db4eb5a7053e388faadb40240671ae1b09b",
  "1dd07e92e20b3cb9208af040031f7cfc4efd46cc31ec27be20a1047965a42849",
  "2709bb9ed27353c1fd76b9240cab7576a44de68945e256ad44b2cb8d849a8060",
  "d0174db2c712573432a7869c1508f371f3a1058aeedddc1b53a7e04d7c56c725",
  "b4a16f724cddb8f77ddf3d2146a12c4be13d503885eaba3518a03da005009f62",
  "2aa706d75decbe57745e01d46f9f5d30a08dedaf3288cee14cc4948e3684e1d4",
  "ee49c5f6a5129ccaf2abebbc1d6d07a402a600af6221476b89aafaa683ca95b7",
  "bea1011c77874845e9b4c876ed2ceebd530d428dd4a564ad003d9211d40bb091",
  "f1e88ffc2b1de2aa4827002f06943ce5468735f7433f960bf01e75885b9f832b",
  "19247d017e002fb9143d1a89eb921222a94f8a3d0faaf2e05b0f594989edc4c4",
  "13f714ff62ee7d26b6d69ca980c141ebc54e9f71d2697083fe6c5efc1b02bd0f",
  "0c78cbb8246572f015fbdc53dc9798fa54d1119ec77c1f07ac310bcbcc40dbf8",
  "4bcde0ef92a6d24a2be7be50ac5e5299d776df2e6229ba5d475c2491da94f255",
  "0cfd7d1058502730cf0b2ffa880c78ef534651e06832b5d87c0d7eb84eac5b0c",
  "3a168f794d6e0c614429ad874317cc4cd67a8177214880ff6ea1704d29228c2f",
  "f9a555d817334397b402518d6fd959dc73d981ee7f5fe67969b63974ebbef127",
  "24b52691f66eaed4ce391a473902e309018257c98b9f02aaa33b399c9e6f3168",
  "a37b5e623dc26a180d9e2c9510d06885b014e86e533adb63ec40511e10b55046",
  "9dbaeb485e51d9e25a5621dc46e0bc0aaf51fb26be5acc4e370b96f62c469b80",
  "a6431d3d39f6c38c5df48405090752cab03bfdf5c77cf881b18a946807fba74a",
  "faa77e309f125373acf19855dd496fffe2f74962e545420844557a3adc7ebc11",
  "3523f52543ecfea2f78486dc91550fad0e6467d46d9d9c82ca63b2e0230bfa71",
  "a0583e358e42d77d18d1fd0533ff0a65615fc3b3112061ef92f168a00bf640c1",
  "42ae900888d5e5dde59c8e3d06e13db9e84ef05d27726d4b67fd00c50cd9406a",
  "154940777d3ff78f592ef02790131a59263c36b4958bbc836f9a767ea1a9f178",
  "6a0337de6ac75eecf748306e8ebc5bfe5c811a1481ae50f6956a9e7f26a679f5",
  "c99530c2148e09688d0b88795625943371183bf1f5d56c7446c6ed51ea133589",
  "626421dbe8ad6a0fd0d622d5dd3308a1cdc00b98575a41a91fe01a439e6f40bd",
  "b2f3a559f605a158cc395126c3cf394a7e92a53b7514c75157e1dc43a6c7f93e",
  "dffe06d1bea81f2a01c76786404bb867258f9e68013bf25454097ce935090738",
  "0860159ec7a2a51ce107c182a988c40b4bc2057a734354a1219b6c65e72640ed",
  "a405ff1bb51846b1867acc0b0da17f6f9616e592a0a7ff5ef3297c1ecfd60911",
  "a7d451924263284765f6343bca8a21b79b89ebfe611c7355dd88e0ec1c29e232",
  "41c758d08a4d3fe4d90645711589b832a2cd54dd25bd5b66e463e5d389a53aff",
  "a05c1a93a521fa5dbc1790cfbb808893453a428a65f2c6b2d51249fbb12db309",
  "90997920aa9786e10f513cfdd14e294feee6739cee1ab61b3fb1e3f42e7a915d",
  "99fcb9cb62c20a3135484a70bd3f73983f8f3b7b26266dad34f3993958a7642c",
  "e05f9a668b37e5f78bd3b9d047f29f92b33a87f11dd48390410006f858188b7b",
  "56dbc65895f7992da4a6985e7edba4d1c00879f1b28442c644c8a07658ceab27",
  "5e9004fe262b829563d0804656ba68b1de1690401f08a1915273230d8c902fc0",
  "1ea9ed3717523c5e304b7a7ac8058a87fb4f3fed8c6004769f226c9bb67e79c5",
  "f0f1a4c009b3f1b2729e89898e2f5c0fcdc312edea5df884a9c897cb90e4c566",
  "b5bb4ddf04863e6a60f33cb96c20dac8175d3bae55f335781503143c97a50e43",
  "f14cc97a20c6f627b4b78301352ae35463bc359362589cd178a06c0fa90850b7",
  "628801c8f614015c0fa0ccb2768cccc3e7b9d41ceed06071ce2534d31f7236d6",
  "3be1013c8f8da150e2195408093153b55b08b037fd92db8bb5e803f4c2538aae",
  "c9e1f8777685f54ba65c4e02915fd649ee1edcbf9c77ddf584b943d27efb86c3",
  "4274e92ed3bd02eb101baa5fb8ff7b96236830762d08273749fbb5166db8ab0b",
  "aa84c955bea04c7cee8f5bbbec97d25930fcaca363eed1b8cad37b931556d3e3",
  "d6a29c948677fb1f71aaf16debc3d071a4dd349458eb9e056dce3a000ff853da",
  "ba84bdb3d78367ca365016ac4bff9269576eb010f874c2967af73e0de5638de0",
  "1546c79951e3b541bc64d1957b565b7a2850fc87192c7b374aee6cfc69b9805e",
  "f119227d492ebe27fe9aae321980802454dfa64b2691efbe796c5075d5b07f62",
  "b8cf13d64818b32f96bbb585998b1bc9505f6a94055488e5a71fee9479c6f2a9",
  "1aaf459705b6afef2d7b83e3f181f1af55be0813daf55edce104cc59abc28ed7",
  "61ac185c8f520b5e3134953dc52ff292a40e1e96b088dab259558a9d240ec02f",
  "2da96e3154d7ec2329f787b73cb8a436b92d64cf3cc28e920d073279ea73b5f8",
  "1c4d72ce733b971b9ec4e24f37d733355f6f2ea635cc67ffb3e22748484df446",
  "2a6f89769f3272ac8c7a36a42a57627eca6b260ab2c76d8046a27d44d4034893",
  "f8d11df51a2cc113698ebf39a958fe81179d7d973d2044322771c0fe63f4d7c9",
  "f2287f17a4fa232dca5715c24a92f7112402a8101b9a7b276fb8c8f617376b90",
  "bb5ee510a4fda29cae30c97e7eee80569d3ec3598465f2d7e0674c395e0256e9",
  "647ab8c84365620d60f2523505d14bd230b5e650c96dee48be47770063ee7461",
  "34b06018fcc33ba6ebb01198d785b0629fbdc5d1948f688059158f053093f08b",
  "ff58b258dab0d7f36a2908e6c75229ce308d34806289c912a1a5f39a5aa71f9f",
  "232fc124803668a9f23b1c3bcb1134274303f5c0e1b0e27c9b6c7db59f0e2a4d",
  "27a0797cc5b042ba4c11e72a9555d13a67f00161550b32ede0511718b22dbc2c",
]

Function to generate the (pair-wise) Merkle hash.

In [31]:
# Hash pairs of items recursively until a single value is obtained
def merkle(hashList):
    if len(hashList) == 1:
        return hashList[0]
    newHashList = []
    # Process pairs. For odd length, the last is skipped
    for i in range(0, len(hashList)-1, 2):
        newHashList.append(hash2(hashList[i], hashList[i+1]))
    if len(hashList) % 2 == 1: # odd, hash last item twice
        newHashList.append(hash2(hashList[-1], hashList[-1]))
    return merkle(newHashList)

def hash2(a, b):
    # Reverse inputs before and after hashing
    # due to big-endian / little-endian nonsense
    a1 = a.decode('hex')[::-1]
    b1 = b.decode('hex')[::-1]
    h = hashlib.sha256(hashlib.sha256(a1+b1).digest()).digest()
    return h[::-1].encode('hex')

Finally, the Merkle hash code for the above transaction hashes as found in the block header.

In [32]:
print merkle(txHashes)
871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a

The Python Quants

http://tpq.io | @dyjh | team@tpq.io

Python Quant Platform | http://quant-platform.com

Python for Finance | Python for Finance @ O'Reilly

Derivatives Analytics with Python | Derivatives Analytics @ Wiley Finance

Listed Volatility and Variance Derivatives | Listed VV Derivatives @ Wiley Finance