Bitcoin Forum
November 15, 2024, 12:37:51 PM *
News: Latest Bitcoin Core release: 28.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: BIP0032 Hierarchical Deterministic Wallet key generator bip32utils (Python)  (Read 2626 times)
Johnathan (OP)
Newbie
*
Offline Offline

Activity: 39
Merit: 0



View Profile
February 04, 2014, 07:52:59 PM
 #1

I've published an experimental version of my bip32utils library and generator script:

https://github.com/jmcorgan/bip32utils

This is pure Python implementation of the BIP0032 draft standard, as recently amended by Peter Wiulle in a pull request on the BIP github account, and is dependent only on the Python ecdsa library available in pypi.

BIP0032 describes a mechanism for generating a hierarchical tree of ECDSA private and public key pairs in a deterministic way using an initial seed.  In addition, one can export an extended private key for a particular tree node that allows generating public and and private child keys underneath, or export an extended public key that only allows generating public keys for child nodes below it in the hierarchy.

There are number of use cases this enables, including single seed backup for an entire hierarchy, allowing auditors to have access to transactions but without the ability to spend them, the ability for a website to generate receive addresses without a compromise allowing spending from those addresses, and delegation of spending authority to keys lower in the hierarchy.

The bip32utils library provides a Python class encapsulating a node in this hierarchy, and a command-line Swiss army knife style script bip32gen that uses this class to create keys in a hierarchy from either entropy or an extended key import format.

The tests directory contains scripts that verify conformance to the BIP0032 test vectors as published.

This is an initial effort that hasn't received a great deal of testing and feedback, so I would recommend against relying on this for anything but token amounts of BTC until it is more mature.

Feedback is welcome.
teukon
Legendary
*
Offline Offline

Activity: 1246
Merit: 1011



View Profile
February 05, 2014, 12:27:33 AM
 #2

Nice!

I'll play with this tomorrow and post some feedback here.
xeroc
Sr. Member
****
Offline Offline

Activity: 345
Merit: 250



View Profile
February 05, 2014, 12:39:18 PM
 #3

wow .. couldn't get around coding it my self .. thanks
Johnathan (OP)
Newbie
*
Offline Offline

Activity: 39
Merit: 0



View Profile
February 05, 2014, 05:00:30 PM
 #4

I'll play with this tomorrow and post some feedback here.
Thanks, looking forward to it.
teukon
Legendary
*
Offline Offline

Activity: 1246
Merit: 1011



View Profile
February 05, 2014, 06:50:31 PM
 #5

Disclaimer: Don't expect much from me.  I'm not a programmer and only created a GitHub account so I could comment on a Regex Golf Gist.

So far I've just been playing with the basics.

I generated BIP0032 test vector #1 using the command in your readme and got the desired result.

I then created my own master key with bip32gen and used your Base58 module to decompose the output and compare it with the serialisation format as specified by BIP0032.  I managed to recover the private key just fine.

Code:
$ bip32gen -i entropy -f /dev/random -n 128 -o privkey,xprv -F - -X m
aec8cfc47b43d518e1c6ce27ca2035af7f598f39e10748be395a27be23dcf1ee
xprv9s21ZrQH143K3E8CHFyZactH1tY5gnofwvtELcdtUeZuewTYh32z1sQdBfCdUdc1CcGAMVLddqUK9ioP6NGRtPNRAbFRp6RLbte1iVqduC2

Code:
>>> Base58.decode('xprv9s21ZrQH143K3E8CHFyZactH1tY5gnofwvtELcdtUeZuewTYh32z1sQdBfCdUdc1CcGAMVLddqUK9ioP6NGRtPNRAbFRp6RLbte1iVqduC2').encode('hex')[92:-8]
'aec8cfc47b43d518e1c6ce27ca2035af7f598f39e10748be395a27be23dcf1ee'

I did have a quick look at the code but I didn't get so far with it.  I got a little confused as your style changed.  For example, compare the extended key version handling in fromExtendedKey
Code:
        # Verify address version/type
        version = raw[:4]
        if version.encode('hex') == '0488ade4':
            keytype = 'xprv'
        elif version.encode('hex') == '0488b21e':
            keytype = 'xpub'
        else:
            raise ValueError("unknown extended key version")
to that in ExtendedKey
Code:
        version = '\x04\x88\xB2\x1E' if private is False else '\x04\x88\xAD\xE4'

On this topic:  Would 0x0488ade4 and 0x0488b21e be better as module constants?  How easy would it be to add support for testnet keys?

That's all I have time for today.  Hopefully I'll find time to move some funds around tomorrow.
Johnathan (OP)
Newbie
*
Offline Offline

Activity: 39
Merit: 0



View Profile
February 05, 2014, 06:59:41 PM
 #6

I generated BIP0032 test vector #1 using the command in your readme and got the desired result.

I then created my own master key with bip32gen and used your Base58 module to decompose the output and compare it with the serialisation format as specified by BIP0032.  I managed to recover the private key just fine.
Good.  Thanks for testing.

I did have a quick look at the code but I didn't get so far with it.  I got a little confused as your style changed.  For example, compare the extended key version handling in fromExtendedKey
Code:
        # Verify address version/type
        version = raw[:4]
        if version.encode('hex') == '0488ade4':
            keytype = 'xprv'
        elif version.encode('hex') == '0488b21e':
            keytype = 'xpub'
        else:
            raise ValueError("unknown extended key version")
to that in ExtendedKey
Code:
        version = '\x04\x88\xB2\x1E' if private is False else '\x04\x88\xAD\xE4'

On this topic:  Would 0x0488ade4 and 0x0488b21e be better as module constants?  How easy would it be to add support for testnet keys?
Yes, it would be cleaner to make those module constants; I was in a bit of a rush to get this part implemented.  That's good feedback for cleanup.

That's all I have time for today.  Hopefully I'll find time to move some funds around tomorrow.
Please take into account the experimental nature of the software.
teukon
Legendary
*
Offline Offline

Activity: 1246
Merit: 1011



View Profile
February 05, 2014, 07:23:12 PM
 #7

Yes, it would be cleaner to make those module constants; I was in a bit of a rush to get this part implemented.  That's good feedback for cleanup.

Ah, that makes sense.  I didn't consider that any of this work was rushed because, frankly, if I were to rush a bit of code, it simply wouldn't run.

Please take into account the experimental nature of the software.

Don't worry.  I'll only be playing with trivial amounts.
Johnathan (OP)
Newbie
*
Offline Offline

Activity: 39
Merit: 0



View Profile
February 05, 2014, 09:48:45 PM
 #8

Ah, that makes sense.  I didn't consider that any of this work was rushed because, frankly, if I were to rush a bit of code, it simply wouldn't run.
No worries.  I wanted get something up for people to review, and perfect is the enemy of good enough.
Deafboy
Hero Member
*****
Offline Offline

Activity: 482
Merit: 502



View Profile WWW
August 20, 2014, 08:34:18 PM
 #9

Can you describe like I'm 5 how can I get the first address of the first account with this tool according to BIP-0044 given I know the xpub?
It should be m/44'/0'/0'/0/0
Johnathan (OP)
Newbie
*
Offline Offline

Activity: 39
Merit: 0



View Profile
August 20, 2014, 09:36:33 PM
 #10

Can you describe like I'm 5 how can I get the first address of the first account with this tool according to BIP-0044 given I know the xpub?
It should be m/44'/0'/0'/0/0

If you have the extended public key corresponding to m/44h/0h/0h/0 (note the syntax in BIP32 has changed) in a file, say test.xpub, you can simply:

Code:
$ bip32gen -i xpub -f test.xpub -o addr 0
1NaKvDgeVnXqvTpFzzngmH1RG9cN3BkVfh

This translates as "starting with an extended public key stored in file 'test.xpub', generate the address associated with child number 0, and write it to stdout". (Address shown is from an xpub from an arbitrary wallet seed).
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!