py3port: make hexadecimal values be strings instead of bytes type

- binascii.hexlify(b'foo') -> b'foo'.hex()
- binascii.unhexlify('aabb') -> bytes.fromhex('aabb')
- replace HexBytes class with HexStr

This change has led to a ≈10% speedup in the full test-release.sh run
This commit is contained in:
The MMGen Project 2019-03-17 10:33:55 +00:00
commit b5f1ebc640
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
24 changed files with 222 additions and 263 deletions

View file

@ -21,7 +21,6 @@ addr.py: Address generation/display routines for the MMGen suite
"""
from hashlib import sha256,sha512
from binascii import hexlify,unhexlify
from mmgen.common import *
from mmgen.obj import *
@ -67,7 +66,7 @@ class AddrGeneratorSegwit(AddrGenerator):
def to_segwit_redeem_script(self,pubhex):
assert pubhex.compressed,'Uncompressed public keys incompatible with Segwit'
return HexBytes(g.proto.pubhex2redeem_script(pubhex))
return HexStr(g.proto.pubhex2redeem_script(pubhex))
class AddrGeneratorBech32(AddrGenerator):
def to_addr(self,pubhex):
@ -82,7 +81,7 @@ class AddrGeneratorEthereum(AddrGenerator):
def to_addr(self,pubhex):
assert type(pubhex) == PubKey
import sha3
return CoinAddr(hexlify(sha3.keccak_256(unhexlify(pubhex[2:])).digest()[12:]).decode())
return CoinAddr(sha3.keccak_256(bytes.fromhex(pubhex[2:])).hexdigest()[24:])
def to_wallet_passwd(self,sk_hex):
from mmgen.protocol import hash256
@ -105,26 +104,26 @@ class AddrGeneratorZcashZ(AddrGenerator):
return Sha256(s,preprocess=False).digest()
def to_addr(self,pubhex): # pubhex is really privhex
key = unhexlify(pubhex)
key = bytes.fromhex(pubhex)
assert len(key) == 32,'{}: incorrect privkey length'.format(len(key))
if g.platform == 'win':
ydie(1,'Zcash z-addresses not supported on Windows platform')
from nacl.bindings import crypto_scalarmult_base
p2 = crypto_scalarmult_base(self.zhash256(key,1))
from mmgen.protocol import _b58chk_encode
ret = _b58chk_encode(g.proto.addr_ver_num['zcash_z'][0] + hexlify(self.zhash256(key,0)+p2))
ret = _b58chk_encode(g.proto.addr_ver_num['zcash_z'][0] + (self.zhash256(key,0)+p2).hex())
assert len(ret) == self.addr_width,'Invalid Zcash z-address length'
return CoinAddr(ret)
def to_viewkey(self,pubhex): # pubhex is really privhex
key = unhexlify(pubhex)
key = bytes.fromhex(pubhex)
assert len(key) == 32,'{}: incorrect privkey length'.format(len(key))
vk = bytearray(self.zhash256(key,0)+self.zhash256(key,1))
vk[32] &= 0xf8
vk[63] &= 0x7f
vk[63] |= 0x40
from mmgen.protocol import _b58chk_encode
ret = _b58chk_encode(g.proto.addr_ver_num['viewkey'][0] + hexlify(vk))
ret = _b58chk_encode(g.proto.addr_ver_num['viewkey'][0] + vk.hex())
assert len(ret) == self.vk_width,'Invalid Zcash view key length'
return ZcashViewKey(ret)
@ -133,10 +132,11 @@ class AddrGeneratorZcashZ(AddrGenerator):
class AddrGeneratorMonero(AddrGenerator):
def b58enc(self,addr_str):
enc,l = baseconv.fromhex,len(addr_str)
a = ''.join([enc(hexlify(addr_str[i*8:i*8+8]),'b58',pad=11,tostr=True) for i in range(l//8)])
b = enc(hexlify(addr_str[l-l%8:]),'b58',pad=7,tostr=True)
def b58enc(self,addr_bytes):
enc = baseconv.fromhex
l = len(addr_bytes)
a = ''.join([enc((addr_bytes[i*8:i*8+8]).hex(),'b58',pad=11,tostr=True) for i in range(l//8)])
b = enc((addr_bytes[l-l%8:]).hex(),'b58',pad=7,tostr=True)
return a + b
def to_addr(self,sk_hex): # sk_hex instead of pubhex
@ -159,12 +159,12 @@ class AddrGeneratorMonero(AddrGenerator):
return Q
def hex2int_le(hexstr):
return int(hexlify(unhexlify(hexstr)[::-1]),16)
return int((bytes.fromhex(hexstr)[::-1]).hex(),16)
vk_hex = self.to_viewkey(sk_hex)
pk_str = encodepoint(scalarmultbase(hex2int_le(sk_hex)))
pvk_str = encodepoint(scalarmultbase(hex2int_le(vk_hex)))
addr_p1 = unhexlify(g.proto.addr_ver_num['monero'][0]) + pk_str + pvk_str
addr_p1 = bytes.fromhex(g.proto.addr_ver_num['monero'][0]) + pk_str + pvk_str
import sha3
return CoinAddr(self.b58enc(addr_p1 + sha3.keccak_256(addr_p1).digest()[:4]))
@ -176,7 +176,7 @@ class AddrGeneratorMonero(AddrGenerator):
def to_viewkey(self,sk_hex):
assert len(sk_hex) == 64,'{}: incorrect privkey length'.format(len(sk_hex))
import sha3
return MoneroViewKey(g.proto.preprocess_key(sha3.keccak_256(unhexlify(sk_hex)).hexdigest(),None))
return MoneroViewKey(g.proto.preprocess_key(sha3.keccak_256(bytes.fromhex(sk_hex)).hexdigest(),None))
def to_segwit_redeem_script(self,sk_hex):
raise NotImplementedError('Monero addresses incompatible with Segwit')
@ -210,7 +210,7 @@ class KeyGenerator(MMGenObject):
try:
from mmgen.secp256k1 import priv2pub
m = 'Unable to execute priv2pub() from secp256k1 extension module'
assert priv2pub(unhexlify('deadbeef'*8),1),m
assert priv2pub(bytes.fromhex('deadbeef'*8),1),m
return True
except:
return False
@ -239,12 +239,12 @@ class KeyGeneratorPython(KeyGenerator):
def privnum2pubhex(self,numpriv,compressed=False):
pko = ecdsa.SigningKey.from_secret_exponent(numpriv,self.secp256k1)
# pubkey = x (32 bytes) + y (32 bytes) (unsigned big-endian)
pubkey = hexlify(pko.get_verifying_key().to_string())
pubkey = (pko.get_verifying_key().to_string()).hex()
if compressed: # discard Y coord, replace with appropriate version byte
# even y: <0, odd y: >0 -- https://bitcointalk.org/index.php?topic=129652.0
return (b'03',b'02')[pubkey[-1] in b'02468ace'] + pubkey[:64]
return ('03','02')[pubkey[-1] in '02468ace'] + pubkey[:64]
else:
return b'04' + pubkey
return '04' + pubkey
def to_pubhex(self,privhex):
assert type(privhex) == PrivKey
@ -256,13 +256,13 @@ class KeyGeneratorSecp256k1(KeyGenerator):
def to_pubhex(self,privhex):
assert type(privhex) == PrivKey
from mmgen.secp256k1 import priv2pub
return PubKey(hexlify(priv2pub(unhexlify(privhex),int(privhex.compressed))),compressed=privhex.compressed)
return PubKey(priv2pub(bytes.fromhex(privhex),int(privhex.compressed)).hex(),compressed=privhex.compressed)
class KeyGeneratorDummy(KeyGenerator):
desc = 'mmgen-dummy'
def to_pubhex(self,privhex):
assert type(privhex) == PrivKey
return PubKey(privhex.decode(),compressed=privhex.compressed)
return PubKey(privhex,compressed=privhex.compressed)
class AddrListEntry(MMGenListItem):
addr = MMGenListItemAttr('addr','CoinAddr')
@ -404,7 +404,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
seed = seed.get_data()
seed = self.scramble_seed(seed)
dmsg_sc('seed',hexlify(seed[:8]).decode())
dmsg_sc('seed',seed[:8].hex())
compressed = self.al_id.mmtype.compressed
pubkey_type = self.al_id.mmtype.pubkey_type
@ -838,7 +838,7 @@ Record this checksum: it will be used to verify the password file in the future
def make_passwd(self,hex_sec):
assert self.pw_fmt in self.pw_info
if self.pw_fmt == 'hex':
return hex_sec.decode()
return hex_sec
else:
# we take least significant part
return baseconv.fromhex(hex_sec,self.pw_fmt,pad=self.pw_len,tostr=True)[-self.pw_len:]

View file

@ -70,8 +70,8 @@ class Token(MMGenObject): # ERC20
except:
"RPC call to decimals() failed (returned '{}')".format(ret)
return int(b,16) if b else None
def name(self): return self.strip(unhexlify(self.do_call('name()')[2:]))
def symbol(self): return self.strip(unhexlify(self.do_call('symbol()')[2:]))
def name(self): return self.strip(bytes.fromhex(self.do_call('name()')[2:]))
def symbol(self): return self.strip(bytes.fromhex(self.do_call('symbol()')[2:]))
def info(self):
fs = '{:15}{}\n' * 5
@ -95,12 +95,12 @@ class Token(MMGenObject): # ERC20
if nonce is None:
nonce = int(g.rpch.parity_nextNonce('0x'+from_addr),16)
data = self.create_data(to_addr,amt,method_sig=method_sig,from_addr=from_addr2)
return {'to': unhexlify(self.addr),
return {'to': bytes.fromhex(self.addr),
'startgas': start_gas.toWei(),
'gasprice': gasPrice.toWei(),
'value': 0,
'nonce': nonce,
'data': unhexlify(data) }
'data': bytes.fromhex(data) }
def txsign(self,tx_in,key,from_addr,chain_id=None):
from ethereum.transactions import Transaction
@ -108,11 +108,11 @@ class Token(MMGenObject): # ERC20
chain_id_method = ('parity_chainId','eth_chainId')['eth_chainId' in g.rpch.caps]
chain_id = int(g.rpch.request(chain_id_method),16)
tx = Transaction(**tx_in).sign(key,chain_id)
hex_tx = hexlify(rlp.encode(tx))
coin_txid = CoinTxID(hexlify(tx.hash))
if hexlify(tx.sender).decode() != from_addr:
hex_tx = rlp.encode(tx).hex()
coin_txid = CoinTxID(tx.hash.hex())
if tx.sender.hex() != from_addr:
m = "Sender address '{}' does not match address of key '{}'!"
die(3,m.format(from_addr,hexlify(tx.sender).decode()))
die(3,m.format(from_addr,tx.sender.hex()))
if g.debug:
msg('{}'.format('\n '.join(parse_abi(data))))
pmsg(tx.to_dict())
@ -121,7 +121,7 @@ class Token(MMGenObject): # ERC20
# The following are used for token deployment only:
def txsend(self,hex_tx):
return g.rpch.eth_sendRawTransaction('0x'+hex_tx.decode()).replace('0x','',1).encode()
return g.rpch.eth_sendRawTransaction('0x'+hex_tx).replace('0x','',1)
def transfer( self,from_addr,to_addr,amt,key,start_gas,gasPrice,
method_sig='transfer(address,uint256)',

View file

@ -44,7 +44,7 @@ class EthereumMMGenTX(MMGenTX):
usr_rel_fee = None # not in MMGenTX
disable_fee_check = False
txobj = None # ""
data = HexBytes('')
data = HexStr('')
def __init__(self,*args,**kwargs):
super(EthereumMMGenTX,self).__init__(*args,**kwargs)
@ -53,16 +53,16 @@ class EthereumMMGenTX(MMGenTX):
if hasattr(opt,'contract_data') and opt.contract_data:
m = "'--contract-data' option may not be used with token transaction"
assert not 'Token' in type(self).__name__, m
self.data = HexBytes(open(opt.contract_data).read().strip())
self.data = HexStr(open(opt.contract_data).read().strip())
self.disable_fee_check = True
@classmethod
def get_receipt(cls,txid):
return g.rpch.eth_getTransactionReceipt('0x'+txid.decode())
return g.rpch.eth_getTransactionReceipt('0x'+txid)
@classmethod
def get_exec_status(cls,txid,silent=False):
d = g.rpch.eth_getTransactionReceipt('0x'+txid.decode())
d = g.rpch.eth_getTransactionReceipt('0x'+txid)
if not silent:
if 'contractAddress' in d and d['contractAddress']:
msg('Contract address: {}'.format(d['contractAddress'].replace('0x','')))
@ -82,18 +82,17 @@ class EthereumMMGenTX(MMGenTX):
def check_pubkey_scripts(self): pass
def check_sigs(self,deserial_tx=None):
if is_hex_bytes(self.hex):
if is_hex_str(self.hex):
self.mark_signed()
return True
return False
# hex data if signed, json if unsigned: see create_raw()
def check_txfile_hex_data(self):
if type(self.hex) == str: self.hex = self.hex.encode()
if self.check_sigs():
from ethereum.transactions import Transaction
import rlp
etx = rlp.decode(unhexlify(self.hex),Transaction)
etx = rlp.decode(bytes.fromhex(self.hex),Transaction)
d = etx.to_dict() # ==> hex values have '0x' prefix, 0 is '0x'
for k in ('sender','to','data'):
if k in d: d[k] = d[k].replace('0x','',1)
@ -103,13 +102,13 @@ class EthereumMMGenTX(MMGenTX):
'gasPrice': ETHAmt(d['gasprice'],'wei'),
'startGas': ETHAmt(d['startgas'],'wei'),
'nonce': ETHNonce(d['nonce']),
'data': HexBytes(d['data']) }
'data': HexStr(d['data']) }
if o['data'] and not o['to']:
self.token_addr = TokenAddr(hexlify(etx.creates).decode())
txid = CoinTxID(hexlify(etx.hash))
self.token_addr = TokenAddr(etx.creates.hex())
txid = CoinTxID(etx.hash.hex())
assert txid == self.coin_txid,"txid in tx.hex doesn't match value in MMGen transaction file"
else:
d = json.loads(self.hex.decode())
d = json.loads(self.hex)
o = { 'from': CoinAddr(d['from']),
'to': CoinAddr(d['to']) if d['to'] else Str(''),
'amt': ETHAmt(d['amt']),
@ -117,7 +116,7 @@ class EthereumMMGenTX(MMGenTX):
'startGas': ETHAmt(d['startGas']),
'nonce': ETHNonce(d['nonce']),
'chainId': Int(d['chainId']),
'data': HexBytes(d['data']) }
'data': HexStr(d['data']) }
self.tx_gas = o['startGas'] # approximate, but better than nothing
self.data = o['data']
if o['data'] and not o['to']: self.disable_fee_check = True
@ -151,7 +150,7 @@ class EthereumMMGenTX(MMGenTX):
assert o_num in o_ok,'Transaction has invalid number of outputs!'.format(o_num)
self.make_txobj()
ol = {k: (v.decode() if issubclass(type(v),bytes) else str(v)) for k,v in self.txobj.items()}
self.hex = json.dumps(ol).encode()
self.hex = json.dumps(ol)
self.update_txid()
def del_output(self,idx): pass
@ -278,22 +277,22 @@ class EthereumMMGenTX(MMGenTX):
return m.format(ETHAmt(chg).hl(),g.coin)
def do_sign(self,d,wif,tx_num_str):
d_in = {'to': unhexlify(d['to']),
d_in = {'to': bytes.fromhex(d['to']),
'startgas': d['startGas'].toWei(),
'gasprice': d['gasPrice'].toWei(),
'value': d['amt'].toWei() if d['amt'] else 0,
'nonce': d['nonce'],
'data': unhexlify(d['data'])}
'data': bytes.fromhex(d['data'])}
from ethereum.transactions import Transaction
etx = Transaction(**d_in).sign(wif,d['chainId'])
assert hexlify(etx.sender).decode() == d['from'],(
assert etx.sender.hex() == d['from'],(
'Sender address recovered from signature does not match true sender')
import rlp
self.hex = hexlify(rlp.encode(etx))
self.coin_txid = CoinTxID(hexlify(etx.hash))
self.hex = rlp.encode(etx).hex()
self.coin_txid = CoinTxID(etx.hash.hex())
if d['data']:
self.token_addr = TokenAddr(hexlify(etx.creates).decode())
self.token_addr = TokenAddr(etx.creates.hex())
assert self.check_sigs(),'Signature check failed'
def sign(self,tx_num_str,keys): # return True or False; don't exit or raise exception
@ -320,10 +319,10 @@ class EthereumMMGenTX(MMGenTX):
return False
def is_in_mempool(self):
return '0x'+self.coin_txid.decode() in [x['hash'] for x in g.rpch.parity_pendingTransactions()]
return '0x'+self.coin_txid in [x['hash'] for x in g.rpch.parity_pendingTransactions()]
def is_in_wallet(self):
d = g.rpch.eth_getTransactionReceipt('0x'+self.coin_txid.decode())
d = g.rpch.eth_getTransactionReceipt('0x'+self.coin_txid)
if d and 'blockNumber' in d and d['blockNumber'] is not None:
return 1 + int(g.rpch.eth_blockNumber(),16) - int(d['blockNumber'],16)
return False
@ -365,7 +364,7 @@ class EthereumMMGenTX(MMGenTX):
if prompt_user: self.confirm_send()
ret = None if bogus_send else g.rpch.eth_sendRawTransaction('0x'+self.hex.decode(),on_fail='return')
ret = None if bogus_send else g.rpch.eth_sendRawTransaction('0x'+self.hex,on_fail='return')
from mmgen.rpc import rpc_error,rpc_errmsg
if rpc_error(ret):
@ -376,7 +375,7 @@ class EthereumMMGenTX(MMGenTX):
else:
m = 'BOGUS transaction NOT sent: {}' if bogus_send else 'Transaction sent: {}'
if not bogus_send:
assert ret == '0x'+self.coin_txid.decode(),'txid mismatch (after sending)'
assert ret == '0x'+self.coin_txid,'txid mismatch (after sending)'
self.desc = 'sent transaction'
msg(m.format(self.coin_txid.hl()))
self.add_timestamp()
@ -418,8 +417,8 @@ class EthereumTokenMMGenTX(EthereumMMGenTX):
def set_g_token(self):
g.dcoin = self.dcoin
if is_hex_bytes(self.hex): return # for txsend we can leave g.token uninitialized
d = json.loads(self.hex.decode())
if is_hex_str(self.hex): return # for txsend we can leave g.token uninitialized
d = json.loads(self.hex)
if g.token.upper() == self.dcoin:
g.token = d['token_addr']
elif g.token != d['token_addr']:

View file

@ -20,7 +20,6 @@
crypto.py: Cryptographic and related routines for the MMGen suite
"""
from binascii import hexlify
from hashlib import sha256
from mmgen.common import *
@ -46,7 +45,7 @@ def scramble_seed(seed,scramble_key,hash_rounds):
import hmac
scr_seed = hmac.new(seed,scramble_key,sha256).digest()
fs = 'Seed: {}\nScramble key: {}\nScrambled seed: {}'
dmsg(fs.format(hexlify(seed),scramble_key.decode('utf8'),hexlify(scr_seed)))
dmsg(fs.format(seed.hex(),scramble_key.decode(),scr_seed.hex()))
return sha256_rounds(scr_seed,hash_rounds)
def encrypt_seed(seed,key):
@ -77,7 +76,7 @@ def decrypt_seed(enc_seed,key,seed_id,key_id):
# else:
# qmsg('Generated IDs (Seed/Key): {}/{}'.format(chk2,chk1))
dmsg('Decrypted seed: {}'.format(hexlify(dec_seed)))
dmsg('Decrypted seed: {}'.format(dec_seed.hex()))
return dec_seed
def encrypt_data(data,key,iv=1,desc='data',verify=True):
@ -120,7 +119,7 @@ def make_key(passwd,salt,hash_preset,desc='encryption key',from_what='passphrase
msg_r('Generating {}{}...'.format(desc,from_what))
key = scrypt_hash_passphrase(passwd,salt,hash_preset)
if opt.verbose or verbose: msg('done')
dmsg('Key: {}'.format(hexlify(key)))
dmsg('Key: {}'.format(key.hex()))
return key
def _get_random_data_from_user(uchars):
@ -189,7 +188,7 @@ def mmgen_encrypt(data,desc='data',hash_preset=''):
qmsg("Using {} hash preset of '{}'".format(m,hp))
passwd = get_new_passphrase(desc,{})
key = make_key(passwd,salt,hp)
enc_d = encrypt_data(sha256(nonce+data).digest()+nonce+data,key,int(hexlify(iv),16),desc=desc)
enc_d = encrypt_data(sha256(nonce+data).digest()+nonce+data,key,int(iv.hex(),16),desc=desc)
return salt+iv+enc_d
def mmgen_decrypt(data,desc='data',hash_preset=''):
@ -204,7 +203,7 @@ def mmgen_decrypt(data,desc='data',hash_preset=''):
qmsg("Using {} hash preset of '{}'".format(m,hp))
passwd = get_mmgen_passphrase(desc)
key = make_key(passwd,salt,hp)
dec_d = decrypt_data(enc_d,key,int(hexlify(iv),16),desc)
dec_d = decrypt_data(enc_d,key,int(iv.hex(),16),desc)
if dec_d[:_sha256_len] == sha256(dec_d[_sha256_len:]).digest():
vmsg('OK')
return dec_d[_sha256_len+_nonce_len:]

View file

@ -269,13 +269,12 @@ def wipe_existing_key():
subprocess.call(['wipe','-cf',fn])
def create_key():
from binascii import hexlify
kdata = hexlify(os.urandom(32)).decode()
kdata = os.urandom(32).hex()
fn = os.path.join(tx_dir,key_fn)
desc = 'key file {}'.format(fn)
msg('Creating ' + desc)
try:
with open(fn,'w') as f: f.write(kdata+'\n')
open(fn,'w').write(kdata+'\n')
os.chmod(fn,0o400)
msg('Wrote ' + desc)
except:

View file

@ -24,7 +24,6 @@ import sys,os,unicodedata
from decimal import *
from mmgen.color import *
from string import hexdigits,ascii_letters,digits
from binascii import hexlify
def is_mmgen_seed_id(s): return SeedID(sid=s,on_fail='silent')
def is_mmgen_idx(s): return AddrIdx(s,on_fail='silent')
@ -562,20 +561,19 @@ class TwLabel(str,InitErrors,MMGenObject):
m = "{}\n{!r}: value cannot be converted to TwLabel"
return cls.init_fail(m.format(e.args[0],s),on_fail)
class HexBytes(bytes,Hilite,InitErrors):
class HexStr(str,Hilite,InitErrors):
color = 'red'
trunc_ok = False
dtype = bytes
dtype = str
def __new__(cls,s,on_fail='die',case='lower'):
if type(s) == cls: return s
assert case in ('upper','lower')
cls.arg_chk(cls,on_fail)
if issubclass(type(s),bytes): s = s.decode()
try:
assert type(s) == str,'not a string'
assert issubclass(type(s),str),'not a string or string subclass'
assert set(s) <= set(getattr(hexdigits,case)()),'not {}case hexadecimal symbols'.format(case)
assert not len(s) % 2,'odd-length string'
return cls.dtype.__new__(cls,s.encode() if cls.dtype == bytes else s)
return cls.dtype.__new__(cls,s)
except Exception as e:
m = "{!r}: value cannot be converted to {} (value is {})"
return cls.init_fail(m.format(s,cls.__name__,e.args[0]),on_fail)
@ -583,11 +581,11 @@ class HexBytes(bytes,Hilite,InitErrors):
class Str(str,Hilite): pass
class Int(int,Hilite): pass
class HexBytesWithWidth(HexBytes):
class HexStrWithWidth(HexStr):
color = 'nocolor'
hexcase = 'lower'
width = None
parent_cls = HexBytes
parent_cls = HexStr
def __new__(cls,s,on_fail='die'):
cls.arg_chk(cls,on_fail)
try:
@ -598,23 +596,7 @@ class HexBytesWithWidth(HexBytes):
m = "{}\n{!r}: value cannot be converted to {}"
return cls.init_fail(m.format(e.args[0],s,cls.__name__),on_fail)
class CoinTxID(HexBytesWithWidth): color,width,hexcase = 'purple',64,'lower'
class HexStr(str,Hilite,InitErrors):
color = 'red'
trunc_ok = False
dtype = str
def __new__(cls,s,on_fail='die',case='lower'):
return HexBytes.__new__(cls,s,on_fail=on_fail,case=case)
class HexStrWithWidth(HexStr):
color = 'nocolor'
hexcase = 'lower'
width = None
parent_cls = HexStr
def __new__(cls,s,on_fail='die'):
return HexBytesWithWidth.__new__(cls,s,on_fail=on_fail)
class CoinTxID(HexStrWithWidth): color,width,hexcase = 'purple',64,'lower'
class WalletPassword(HexStrWithWidth): color,width,hexcase = 'blue',32,'lower'
class MoneroViewKey(HexStrWithWidth): color,width,hexcase = 'cyan',64,'lower'
class MMGenTxID(HexStrWithWidth): color,width,hexcase = 'red',6,'upper'
@ -634,18 +616,18 @@ class WifKey(str,Hilite,InitErrors):
m = '{!r}: invalid value for WIF key ({})'.format(s,e.args[0])
return cls.init_fail(m,on_fail)
class PubKey(HexBytes,MMGenObject): # TODO: add some real checks
class PubKey(HexStr,MMGenObject): # TODO: add some real checks
def __new__(cls,s,compressed,on_fail='die'):
try:
assert type(compressed) == bool,"'compressed' must be of type bool"
me = HexBytes.__new__(cls,s,case='lower',on_fail='raise')
me = HexStr.__new__(cls,s,case='lower',on_fail='raise')
me.compressed = compressed
return me
except Exception as e:
m = '{!r}: invalid value for pubkey ({})'.format(s,e.args[0])
return cls.init_fail(m,on_fail)
class PrivKey(bytes,Hilite,InitErrors,MMGenObject):
class PrivKey(str,Hilite,InitErrors,MMGenObject):
color = 'red'
width = 64
@ -666,7 +648,7 @@ class PrivKey(bytes,Hilite,InitErrors,MMGenObject):
assert s == None
assert set(wif) <= set(ascii_letters+digits),'not an ascii alphanumeric string'
w2h = g.proto.wif2hex(wif) # raises exception on error
me = bytes.__new__(cls,w2h['hex'])
me = str.__new__(cls,w2h['hex'])
me.compressed = w2h['compressed']
me.pubkey_type = w2h['pubkey_type']
me.wif = str.__new__(WifKey,wif) # check has been done
@ -680,13 +662,13 @@ class PrivKey(bytes,Hilite,InitErrors,MMGenObject):
assert s and type(compressed) == bool and pubkey_type,'Incorrect args for PrivKey()'
assert len(s) == cls.width // 2,'Key length must be {}'.format(cls.width//2)
if pubkey_type == 'password': # skip WIF creation and pre-processing for passwds
me = bytes.__new__(cls,hexlify(s))
me = str.__new__(cls,s.hex())
else:
me = bytes.__new__(cls,g.proto.preprocess_key(hexlify(s),pubkey_type))
me = str.__new__(cls,g.proto.preprocess_key(s.hex(),pubkey_type))
me.wif = WifKey(g.proto.hex2wif(me,pubkey_type,compressed),on_fail='raise')
me.compressed = compressed
me.pubkey_type = pubkey_type
me.orig_hex = hexlify(s) # save the non-preprocessed key
me.orig_hex = s.hex() # save the non-preprocessed key
return me
except Exception as e:
fs = "Key={!r}\nCompressed={}\nValue pair cannot be converted to PrivKey\n({})"

View file

@ -21,17 +21,16 @@ protocol.py: Coin protocol functions, classes and methods
"""
import sys,os,hashlib
from binascii import hexlify,unhexlify
from mmgen.util import msg,pmsg,ymsg,Msg,pdie,ydie
from mmgen.obj import MMGenObject,BTCAmt,LTCAmt,BCHAmt,B2XAmt,ETHAmt
from mmgen.globalvars import g
import mmgen.bech32 as bech32
def hash160(hexnum): # take hex, return hex - OP_HASH160
return hashlib.new('ripemd160',hashlib.sha256(unhexlify(hexnum)).digest()).hexdigest().encode()
return hashlib.new('ripemd160',hashlib.sha256(bytes.fromhex(hexnum)).digest()).hexdigest()
def hash256(hexnum): # take hex, return hex - OP_HASH256
return hashlib.sha256(hashlib.sha256(unhexlify(hexnum)).digest()).hexdigest().encode()
return hashlib.sha256(hashlib.sha256(bytes.fromhex(hexnum)).digest()).hexdigest()
_b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
@ -43,7 +42,7 @@ _b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
# 1111111111111111111114oLvT2 (pubkeyhash = '\0'*20)
def _b58chk_encode(hexstr):
lzeroes = (len(hexstr) - len(hexstr.lstrip(b'0'))) // 2
lzeroes = (len(hexstr) - len(hexstr.lstrip('0'))) // 2
def b58enc(n):
while n:
yield _b58a[n % 58]
@ -53,10 +52,9 @@ def _b58chk_encode(hexstr):
def _b58chk_decode(s):
lzeroes = len(s) - len(s.lstrip('1'))
hexstr = '{}{:x}'.format(
'00' * lzeroes,
sum(_b58a.index(ch) * 58**n for n,ch in enumerate(s[::-1]))
).encode()
if len(hexstr) % 2: hexstr = b'0' + hexstr
'00' * lzeroes,
sum(_b58a.index(ch) * 58**n for n,ch in enumerate(s[::-1])) )
if len(hexstr) % 2: hexstr = '0' + hexstr
if hexstr[-8:] != hash256(hexstr[:-8])[:8]:
raise ValueError('_b58chk_decode(): {}: incorrect checksum for {}, expected {}'.format(
hexstr[-8:],hexstr[:-8],hash256(hexstr[:-8])[:8]))
@ -67,8 +65,8 @@ class BitcoinProtocol(MMGenObject):
name = 'bitcoin'
daemon_name = 'bitcoind'
daemon_family = 'bitcoind'
addr_ver_num = { 'p2pkh': (b'00','1'), 'p2sh': (b'05','3') }
wif_ver_num = { 'std': b'80' }
addr_ver_num = { 'p2pkh': ('00','1'), 'p2sh': ('05','3') }
wif_ver_num = { 'std': '80' }
mmtypes = ('L','C','S','B')
dfl_mmtype = 'L'
data_subdir = ''
@ -90,7 +88,7 @@ class BitcoinProtocol(MMGenObject):
base_coin = 'BTC'
# From BIP173: witness version 'n' is stored as 'OP_n'. OP_0 is encoded as 0x00,
# but OP_1 through OP_16 are encoded as 0x51 though 0x60 (81 to 96 in decimal).
witness_vernum_hex = b'00'
witness_vernum_hex = '00'
witness_vernum = int(witness_vernum_hex,16)
bech32_hrp = 'bc'
sign_mode = 'daemon'
@ -126,7 +124,7 @@ class BitcoinProtocol(MMGenObject):
@classmethod
def hex2wif(cls,hexpriv,pubkey_type,compressed): # PrivKey
assert len(hexpriv) == cls.privkey_len*2, '{} bytes: incorrect private key length!'.format(len(hexpriv)//2)
return _b58chk_encode(cls.wif_ver_num[pubkey_type] + hexpriv + (b'',b'01')[bool(compressed)])
return _b58chk_encode(cls.wif_ver_num[pubkey_type] + hexpriv + ('','01')[bool(compressed)])
@classmethod
def wif2hex(cls,wif):
@ -138,7 +136,7 @@ class BitcoinProtocol(MMGenObject):
key = key[len(v):]
assert pubkey_type,'invalid WIF version number'
if len(key) == 66:
assert key[-2:] == b'01','invalid compressed key suffix'
assert key[-2:] == '01','invalid compressed key suffix'
compressed = True
else:
assert len(key) == 64,'invalid key length'
@ -156,7 +154,7 @@ class BitcoinProtocol(MMGenObject):
msg('{}: Invalid witness version number'.format(ret[0]))
elif ret[1]:
return {
'hex': hexlify(bytes(ret[1])),
'hex': bytes(ret[1]).hex(),
'format': 'bech32'
} if return_dict else True
return False
@ -191,7 +189,7 @@ class BitcoinProtocol(MMGenObject):
# https://bitcoincore.org/en/segwit_wallet_dev/
# The P2SH redeemScript is always 22 bytes. It starts with a OP_0, followed
# by a canonical push of the keyhash (i.e. 0x0014{20-byte keyhash})
return cls.witness_vernum_hex + b'14' + hash160(pubhex)
return cls.witness_vernum_hex + '14' + hash160(pubhex)
@classmethod
def pubhex2segwitaddr(cls,pubhex):
@ -199,12 +197,12 @@ class BitcoinProtocol(MMGenObject):
@classmethod
def pubhash2bech32addr(cls,pubhash):
d = list(unhexlify(pubhash))
d = list(bytes.fromhex(pubhash))
return bech32.bech32_encode(cls.bech32_hrp,[cls.witness_vernum]+bech32.convertbits(d,8,5))
class BitcoinTestnetProtocol(BitcoinProtocol):
addr_ver_num = { 'p2pkh': (b'6f',('m','n')), 'p2sh': (b'c4','2') }
wif_ver_num = { 'std': b'ef' }
addr_ver_num = { 'p2pkh': ('6f',('m','n')), 'p2sh': ('c4','2') }
wif_ver_num = { 'std': 'ef' }
data_subdir = 'testnet'
daemon_data_subdir = 'testnet3'
rpc_port = 18332
@ -233,8 +231,8 @@ class BitcoinCashProtocol(BitcoinProtocol):
class BitcoinCashTestnetProtocol(BitcoinCashProtocol):
rpc_port = 18442
addr_ver_num = { 'p2pkh': (b'6f',('m','n')), 'p2sh': (b'c4','2') }
wif_ver_num = { 'std': b'ef' }
addr_ver_num = { 'p2pkh': ('6f',('m','n')), 'p2sh': ('c4','2') }
wif_ver_num = { 'std': 'ef' }
data_subdir = 'testnet'
daemon_data_subdir = 'testnet3'
@ -250,8 +248,8 @@ class B2XProtocol(BitcoinProtocol):
]
class B2XTestnetProtocol(B2XProtocol):
addr_ver_num = { 'p2pkh': (b'6f',('m','n')), 'p2sh': (b'c4','2') }
wif_ver_num = { 'std': b'ef' }
addr_ver_num = { 'p2pkh': ('6f',('m','n')), 'p2sh': ('c4','2') }
wif_ver_num = { 'std': 'ef' }
data_subdir = 'testnet'
daemon_data_subdir = 'testnet5'
rpc_port = 18338
@ -262,8 +260,8 @@ class LitecoinProtocol(BitcoinProtocol):
daemon_name = 'litecoind'
daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Litecoin') if g.platform == 'win' \
else os.path.join(g.home_dir,'.litecoin')
addr_ver_num = { 'p2pkh': (b'30','L'), 'p2sh': (b'32','M'), 'p2sh2': (b'05','3') } # 'p2sh' is new fmt
wif_ver_num = { 'std': b'b0' }
addr_ver_num = { 'p2pkh': ('30','L'), 'p2sh': ('32','M'), 'p2sh2': ('05','3') } # 'p2sh' is new fmt
wif_ver_num = { 'std': 'b0' }
mmtypes = ('L','C','S','B')
secs_per_block = 150
rpc_port = 9332
@ -275,8 +273,8 @@ class LitecoinProtocol(BitcoinProtocol):
class LitecoinTestnetProtocol(LitecoinProtocol):
# addr ver nums same as Bitcoin testnet, except for 'p2sh'
addr_ver_num = { 'p2pkh': (b'6f',('m','n')), 'p2sh': (b'3a','Q'), 'p2sh2': (b'c4','2') }
wif_ver_num = { 'std': b'ef' } # same as Bitcoin testnet
addr_ver_num = { 'p2pkh': ('6f',('m','n')), 'p2sh': ('3a','Q'), 'p2sh2': ('c4','2') }
wif_ver_num = { 'std': 'ef' } # same as Bitcoin testnet
data_subdir = 'testnet'
daemon_data_subdir = 'testnet4'
rpc_port = 19332
@ -293,11 +291,11 @@ class DummyWIF(object):
n = cls.name.capitalize()
assert pubkey_type == cls.pubkey_type,'{}: invalid pubkey_type for {}!'.format(pubkey_type,n)
assert compressed == False,'{} does not support compressed pubkeys!'.format(n)
return hexpriv.decode()
return hexpriv
@classmethod
def wif2hex(cls,wif):
return { 'hex':wif.encode(), 'pubkey_type':cls.pubkey_type, 'compressed':False }
return { 'hex':wif, 'pubkey_type':cls.pubkey_type, 'compressed':False }
class EthereumProtocol(DummyWIF,BitcoinProtocol):
@ -323,7 +321,7 @@ class EthereumProtocol(DummyWIF,BitcoinProtocol):
def verify_addr(cls,addr,hex_width,return_dict=False):
from mmgen.util import is_hex_str_lc
if is_hex_str_lc(addr) and len(addr) == cls.addr_width:
return { 'hex': addr.encode(), 'format': 'ethereum' } if return_dict else True
return { 'hex': addr, 'format': 'ethereum' } if return_dict else True
if g.debug: Msg("Invalid address '{}'".format(addr))
return False
@ -331,7 +329,7 @@ class EthereumProtocol(DummyWIF,BitcoinProtocol):
def pubhash2addr(cls,pubkey_hash,p2sh):
assert len(pubkey_hash) == 40,'{}: invalid length for pubkey hash'.format(len(pubkey_hash))
assert not p2sh,'Ethereum has no P2SH address format'
return pubkey_hash.decode()
return pubkey_hash
class EthereumTestnetProtocol(EthereumProtocol):
data_subdir = 'testnet'
@ -352,18 +350,18 @@ class ZcashProtocol(BitcoinProtocolAddrgen):
name = 'zcash'
base_coin = 'ZEC'
addr_ver_num = {
'p2pkh': (b'1cb8','t1'),
'p2sh': (b'1cbd','t3'),
'zcash_z': (b'169a','zc'),
'viewkey': (b'a8abd3','ZiVK') }
wif_ver_num = { 'std': b'80', 'zcash_z': b'ab36' }
'p2pkh': ('1cb8','t1'),
'p2sh': ('1cbd','t3'),
'zcash_z': ('169a','zc'),
'viewkey': ('a8abd3','ZiVK') }
wif_ver_num = { 'std': '80', 'zcash_z': 'ab36' }
mmtypes = ('L','C','Z')
dfl_mmtype = 'L'
@classmethod
def preprocess_key(cls,hexpriv,pubkey_type): # zero the first four bits
if pubkey_type == 'zcash_z':
return '{:02x}'.format(int(hexpriv[:2],16) & 0x0f).encode() + hexpriv[2:]
return '{:02x}'.format(int(hexpriv[:2],16) & 0x0f) + hexpriv[2:]
else:
return hexpriv
@ -378,18 +376,18 @@ class ZcashProtocol(BitcoinProtocolAddrgen):
raise ValueError('{}: incorrect pubkey_hash length'.format(hl))
class ZcashTestnetProtocol(ZcashProtocol):
wif_ver_num = { 'std': b'ef', 'zcash_z': b'ac08' }
wif_ver_num = { 'std': 'ef', 'zcash_z': 'ac08' }
addr_ver_num = {
'p2pkh': (b'1d25','tm'),
'p2sh': (b'1cba','t2'),
'zcash_z': (b'16b6','zt'),
'viewkey': (b'a8ac0c','ZiVt') }
'p2pkh': ('1d25','tm'),
'p2sh': ('1cba','t2'),
'zcash_z': ('16b6','zt'),
'viewkey': ('a8ac0c','ZiVt') }
# https://github.com/monero-project/monero/blob/master/src/cryptonote_config.h
class MoneroProtocol(DummyWIF,BitcoinProtocolAddrgen):
name = 'monero'
base_coin = 'XMR'
addr_ver_num = { 'monero': (b'12','4'), 'monero_sub': (b'2a','8') } # 18,42
addr_ver_num = { 'monero': ('12','4'), 'monero_sub': ('2a','8') } # 18,42
wif_ver_num = {}
mmtypes = ('M',)
dfl_mmtype = 'M'
@ -399,8 +397,8 @@ class MoneroProtocol(DummyWIF,BitcoinProtocolAddrgen):
@classmethod
def preprocess_key(cls,hexpriv,pubkey_type): # reduce key
from mmgen.ed25519 import l
n = int(hexlify(unhexlify(hexpriv)[::-1]),16) % l
return hexlify(unhexlify('{:064x}'.format(n))[::-1])
n = int(bytes.fromhex(hexpriv)[::-1].hex(),16) % l
return bytes.fromhex('{:064x}'.format(n))[::-1].hex()
@classmethod
def verify_addr(cls,addr,hex_width,return_dict=False):
@ -408,7 +406,7 @@ class MoneroProtocol(DummyWIF,BitcoinProtocolAddrgen):
def b58dec(addr_str):
from mmgen.util import baseconv
l = len(addr_str)
a = b''.join([baseconv.tohex(addr_str[i*11:i*11+11],'b58',pad=16) for i in range(l//11)])
a = ''.join([baseconv.tohex(addr_str[i*11:i*11+11],'b58',pad=16) for i in range(l//11)])
b = baseconv.tohex(addr_str[-(l%11):],'b58',pad=10)
return a + b
@ -418,13 +416,13 @@ class MoneroProtocol(DummyWIF,BitcoinProtocolAddrgen):
ret = b58dec(addr)
import sha3
chk = sha3.keccak_256(unhexlify(ret)[:-4]).hexdigest()[:8]
assert chk.encode() == ret[-8:],'Incorrect checksum'
chk = sha3.keccak_256(bytes.fromhex(ret)[:-4]).hexdigest()[:8]
assert chk == ret[-8:],'{}: incorrect checksum. Correct value: {}'.format(ret[-8:],chk)
return { 'hex': ret, 'format': 'monero' } if return_dict else True
class MoneroTestnetProtocol(MoneroProtocol):
addr_ver_num = { 'monero': (b'35','4'), 'monero_sub': (b'3f','8') } # 53,63
addr_ver_num = { 'monero': ('35','4'), 'monero_sub': ('3f','8') } # 53,63
class CoinProtocol(MMGenObject):
coins = {
@ -484,17 +482,17 @@ def make_init_genonly_altcoins_str(data):
if proto in globals(): return ''
if coin.lower() in CoinProtocol.coins: return ''
def num2hexbytes(n):
return "b'{:0{}x}'".format(n,(4,2)[n < 256])
def num2hexstr(n):
return "'{:0{}x}'".format(n,(4,2)[n < 256])
o = ['class {}(Bitcoin{}ProtocolAddrgen):'.format(proto,tn_str)]
o += ["base_coin = '{}'".format(coin)]
o += ["name = '{}'".format(e[0].lower())]
o += ["nameCaps = '{}'".format(e[0])]
a = "addr_ver_num = {{ 'p2pkh': ({},{!r})".format(num2hexbytes(e[3][0]),e[3][1])
b = ", 'p2sh': ({},{!r})".format(num2hexbytes(e[4][0]),e[4][1]) if e[4] else ''
a = "addr_ver_num = {{ 'p2pkh': ({},{!r})".format(num2hexstr(e[3][0]),e[3][1])
b = ", 'p2sh': ({},{!r})".format(num2hexstr(e[4][0]),e[4][1]) if e[4] else ''
o += [a+b+' }']
o += ["wif_ver_num = {{ 'std': {} }}".format(num2hexbytes(e[2]))]
o += ["wif_ver_num = {{ 'std': {} }}".format(num2hexstr(e[2]))]
o += ["mmtypes = ('L','C'{})".format(",'S'" if e[5] else '')]
o += ["dfl_mmtype = '{}'".format('L')]
return '\n\t'.join(o) + '\n'

View file

@ -110,13 +110,13 @@ class CoinDaemonRPCConnection(object):
dmsg_rpc(' RPC POST data ==> {}\n'.format(p))
ca_type = self.coin_amt_type if hasattr(self,'coin_amt_type') else str
from mmgen.obj import CoinTxID,HexBytes
from mmgen.obj import HexStr
class MyJSONEncoder(json.JSONEncoder):
def default(self,obj):
if isinstance(obj,g.proto.coin_amt):
return ca_type(obj)
elif isinstance(obj,CoinTxID) or isinstance(obj,HexBytes):
return obj.decode()
elif isinstance(obj,HexStr):
return obj
else:
return json.JSONEncoder.default(self,obj)

View file

@ -21,7 +21,6 @@ seed.py: Seed-related classes and methods for the MMGen suite
"""
import os
from binascii import hexlify,unhexlify
from mmgen.common import *
from mmgen.obj import *
@ -55,7 +54,7 @@ class Seed(MMGenObject):
die(3,'{}: invalid seed length'.format(len(seed_bin)))
self.data = seed_bin
self.hexdata = hexlify(seed_bin)
self.hexdata = seed_bin.hex()
self.sid = SeedID(seed=self)
self.length = len(seed_bin) * 8
@ -485,7 +484,7 @@ class Mnemonic (SeedSourceUnenc):
# Internal error, so just die
compare_or_die(' '.join(ret),'recomputed mnemonic',' '.join(mn),'original',e='Internal error')
self.seed = Seed(unhexlify(hexseed))
self.seed = Seed(bytes.fromhex(hexseed))
self.ssdata.mnemonic = mn
check_usr_seed_len(self.seed.length)
@ -542,7 +541,7 @@ class SeedFile (SeedSourceUnenc):
return True
class HexSeedFile (SeedSourceUnenc):
class HexSeedFile(SeedSourceUnenc):
stdin_ok = True
fmt_codes = 'seedhex','hexseed','hex','mmhex'
@ -553,7 +552,7 @@ class HexSeedFile (SeedSourceUnenc):
h = self.seed.hexdata
self.ssdata.chksum = make_chksum_6(h)
self.ssdata.hexseed = h
self.fmt_data = '{} {}\n'.format(self.ssdata.chksum, split_into_cols(4,h.decode()))
self.fmt_data = '{} {}\n'.format(self.ssdata.chksum, split_into_cols(4,h))
def _deformat(self):
desc = self.desc
@ -582,7 +581,7 @@ class HexSeedFile (SeedSourceUnenc):
if not compare_chksums(chk,'file',make_chksum_6(hstr),'computed',verbose=True):
return False
self.seed = Seed(unhexlify(hstr))
self.seed = Seed(bytes.fromhex(hstr))
self.ssdata.chksum = chk
self.ssdata.hexseed = hstr
@ -869,7 +868,7 @@ to exit and re-run the program with the '--old-incog-fmt' option.
self.fmt_data = d.iv + encrypt_data(
d.salt + d.enc_seed,
d.wrapper_key,
int(hexlify(d.iv),16),
int(d.iv.hex(),16),
self.desc)
# print len(self.fmt_data)
@ -923,7 +922,7 @@ to exit and re-run the program with the '--old-incog-fmt' option.
# IV is used BOTH to initialize counter and to salt password!
key = make_key(d.passwd, d.iv, d.hash_preset, 'wrapper key')
dd = decrypt_data(d.enc_incog_data, key,
int(hexlify(d.iv),16), 'incog data')
int(d.iv.hex(),16), 'incog data')
d.salt = dd[0:g.salt_len]
d.enc_seed = dd[g.salt_len:]

View file

@ -22,7 +22,6 @@ sha2.py: A non-optimized but very compact implementation of the SHA2 hash
SHA256Compress (unpadded SHA256, required for Zcash addresses)
"""
from binascii import hexlify
from struct import pack,unpack
class Sha2(object):
@ -103,7 +102,7 @@ class Sha2(object):
return b''.join((pack(self.word_fmt,w) for w in self.H))
def hexdigest(self):
return hexlify(self.digest())
return self.digest().hex()
def compute(self):
for i in range(0,len(self.M),16):

View file

@ -20,8 +20,6 @@
tool.py: Routines for the 'mmgen-tool' utility
"""
from binascii import hexlify,unhexlify
from mmgen.protocol import hash160
from mmgen.common import *
from mmgen.crypto import *
@ -248,20 +246,20 @@ class MMGenToolCmdUtil(MMGenToolCmdBase):
def randhex(self,nbytes='32'):
"print 'n' bytes (default 32) of random data in hex format"
return hexlify(get_random(int(nbytes)))
return get_random(int(nbytes)).hex()
def hexreverse(self,hexstr:'sstr'):
"reverse bytes of a hexadecimal string"
return hexlify(unhexlify(hexstr.strip())[::-1])
return bytes.fromhex(hexstr.strip())[::-1].hex()
def hexlify(self,infile:str):
"convert bytes in file to hexadecimal (use '-' for stdin)"
data = get_data_from_file(infile,dash=True,silent=True,binary=True)
return hexlify(data)
return data.hex()
def unhexlify(self,hexstr:'sstr'):
"convert hexadecimal value to bytes (warning: outputs binary data)"
return unhexlify(hexstr.encode())
return bytes.fromhex(hexstr)
def hexdump(self,infile:str,cols=8,line_nums=True):
"create hexdump of data from file (use '-' for stdin)"
@ -286,7 +284,7 @@ class MMGenToolCmdUtil(MMGenToolCmdBase):
if file_input: b = get_data_from_file(string_or_bytes,binary=True)
elif hex_input: b = decode_pretty_hexdump(string_or_bytes)
else: b = string_or_bytes
return sha256(sha256(b.encode()).digest()).hexdigest().encode()
return sha256(sha256(b.encode()).digest()).hexdigest()
def id6(self,infile:str):
"generate 6-character MMGen ID for a file (use '-' for stdin)"
@ -309,15 +307,15 @@ class MMGenToolCmdUtil(MMGenToolCmdBase):
def bytestob58(self,infile:str,pad=0):
"convert bytes to base 58 (supply data via STDIN)"
data = get_data_from_file(infile,dash=True,silent=True,binary=True)
return baseconv.fromhex(hexlify(data),'b58',pad=pad,tostr=True)
return baseconv.fromhex(data.hex(),'b58',pad=pad,tostr=True)
def b58tobytes(self,b58num:'sstr',pad=0):
"convert a base 58 number to bytes (warning: outputs binary data)"
return unhexlify(baseconv.tohex(b58num,'b58',pad=pad))
return bytes.fromhex(baseconv.tohex(b58num,'b58',pad=pad))
def hextob58(self,hexstr:'sstr',pad=0):
"convert a hexadecimal number to base 58"
return baseconv.fromhex(hexstr.encode(),'b58',pad=pad,tostr=True)
return baseconv.fromhex(hexstr,'b58',pad=pad,tostr=True)
def b58tohex(self,b58num:'sstr',pad=0):
"convert a base 58 number to hexadecimal"
@ -326,7 +324,7 @@ class MMGenToolCmdUtil(MMGenToolCmdBase):
def hextob58chk(self,hexstr:'sstr'):
"convert a hexadecimal number to base58-check encoding"
from mmgen.protocol import _b58chk_encode
return _b58chk_encode(hexstr.encode())
return _b58chk_encode(hexstr)
def b58chktohex(self,b58chk_num:'sstr'):
"convert a base58-check encoded number to hexadecimal"
@ -335,7 +333,7 @@ class MMGenToolCmdUtil(MMGenToolCmdBase):
def hextob32(self,hexstr:'sstr',pad=0):
"convert a hexadecimal number to MMGen's flavor of base 32"
return baseconv.fromhex(hexstr.encode(),'b32',pad,tostr=True)
return baseconv.fromhex(hexstr,'b32',pad,tostr=True)
def b32tohex(self,b32num:'sstr',pad=0):
"convert an MMGen-flavor base 32 number to hexadecimal"
@ -370,7 +368,7 @@ class MMGenToolCmdCoin(MMGenToolCmdBase):
def hex2wif(self,privhex:'sstr'):
"convert a private key from hex to WIF format"
init_generators('at')
return g.proto.hex2wif(privhex.encode(),pubkey_type=at.pubkey_type,compressed=at.compressed)
return g.proto.hex2wif(privhex,pubkey_type=at.pubkey_type,compressed=at.compressed)
def wif2addr(self,wifkey:'sstr'):
"generate a coin address from a key in WIF format"
@ -398,7 +396,7 @@ class MMGenToolCmdCoin(MMGenToolCmdBase):
def privhex2addr(self,privhex:'sstr',output_pubhex=False):
"generate coin address from private key in hex format"
init_generators()
pk = PrivKey(unhexlify(privhex),compressed=at.compressed,pubkey_type=at.pubkey_type)
pk = PrivKey(bytes.fromhex(privhex),compressed=at.compressed,pubkey_type=at.pubkey_type)
ph = kg.to_pubhex(pk)
return ph if output_pubhex else ag.to_addr(ph)
@ -409,9 +407,9 @@ class MMGenToolCmdCoin(MMGenToolCmdBase):
def pubhex2addr(self,pubkeyhex:'sstr'):
"convert a hex pubkey to an address"
if opt.type == 'segwit':
return g.proto.pubhex2segwitaddr(pubkeyhex.encode())
return g.proto.pubhex2segwitaddr(pubkeyhex)
else:
return self.pubhash2addr(hash160(pubkeyhex.encode()).decode())
return self.pubhash2addr(hash160(pubkeyhex))
def pubhex2redeem_script(self,pubkeyhex:'sstr'): # new
"convert a hex pubkey to a Segwit P2SH-P2WPKH redeem script"
@ -423,15 +421,15 @@ class MMGenToolCmdCoin(MMGenToolCmdBase):
assert opt.type == 'segwit','This command is meaningful only for --type=segwit'
assert redeem_scripthex[:4] == '0014','{!r}: invalid redeem script'.format(redeem_scripthex)
assert len(redeem_scripthex) == 44,'{} bytes: invalid redeem script length'.format(len(redeem_scripthex)//2)
return self.pubhash2addr(self.hash160(redeem_scripthex).decode())
return self.pubhash2addr(self.hash160(redeem_scripthex))
def pubhash2addr(self,pubhashhex:'sstr'):
"convert public key hash to address"
if opt.type == 'bech32':
return g.proto.pubhash2bech32addr(pubhashhex.encode())
return g.proto.pubhash2bech32addr(pubhashhex)
else:
init_generators('at')
return g.proto.pubhash2addr(pubhashhex.encode(),at.addr_fmt=='p2sh')
return g.proto.pubhash2addr(pubhashhex,at.addr_fmt=='p2sh')
def addr2pubhash(self,addr:'sstr'):
"convert coin address to public key hash"
@ -446,7 +444,7 @@ class MMGenToolCmdMnemonic(MMGenToolCmdBase):
"""
def _do_random_mn(self,nbytes:int,wordlist_id:str):
assert nbytes in (16,24,32), 'nbytes must be 16, 24 or 32'
hexrand = hexlify(get_random(nbytes))
hexrand = get_random(nbytes).hex()
Vmsg('Seed: {}'.format(hexrand))
return self.hex2mn(hexrand,wordlist_id=wordlist_id)
@ -466,7 +464,7 @@ class MMGenToolCmdMnemonic(MMGenToolCmdBase):
"convert a 16, 24 or 32-byte hexadecimal number to a mnemonic"
opt.out_fmt = 'words'
from mmgen.seed import SeedSource
s = SeedSource(seed=unhexlify(hexstr))
s = SeedSource(seed=bytes.fromhex(hexstr))
s._format()
return ' '.join(s.ssdata.mnemonic)
@ -820,7 +818,7 @@ class MMGenToolCmdMonero(MMGenToolCmdBase):
p = pexpect.spawn('monero-wallet-cli --generate-from-spend-key {}'.format(fn))
if g.debug: p.logfile = sys.stdout
my_expect(p,'Awaiting initial prompt','Secret spend key: ')
my_sendline(p,'',d.sec.decode(),65)
my_sendline(p,'',d.sec,65)
my_expect(p,'','Enter.* new.* password.*: ',regex=True)
my_sendline(p,'Sending password',d.wallet_passwd,33)
my_expect(p,'','Confirm password: ')

View file

@ -63,7 +63,7 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel:
twmmid = MMGenImmutableAttr('twmmid','TwMMGenID')
addr = MMGenImmutableAttr('addr','CoinAddr')
confs = MMGenImmutableAttr('confs',int,typeconv=False)
scriptPubKey = MMGenImmutableAttr('scriptPubKey','HexBytes')
scriptPubKey = MMGenImmutableAttr('scriptPubKey','HexStr')
days = MMGenListItemAttr('days',int,typeconv=False)
skip = MMGenListItemAttr('skip',str,typeconv=False,reassign_ok=True)
@ -231,7 +231,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
out.append(fs.format( n=str(n+1)+')',
t='' if not i.txid else \
' ' * (tx_w-4) + '|...' if i.skip == 'txid' \
else i.txid.decode()[:tx_w-len(txdots)]+txdots,
else i.txid[:tx_w-len(txdots)] + txdots,
v=i.vout,
a=addr_out,
A=i.amt.fmt(color=True,prec=self.disp_prec),

View file

@ -22,7 +22,6 @@ tx.py: Transaction routines for the MMGen suite
import sys,os,json
from stat import *
from binascii import unhexlify
from mmgen.common import *
from mmgen.obj import *
@ -98,8 +97,8 @@ def segwit_is_active(exit_on_error=False):
return False
def bytes2int(hex_bytes):
r = hexlify(unhexlify(hex_bytes)[::-1])
if hexlify(bytes([r[0]])) in b'89abcdef':
r = bytes.fromhex(hex_bytes)[::-1].hex()
if r[0] in '89abcdef': # sign bit is set
die(3,"{}: Negative values not permitted in transaction!".format(hex_bytes))
return int(r,16)
@ -107,11 +106,11 @@ def bytes2coin_amt(hex_bytes):
return g.proto.coin_amt(bytes2int(hex_bytes) * g.proto.coin_amt.min_coin_unit)
def scriptPubKey2addr(s):
if len(s) == 50 and s[:6] == b'76a914' and s[-4:] == b'88ac':
if len(s) == 50 and s[:6] == '76a914' and s[-4:] == '88ac':
return g.proto.pubhash2addr(s[6:-4],p2sh=False),'p2pkh'
elif len(s) == 46 and s[:4] == b'a914' and s[-2:] == b'87':
elif len(s) == 46 and s[:4] == 'a914' and s[-2:] == '87':
return g.proto.pubhash2addr(s[4:-2],p2sh=True),'p2sh'
elif len(s) == 44 and s[:4] == g.proto.witness_vernum_hex + b'14':
elif len(s) == 44 and s[:4] == g.proto.witness_vernum_hex + '14':
return g.proto.pubhash2bech32addr(s[4:]),'bech32'
else:
raise NotImplementedError('Unknown scriptPubKey ({})'.format(s))
@ -119,7 +118,7 @@ def scriptPubKey2addr(s):
from collections import OrderedDict
class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
def __init__(self,txhex):
tx = list(unhexlify(txhex))
tx = list(bytes.fromhex(txhex))
tx_copy = tx[:]
d = { 'raw_tx': [] }
@ -127,7 +126,7 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
ret = l[:n]
if not skip: d['raw_tx'] += ret
del l[:n]
return hexlify(bytes(ret[::-1] if reverse else ret))
return bytes(ret[::-1] if reverse else ret).hex()
# https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers
# For example, the number 515 is encoded as 0xfd0302.
@ -135,8 +134,8 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
s = l[0]
bytes_len = 1 if s < 0xfd else 2 if s == 0xfd else 4 if s == 0xfe else 8
if bytes_len != 1: del l[0]
ret = int(hexlify(bytes(l[:bytes_len][::-1])),16)
if sub_null: d['raw_tx'] += b'\0'
ret = int(bytes(l[:bytes_len][::-1]).hex(),16)
if sub_null: d['raw_tx'] += b'\x00'
elif not skip: d['raw_tx'] += l[:bytes_len]
del l[:bytes_len]
return ret
@ -145,7 +144,7 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
has_witness = tx[0] == 0
if has_witness:
u = hshift(tx,2,skip=True)
if u != b'0001':
if u != '0001':
raise IllegalWitnessFlagValue("'{}': Illegal value for flag in transaction!".format(u))
del tx_copy[-len(tx)-2:-len(tx)]
@ -186,8 +185,8 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
raise WitnessSizeMismatch('More witness data than inputs with witnesses!')
d['lock_time'] = bytes2int(hshift(tx,4))
d['txid'] = hexlify(sha256(sha256(bytes(tx_copy)).digest()).digest()[::-1])
d['unsigned_hex'] = hexlify(bytes(d['raw_tx']))
d['txid'] = sha256(sha256(bytes(tx_copy)).digest()).digest()[::-1].hex()
d['unsigned_hex'] = bytes(d['raw_tx']).hex()
del d['raw_tx']
keys = 'txid','version','lock_time','witness_size','num_txins','txins','num_txouts','txouts','unsigned_hex'
@ -240,7 +239,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
class MMGenTxInput(MMGenListItem):
for k in txio_attrs: locals()[k] = txio_attrs[k] # in lieu of inheritance
scriptPubKey = MMGenListItemAttr('scriptPubKey','HexBytes')
scriptPubKey = MMGenListItemAttr('scriptPubKey','HexStr')
sequence = MMGenListItemAttr('sequence',int,typeconv=False)
class MMGenTxOutput(MMGenListItem):
@ -279,7 +278,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
self.outputs = self.MMGenTxOutputList()
self.send_amt = g.proto.coin_amt('0') # total amt minus change
self.fee = g.proto.coin_amt('0')
self.hex = b'' # raw serialized hex transaction
self.hex = '' # raw serialized hex transaction
self.label = MMGenTXLabel('')
self.txid = ''
self.coin_txid = ''
@ -362,14 +361,14 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
die(2,'{}: duplicate address in transaction {}'.format(attr,io_str))
def update_txid(self):
self.txid = MMGenTxID(make_chksum_6(unhexlify(self.hex)).upper())
self.txid = MMGenTxID(make_chksum_6(bytes.fromhex(self.hex)).upper())
def create_raw(self):
i = [{'txid':e.txid,'vout':e.vout} for e in self.inputs]
if self.inputs[0].sequence:
i[0]['sequence'] = self.inputs[0].sequence
o = {e.addr:e.amt for e in self.outputs}
self.hex = HexBytes(g.rpch.createrawtransaction(i,o))
self.hex = HexStr(g.rpch.createrawtransaction(i,o))
self.update_txid()
# returns true if comment added or changed
@ -625,11 +624,11 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
self.timestamp = make_timestamp()
def get_hex_locktime(self):
return int(hexlify(unhexlify(self.hex[-8:])[::-1]),16)
return int(bytes.fromhex(self.hex[-8:])[::-1].hex(),16)
def set_hex_locktime(self,val):
assert type(val) == int,'locktime value not an integer'
self.hex = self.hex[:-8] + hexlify(unhexlify('{:08x}'.format(val))[::-1])
self.hex = self.hex[:-8] + bytes.fromhex('{:08x}'.format(val))[::-1].hex()
def get_blockcount(self):
return int(g.rpch.getblockcount())
@ -653,7 +652,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
self.blockcount,
('',' LT={}'.format(self.locktime))[bool(self.locktime)]
),
self.hex.decode(),
self.hex,
repr([amt_to_str(e.__dict__) for e in self.inputs]),
repr([amt_to_str(e.__dict__) for e in self.outputs])
]
@ -661,7 +660,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
lines.append(baseconv.b58encode(self.label.encode()))
if self.coin_txid:
if not self.label: lines.append('-') # keep old tx files backwards compatible
lines.append(self.coin_txid.decode())
lines.append(self.coin_txid)
self.chksum = make_chksum_6(' '.join(lines))
self.fmt_data = '\n'.join([self.chksum] + lines)+'\n'
@ -721,13 +720,13 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
return False
try:
self.hex = HexBytes(ret['hex'])
self.hex = HexStr(ret['hex'])
self.compare_size_and_estimated_size()
dt = DeserializedTX(self.hex)
self.check_hex_tx_matches_mmgen_tx(dt)
self.coin_txid = CoinTxID(dt['txid'],on_fail='raise')
self.check_sigs(dt)
if not self.coin_txid.decode() == g.rpch.decoderawtransaction(ret['hex'])['txid']:
if not self.coin_txid == g.rpch.decoderawtransaction(ret['hex'])['txid']:
raise BadMMGenTxID('txid mismatch (after signing)')
msg('OK')
return True
@ -782,7 +781,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
check_equal('outputs',d_hex,d_mmgen)
uh = deserial_tx['unsigned_hex']
if str(self.txid) != make_chksum_6(unhexlify(uh)).upper():
if str(self.txid) != make_chksum_6(bytes.fromhex(uh)).upper():
raise TxHexMismatch('MMGen TxID ({}) does not match hex transaction data!\n{}'.format(self.txid,m))
def check_pubkey_scripts(self):
@ -807,13 +806,13 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
fs = "Hex TX has {} scriptSig but input is of type '{}'!"
for n in range(len(txins)):
ti,mmti = txins[n],self.inputs[n]
if ti['scriptSig'] == b'' or ( len(ti['scriptSig']) == 46 and # native P2WPKH or P2SH-P2WPKH
ti['scriptSig'][:6] == b'16' + g.proto.witness_vernum_hex + b'14' ):
if ti['scriptSig'] == '' or ( len(ti['scriptSig']) == 46 and # native P2WPKH or P2SH-P2WPKH
ti['scriptSig'][:6] == '16' + g.proto.witness_vernum_hex + '14' ):
assert 'witness' in ti, 'missing witness'
assert type(ti['witness']) == list and len(ti['witness']) == 2, 'malformed witness'
assert len(ti['witness'][1]) == 66, 'incorrect witness pubkey length'
assert mmti.mmid, fs.format('witness-type','non-MMGen')
assert mmti.mmid.mmtype == ('S','B')[ti['scriptSig']==b''],(
assert mmti.mmid.mmtype == ('S','B')[ti['scriptSig']==''],(
fs.format('witness-type',mmti.mmid.mmtype))
else: # non-witness
if mmti.mmid:
@ -936,7 +935,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
if bogus_send:
m = 'BOGUS transaction NOT sent: {}'
else:
assert ret.encode() == self.coin_txid, 'txid mismatch (after sending)'
assert ret == self.coin_txid, 'txid mismatch (after sending)'
m = 'Transaction sent: {}'
self.desc = 'sent transaction'
msg(m.format(self.coin_txid.hl()))
@ -1034,7 +1033,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
((n+1,'')[ip],'address:',e.addr.fmt(color=True,width=addr_w) + ' '+mmid_fmt),
('','comment:',e.label.hl() if e.label else ''),
('','amount:','{} {}'.format(e.amt.hl(),g.dcoin))]
items = [(n+1, 'tx,vout:','{},{}'.format(e.txid.decode(),e.vout))] + icommon + [
items = [(n+1, 'tx,vout:','{},{}'.format(e.txid,e.vout))] + icommon + [
('','confirmations:','{} (around {} days)'.format(confs,days) if blockcount else '')
] if ip else icommon + [
('','change:',green('True') if e.is_chg else '')]
@ -1110,7 +1109,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
return out # TX label might contain non-ascii chars
def check_txfile_hex_data(self):
self.hex = HexBytes(self.hex,on_fail='raise')
self.hex = HexStr(self.hex,on_fail='raise')
def parse_tx_file(self,infile,metadata_only=False,silent_open=False):

View file

@ -22,7 +22,6 @@ util.py: Low-level routines imported by other modules in the MMGen suite
import sys,os,time,stat,re,unicodedata
from hashlib import sha256
from binascii import hexlify,unhexlify
from string import hexdigits,digits
from mmgen.color import *
from mmgen.exception import *
@ -260,8 +259,6 @@ def is_int(s):
# https://en.wikipedia.org/wiki/Base32#RFC_4648_Base32_alphabet
# https://tools.ietf.org/html/rfc4648
def is_hex_bytes(s): return set(list(s.lower())) <= set(list(hexdigits.lower().encode()))
def is_hex_str(s): return set(list(s.lower())) <= set(list(hexdigits.lower()))
def is_hex_str_lc(s): return set(list(s)) <= set(list(hexdigits.lower()))
def is_hex_str_uc(s): return set(list(s)) <= set(list(hexdigits.upper()))
@ -298,12 +295,12 @@ class baseconv(object):
@classmethod
def b58encode(cls,s,pad=None):
pad = cls.get_pad(s,pad,'en',cls.b58pad_lens,[bytes])
return cls.fromhex(hexlify(s),'b58',pad=pad,tostr=True)
return cls.fromhex(s.hex(),'b58',pad=pad,tostr=True)
@classmethod
def b58decode(cls,s,pad=None):
pad = cls.get_pad(s,pad,'de',cls.b58pad_lens_rev,[bytes,str])
return unhexlify(cls.tohex(s,'b58',pad=pad*2 if pad else None))
return bytes.fromhex(cls.tohex(s,'b58',pad=pad*2 if pad else None))
@staticmethod
def get_pad(s,pad,op,pad_map,ok_types):
@ -353,13 +350,13 @@ class baseconv(object):
deconv = [wl.index(words[::-1][i])*(base**i) for i in range(len(words))]
ret = ('{:0{w}x}'.format(sum(deconv),w=pad or 0))
return (('','0')[len(ret) % 2] + ret).encode() # return bytes, for consistency with hexlify()
return (('','0')[len(ret) % 2] + ret)
@classmethod
def fromhex(cls,hexnum,wl_id,pad=None,tostr=False):
if not is_hex_str(hexnum.decode()):
die(2,"'{}': not a hexadecimal number".format(hexnum.decode()))
if not is_hex_str(hexnum):
die(2,"{!r}: not a hexadecimal number".format(hexnum))
wl = cls.digits[wl_id]
base = len(wl)
@ -411,7 +408,7 @@ def pretty_hexdump(data,gw=2,cols=8,line_nums=False):
return ''.join(
[
('' if (line_nums == False or i % cols) else '{:06x}: '.format(i*gw)) +
hexlify(data[i*gw:i*gw+gw]).decode() + ('\n',' ')[bool((i+1) % cols)]
data[i*gw:i*gw+gw].hex() + ('\n',' ')[bool((i+1) % cols)]
for i in range(len(data)//gw + r)
]
).rstrip() + '\n'
@ -421,7 +418,7 @@ def decode_pretty_hexdump(data):
pat = r'^[{}]+:\s+'.format(hexdigits)
lines = [re.sub(pat,'',l) for l in data.splitlines()]
try:
return unhexlify(''.join((''.join(lines).split())))
return bytes.fromhex(''.join((''.join(lines).split())))
except:
msg('Data not in hexdump format')
return False

View file

@ -29,14 +29,13 @@ class TestSuiteException(Exception): pass
class TestSuiteFatalException(Exception): pass
import os
from binascii import hexlify
from mmgen.common import *
def getrandnum(n): return int(hexlify(os.urandom(n)),16)
def getrandhex(n): return hexlify(os.urandom(n)).decode()
def getrandnum(n): return int(os.urandom(n).hex(),16)
def getrandhex(n): return os.urandom(n).hex()
def getrandnum_range(nbytes,rn_max):
while True:
rn = int(hexlify(os.urandom(nbytes)),16)
rn = int(os.urandom(nbytes).hex(),16)
if rn < rn_max: return rn
def getrandstr(num_chars,no_space=False):

View file

@ -26,8 +26,6 @@ os.chdir(os.path.join(pn,os.pardir))
sys.path.__setitem__(0,os.path.abspath(os.curdir))
os.environ['MMGEN_TEST_SUITE'] = '1'
from binascii import hexlify
# Import these _after_ local path's been added to sys.path
from mmgen.common import *
from mmgen.obj import MMGenAddrType
@ -81,7 +79,7 @@ if not 1 <= len(cmd_args) <= 2: opts.usage()
addr_type = MMGenAddrType(opt.type or g.proto.dfl_mmtype)
def pyethereum_sec2addr(sec):
return sec.decode(),hexlify(eth.privtoaddr(sec.decode())).decode()
return sec,eth.privtoaddr(sec).hex()
def keyconv_sec2addr(sec):
p = sp.Popen(['keyconv','-C',g.coin,sec.wif],stderr=sp.PIPE,stdout=sp.PIPE)
@ -95,7 +93,7 @@ def zcash_mini_sec2addr(sec):
def pycoin_sec2addr(sec):
coin = ci.external_tests['testnet']['pycoin'][g.coin] if g.testnet else g.coin
key = pcku.parse_key(sec.decode(),[network_for_netcode(coin)])[1]
key = pcku.parse_key(sec,[network_for_netcode(coin)])[1]
if key is None: die(1,"can't parse {}".format(sec))
d = {
'legacy': ('wif_uncompressed','address_uncompressed'),
@ -205,7 +203,7 @@ def speed_test():
from struct import pack,unpack
seed = os.urandom(28)
print('Incrementing key with each round')
print('Starting key:', hexlify(seed+pack('I',0)))
print('Starting key:', (seed + pack('I',0)).hex())
import time
start = last_t = time.time()

View file

@ -25,8 +25,6 @@ pn = os.path.dirname(sys.argv[0])
os.chdir(os.path.join(pn,os.pardir))
sys.path.__setitem__(0,os.path.abspath(os.curdir))
from binascii import hexlify
# Import these _after_ local path's been added to sys.path
from mmgen.common import *
from mmgen.obj import *
@ -162,20 +160,16 @@ tests = OrderedDict([
'F00BAA12:S:9999999 comment',
tw_pfx+'x comment')
}),
('HexBytes', {
'bad': (1,[],'\0','\1','я','g','gg','FF','f00'),
'good': ('deadbeef','f00baa12')
}),
('MMGenTxID', {
'bad': (1,[],'\0','\1','я','g','gg','FF','f00','F00F0012'),
'good': ('DEADBE','F00BAA')
}),
('CoinTxID',{
'bad': (1,[],'\0','\1','я','g','gg','FF','f00','F00F0012',hexlify(r16),hexlify(r32)+b'ee'),
'good': (hexlify(r32),)
'bad': (1,[],'\0','\1','я','g','gg','FF','f00','F00F0012',r16.hex(),r32.hex()+'ee'),
'good': (r32.hex(),)
}),
('WifKey', {
'bad': (1,[],'\0','\1','я','g','gg','FF','f00',hexlify(r16),'2MspvWFjBbkv2wzQGqhxJUYPCk3Y2jMaxLN'),
'bad': (1,[],'\0','\1','я','g','gg','FF','f00',r16.hex(),'2MspvWFjBbkv2wzQGqhxJUYPCk3Y2jMaxLN'),
'good': {
'btc': (('5KXEpVzjWreTcQoG5hX357s1969MUKNLuSfcszF6yu84kpsNZKb',
'KwWr9rDh8KK5TtDa3HLChEvQXNYcUXpwhRFUPc5uSNnMtqNKLFhk'),
@ -211,8 +205,8 @@ tests = OrderedDict([
{'wif':'cSaJAXBAm9ooHpVJgoxqjDG3AcareFy29Cz8mhnNTRijjv2HLgta',
'ret':'94fa8b90c11fea8fb907c9376b919534b0a75b9a9621edf71a78753544b4101c'})),
}[g.coin.lower()][bool(g.testnet)],
{'s':r32,'compressed':False,'pubkey_type':'std','ret':hexlify(r32)},
{'s':r32,'compressed':True,'pubkey_type':'std','ret':hexlify(r32)}
{'s':r32,'compressed':False,'pubkey_type':'std','ret':r32.hex()},
{'s':r32,'compressed':True,'pubkey_type':'std','ret':r32.hex()}
)
}),
('AddrListID', { # a rather pointless test, but do it anyway

View file

@ -20,7 +20,6 @@ test/sha2test.py: Test MMGen's SHA256 and SHA512 implementations
"""
import sys,os
from binascii import hexlify
from mmgen.sha2 import Sha256,Sha512
from mmgen.util import die
@ -47,10 +46,11 @@ class TestSha2(object):
def compare_hashes(self,dlen,data):
import hashlib
sha2 = getattr(hashlib,self.desc)(data).hexdigest().encode()
my_sha2 = self.t_cls(data).hexdigest()
if my_sha2 != sha2:
die(3,'Hashes do not match!\nmy_sha2: {}\nsha2: {}\n'.format(my_sha2,sha2))
sha2_ref = getattr(hashlib,self.desc)(data).hexdigest()
ret = self.t_cls(data).hexdigest()
if ret != sha2_ref:
m ='\nHashes do not match!\nReference {d}: {}\nMMGen {d}: {}'
die(3,m.format(sha2_ref,ret,d=self.desc.upper()))
def test_ref(self,input_n=None):
@ -77,7 +77,7 @@ class TestSha2(object):
for i in range(rounds):
if i+1 in (1,rounds) or not (i+1) % 10:
msg('\rTesting random input data: {:4}/{} '.format(i+1,rounds))
dlen = int(hexlify(os.urandom(4)),16) >> 18
dlen = int(os.urandom(4).hex(),16) >> 18
self.compare_hashes(dlen,os.urandom(dlen))
msg('OK\n')

View file

@ -360,7 +360,7 @@ def list_cmds():
def do_between():
if opt.pause:
confirm_continue()
elif opt.verbose or opt.exact_output:
elif (opt.verbose or opt.exact_output) and not opt.skip_deps:
sys.stderr.write('\n')
def list_tmpdirs():
@ -747,7 +747,6 @@ class TestSuiteRunner(object):
# delete files depended on by this cmd
arg_list = [get_file_with_ext(cfgs[num]['tmpdir'],ext) for num,ext in d]
if opt.resume:
if cmd == opt.resume:
bmsg('Resuming at {!r}'.format(cmd))

View file

@ -104,7 +104,7 @@ def end_silence():
g.stdout_fileno = 1
def randbool():
return hexlify(os.urandom(1))[1] in b'12345678'
return os.urandom(1).hex()[0] in '13579ace'
def disable_debug():
global save_debug

View file

@ -73,7 +73,7 @@ class TestSuiteAutosign(TestSuiteBase):
def get_pad_chars(n):
ret = ''
for i in range(n):
m = int(hexlify(os.urandom(1)),16) % 32
m = int(os.urandom(1).hex(),16) % 32
ret += r'123579!@#$%^&*()_+-=[]{}"?/,.<>|'[m]
return ret

View file

@ -524,7 +524,7 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
txid = self.txsend_ui_common(t,caller=mmgen_cmd,quiet=True,bogus_send=False)
addr = t.expect_getend('Contract address: ')
from mmgen.altcoins.eth.tx import EthereumMMGenTX as etx
assert etx.get_exec_status(txid.encode(),True) != 0,(
assert etx.get_exec_status(txid,True) != 0,(
"Contract '{}:{}' failed to execute. Aborting".format(num,key))
if key == 'Token':
self.write_to_tmpfile('token_addr{}'.format(num),addr+'\n')

View file

@ -258,17 +258,17 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
if not segwit and k == 'p2sh': k = 'p2pkh'
s_beg,s_end = { 'p2pkh': ('76a914','88ac'),
'p2sh': ('a914','87'),
'bech32': (g.proto.witness_vernum_hex.decode()+'14','') }[k]
'bech32': (g.proto.witness_vernum_hex + '14','') }[k]
amt1,amt2 = {'btc':(10,40),'bch':(10,40),'ltc':(1000,4000)}[g.coin.lower()]
ret = {
self.lbl_id: '{}:{}'.format(g.proto.base_coin.lower(),coinaddr) if non_mmgen \
else ('{}:{}{}'.format(al_id,idx,lbl)),
'vout': int(getrandnum(4) % 8),
'txid': hexlify(os.urandom(32)),
'txid': os.urandom(32).hex(),
'amount': g.proto.coin_amt('{}.{}'.format(amt1 + getrandnum(4) % amt2, getrandnum(4) % 100000000)),
'address': coinaddr,
'spendable': False,
'scriptPubKey': '{}{}{}'.format(s_beg,coinaddr.hex.decode(),s_end).encode(),
'scriptPubKey': '{}{}{}'.format(s_beg,coinaddr.hex,s_end),
'confirmations': getrandnum(3) // 2 # max: 8388608 (7 digits)
}
return ret

View file

@ -530,7 +530,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
return self.alice_add_label_badaddr(rt_pw,'Invalid coin address for this chain: '+rt_pw)
def alice_add_label_badaddr2(self):
addr = g.proto.pubhash2addr(b'00'*20,False) # mainnet zero address
addr = g.proto.pubhash2addr('00'*20,False) # mainnet zero address
return self.alice_add_label_badaddr(addr,'Invalid coin address for this chain: '+addr)
def alice_add_label_badaddr3(self):
@ -539,7 +539,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
"MMGen address '{}' not found in tracking wallet".format(addr))
def alice_add_label_badaddr4(self):
addr = CoinProtocol(g.coin,True).pubhash2addr(b'00'*20,False) # testnet zero address
addr = CoinProtocol(g.coin,True).pubhash2addr('00'*20,False) # testnet zero address
return self.alice_add_label_badaddr(addr,
"Address '{}' not found in tracking wallet".format(addr))