Browse Source

add proto.common module

The MMGen Project 3 years ago
parent
commit
362d8cfeed
9 changed files with 69 additions and 53 deletions
  1. 3 3
      mmgen/addrgen.py
  2. 1 1
      mmgen/addrlist.py
  3. 2 2
      mmgen/altcoin.py
  4. 6 36
      mmgen/proto/btc.py
  5. 47 0
      mmgen/proto/common.py
  6. 0 2
      mmgen/protocol.py
  7. 2 2
      mmgen/tool/coin.py
  8. 5 5
      mmgen/tool/util.py
  9. 3 2
      mmgen/xmrwallet.py

+ 3 - 3
mmgen/addrgen.py

@@ -20,7 +20,7 @@
 addrgen.py: Address and view key generation classes for the MMGen suite
 """
 
-from .proto.btc import hash160,_b58chk_encode
+from .proto.common import hash160,b58chk_encode
 from .addr import CoinAddr,MMGenAddrType,MoneroViewKey,ZcashViewKey
 
 # decorator for to_addr() and to_viewkey()
@@ -118,14 +118,14 @@ class addr_generator:
 
 		@check_data
 		def to_addr(self,data):
-			ret = _b58chk_encode(
+			ret = b58chk_encode(
 				self.proto.addr_fmt_to_ver_bytes('zcash_z')
 				+ data.pubkey )
 			return CoinAddr( self.proto, ret )
 
 		@check_data
 		def to_viewkey(self,data):
-			ret = _b58chk_encode(
+			ret = b58chk_encode(
 				self.proto.addr_fmt_to_ver_bytes('viewkey')
 				+ data.viewkey_bytes )
 			return ZcashViewKey( self.proto, ret )

+ 1 - 1
mmgen/addrlist.py

@@ -281,7 +281,7 @@ class AddrList(MMGenObject): # Address info for a single seed ID
 		return out
 
 	def gen_wallet_passwd(self,privbytes):
-		from .proto.btc import hash256
+		from .proto.common import hash256
 		return WalletPassword( hash256(privbytes)[:16].hex() )
 
 	def check_format(self,addr):

+ 2 - 2
mmgen/altcoin.py

@@ -556,10 +556,10 @@ class CoinInfo(object):
 			return '1'
 
 		def phash2addr(ver_num,pk_hash):
-			from .proto.btc import _b58chk_encode
+			from .proto.common import b58chk_encode
 			bl = ver_num.bit_length()
 			ver_bytes = int.to_bytes(ver_num,bl//8 + bool(bl%8),'big')
-			return _b58chk_encode(ver_bytes + pk_hash)
+			return b58chk_encode(ver_bytes + pk_hash)
 
 		low = phash2addr(ver_num,b'\x00'*20)
 		high = phash2addr(ver_num,b'\xff'*20)

+ 6 - 36
mmgen/proto/btc.py

@@ -12,38 +12,8 @@
 Bitcoin protocol
 """
 
-from ..protocol import CoinProtocol,parsed_wif,parsed_addr,_finfo,_b58a,_nw
-import hashlib
-
-def hash160(in_bytes): # OP_HASH160
-	return hashlib.new('ripemd160',hashlib.sha256(in_bytes).digest()).digest()
-
-def hash256(in_bytes): # OP_HASH256
-	return hashlib.sha256(hashlib.sha256(in_bytes).digest()).digest()
-
-# From en.bitcoin.it:
-#  The Base58 encoding used is home made, and has some differences.
-#  Especially, leading zeroes are kept as single zeroes when conversion happens.
-# Test: 5JbQQTs3cnoYN9vDYaGY6nhQ1DggVsY4FJNBUfEfpSQqrEp3srk
-# The 'zero address':
-# 1111111111111111111114oLvT2 (pubkeyhash = '\0'*20)
-
-def _b58chk_encode(in_bytes):
-	lzeroes = len(in_bytes) - len(in_bytes.lstrip(b'\x00'))
-	def do_enc(n):
-		while n:
-			yield _b58a[n % 58]
-			n //= 58
-	return ('1' * lzeroes) + ''.join(do_enc(int.from_bytes(in_bytes+hash256(in_bytes)[:4],'big')))[::-1]
-
-def _b58chk_decode(s):
-	lzeroes = len(s) - len(s.lstrip('1'))
-	res = sum(_b58a.index(ch) * 58**n for n,ch in enumerate(s[::-1]))
-	bl = res.bit_length()
-	out = b'\x00' * lzeroes + res.to_bytes(bl//8 + bool(bl%8),'big')
-	if out[-4:] != hash256(out[:-4])[:4]:
-		raise ValueError('_b58chk_decode(): incorrect checksum')
-	return out[:-4]
+from ..protocol import CoinProtocol,parsed_wif,parsed_addr,_finfo,_nw
+from .common import *
 
 class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp
 	"""
@@ -83,13 +53,13 @@ class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp
 	def bytes2wif(self,privbytes,pubkey_type,compressed): # input is preprocessed hex
 		assert len(privbytes) == self.privkey_len, f'{len(privbytes)} bytes: incorrect private key length!'
 		assert pubkey_type in self.wif_ver_num, f'{pubkey_type!r}: invalid pubkey_type'
-		return _b58chk_encode(
+		return b58chk_encode(
 			bytes.fromhex(self.wif_ver_num[pubkey_type])
 			+ privbytes
 			+ (b'',b'\x01')[bool(compressed)])
 
 	def parse_wif(self,wif):
-		key = _b58chk_decode(wif)
+		key = b58chk_decode(wif)
 
 		for k,v in self.wif_ver_num.items():
 			v = bytes.fromhex(v)
@@ -126,11 +96,11 @@ class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp
 
 			return parsed_addr( bytes(ret[1]), 'bech32' ) if ret[1] else False
 
-		return self.parse_addr_bytes(_b58chk_decode(addr))
+		return self.parse_addr_bytes(b58chk_decode(addr))
 
 	def pubhash2addr(self,pubkey_hash,p2sh):
 		assert len(pubkey_hash) == 20, f'{len(pubkey_hash)}: invalid length for pubkey hash'
-		return _b58chk_encode(
+		return b58chk_encode(
 			self.addr_fmt_to_ver_bytes(('p2pkh','p2sh')[p2sh],return_hex=False) + pubkey_hash
 		)
 

+ 47 - 0
mmgen/proto/common.py

@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+#
+# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
+# Copyright (C)2013-2022 The MMGen Project <mmgen@tuta.io>
+# Licensed under the GNU General Public License, Version 3:
+#   https://www.gnu.org/licenses
+# Public project repositories:
+#   https://github.com/mmgen/mmgen
+#   https://gitlab.com/mmgen/mmgen
+
+"""
+Functions and constants used by multiple protocols
+"""
+
+import hashlib
+
+b58a = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
+
+def hash160(in_bytes): # OP_HASH160
+	return hashlib.new('ripemd160',hashlib.sha256(in_bytes).digest()).digest()
+
+def hash256(in_bytes): # OP_HASH256
+	return hashlib.sha256(hashlib.sha256(in_bytes).digest()).digest()
+
+# From en.bitcoin.it:
+#  The Base58 encoding used is home made, and has some differences.
+#  Especially, leading zeroes are kept as single zeroes when conversion happens.
+# Test: 5JbQQTs3cnoYN9vDYaGY6nhQ1DggVsY4FJNBUfEfpSQqrEp3srk
+# The 'zero address':
+# 1111111111111111111114oLvT2 (pubkeyhash = '\0'*20)
+
+def b58chk_encode(in_bytes):
+	lzeroes = len(in_bytes) - len(in_bytes.lstrip(b'\x00'))
+	def do_enc(n):
+		while n:
+			yield b58a[n % 58]
+			n //= 58
+	return ('1' * lzeroes) + ''.join(do_enc(int.from_bytes(in_bytes+hash256(in_bytes)[:4],'big')))[::-1]
+
+def b58chk_decode(s):
+	lzeroes = len(s) - len(s.lstrip('1'))
+	res = sum(b58a.index(ch) * 58**n for n,ch in enumerate(s[::-1]))
+	bl = res.bit_length()
+	out = b'\x00' * lzeroes + res.to_bytes(bl//8 + bool(bl%8),'big')
+	if out[-4:] != hash256(out[:-4])[:4]:
+		raise ValueError('b58chk_decode(): incorrect checksum')
+	return out[:-4]

+ 0 - 2
mmgen/protocol.py

@@ -31,8 +31,6 @@ parsed_addr = namedtuple('parsed_addr',['bytes','fmt'])
 _finfo = namedtuple('fork_info',['height','hash','name','replayable'])
 _nw = namedtuple('coin_networks',['mainnet','testnet','regtest'])
 
-_b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' # shared by Bitcoin and Monero
-
 class CoinProtocol(MMGenObject):
 
 	proto_info = namedtuple('proto_info',['name','trust_level']) # trust levels: see altcoin.py

+ 2 - 2
mmgen/tool/coin.py

@@ -133,7 +133,7 @@ class tool_cmd(tool_cmd_base):
 		if self.mmtype.name == 'segwit':
 			return self.proto.pubkey2segwitaddr( pubkey )
 		else:
-			from ..proto.btc import hash160
+			from ..proto.common import hash160
 			return self.pubhash2addr( hash160(pubkey).hex() )
 
 	def pubhex2redeem_script(self,pubkeyhex:'sstr'): # new
@@ -146,7 +146,7 @@ class tool_cmd(tool_cmd_base):
 		assert self.mmtype.name == 'segwit', 'This command is meaningful only for --type=segwit'
 		assert redeem_scripthex[:4] == '0014', f'{redeem_scripthex!r}: invalid redeem script'
 		assert len(redeem_scripthex) == 44, f'{len(redeem_scripthex)//2} bytes: invalid redeem script length'
-		from ..proto.btc import hash160
+		from ..proto.common import hash160
 		return self.pubhash2addr( hash160(bytes.fromhex(redeem_scripthex)).hex() )
 
 	def pubhash2addr(self,pubhashhex:'sstr'):

+ 5 - 5
mmgen/tool/util.py

@@ -78,7 +78,7 @@ class tool_cmd(tool_cmd_base):
 
 	def hash160(self,hexstr:'sstr'):
 		"compute ripemd160(sha256(data)) (convert hex pubkey to hex addr)"
-		from ..proto.btc import hash160
+		from ..proto.common import hash160
 		return hash160( bytes.fromhex(hexstr) ).hex()
 
 	def hash256(self,string_or_bytes:str,file_input=False,hex_input=False): # TODO: handle stdin
@@ -143,13 +143,13 @@ class tool_cmd(tool_cmd_base):
 
 	def hextob58chk(self,hexstr:'sstr'):
 		"convert a hexadecimal number to base58-check encoding"
-		from ..proto.btc import _b58chk_encode
-		return _b58chk_encode( bytes.fromhex(hexstr) )
+		from ..proto.common import b58chk_encode
+		return b58chk_encode( bytes.fromhex(hexstr) )
 
 	def b58chktohex(self,b58chk_num:'sstr'):
 		"convert a base58-check encoded number to hexadecimal"
-		from ..proto.btc import _b58chk_decode
-		return _b58chk_decode(b58chk_num).hex()
+		from ..proto.common import b58chk_decode
+		return b58chk_decode(b58chk_num).hex()
 
 	def hextob32(self,hexstr:'sstr',pad=0):
 		"convert a hexadecimal number to MMGen's flavor of base 32"

+ 3 - 2
mmgen/xmrwallet.py

@@ -26,7 +26,8 @@ from .common import *
 from .objmethods import Hilite,InitErrors
 from .obj import CoinTxID
 from .seed import SeedID
-from .protocol import init_proto,_b58a
+from .protocol import init_proto
+from .proto.common import b58a
 from .addr import CoinAddr,AddrIdx
 from .addrlist import KeyAddrList,AddrIdxList
 from .rpc import MoneroRPCClientRaw,MoneroWalletRPCClient,json_encoder
@@ -36,7 +37,7 @@ xmrwallet_uarg_info = (
 	lambda e,hp: {
 		'daemon':          e('HOST:PORT', hp),
 		'tx_relay_daemon': e('HOST:PORT[:PROXY_HOST:PROXY_PORT]', rf'({hp})(?::({hp}))?'),
-		'transfer_spec':   e('SOURCE_WALLET_NUM:ACCOUNT:ADDRESS,AMOUNT', rf'(\d+):(\d+):([{_b58a}]+),([0-9.]+)'),
+		'transfer_spec':   e('SOURCE_WALLET_NUM:ACCOUNT:ADDRESS,AMOUNT', rf'(\d+):(\d+):([{b58a}]+),([0-9.]+)'),
 		'sweep_spec':      e('SOURCE_WALLET_NUM:ACCOUNT[,DEST_WALLET_NUM]', r'(\d+):(\d+)(?:,(\d+))?'),
 	})(
 		namedtuple('uarg_info_entry',['annot','pat']),