{"id":313,"date":"2013-07-08T11:34:24","date_gmt":"2013-07-08T19:34:24","guid":{"rendered":"http:\/\/blog.richardkiss.com\/?p=313"},"modified":"2021-02-05T17:30:13","modified_gmt":"2021-02-06T01:30:13","slug":"313","status":"publish","type":"post","link":"https:\/\/blog.richardkiss.com\/?p=313","title":{"rendered":"On BIP0032 and Bitcoin Deterministic Wallets"},"content":{"rendered":"<p><a href=\"https:\/\/en.bitcoin.it\/wiki\/BIP_0032\">BIP0032<\/a> defines a way to create a hierarchical deterministic wallet (that is, a way to create an entire tree of Bitcoin addresses and private keys) through a tree of wallet key nodes.<\/p>\n<p>Each node has a public and private key associated with it, which can be displayed as a Bitcoin address and a WIF string. But each node also has additional entropy information, called the &#8220;chain code&#8221;, which gets fed back into the algorithm that generates the children, so revealing even the WIF doesn&#8217;t give enough information to reveal the children.<\/p>\n<p>A node can be stripped of private key information, yielding a public key node. These nodes can only generate the Bitcoin address, and not the WIF. But they can still generate half of the child nodes. But only the public key node versions. So once you strip out the private-ness from a node, it&#8217;s gone forever.<\/p>\n<p>Each node element can be represented by a 111-digit base58 number that looks like this:<\/p>\n<pre><code>xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi\r\nxpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8\r\n<\/code><\/pre>\n<p>Keys for the main network start with &#8220;xprv&#8221; (private) or &#8220;xpub&#8221; (public).<\/p>\n<p>A node has 2^32 children, enumerated 0, 1, 2 .. 4294967295. Children with index at least 2^31=2147483648=0x80000000 are derived using &#8220;prime&#8221; or &#8220;private key&#8221; derivation, and can only be generated by the private wallet key. We use the shortcut 2p or 2&#8217; to indicate child number 2+0x80000000.<\/p>\n<p>A &#8220;key path&#8221; is a route down the tree. It&#8217;s a &#8220;\/&#8221;-separated list of numbers, where each number can optionally have a trailing p or &#8217; character to indicate &#8220;prime&#8221;. (Typing &#8220;p&#8221; is much easier than &#8220;&#8217;&#8221; which needs to be escaped or quoted in the shell.)<\/p>\n<p>Example key paths: &#8220;1&#8221;, &#8220;0\/2p&#8221;, &#8220;0p\/1000\/5&#8221;, &#8220;0\/0\/0\/0\/0\/37&#8221;.<\/p>\n<p>Reading the BIP0032 is a hard slog. Maybe some examples will make this clearer. I&#8217;ve created a script for now called genwallet (I know, I know, I need a better name) that lives in my <a href=\"https:\/\/github.com\/richardkiss\/pycoin\">pycoin<\/a> project. Create a virtualenv and install it. This has been tested with Python 3.3 but should work in Python 2.7 too. There may be minor discrepencies in what you see here and what you see on your terminal if you follow along, as this project has been undergoing heavy changes lately. Forgive me.<\/p>\n<pre><code>$ virtualenv pycoin.env\r\n$ source pycoin.env\/bin\/activate\r\n$ pip install pycoin\r\nDownloading\/unpacking pycoin\r\n  Downloading pycoin-0.15.tar.gz\r\n  Running setup.py egg_info for package pycoin\r\n\r\nInstalling collected packages: pycoin\r\n  Running setup.py install for pycoin\r\n\r\n    Installing genwallet script to (...)\/pycoin.env\/bin\r\nSuccessfully installed pycoin\r\nCleaning up...\r\n<\/code><\/pre>\n<p>You create the top node of a tree by feeding it entropy.<\/p>\n<pre><code>$ head -c200 \/dev\/random | genwallet -\r\nxprv9s21ZrQH143K3wqna1KnwoSH3reKVVp68cAuJ4izQMMe7VvzBcFdnxYvtMifigMDynsTzCSiLvCt2ksKYrSY4m5z2AQc7g7vZL6uvdaSiBn\r\n<\/code><\/pre>\n<p>Your results may vary. Hopefully.<\/p>\n<p>Let&#8217;s use a known key so we can check our results. BIP0032 has some <a href=\"https:\/\/en.bitcoin.it\/wiki\/BIP_0032_TestVectors\">test vectors<\/a>. Let&#8217;s try the first one.<\/p>\n<pre><code>$ python -c 'import binascii; open(\"master-private-key-entropy\", \"w+b\").write(binascii.unhexlify(\"000102030405060708090a0b0c0d0e0f\"))'\r\n$ hd master-private-key-entropy\r\n00000000  00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f  |................|\r\n00000010\r\n<\/code><\/pre>\n<p>This is the initial entropy for test vector #1. Don&#8217;t use any of these key address for real storage of Bitcoin, since the private keys are all over the internet. All right? Good.<\/p>\n<pre><code>$ genwallet master-private-key-entropy &gt; master-private-key\r\n$ cat master-private-key \r\nxprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi\r\n<\/code><\/pre>\n<p>It matches the test vector! How about the public key? Use <code>-s<\/code> to pass in the key path. We use a trick here that the &#8220;.pub&#8221; suffix means &#8220;strip down to public key only by stripping out secret exponent information&#8221;. And that an empty key path stays on the current node. (Ugh. Need to add a <code>-P<\/code> flag.)<\/p>\n<pre><code>$ genwallet -f master-private-key -s .pub &gt; master-public-key\r\n$ cat master-public-key\r\nxpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8\r\n<\/code><\/pre>\n<p>That matches the test vector too! Let&#8217;s generate the rest of them.<\/p>\n<pre><code>$ genwallet -f master-private-key -s 0p.pub\r\nxpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw\r\n$ genwallet -f master-private-key -s 0p\r\nxprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7\r\n$ genwallet -f master-private-key -s 0p\/1.pub\r\nxpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ\r\n$ genwallet -f master-private-key -s 0p\/1\r\nxprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs\r\n$ genwallet -f master-private-key -s 0p\/1\/2p.pub\r\nxpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5\r\n$ genwallet -f master-private-key -s 0p\/1\/2p\r\nxprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM\r\n$ genwallet -f master-private-key -s 0p\/1\/2p\/2.pub\r\nxpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV\r\n$ genwallet -f master-private-key -s 0p\/1\/2p\/2\r\nxprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334\r\n$ genwallet -f master-private-key -s 0p\/1\/2p\/2\/1000000000.pub\r\nxpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy\r\n$ genwallet -f master-private-key -s 0p\/1\/2p\/2\/1000000000\r\nxprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76\r\n<\/code><\/pre>\n<p>The <code>-i<\/code> flag dumps out a bunch of extra info.<\/p>\n<pre><code>$ genwallet -f master-private-key -s 0p\/1\/2p\/2 -i\r\nxprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334\r\nmain network\r\nprivate key\r\nsecret exponent: 6911148411995144978760870745829922996940679624545579157337939690887778291444\r\npublic pair x:   105057282133830096634347636156404839657295714659718969275583812905733562047785\r\npublic pair y:   17712072790142815456499743834226465136387452166901773802686902612896636999328\r\ntree depth:      4\r\nfingerprint:     d880d7d8\r\nparent f'print:  ee7ab90c\r\nchild index:     2\r\nchain code:      cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd\r\nWIF:             KwjQsVuMjbCP2Zmr3VaFaStav7NvevwjvvkqrWd5Qmh1XVnCteBR\r\n  uncompressed:  5Hw1ss3oPLXfyYSZrxQr4xFrpq7nEaX5HkSnxdAXuWcM4JEio8S\r\nBitcoin address: 1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt\r\n  uncompressed:  1FzKW1LPEjEeRamxYR8oxVPLFJt525Nffm\r\n\r\n$ genwallet -f master-private-key -s 0p\/1\/2p\/2\/1000000000 -i\r\nxprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76\r\nmain network\r\nprivate key\r\nsecret exponent: 32162737660659799401901343156672072893797470137297259782459076395168682141640\r\npublic pair x:   19122724810578381401279259492091176497647579703487086604820598127878910996497\r\npublic pair y:   93716738155005567718020901196556981584525395439024483644561058920479008416610\r\ntree depth:      5\r\nfingerprint:     d69aa102\r\nparent f'print:  d880d7d8\r\nchild index:     1000000000\r\nchain code:      c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e\r\nWIF:             Kybw8izYevo5xMh1TK7aUr7jHFCxXS1zv8p3oqFz3o2zFbhRXHYs\r\n  uncompressed:  5JMbvQZXHJAzJyoDnqWasGCwtiHJZivF2ckjn3n5mazYYtGNvJf\r\nBitcoin address: 1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam\r\n  uncompressed:  1N7NsvfJJqhjjFp5R2X9FmBc8MLU7gxbsL\r\n<\/code><\/pre>\n<p>Note how the second example suggests that the first example is its parent by identifying its fingerprint, and having a depth that&#8217;s one deeper.<\/p>\n<p>We can feed the key on the command-line too using <code>-k<\/code> (although it&#8217;s a bad idea for real keys, since it exposes it in <code>ps<\/code> and your shell&#8217;s history). Every bit of this data is encoded in the 111-character wallet key.<\/p>\n<pre><code>$ genwallet -i -k xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76\r\nxprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76\r\nmain network\r\nprivate key\r\nsecret exponent: 32162737660659799401901343156672072893797470137297259782459076395168682141640\r\npublic pair x:   19122724810578381401279259492091176497647579703487086604820598127878910996497\r\npublic pair y:   93716738155005567718020901196556981584525395439024483644561058920479008416610\r\ntree depth:      5\r\nfingerprint:     d69aa102\r\nparent f'print:  d880d7d8\r\nchild index:     1000000000\r\nchain code:      c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e\r\nWIF:             Kybw8izYevo5xMh1TK7aUr7jHFCxXS1zv8p3oqFz3o2zFbhRXHYs\r\n  uncompressed:  5JMbvQZXHJAzJyoDnqWasGCwtiHJZivF2ckjn3n5mazYYtGNvJf\r\nBitcoin address: 1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam\r\n  uncompressed:  1N7NsvfJJqhjjFp5R2X9FmBc8MLU7gxbsL\r\n<\/code><\/pre>\n<p>You can traverse the tree partially, and still get descendents from the child node. Here we see the path from the master M through 0\/1\/0\/1 yields the same results as we get from going from M to 0\/1\/0, stopping there for a moment, then going to 1.<\/p>\n<pre><code>$ genwallet -f master-private-key -s 0\/1\/0 &gt; m0,1,0\r\n$ cat m0,1,0 \r\nxprv9xrdP7iD2L1YW43ygAskFNznwRQAFkb67X6vK5mJF1tdDQWXJdQnBjQqwYaHKPQ5wseEEDWmgBFpXmtxfGvAERhfiUZfoCyRfgMfGhPqx94\r\n$ genwallet -f master-private-key -s 0\/1\/0\/1\r\nxprvA1fSfYjT9jfrP4WfUgMEcvTRYyQ6qoqRT2t7Z9qZ41TEG7egUv28pL5dHodAkrET8k7UqjzKRKCFUR1V36E9egU9sHoKXuiAFNbVsZdrnhj\r\n$ genwallet -f m0,1,0 -s 1\r\nxprvA1fSfYjT9jfrP4WfUgMEcvTRYyQ6qoqRT2t7Z9qZ41TEG7egUv28pL5dHodAkrET8k7UqjzKRKCFUR1V36E9egU9sHoKXuiAFNbVsZdrnhj\r\n<\/code><\/pre>\n<p>We&#8217;ve descended from master to 0\/1\/0\/1 two ways. Same output.<\/p>\n<p>You can strip out private key information, but still get the hierarchy of public keys.<\/p>\n<pre><code>$ genwallet -f master-private-key -s .pub &gt; master-public-key\r\n$ cat master-public-key\r\nxpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8\r\n$ genwallet -f master-public-key -s 0\/2\r\nxpub6AvUGrnEpfvJFYHymqh5qJ3V7qFyEFdpQom2tRQdV4Eo25kxagwHwVCMX1opKqAXxacHPAJafQW1uvH3bYQi1zbE5DMgXGAGNkHajLEuoa2\r\n$ genwallet -f master-private-key -s 0\/2.pub\r\nxpub6AvUGrnEpfvJFYHymqh5qJ3V7qFyEFdpQom2tRQdV4Eo25kxagwHwVCMX1opKqAXxacHPAJafQW1uvH3bYQi1zbE5DMgXGAGNkHajLEuoa2\r\n<\/code><\/pre>\n<p>So public wallet keys can generate Bitcoin addresses. But getting WIF information requires the secret exponent, which has been stripped out.<\/p>\n<pre><code>$ genwallet -f master-private-key -s 0\/2 -a\r\n1J4LVanjHMu3JkXbVrahNuQCTGCRRgfWWx\r\n$ genwallet -f master-public-key -s 0\/2 -a\r\n1J4LVanjHMu3JkXbVrahNuQCTGCRRgfWWx\r\n$ genwallet -f master-private-key -s 0\/2 -w\r\nKxtby4wzfHeCaRXma16dBNLgUE7Ct3Xkb6sRs3aZ56Bmtf1rcNWs\r\n$ genwallet -f master-public-key -s 0\/2 -w\r\ncan't generate WIF for public key\r\n<\/code><\/pre>\n<p>That means we can put a public wallet key on a web server, and even if a hacker steals it, all he (or she?) can do is generate the list of public keys. He can&#8217;t steal the Bitcoin since he has no access to the private keys. But keep those private wallet keys offline!!<\/p>\n<p>We can generate uncompressed versions of Bitcoin addresses too, if you&#8217;re interested in that sort of anachronism.<\/p>\n<pre><code>$ genwallet -f master-private-key -s 0\/2 -a -n\r\n1HSEorKrq3DjqxtgETbLvnka62Wc4NZj3M\r\n$ genwallet -f master-public-key -s 0\/2 -a -n\r\n1HSEorKrq3DjqxtgETbLvnka62Wc4NZj3M\r\n$ genwallet -f master-private-key -s 0\/2 -w -n\r\n5JCEp99P8KGgKuEKFjARxpRrGgg1szDQUDCswqchLxYtrqZNgJh\r\n<\/code><\/pre>\n<p>Doesn&#8217;t it seem strange that the compressed WIF is longer than the uncompressed WIF? It&#8217;s true.<\/p>\n<p>Private wallet keys have one additional power over public keys: only <em>private<\/em> wallet keys can generate children that use the &#8220;prime&#8221; directive. This derivation requires information about the secret exponent, which is stripped out of public keys. You can use this to generate change addresses, for example, which you probably want to keep slightly more private.<\/p>\n<pre><code>$ genwallet -f master-private-key -s 0p\r\nxprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7\r\n$ genwallet -f master-public-key -s 0p\r\ncan't derive a private key from a public key\r\n<\/code><\/pre>\n<p>You can strip it out later though, and you&#8217;re fine.<\/p>\n<pre><code>$ genwallet -f master-private-key -s 0p\/5 &gt; m0p,5\r\n$ genwallet -f master-private-key -s 0p\/5.pub &gt; m0p,5.pub\r\n$ genwallet -f m0p,5 -s 1 -a\r\n1CxkGdM4oVdWdovcBHqUCeiUWUtN5EtR1a\r\n$ genwallet -f m0p,5.pub -s 1 -a\r\n1CxkGdM4oVdWdovcBHqUCeiUWUtN5EtR1a\r\n<\/code><\/pre>\n<p>In conclusion, this is pretty neat stuff.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>BIP0032 defines a way to create a hierarchical deterministic wallet (that is, a way to create an entire tree of Bitcoin addresses and private keys) through a tree of wallet key nodes. Each node has a public and private key associated with it, which can be displayed as a Bitcoin address and a WIF string. &hellip; <a href=\"https:\/\/blog.richardkiss.com\/?p=313\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">On BIP0032 and Bitcoin Deterministic Wallets<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-313","post","type-post","status-publish","format-standard","hentry","category-computers"],"_links":{"self":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=313"}],"version-history":[{"count":12,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/313\/revisions"}],"predecessor-version":[{"id":321,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/313\/revisions\/321"}],"wp:attachment":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}