Пример #1
0
 def get_mixing_depth_keys(self, master):
     pre_root = btc.bip32_ckd(master, 49 + 2**31)
     testnet_flag = 1 if get_network() == "testnet" else 0
     root = btc.bip32_ckd(pre_root, testnet_flag + 2**31)
     return [
         btc.bip32_ckd(root, c + 2**31) for c in range(self.max_mix_depth)
     ]
Пример #2
0
def create_wallet_file(pwd, seed):
    password_key = btc.bin_dbl_sha256(pwd)
    encrypted_seed = encryptData(password_key, seed.decode('hex'))
    timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
    return json.dumps({'creator': 'joinmarket project',
                             'creation_time': timestamp,
                             'encrypted_seed': encrypted_seed.encode('hex'),
                             'network': get_network()})
Пример #3
0
 def entropy_to_seed(self, entropy):
     if entropy is None:
         return None
     if get_network() == "testnet":
         if entropy.startswith("FAKESEED"):
             return entropy[8:]
     self.entropy = entropy.decode('hex')
     m = Mnemonic("english")
     return m.to_seed(m.to_mnemonic(self.entropy)).encode('hex')
Пример #4
0
 def get_master_key(self):
     if not self.seed:
         raise Exception("Cannot extract master key of wallet, no seed.")
     #Legacy used the seed in hex
     if not isinstance(self, SegwitWallet):
         bip32seed = self.seed
     else:
         bip32seed = self.seed.decode('hex')
     return btc.bip32_master_key(bip32seed, (btc.MAINNET_PRIVATE if get_network(
             ) == 'mainnet' else btc.TESTNET_PRIVATE))
Пример #5
0
 def wallet_data_to_seed(self, data):
     if data is None:
         return None
     self.mnemonic_extension = None
     if isinstance(data, tuple):
         entropy, self.mnemonic_extension = data
     else:
         entropy = data
     if get_network() == "testnet":
         if entropy.startswith("FAKESEED"):
             return entropy[8:]
     self.entropy = entropy.decode('hex')
     m = Mnemonic("english")
     return m.to_seed(m.to_mnemonic(self.entropy),
         '' if not self.mnemonic_extension else self.mnemonic_extension).encode('hex')
Пример #6
0
    def __init__(self,
                 seedarg,
                 pwd,
                 max_mix_depth=2,
                 gaplimit=6,
                 extend_mixdepth=False,
                 storepassword=False,
                 wallet_dir=None):
        super(Wallet, self).__init__()
        self.max_mix_depth = max_mix_depth
        self.storepassword = storepassword
        # key is address, value is (mixdepth, forchange, index) if mixdepth =
        #  -1 it's an imported key and index refers to imported_privkeys
        self.addr_cache = {}
        self.unspent = {}
        self.spent_utxos = []
        self.imported_privkeys = {}
        self.seed = self.read_wallet_file_data(seedarg,
                                               pwd,
                                               wallet_dir=wallet_dir)
        if not self.seed:
            raise WalletError("Failed to decrypt wallet")
        if extend_mixdepth and len(self.index_cache) > max_mix_depth:
            self.max_mix_depth = len(self.index_cache)
        self.gaplimit = gaplimit
        master = btc.bip32_master_key(self.seed,
                                      (btc.MAINNET_PRIVATE if get_network()
                                       == 'mainnet' else btc.TESTNET_PRIVATE))
        m_0 = btc.bip32_ckd(master, 0)
        mixing_depth_keys = [
            btc.bip32_ckd(m_0, c) for c in range(self.max_mix_depth)
        ]
        self.keys = [(btc.bip32_ckd(m, 0), btc.bip32_ckd(m, 1))
                     for m in mixing_depth_keys]

        # self.index = [[0, 0]]*max_mix_depth
        self.index = []
        for i in range(self.max_mix_depth):
            self.index.append([0, 0])
Пример #7
0
 def get_root_path(self):
     testflag = "1'" if get_network() == "testnet" else "0'"
     return "m/49'/" + testflag
Пример #8
0
    def read_wallet_file_data(self, filename, pwd=None, wallet_dir=None):
        self.path = None
        wallet_dir = wallet_dir if wallet_dir else 'wallets'
        self.index_cache = [[0, 0]] * self.max_mix_depth
        path = os.path.join(wallet_dir, filename)
        if not os.path.isfile(path):
            if get_network() == 'testnet':
                log.debug('filename interpreted as seed, only available in '
                          'testnet because this probably has lower entropy')
                return "FAKESEED" + filename
            else:
                raise IOError('wallet file not found')
        if not pwd:
            log.info("Password required for non-testnet seed wallet")
            return None
        self.path = path
        fd = open(path, 'r')
        walletfile = fd.read()
        fd.close()
        walletdata = json.loads(walletfile)
        if walletdata['network'] != get_network():
            raise ValueError('wallet network(%s) does not match '
                             'joinmarket configured network(%s)' %
                             (walletdata['network'], get_network()))
        if 'index_cache' in walletdata:
            self.index_cache = walletdata['index_cache']
            if self.max_mix_depth > len(self.index_cache):
                #This can happen e.g. in tumbler when we need more mixdepths
                #than currently exist. Since we have no info for those extra
                #depths, we must default to (0,0) (but sync should find used
                #adddresses).
                self.index_cache += [[0, 0]] * (self.max_mix_depth -
                                                len(self.index_cache))
        password_key = btc.bin_dbl_sha256(pwd)
        if 'encrypted_seed' in walletdata:  #accept old field name
            encrypted_entropy = walletdata['encrypted_seed']
        elif 'encrypted_entropy' in walletdata:
            encrypted_entropy = walletdata['encrypted_entropy']
        try:
            decrypted_entropy = decryptData(
                password_key, encrypted_entropy.decode('hex')).encode('hex')
            # there is a small probability of getting a valid PKCS7
            # padding by chance from a wrong password; sanity check the
            # seed length
            if len(decrypted_entropy) != 32:
                raise ValueError
        except ValueError:
            log.info('Incorrect password')
            return None

        if 'encrypted_mnemonic_extension' in walletdata:
            try:
                cleartext = decryptData(
                    password_key,
                    walletdata['encrypted_mnemonic_extension'].decode('hex'))
                #theres a small chance of not getting a ValueError from the wrong
                # password so also check the sum
                if cleartext[-9] != '\xff':
                    raise ValueError
                chunks = cleartext.split('\xff')
                if len(chunks) < 3 or cleartext[-8:] != btc.dbl_sha256(
                        chunks[1])[:8]:
                    raise ValueError
                mnemonic_extension = chunks[1]
            except ValueError:
                log.info('incorrect password')
                return None
        else:
            mnemonic_extension = None

        if self.storepassword:
            self.password_key = password_key
            self.walletdata = walletdata
        if 'imported_keys' in walletdata:
            for epk_m in walletdata['imported_keys']:
                privkey = decryptData(
                    password_key,
                    epk_m['encrypted_privkey'].decode('hex')).encode('hex')
                #Imported keys are stored as 32 byte strings only, so the
                #second version below is sufficient, really.
                if len(privkey) != 64:
                    raise Exception(
                        "Unexpected privkey format; already compressed?:" +
                        privkey)
                privkey += "01"
                if epk_m['mixdepth'] not in self.imported_privkeys:
                    self.imported_privkeys[epk_m['mixdepth']] = []
                self.addr_cache[btc.privtoaddr(
                    privkey, magicbyte=get_p2pk_vbyte())] = (
                        epk_m['mixdepth'], -1,
                        len(self.imported_privkeys[epk_m['mixdepth']]))
                self.imported_privkeys[epk_m['mixdepth']].append(privkey)

        if mnemonic_extension:
            return (decrypted_entropy, mnemonic_extension)
        else:
            return decrypted_entropy