|
@@ -28,53 +28,82 @@ os.environ['MMGEN_TEST_SUITE'] = '1'
|
|
|
|
|
|
# Import these _after_ local path's been added to sys.path
|
|
|
from mmgen.common import *
|
|
|
-from mmgen.obj import MMGenAddrType
|
|
|
|
|
|
rounds = 100
|
|
|
opts_data = {
|
|
|
'text': {
|
|
|
- 'desc': 'Test address generation in various ways',
|
|
|
+ 'desc': 'Test address generation of the MMGen suite in various ways',
|
|
|
'usage':'[options] [spec] [rounds | dump file]',
|
|
|
'options': """
|
|
|
-h, --help Print this help message
|
|
|
--a, --all Test all supported coins for external generator 'ext'
|
|
|
+-a, --all Test all coins supported by specified external tool
|
|
|
-k, --use-internal-keccak-module Force use of the internal keccak module
|
|
|
--, --longhelp Print help message for long options (common options)
|
|
|
-q, --quiet Produce quieter output
|
|
|
--t, --type=t Specify address type (valid options: 'compressed','segwit','zcash_z')
|
|
|
+-t, --type=t Specify address type (e.g. 'compressed','segwit','zcash_z','bech32')
|
|
|
-v, --verbose Produce more verbose output
|
|
|
""",
|
|
|
'notes': """
|
|
|
- Tests:
|
|
|
- A/B: {prog} a:b [rounds] (compare output of two key generators)
|
|
|
- Speed: {prog} a [rounds] (test speed of one key generator)
|
|
|
- Compare: {prog} a <dump file> (compare output of a key generator against wallet dump)
|
|
|
- where a and b are one of:
|
|
|
- '1' - native Python ecdsa library (very slow)
|
|
|
- '2' - bitcoincore.org's secp256k1 library (default from v0.8.6)
|
|
|
+TEST TYPES:
|
|
|
+
|
|
|
+ A/B: {prog} A:B [rounds] (compare key generators A and B)
|
|
|
+ Speed: {prog} A [rounds] (test speed of key generator A)
|
|
|
+ Compare: {prog} A <dump file> (compare generator A to wallet dump)
|
|
|
+
|
|
|
+ where A and B are one of:
|
|
|
+ '1' - native Python ECDSA library (slow), or
|
|
|
+ '2' - bitcoincore.org's libsecp256k1 library (default);
|
|
|
+ or:
|
|
|
+ B is name of an external tool (see below) or 'ext'.
|
|
|
+ If B is 'ext', the external tool will be chosen automatically.
|
|
|
|
|
|
EXAMPLES:
|
|
|
- {prog} 1:2 100
|
|
|
- (compare output of native Python ECDSA with secp256k1 library, 100 rounds)
|
|
|
- {prog} 2:ext 100
|
|
|
- (compare output of secp256k1 library with external library (see below), 100 rounds)
|
|
|
- {prog} 2 1000
|
|
|
- (test speed of secp256k1 library address generation, 1000 rounds)
|
|
|
- {prog} 2 my.dump
|
|
|
- (compare addrs generated with secp256k1 library to {dn} wallet dump)
|
|
|
-
|
|
|
- External libraries required for the 'ext' generator:
|
|
|
- + ethkey (for ETH,ETC) https://github.com/paritytech/parity-ethereum
|
|
|
- + zcash-mini (for zcash_z addresses) https://github.com/FiloSottile/zcash-mini
|
|
|
- + moneropy (for Monero addresses) https://github.com/bigreddmachine/MoneroPy
|
|
|
- + pycoin (for supported coins) https://github.com/richardkiss/pycoin
|
|
|
- + keyconv (for all other coins) https://github.com/exploitagency/vanitygen-plus
|
|
|
- ('keyconv' generates uncompressed addresses only)
|
|
|
+
|
|
|
+ Compare addresses generated by native Python ECDSA library and libsecp256k1,
|
|
|
+ 100 rounds:
|
|
|
+ $ {prog} 1:2 100
|
|
|
+
|
|
|
+ Compare mmgen-secp256k1 Segwit address generation to pycoin library for all
|
|
|
+ supported coins, 100 rounds:
|
|
|
+ $ {prog} --all --type=segwit 2:pycoin 100
|
|
|
+
|
|
|
+ Compare mmgen-secp256k1 address generation to keyconv tool for all
|
|
|
+ supported coins, 100 rounds:
|
|
|
+ $ {prog} --all --type=compressed 2:keyconv 100
|
|
|
+
|
|
|
+ Compare mmgen-secp256k1 XMR address generation to configured external tool,
|
|
|
+ 10 rounds:
|
|
|
+ $ {prog} --coin=xmr 2:ext 10
|
|
|
+
|
|
|
+ Test speed of mmgen-secp256k1 address generation, 10,000 rounds:
|
|
|
+ $ {prog} 2 10000
|
|
|
+
|
|
|
+ Compare mmgen-secp256k1-generated bech32 addrs to {dn} wallet dump:
|
|
|
+ $ {prog} --type=bech32 2 bech32wallet.dump
|
|
|
+
|
|
|
+Supported external tools:
|
|
|
+
|
|
|
+ + ethkey (for ETH,ETC)
|
|
|
+ https://github.com/paritytech/parity-ethereum
|
|
|
+ (build with 'cargo build -p ethkey-cli --release')
|
|
|
+
|
|
|
+ + zcash-mini (for Zcash Z-addresses)
|
|
|
+ https://github.com/FiloSottile/zcash-mini
|
|
|
+
|
|
|
+ + moneropy (for Monero addresses)
|
|
|
+ https://github.com/bigreddmachine/MoneroPy
|
|
|
+
|
|
|
+ + pycoin (for supported coins)
|
|
|
+ https://github.com/richardkiss/pycoin
|
|
|
+
|
|
|
+ + keyconv (for supported coins)
|
|
|
+ https://github.com/exploitagency/vanitygen-plus
|
|
|
+ ('keyconv' does not generate Segwit addresses)
|
|
|
"""
|
|
|
},
|
|
|
'code': {
|
|
|
'notes': lambda s: s.format(
|
|
|
- prog='gentest.py',
|
|
|
+ prog='test/gentest.py',
|
|
|
pnm=g.proj_name,
|
|
|
snum=rounds,
|
|
|
dn=g.proto.daemon_name)
|
|
@@ -85,98 +114,120 @@ sys.argv = [sys.argv[0]] + ['--skip-cfg-file'] + sys.argv[1:]
|
|
|
|
|
|
cmd_args = opts.init(opts_data,add_opts=['exact_output','use_old_ed25519'])
|
|
|
|
|
|
-if not 1 <= len(cmd_args) <= 2: opts.usage()
|
|
|
-
|
|
|
-addr_type = MMGenAddrType(opt.type or g.proto.dfl_mmtype)
|
|
|
-
|
|
|
-from collections import namedtuple
|
|
|
-ep = namedtuple('external_prog_output',['wif','addr','vk'])
|
|
|
+if not 1 <= len(cmd_args) <= 2:
|
|
|
+ opts.usage()
|
|
|
|
|
|
from subprocess import run,PIPE,DEVNULL
|
|
|
def get_cmd_output(cmd,input=None):
|
|
|
return run(cmd,input=input,stdout=PIPE,stderr=DEVNULL).stdout.decode().splitlines()
|
|
|
|
|
|
-def ethkey_sec2addr(sec):
|
|
|
- o = get_cmd_output(['ethkey','info',sec])
|
|
|
- return ep(o[0].split()[1],o[-1].split()[1],None)
|
|
|
-
|
|
|
-def keyconv_sec2addr(sec):
|
|
|
- o = get_cmd_output(['keyconv','-C',g.coin,sec.wif])
|
|
|
- return ep(o[1].split()[1],o[0].split()[1],None)
|
|
|
-
|
|
|
-def zcash_mini_sec2addr(sec):
|
|
|
- o = get_cmd_output(['zcash-mini','-key','-simple'],input=(sec.wif+'\n').encode())
|
|
|
- return ep(o[1],o[0],o[-1])
|
|
|
-
|
|
|
-def pycoin_sec2addr(sec):
|
|
|
- coin = ci.external_tests['testnet']['pycoin'][g.coin] if g.testnet else g.coin
|
|
|
- network = network_for_netcode(coin)
|
|
|
- key = network.keys.private(secret_exponent=int(sec,16),is_compressed=addr_type.name != 'legacy')
|
|
|
- if key is None:
|
|
|
- die(1,"can't parse {}".format(sec))
|
|
|
- if addr_type.name in ('segwit','bech32'):
|
|
|
- hash160_c = key.hash160(is_compressed=True)
|
|
|
- if addr_type.name == 'segwit':
|
|
|
- p2sh_script = network.contract.for_p2pkh_wit(hash160_c)
|
|
|
- addr = network.address.for_p2s(p2sh_script)
|
|
|
- else:
|
|
|
- addr = network.address.for_p2pkh_wit(hash160_c)
|
|
|
- else:
|
|
|
- addr = key.address()
|
|
|
- return ep(key.wif(),addr,None)
|
|
|
-
|
|
|
-def moneropy_sec2addr(sec):
|
|
|
- sk_t,vk_t,addr_t = mp_acc.account_from_spend_key(sec) # VERY slow!
|
|
|
- return ep(sk_t,addr_t,vk_t)
|
|
|
-
|
|
|
-# pycoin/networks/all.py pycoin/networks/legacy_networks.py
|
|
|
-def init_external_prog():
|
|
|
- global b,b_desc,ext_prog,ext_sec2addr,eth,addr_type
|
|
|
-
|
|
|
- def test_support(k):
|
|
|
- if b == k: return True
|
|
|
- if b != 'ext' and b != k: return False
|
|
|
- if g.coin in ci.external_tests['mainnet'][k] and not g.testnet: return True
|
|
|
- if g.coin in ci.external_tests['testnet'][k]: return True
|
|
|
- return False
|
|
|
-
|
|
|
- if b == 'zcash_mini' or addr_type.name == 'zcash_z':
|
|
|
- ext_sec2addr = zcash_mini_sec2addr
|
|
|
- ext_prog = 'zcash_mini'
|
|
|
+from collections import namedtuple
|
|
|
+gtr = namedtuple('gen_tool_result',['wif','addr','vk'])
|
|
|
+
|
|
|
+class GenTool(object): pass
|
|
|
+
|
|
|
+class GenToolEthkey(GenTool):
|
|
|
+ desc = 'ethkey'
|
|
|
+ def __init__(self):
|
|
|
+ init_coin('eth')
|
|
|
+ global addr_type
|
|
|
+ addr_type = MMGenAddrType('E')
|
|
|
+
|
|
|
+ def run(self,sec):
|
|
|
+ o = get_cmd_output(['ethkey','info',sec])
|
|
|
+ return gtr(o[0].split()[1],o[-1].split()[1],None)
|
|
|
+
|
|
|
+class GenToolKeyconv(GenTool):
|
|
|
+ desc = 'keyconv'
|
|
|
+ def run(self,sec):
|
|
|
+ o = get_cmd_output(['keyconv','-C',g.coin,sec.wif])
|
|
|
+ return gtr(o[1].split()[1],o[0].split()[1],None)
|
|
|
+
|
|
|
+class GenToolZcash_mini(GenTool):
|
|
|
+ desc = 'zcash-mini'
|
|
|
+ def __init__(self):
|
|
|
init_coin('zec')
|
|
|
+ global addr_type
|
|
|
addr_type = MMGenAddrType('Z')
|
|
|
- elif test_support('ethkey'): # build with 'cargo build -p ethkey-cli --release'
|
|
|
- ext_sec2addr = ethkey_sec2addr
|
|
|
- ext_prog = 'ethkey'
|
|
|
- elif test_support('pycoin'):
|
|
|
- global network_for_netcode
|
|
|
+
|
|
|
+ def run(self,sec):
|
|
|
+ o = get_cmd_output(['zcash-mini','-key','-simple'],input=(sec.wif+'\n').encode())
|
|
|
+ return gtr(o[1],o[0],o[-1])
|
|
|
+
|
|
|
+class GenToolPycoin(GenTool):
|
|
|
+ """
|
|
|
+ pycoin/networks/all.py pycoin/networks/legacy_networks.py
|
|
|
+ """
|
|
|
+ desc = 'pycoin'
|
|
|
+ def __init__(self):
|
|
|
+ m = "Unable to import pycoin.networks.registry. Is pycoin installed on your system?"
|
|
|
try:
|
|
|
from pycoin.networks.registry import network_for_netcode
|
|
|
except:
|
|
|
- raise ImportError("Unable to import pycoin.networks.registry. Is pycoin installed on your system?")
|
|
|
- ext_sec2addr = pycoin_sec2addr
|
|
|
- ext_prog = 'pycoin'
|
|
|
- elif test_support('moneropy'):
|
|
|
- global mp_acc
|
|
|
+ raise ImportError(m)
|
|
|
+ self.nfnc = network_for_netcode
|
|
|
+
|
|
|
+ def run(self,sec):
|
|
|
+ coin = ci.external_tests['testnet']['pycoin'][g.coin] if g.testnet else g.coin
|
|
|
+ network = self.nfnc(coin)
|
|
|
+ key = network.keys.private(secret_exponent=int(sec,16),is_compressed=addr_type.name != 'legacy')
|
|
|
+ if key is None:
|
|
|
+ die(1,"can't parse {}".format(sec))
|
|
|
+ if addr_type.name in ('segwit','bech32'):
|
|
|
+ hash160_c = key.hash160(is_compressed=True)
|
|
|
+ if addr_type.name == 'segwit':
|
|
|
+ p2sh_script = network.contract.for_p2pkh_wit(hash160_c)
|
|
|
+ addr = network.address.for_p2s(p2sh_script)
|
|
|
+ else:
|
|
|
+ addr = network.address.for_p2pkh_wit(hash160_c)
|
|
|
+ else:
|
|
|
+ addr = key.address()
|
|
|
+ return gtr(key.wif(),addr,None)
|
|
|
+
|
|
|
+class GenToolMoneropy(GenTool):
|
|
|
+ desc = 'moneropy'
|
|
|
+ def __init__(self):
|
|
|
+
|
|
|
+ m = "Unable to import moneropy. Is moneropy installed on your system?"
|
|
|
try:
|
|
|
- import moneropy.account as mp_acc
|
|
|
+ import moneropy.account
|
|
|
except:
|
|
|
- raise ImportError("Unable to import moneropy. Is moneropy installed on your system?")
|
|
|
- ext_sec2addr = moneropy_sec2addr
|
|
|
+ raise ImportError(m)
|
|
|
+
|
|
|
+ self.mpa = moneropy.account
|
|
|
init_coin('xmr')
|
|
|
- ext_prog = 'moneropy'
|
|
|
+
|
|
|
+ global addr_type
|
|
|
addr_type = MMGenAddrType('M')
|
|
|
- elif test_support('keyconv'):
|
|
|
- ext_sec2addr = keyconv_sec2addr
|
|
|
- ext_prog = 'keyconv'
|
|
|
- else:
|
|
|
- m = '{}: coin supported by MMGen but unsupported by gentest.py for {}'
|
|
|
- raise ValueError(m.format(g.coin,('mainnet','testnet')[g.testnet]))
|
|
|
- b_desc = ext_prog
|
|
|
- b = 'ext'
|
|
|
|
|
|
-def test_equal(a_addr,b_addr,in_bytes,sec,wif,a,b):
|
|
|
- if a_addr != b_addr:
|
|
|
+ def run(self,sec):
|
|
|
+ sk_t,vk_t,addr_t = self.mpa.account_from_spend_key(sec) # VERY slow!
|
|
|
+ return gtr(sk_t,addr_t,vk_t)
|
|
|
+
|
|
|
+def get_tool(arg):
|
|
|
+
|
|
|
+ if arg not in ext_progs + ['ext']:
|
|
|
+ die(1,'{!r}: unsupported tool for network {}'.format(arg,g.network))
|
|
|
+
|
|
|
+ if opt.all:
|
|
|
+ if arg == 'ext':
|
|
|
+ die(1,"'--all' must be combined with a specific external testing tool")
|
|
|
+ return arg
|
|
|
+ else:
|
|
|
+ tool = ci.get_test_support(
|
|
|
+ g.coin,
|
|
|
+ addr_type.name,
|
|
|
+ g.network,
|
|
|
+ verbose = not opt.quiet,
|
|
|
+ tool = arg if arg in ext_progs else None )
|
|
|
+ if not tool:
|
|
|
+ sys.exit(2)
|
|
|
+ if arg in ext_progs and arg != tool:
|
|
|
+ sys.exit(3)
|
|
|
+ return tool
|
|
|
+
|
|
|
+def test_equal(desc,a_val,b_val,in_bytes,sec,wif,a_desc,b_desc):
|
|
|
+ if a_val != b_val:
|
|
|
fs = """
|
|
|
{i:{w}}: {}
|
|
|
{s:{w}}: {}
|
|
@@ -185,32 +236,27 @@ def test_equal(a_addr,b_addr,in_bytes,sec,wif,a,b):
|
|
|
{b:{w}}: {}
|
|
|
"""
|
|
|
die(3,
|
|
|
- red('\nERROR: Values do not match!')
|
|
|
+ red('\nERROR: {} do not match!').format(desc)
|
|
|
+ fs.format(
|
|
|
- in_bytes.hex(), sec, wif, a_addr, b_addr,
|
|
|
- i='input', s='sec key', W='WIF key', a=kg_a.desc, b=b_desc,
|
|
|
- w=max(len(e) for e in (kg_a.desc,b_desc)) + 1
|
|
|
+ in_bytes.hex(), sec, wif, a_val, b_val,
|
|
|
+ i='input', s='sec key', W='WIF key', a=a_desc, b=b_desc,
|
|
|
+ w=max(len(e) for e in (a_desc,b_desc)) + 1
|
|
|
).rstrip())
|
|
|
|
|
|
-def compare_test():
|
|
|
- for k in ('segwit','compressed'):
|
|
|
- if b == 'ext' and addr_type.name == k and g.coin not in ci.external_tests_segwit_compressed[k]:
|
|
|
- m = 'skipping - external program does not support {} for coin {}'
|
|
|
- msg(m.format(addr_type.name.capitalize(),g.coin))
|
|
|
- return
|
|
|
- if 'ext_prog' in globals():
|
|
|
- if g.coin not in ci.external_tests[('mainnet','testnet')[g.testnet]][ext_prog]:
|
|
|
- msg("Coin '{}' incompatible with external generator '{}'".format(g.coin,ext_prog))
|
|
|
- return
|
|
|
+def gentool_test(kg_a,kg_b,ag,rounds):
|
|
|
+
|
|
|
+ m = "Comparing address generators '{A}' and '{B}' for {N} {c} ({n}), addrtype {a!r}"
|
|
|
+ e = ci.get_entry(g.coin,g.network)
|
|
|
+ qmsg(green(m.format(
|
|
|
+ A = kg_a.desc,
|
|
|
+ B = kg_b.desc,
|
|
|
+ N = g.network,
|
|
|
+ c = g.coin,
|
|
|
+ n = e.name if e else '---',
|
|
|
+ a = addr_type.name )))
|
|
|
+
|
|
|
global last_t
|
|
|
last_t = time.time()
|
|
|
- A = kg_a.desc
|
|
|
- B = b_desc
|
|
|
- if A == B:
|
|
|
- msg('skipping - generation methods A and B are the same ({})'.format(A))
|
|
|
- return
|
|
|
- m = "Comparing address generators '{}' and '{}' for coin {}, addrtype {!r}"
|
|
|
- qmsg(green(m.format(A,B,g.coin,addr_type.name)))
|
|
|
|
|
|
def do_compare_test(n,trounds,in_bytes):
|
|
|
global last_t
|
|
@@ -221,24 +267,23 @@ def compare_test():
|
|
|
a_ph = kg_a.to_pubhex(sec)
|
|
|
a_addr = ag.to_addr(a_ph)
|
|
|
a_vk = None
|
|
|
- if b == 'ext':
|
|
|
- ret = ext_sec2addr(sec)
|
|
|
- tinfo = (in_bytes,sec,sec.wif,a,ext_prog)
|
|
|
- test_equal(sec.wif,ret.wif,*tinfo)
|
|
|
- test_equal(a_addr,ret.addr,*tinfo)
|
|
|
- if ret.vk:
|
|
|
+ tinfo = (in_bytes,sec,sec.wif,kg_a.desc,kg_b.desc)
|
|
|
+ if isinstance(kg_b,GenTool):
|
|
|
+ b = kg_b.run(sec)
|
|
|
+ test_equal('WIF keys',sec.wif,b.wif,*tinfo)
|
|
|
+ test_equal('addresses',a_addr,b.addr,*tinfo)
|
|
|
+ if b.vk:
|
|
|
a_vk = ag.to_viewkey(a_ph)
|
|
|
- test_equal(a_vk,ret.vk,*tinfo)
|
|
|
+ test_equal('view keys',a_vk,b.vk,*tinfo)
|
|
|
else:
|
|
|
b_addr = ag.to_addr(kg_b.to_pubhex(sec))
|
|
|
- tinfo = (in_bytes,sec,sec.wif,a,b)
|
|
|
- test_equal(a_addr,b_addr,*tinfo)
|
|
|
- vmsg(ct_fs.format(b=in_bytes.hex(),k=sec.wif,v=a_vk,a=a_addr))
|
|
|
+ test_equal('addresses',a_addr,b_addr,*tinfo)
|
|
|
+ vmsg(fs.format(b=in_bytes.hex(),k=sec.wif,v=a_vk,a=a_addr))
|
|
|
qmsg_r('\rRound {}/{} '.format(n+1,trounds))
|
|
|
|
|
|
- ct_fs = ( '\ninput: {b}\n%-9s {k}\naddr: {a}\n',
|
|
|
- '\ninput: {b}\n%-9s {k}\nviewkey: {v}\naddr: {a}\n')[
|
|
|
- 'viewkey' in addr_type.extra_attrs] % (addr_type.wif_label + ':')
|
|
|
+ fs = ( '\ninput: {b}\n%-9s {k}\naddr: {a}\n',
|
|
|
+ '\ninput: {b}\n%-9s {k}\nviewkey: {v}\naddr: {a}\n')[
|
|
|
+ 'viewkey' in addr_type.extra_attrs] % (addr_type.wif_label + ':')
|
|
|
|
|
|
# test some important private key edge cases:
|
|
|
edgecase_sks = (
|
|
@@ -259,9 +304,9 @@ def compare_test():
|
|
|
do_compare_test(i,rounds,os.urandom(32))
|
|
|
qmsg(green('\rOK ' if opt.verbose else 'OK'))
|
|
|
|
|
|
-def speed_test():
|
|
|
+def speed_test(kg,ag,rounds):
|
|
|
m = "Testing speed of address generator '{}' for coin {}"
|
|
|
- qmsg(green(m.format(kg_a.desc,g.coin)))
|
|
|
+ qmsg(green(m.format(kg.desc,g.coin)))
|
|
|
from struct import pack,unpack
|
|
|
seed = os.urandom(28)
|
|
|
qmsg('Incrementing key with each round')
|
|
@@ -274,101 +319,119 @@ def speed_test():
|
|
|
qmsg_r('\rRound {}/{} '.format(i+1,rounds))
|
|
|
last_t = time.time()
|
|
|
sec = PrivKey(seed+pack('I',i),compressed=addr_type.compressed,pubkey_type=addr_type.pubkey_type)
|
|
|
- a_addr = ag.to_addr(kg_a.to_pubhex(sec))
|
|
|
- vmsg('\nkey: {}\naddr: {}\n'.format(sec.wif,a_addr))
|
|
|
+ addr = ag.to_addr(kg.to_pubhex(sec))
|
|
|
+ vmsg('\nkey: {}\naddr: {}\n'.format(sec.wif,addr))
|
|
|
qmsg_r('\rRound {}/{} '.format(i+1,rounds))
|
|
|
qmsg('\n{} addresses generated in {:.2f} seconds'.format(rounds,time.time()-start))
|
|
|
|
|
|
-def dump_test():
|
|
|
- m = "Comparing output of address generator '{}' against wallet dump '{}'"
|
|
|
- qmsg(green(m.format(kg_a.desc,cmd_args[1])))
|
|
|
- for n,[wif,a_addr] in enumerate(dump,1):
|
|
|
- qmsg_r('\rKey {}/{} '.format(n,len(dump)))
|
|
|
+def dump_test(kg,ag,fh):
|
|
|
+
|
|
|
+ dump = [[*(e.split()[0] for e in line.split('addr='))] for line in fh.readlines() if 'addr=' in line]
|
|
|
+ if not dump:
|
|
|
+ die(1,'File {!r} appears not to be a wallet dump'.format(fh.name))
|
|
|
+
|
|
|
+ m = 'Comparing output of address generator {!r} against wallet dump {!r}'
|
|
|
+ qmsg(green(m.format(kg.desc,fh.name)))
|
|
|
+
|
|
|
+ for count,(b_wif,b_addr) in enumerate(dump,1):
|
|
|
+ qmsg_r('\rKey {}/{} '.format(count,len(dump)))
|
|
|
try:
|
|
|
- sec = PrivKey(wif=wif)
|
|
|
+ b_sec = PrivKey(wif=b_wif)
|
|
|
except:
|
|
|
- die(2,'\nInvalid {}net WIF address in dump file: {}'.format(('main','test')[g.testnet],wif))
|
|
|
- b_addr = ag.to_addr(kg_a.to_pubhex(sec))
|
|
|
- vmsg('\nwif: {}\naddr: {}\n'.format(wif,b_addr))
|
|
|
- tinfo = (bytes.fromhex(sec),sec,wif,3,a)
|
|
|
- test_equal(a_addr,b_addr,*tinfo)
|
|
|
+ die(2,'\nInvalid {} WIF address in dump file: {}'.format(g.network,b_wif))
|
|
|
+ a_addr = ag.to_addr(kg.to_pubhex(b_sec))
|
|
|
+ vmsg('\nwif: {}\naddr: {}\n'.format(b_wif,b_addr))
|
|
|
+ tinfo = (bytes.fromhex(b_sec),b_sec,b_wif,kg.desc,fh.name)
|
|
|
+ test_equal('addresses',a_addr,b_addr,*tinfo)
|
|
|
qmsg(green(('\n','')[bool(opt.verbose)] + 'OK'))
|
|
|
|
|
|
-# begin execution
|
|
|
-from mmgen.protocol import init_coin
|
|
|
-from mmgen.altcoin import CoinInfo as ci
|
|
|
+def init_tool(tname):
|
|
|
+ return globals()['GenTool'+capfirst(tname.replace('-','_'))]()
|
|
|
|
|
|
-urounds,fh = None,None
|
|
|
-dump = []
|
|
|
+def parse_arg1(arg,arg_id):
|
|
|
|
|
|
-if len(cmd_args) == 2:
|
|
|
- try:
|
|
|
- urounds = int(cmd_args[1])
|
|
|
- assert urounds > 0
|
|
|
- except:
|
|
|
- try:
|
|
|
- fh = open(cmd_args[1])
|
|
|
- except:
|
|
|
- die(1,'Second argument must be filename or positive integer')
|
|
|
+ m1 = 'First argument must be a numeric generator ID or two colon-separated generator IDs'
|
|
|
+ m2 = 'Second part of first argument must be a numeric generator ID or one of {}'
|
|
|
+
|
|
|
+ def check_gen_num(n):
|
|
|
+ if not (1 <= int(n) <= len(g.key_generators)):
|
|
|
+ die(1,'{}: invalid generator ID'.format(n))
|
|
|
+ return int(n)
|
|
|
+
|
|
|
+ if arg_id == 'a':
|
|
|
+ if is_int(arg):
|
|
|
+ a_num = check_gen_num(arg)
|
|
|
+ return (KeyGenerator(addr_type,a_num),a_num)
|
|
|
else:
|
|
|
- for line in fh.readlines():
|
|
|
- if 'addr=' in line:
|
|
|
- x,addr = line.split('addr=')
|
|
|
- dump.append([x.split()[0],addr.split()[0]])
|
|
|
-
|
|
|
-if urounds: rounds = urounds
|
|
|
-
|
|
|
-a,b = None,None
|
|
|
-b_desc = 'unknown'
|
|
|
-try:
|
|
|
- a,b = cmd_args[0].split(':')
|
|
|
-except:
|
|
|
+ die(1,m1)
|
|
|
+ elif arg_id == 'b':
|
|
|
+ if is_int(arg):
|
|
|
+ return KeyGenerator(addr_type,check_gen_num(arg))
|
|
|
+ elif arg in ext_progs + ['ext']:
|
|
|
+ return init_tool(get_tool(arg))
|
|
|
+ else:
|
|
|
+ die(1,m2.format(ext_progs))
|
|
|
+
|
|
|
+def parse_arg2():
|
|
|
+ m = 'Second argument must be dump filename or integer rounds specification'
|
|
|
+ if len(cmd_args) == 1:
|
|
|
+ return None
|
|
|
+ arg = cmd_args[1]
|
|
|
+ if is_int(arg) and int(arg) > 0:
|
|
|
+ return int(arg)
|
|
|
try:
|
|
|
- a = cmd_args[0]
|
|
|
- a = int(a)
|
|
|
- assert 1 <= a <= len(g.key_generators)
|
|
|
+ return open(arg)
|
|
|
except:
|
|
|
- die(1,'First argument must be one or two generator IDs, colon separated')
|
|
|
-else:
|
|
|
- try:
|
|
|
- a = int(a)
|
|
|
- assert 1 <= a <= len(g.key_generators),'{}: invalid key generator'.format(a)
|
|
|
- if b in ('ext','ethkey','pycoin','keyconv','zcash_mini','moneropy'):
|
|
|
- init_external_prog()
|
|
|
- else:
|
|
|
- b = int(b)
|
|
|
- assert 1 <= b <= len(g.key_generators),'{}: invalid key generator'.format(b)
|
|
|
- assert a != b,'Key generators are the same!'
|
|
|
- except Exception as e:
|
|
|
- die(1,'{}\n{}: invalid generator argument'.format(e.args[0],cmd_args[0]))
|
|
|
+ die(1,m)
|
|
|
|
|
|
+# begin execution
|
|
|
+from mmgen.protocol import init_coin
|
|
|
+from mmgen.altcoin import CoinInfo as ci
|
|
|
+from mmgen.obj import MMGenAddrType,PrivKey
|
|
|
from mmgen.addr import KeyGenerator,AddrGenerator
|
|
|
-from mmgen.obj import PrivKey
|
|
|
|
|
|
-kg_a = KeyGenerator(addr_type,a)
|
|
|
+addr_type = MMGenAddrType(opt.type or g.proto.dfl_mmtype)
|
|
|
+ext_progs = list(ci.external_tests[g.network])
|
|
|
+
|
|
|
+arg1 = cmd_args[0].split(':')
|
|
|
+if len(arg1) == 1:
|
|
|
+ a,a_num = parse_arg1(arg1[0],'a')
|
|
|
+ b = None
|
|
|
+elif len(arg1) == 2:
|
|
|
+ a,a_num = parse_arg1(arg1[0],'a')
|
|
|
+ b = parse_arg1(arg1[1],'b')
|
|
|
+else:
|
|
|
+ opts.usage()
|
|
|
+
|
|
|
+if type(a) == type(b):
|
|
|
+ die(1,'Address generators are the same!')
|
|
|
+
|
|
|
+arg2 = parse_arg2()
|
|
|
+
|
|
|
ag = AddrGenerator(addr_type)
|
|
|
|
|
|
-if a and b:
|
|
|
+if not b and type(arg2) == int:
|
|
|
+ speed_test(a,ag,arg2)
|
|
|
+elif not b and hasattr(arg2,'read'):
|
|
|
+ dump_test(a,ag,arg2)
|
|
|
+elif a and b and type(arg2) == int:
|
|
|
if opt.all:
|
|
|
from mmgen.protocol import init_genonly_altcoins,CoinProtocol
|
|
|
init_genonly_altcoins()
|
|
|
- for coin in ci.external_tests[('mainnet','testnet')[g.testnet]][ext_prog]:
|
|
|
- if coin not in CoinProtocol.coins: continue
|
|
|
+ for coin in ci.external_tests[g.network][b.desc]:
|
|
|
+ if coin.lower() not in CoinProtocol.coins:
|
|
|
+# ymsg('Coin {} not configured'.format(coin))
|
|
|
+ continue
|
|
|
init_coin(coin)
|
|
|
if addr_type not in g.proto.mmtypes:
|
|
|
- addr_type = MMGenAddrType(g.proto.dfl_mmtype)
|
|
|
- kg_a = KeyGenerator(addr_type,a)
|
|
|
+ continue
|
|
|
+ # g.proto has changed, so reinit kg and ag just to be on the safe side:
|
|
|
+ a = KeyGenerator(addr_type,a_num)
|
|
|
ag = AddrGenerator(addr_type)
|
|
|
- compare_test()
|
|
|
+ b_chk = ci.get_test_support(g.coin,addr_type.name,g.network,tool=b.desc,verbose=not opt.quiet)
|
|
|
+ if b_chk == b.desc:
|
|
|
+ gentool_test(a,b,ag,arg2)
|
|
|
else:
|
|
|
- if b != 'ext':
|
|
|
- kg_b = KeyGenerator(addr_type,b)
|
|
|
- b_desc = kg_b.desc
|
|
|
- compare_test()
|
|
|
-elif a and not fh:
|
|
|
- speed_test()
|
|
|
-elif a and dump:
|
|
|
- b_desc = 'dump'
|
|
|
- dump_test()
|
|
|
+ gentool_test(a,b,ag,arg2)
|
|
|
else:
|
|
|
- die(2,'Illegal invocation')
|
|
|
+ opts.usage()
|