tallow arbitrary derivations with bip39 seeds, to let multibit users recover funds - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 6b45070b2f7c899dd9bdd1a7bf423ad23a014374
 (DIR) parent 2d48aa35af94bfc26ac3353ae732b71b8ee6d93c
 (HTM) Author: ThomasV <thomasv@electrum.org>
       Date:   Tue, 20 Jun 2017 10:47:02 +0200
       
       allow arbitrary derivations with bip39 seeds, to let multibit users recover funds
       
       Diffstat:
         M gui/qt/installwizard.py             |       2 +-
         M lib/base_wizard.py                  |      26 ++++++++++----------------
         M lib/bitcoin.py                      |      15 +++++++++++++++
       
       3 files changed, 26 insertions(+), 17 deletions(-)
       ---
 (DIR) diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
       t@@ -453,7 +453,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                line = QLineEdit()
                line.setText(default)
                def f(text):
       -            self.next_button.setEnabled(test(text))
       +            self.next_button.setEnabled(test(unicode(text)))
                line.textEdited.connect(f)
                vbox.addWidget(line)
                vbox.addWidget(WWLabel(warning))
 (DIR) diff --git a/lib/base_wizard.py b/lib/base_wizard.py
       t@@ -222,21 +222,16 @@ class BaseWizard(object):
                    # This is partially compatible with BIP45; assumes index=0
                    self.on_hw_derivation(name, device_info, "m/45'/0")
                else:
       -            f = lambda x: self.run('on_hw_derivation', name, device_info, bip44_derivation(int(x)))
       -            self.account_id_dialog(f)
       +            f = lambda x: self.run('on_hw_derivation', name, device_info, str(x))
       +            self.derivation_dialog(f)
        
       -    def account_id_dialog(self, f):
       +    def derivation_dialog(self, f):
       +        default = bip44_derivation(0)
                message = '\n'.join([
       -            _('Enter your BIP44 account number here.'),
       -            _('If you are not sure what this is, leave this field to zero.')
       +            _('Enter your wallet derivation here.'),
       +            _('If you are not sure what this is, leave this field unchanged.')
                ])
       -        def is_int(x):
       -            try:
       -                int(x)
       -                return True
       -            except:
       -                return False
       -        self.line_dialog(run_next=f, title=_('Account Number'), message=message, default='0', test=is_int)
       +        self.line_dialog(run_next=f, title=_('Derivation'), message=message, default=default, test=bitcoin.is_bip32_derivation)
        
            def on_hw_derivation(self, name, device_info, derivation):
                from keystore import hardware_keystore
       t@@ -293,17 +288,16 @@ class BaseWizard(object):
                    raise BaseException('Unknown seed type', seed_type)
        
            def on_restore_bip39(self, seed, passphrase):
       -        f = lambda x: self.run('on_bip44', seed, passphrase, int(x))
       -        self.account_id_dialog(f)
       +        f = lambda x: self.run('on_bip44', seed, passphrase, str(x))
       +        self.derivation_dialog(f)
        
            def create_keystore(self, seed, passphrase):
                k = keystore.from_seed(seed, passphrase)
                self.on_keystore(k)
        
       -    def on_bip44(self, seed, passphrase, account_id):
       +    def on_bip44(self, seed, passphrase, derivation):
                k = keystore.BIP32_KeyStore({})
                bip32_seed = keystore.bip39_to_seed(seed, passphrase)
       -        derivation = bip44_derivation(account_id)
                k.add_xprv_from_seed(bip32_seed, 0, derivation)
                self.on_keystore(k)
        
 (DIR) diff --git a/lib/bitcoin.py b/lib/bitcoin.py
       t@@ -820,6 +820,21 @@ def xpub_from_pubkey(xtype, cK):
            return serialize_xpub(xtype, chr(0)*32, cK)
        
        
       +def bip32_derivation(s):
       +    assert s.startswith('m/')
       +    s = s[2:]
       +    for n in s.split('/'):
       +        if n == '': continue
       +        i = int(n[:-1]) + BIP32_PRIME if n[-1] == "'" else int(n)
       +        yield i
       +
       +def is_bip32_derivation(x):
       +    try:
       +        [ i for i in bip32_derivation(x)]
       +        return True
       +    except :
       +        return False
       +
        def bip32_private_derivation(xprv, branch, sequence):
            assert sequence.startswith(branch)
            if branch == sequence: