mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-31 09:21:39 +00:00
move mnemonic to separate class and use slush's wordlist. new commands: make_seed and check_seed
This commit is contained in:
parent
94a5d26013
commit
4dcdcbc068
8 changed files with 3857 additions and 1733 deletions
7
electrum
7
electrum
|
@ -90,6 +90,8 @@ def arg_parser():
|
||||||
parser.add_option("--2of3", action="store_true", dest="2of3", default=False, help="create 2of3 wallet")
|
parser.add_option("--2of3", action="store_true", dest="2of3", default=False, help="create 2of3 wallet")
|
||||||
parser.add_option("--mpk", dest="mpk", default=False, help="restore from master public key")
|
parser.add_option("--mpk", dest="mpk", default=False, help="restore from master public key")
|
||||||
parser.add_option("-m", action="store_true", dest="hide_gui", default=False, help="hide GUI on startup")
|
parser.add_option("-m", action="store_true", dest="hide_gui", default=False, help="hide GUI on startup")
|
||||||
|
parser.add_option("--nbits", dest="nbits", default="128", help="number of bits for make_seed")
|
||||||
|
parser.add_option("--entropy", dest="entropy", default="1", help="custom entropy for make_seed")
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
@ -385,6 +387,9 @@ if __name__ == '__main__':
|
||||||
elif cmd.name == 'listaddresses':
|
elif cmd.name == 'listaddresses':
|
||||||
args = [cmd, options.show_all, options.show_labels]
|
args = [cmd, options.show_all, options.show_labels]
|
||||||
|
|
||||||
|
elif cmd.name == 'make_seed':
|
||||||
|
args = [cmd, int(options.nbits), long(options.entropy)]
|
||||||
|
|
||||||
elif cmd.name in ['payto', 'mktx']:
|
elif cmd.name in ['payto', 'mktx']:
|
||||||
domain = [options.from_addr] if options.from_addr else None
|
domain = [options.from_addr] if options.from_addr else None
|
||||||
args = ['mktx', args[1], Decimal(args[2]), Decimal(options.tx_fee) if options.tx_fee else None, options.change_addr, domain]
|
args = ['mktx', args[1], Decimal(args[2]), Decimal(options.tx_fee) if options.tx_fee else None, options.change_addr, domain]
|
||||||
|
@ -421,6 +426,8 @@ if __name__ == '__main__':
|
||||||
print_msg("Warning: Final argument was reconstructed from several arguments:", repr(message))
|
print_msg("Warning: Final argument was reconstructed from several arguments:", repr(message))
|
||||||
args = args[0:cmd.min_args] + [message]
|
args = args[0:cmd.min_args] + [message]
|
||||||
|
|
||||||
|
if cmd.name == 'check_seed':
|
||||||
|
args.append(long(options.entropy))
|
||||||
|
|
||||||
|
|
||||||
# run the command
|
# run the command
|
||||||
|
|
|
@ -11,8 +11,6 @@ import account
|
||||||
import transaction
|
import transaction
|
||||||
from transaction import Transaction
|
from transaction import Transaction
|
||||||
from plugins import BasePlugin
|
from plugins import BasePlugin
|
||||||
from mnemonic import mn_encode as mnemonic_encode
|
|
||||||
from mnemonic import mn_decode as mnemonic_decode
|
|
||||||
from commands import Commands, known_commands
|
from commands import Commands, known_commands
|
||||||
from daemon import NetworkServer
|
from daemon import NetworkServer
|
||||||
from network_proxy import NetworkProxy
|
from network_proxy import NetworkProxy
|
||||||
|
|
|
@ -111,17 +111,9 @@ def Hash(x):
|
||||||
hash_encode = lambda x: x[::-1].encode('hex')
|
hash_encode = lambda x: x[::-1].encode('hex')
|
||||||
hash_decode = lambda x: x.decode('hex')[::-1]
|
hash_decode = lambda x: x.decode('hex')[::-1]
|
||||||
hmac_sha_512 = lambda x,y: hmac.new(x, y, hashlib.sha512).digest()
|
hmac_sha_512 = lambda x,y: hmac.new(x, y, hashlib.sha512).digest()
|
||||||
|
|
||||||
|
|
||||||
def mnemonic_to_seed(mnemonic, passphrase):
|
|
||||||
from pbkdf2 import PBKDF2
|
|
||||||
import hmac
|
|
||||||
PBKDF2_ROUNDS = 2048
|
|
||||||
return PBKDF2(mnemonic, 'mnemonic' + passphrase, iterations = PBKDF2_ROUNDS, macmodule = hmac, digestmodule = hashlib.sha512).read(64)
|
|
||||||
|
|
||||||
|
|
||||||
is_new_seed = lambda x: hmac_sha_512("Seed version", x.encode('utf8')).encode('hex')[0:2].startswith(SEED_PREFIX)
|
is_new_seed = lambda x: hmac_sha_512("Seed version", x.encode('utf8')).encode('hex')[0:2].startswith(SEED_PREFIX)
|
||||||
|
|
||||||
|
|
||||||
def is_old_seed(seed):
|
def is_old_seed(seed):
|
||||||
import mnemonic
|
import mnemonic
|
||||||
words = seed.strip().split()
|
words = seed.strip().split()
|
||||||
|
|
|
@ -108,6 +108,8 @@ register_command('decrypt', 2,-1, False, True, True, 'decrypt a m
|
||||||
register_command('getproof', 1, 1, True, False, False, 'get merkle proof', 'getproof <address>')
|
register_command('getproof', 1, 1, True, False, False, 'get merkle proof', 'getproof <address>')
|
||||||
register_command('getutxoaddress', 2, 2, True, False, False, 'get the address of an unspent transaction output','getutxoaddress <txid> <pos>')
|
register_command('getutxoaddress', 2, 2, True, False, False, 'get the address of an unspent transaction output','getutxoaddress <txid> <pos>')
|
||||||
register_command('sweep', 2, 3, True, False, False, 'Sweep a private key.', 'sweep privkey addr [fee]')
|
register_command('sweep', 2, 3, True, False, False, 'Sweep a private key.', 'sweep privkey addr [fee]')
|
||||||
|
register_command('make_seed', 2, 2, False, False, False, 'Create a seed.','options: --nbits --entropy')
|
||||||
|
register_command('check_seed', 1,-1, False, False, False, 'Check that a seed was generated with external entropy. Option: --entropy')
|
||||||
|
|
||||||
|
|
||||||
class Commands:
|
class Commands:
|
||||||
|
@ -129,6 +131,15 @@ class Commands:
|
||||||
apply(self._callback, ())
|
apply(self._callback, ())
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def make_seed(self, nbits, custom_entropy):
|
||||||
|
from mnemonic import Mnemonic
|
||||||
|
s = Mnemonic('english').make_seed(nbits, custom_entropy)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def check_seed(self, seed, custom_entropy):
|
||||||
|
from mnemonic import Mnemonic
|
||||||
|
return Mnemonic('english').check_seed(seed, custom_entropy)
|
||||||
|
|
||||||
def getaddresshistory(self, addr):
|
def getaddresshistory(self, addr):
|
||||||
return self.network.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0]
|
return self.network.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0]
|
||||||
|
|
||||||
|
|
1727
lib/mnemonic.py
1727
lib/mnemonic.py
File diff suppressed because it is too large
Load diff
1691
lib/old_mnemonic.py
Normal file
1691
lib/old_mnemonic.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -36,6 +36,7 @@ from transaction import Transaction
|
||||||
from plugins import run_hook
|
from plugins import run_hook
|
||||||
import bitcoin
|
import bitcoin
|
||||||
from synchronizer import WalletSynchronizer
|
from synchronizer import WalletSynchronizer
|
||||||
|
from mnemonic import Mnemonic
|
||||||
|
|
||||||
COINBASE_MATURITY = 100
|
COINBASE_MATURITY = 100
|
||||||
DUST_THRESHOLD = 5430
|
DUST_THRESHOLD = 5430
|
||||||
|
@ -1278,6 +1279,32 @@ class BIP32_Wallet(Deterministic_Wallet):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def create_master_keys(self, password):
|
||||||
|
seed = self.get_seed(password)
|
||||||
|
self.add_cosigner_seed(seed, self.root_name, password)
|
||||||
|
|
||||||
|
def add_cosigner_seed(self, seed, name, password):
|
||||||
|
# we don't store the seed, only the master xpriv
|
||||||
|
xprv, xpub = bip32_root(self.mnemonic_to_seed(seed,''))
|
||||||
|
xprv, xpub = bip32_private_derivation(xprv, "m/", self.root_derivation)
|
||||||
|
self.add_master_public_key(name, xpub)
|
||||||
|
self.add_master_private_key(name, xprv, password)
|
||||||
|
|
||||||
|
def add_cosigner_xpub(self, seed, name):
|
||||||
|
# store only master xpub
|
||||||
|
xprv, xpub = bip32_root(self.mnemonic_to_seed(seed,''))
|
||||||
|
xprv, xpub = bip32_private_derivation(xprv, "m/", self.root_derivation)
|
||||||
|
self.add_master_public_key(name, xpub)
|
||||||
|
|
||||||
|
def mnemonic_to_seed(self, seed, password):
|
||||||
|
return Mnemonic.mnemonic_to_seed(seed, password)
|
||||||
|
|
||||||
|
def make_seed(self):
|
||||||
|
return Mnemonic('english').make_seed()
|
||||||
|
|
||||||
|
def prepare_seed(self, seed):
|
||||||
|
return NEW_SEED_VERSION, Mnemonic.prepare_seed(seed)
|
||||||
|
|
||||||
|
|
||||||
class BIP32_Simple_Wallet(BIP32_Wallet):
|
class BIP32_Simple_Wallet(BIP32_Wallet):
|
||||||
# Wallet with a single BIP32 account, no seed
|
# Wallet with a single BIP32 account, no seed
|
||||||
|
@ -1380,53 +1407,15 @@ class BIP32_HD_Wallet(BIP32_Wallet):
|
||||||
return i
|
return i
|
||||||
|
|
||||||
|
|
||||||
class BIP39_Wallet(BIP32_Wallet):
|
|
||||||
# BIP39 seed generation
|
|
||||||
|
|
||||||
def create_master_keys(self, password):
|
class NewWallet(BIP32_HD_Wallet, Mnemonic):
|
||||||
seed = self.get_seed(password)
|
|
||||||
xprv, xpub = bip32_root(mnemonic_to_seed(seed,''))
|
|
||||||
xprv, xpub = bip32_private_derivation(xprv, "m/", self.root_derivation)
|
|
||||||
self.add_master_public_key(self.root_name, xpub)
|
|
||||||
self.add_master_private_key(self.root_name, xprv, password)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def make_seed(self, custom_entropy=1):
|
|
||||||
import mnemonic
|
|
||||||
import ecdsa
|
|
||||||
import math
|
|
||||||
n = int(math.ceil(math.log(custom_entropy,2)))
|
|
||||||
n_added = max(16, 160-n)
|
|
||||||
print_error("make_seed: adding %d bits"%n_added)
|
|
||||||
my_entropy = ecdsa.util.randrange( pow(2, n_added) )
|
|
||||||
nonce = 0
|
|
||||||
while True:
|
|
||||||
s = "%x"% ( custom_entropy * (my_entropy + nonce))
|
|
||||||
if len(s) % 8:
|
|
||||||
s = "0"* (8 - len(s) % 8) + s
|
|
||||||
words = mnemonic.mn_encode(s)
|
|
||||||
seed = ' '.join(words)
|
|
||||||
# this removes 8 bits of entropy
|
|
||||||
if not is_old_seed(seed) and is_new_seed(seed):
|
|
||||||
break
|
|
||||||
nonce += 1
|
|
||||||
print_error(seed)
|
|
||||||
return seed
|
|
||||||
|
|
||||||
def prepare_seed(self, seed):
|
|
||||||
import unicodedata
|
|
||||||
return NEW_SEED_VERSION, unicodedata.normalize('NFC', unicode(seed.strip()))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class NewWallet(BIP32_HD_Wallet, BIP39_Wallet):
|
|
||||||
# bip 44
|
# bip 44
|
||||||
root_name = 'x/'
|
root_name = 'x/'
|
||||||
root_derivation = "m/44'/0'"
|
root_derivation = "m/44'/0'"
|
||||||
wallet_type = 'standard'
|
wallet_type = 'standard'
|
||||||
|
|
||||||
|
|
||||||
class Wallet_2of2(BIP39_Wallet):
|
class Wallet_2of2(BIP32_Wallet, Mnemonic):
|
||||||
# Wallet with multisig addresses.
|
# Wallet with multisig addresses.
|
||||||
# Cannot create accounts
|
# Cannot create accounts
|
||||||
root_name = "x1/"
|
root_name = "x1/"
|
||||||
|
@ -1457,19 +1446,6 @@ class Wallet_2of2(BIP39_Wallet):
|
||||||
if not self.accounts:
|
if not self.accounts:
|
||||||
return 'create_accounts'
|
return 'create_accounts'
|
||||||
|
|
||||||
def add_cosigner_seed(self, seed, name, password):
|
|
||||||
# we don't store the seed, only the master xpriv
|
|
||||||
xprv, xpub = bip32_root(mnemonic_to_seed(seed,''))
|
|
||||||
xprv, xpub = bip32_private_derivation(xprv, "m/", self.root_derivation)
|
|
||||||
self.add_master_public_key(name, xpub)
|
|
||||||
self.add_master_private_key(name, xprv, password)
|
|
||||||
|
|
||||||
def add_cosigner_xpub(self, seed, name):
|
|
||||||
# store only master xpub
|
|
||||||
xprv, xpub = bip32_root(mnemonic_to_seed(seed,''))
|
|
||||||
xprv, xpub = bip32_private_derivation(xprv, "m/", self.root_derivation)
|
|
||||||
self.add_master_public_key(name, xpub)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Wallet_2of3(Wallet_2of2):
|
class Wallet_2of3(Wallet_2of2):
|
||||||
|
@ -1510,12 +1486,12 @@ class OldWallet(Deterministic_Wallet):
|
||||||
self.gap_limit = storage.get('gap_limit', 5)
|
self.gap_limit = storage.get('gap_limit', 5)
|
||||||
|
|
||||||
def make_seed(self):
|
def make_seed(self):
|
||||||
import mnemonic
|
import old_mnemonic
|
||||||
seed = random_seed(128)
|
seed = random_seed(128)
|
||||||
return ' '.join(mnemonic.mn_encode(seed))
|
return ' '.join(old_mnemonic.mn_encode(seed))
|
||||||
|
|
||||||
def prepare_seed(self, seed):
|
def prepare_seed(self, seed):
|
||||||
import mnemonic
|
import old_mnemonic
|
||||||
# see if seed was entered as hex
|
# see if seed was entered as hex
|
||||||
seed = seed.strip()
|
seed = seed.strip()
|
||||||
try:
|
try:
|
||||||
|
@ -1526,7 +1502,7 @@ class OldWallet(Deterministic_Wallet):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
words = seed.split()
|
words = seed.split()
|
||||||
seed = mnemonic.mn_decode(words)
|
seed = old_mnemonic.mn_decode(words)
|
||||||
if not seed:
|
if not seed:
|
||||||
raise Exception("Invalid seed")
|
raise Exception("Invalid seed")
|
||||||
|
|
||||||
|
@ -1566,9 +1542,9 @@ class OldWallet(Deterministic_Wallet):
|
||||||
self.accounts['0'].check_seed(seed)
|
self.accounts['0'].check_seed(seed)
|
||||||
|
|
||||||
def get_mnemonic(self, password):
|
def get_mnemonic(self, password):
|
||||||
import mnemonic
|
import old_mnemonic
|
||||||
s = self.get_seed(password)
|
s = self.get_seed(password)
|
||||||
return ' '.join(mnemonic.mn_encode(s))
|
return ' '.join(old_mnemonic.mn_encode(s))
|
||||||
|
|
||||||
def can_sign(self, tx):
|
def can_sign(self, tx):
|
||||||
if self.is_watching_only():
|
if self.is_watching_only():
|
||||||
|
|
2048
lib/wordlist/english.txt
Normal file
2048
lib/wordlist/english.txt
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue