addrgen.py: modularize protocol-specific code

This commit is contained in:
The MMGen Project 2022-10-04 13:08:54 +00:00
commit 94680db67d
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
6 changed files with 174 additions and 98 deletions

View file

@ -26,6 +26,7 @@ from .objmethods import Hilite,InitErrors,MMGenObject
from .obj import ImmutableAttr,MMGenIdx,HexStr,get_obj
from .seed import SeedID
from .keygen import KeyGenerator # stub
from .addrgen import AddrGenerator # stub
ati = namedtuple('addrtype_info',
['name','pubkey_type','compressed','gen_method','addr_fmt','wif_label','extra_attrs','desc'])
@ -186,18 +187,3 @@ class MoneroViewKey(HexStr):
class ZcashViewKey(CoinAddr):
hex_width = 128
def AddrGenerator(proto,addr_type):
"""
factory function returning an address generator for the specified address type
"""
if type(addr_type) == str:
addr_type = MMGenAddrType(proto=proto,id_str=addr_type)
elif type(addr_type) == MMGenAddrType:
assert addr_type in proto.mmtypes, f'{addr_type}: invalid address type for coin {proto.coin}'
else:
raise TypeError(f'{type(addr_type)}: incorrect argument type for {cls.__name__}()')
from .addrgen import addr_generator
return getattr(addr_generator,addr_type.name)(proto,addr_type)

View file

@ -17,12 +17,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
addrgen.py: Address and view key generation classes for the MMGen suite
addrgen.py: Address generation initialization code for the MMGen suite
"""
from .proto.common import hash160,b58chk_encode
from .addr import CoinAddr,MMGenAddrType,MoneroViewKey,ZcashViewKey
# decorator for to_addr() and to_viewkey()
def check_data(orig_func):
def f(self,data):
@ -34,9 +31,7 @@ def check_data(orig_func):
return f
class addr_generator:
"""
provide a generator for each supported address format
"""
class base:
def __init__(self,proto,addr_type):
@ -45,39 +40,6 @@ class addr_generator:
self.compressed = addr_type.compressed
desc = f'AddrGenerator {type(self).__name__!r}'
def to_segwit_redeem_script(self,data):
raise NotImplementedError('Segwit redeem script not supported by this address type')
class p2pkh(base):
@check_data
def to_addr(self,data):
return CoinAddr(
self.proto,
self.proto.pubhash2addr( hash160(data.pubkey), p2sh=False ))
class legacy(p2pkh): pass
class compressed(p2pkh): pass
class segwit(base):
@check_data
def to_addr(self,data):
return CoinAddr(
self.proto,
self.proto.pubhash2segwitaddr( hash160(data.pubkey)) )
def to_segwit_redeem_script(self,data): # NB: returns hex
return self.proto.pubhash2redeem_script( hash160(data.pubkey) ).hex()
class bech32(base):
@check_data
def to_addr(self,data):
return CoinAddr(
self.proto,
self.proto.pubhash2bech32addr( hash160(data.pubkey) ))
class keccak(base):
def __init__(self,proto,addr_type):
@ -85,47 +47,31 @@ class addr_generator:
from .util import get_keccak
self.keccak_256 = get_keccak()
class ethereum(keccak):
def AddrGenerator(proto,addr_type):
"""
factory function returning an address generator for the specified address type
"""
@check_data
def to_addr(self,data):
return CoinAddr(
self.proto,
self.keccak_256(data.pubkey[1:]).hexdigest()[24:] )
package_map = {
'legacy': 'btc',
'compressed': 'btc',
'segwit': 'btc',
'bech32': 'btc',
'monero': 'xmr',
'ethereum': 'eth',
'zcash_z': 'zec',
}
class monero(keccak):
from .addr import MMGenAddrType
def b58enc(self,addr_bytes):
from .baseconv import baseconv
enc = baseconv('b58').frombytes
l = len(addr_bytes)
a = ''.join([enc( addr_bytes[i*8:i*8+8], pad=11, tostr=True ) for i in range(l//8)])
b = enc( addr_bytes[l-l%8:], pad=7, tostr=True )
return a + b
if type(addr_type) == str:
addr_type = MMGenAddrType(proto=proto,id_str=addr_type)
elif type(addr_type) == MMGenAddrType:
assert addr_type in proto.mmtypes, f'{addr_type}: invalid address type for coin {proto.coin}'
else:
raise TypeError(f'{type(addr_type)}: incorrect argument type for {cls.__name__}()')
@check_data
def to_addr(self,data):
step1 = self.proto.addr_fmt_to_ver_bytes['monero'] + data.pubkey
return CoinAddr(
proto = self.proto,
addr = self.b58enc( step1 + self.keccak_256(step1).digest()[:4]) )
@check_data
def to_viewkey(self,data):
return MoneroViewKey( data.viewkey_bytes.hex() )
class zcash_z(base):
@check_data
def to_addr(self,data):
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(
self.proto.addr_fmt_to_ver_bytes['viewkey']
+ data.viewkey_bytes )
return ZcashViewKey( self.proto, ret )
import importlib
return getattr(
importlib.import_module(f'mmgen.proto.{package_map[addr_type.name]}.addrgen'),
addr_type.name )(proto,addr_type)

50
mmgen/proto/btc/addrgen.py Executable file
View file

@ -0,0 +1,50 @@
#!/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
"""
proto.btc.addrgen: Bitcoin address generation classes for the MMGen suite
"""
from ...addrgen import addr_generator,check_data
from ...addr import CoinAddr
from ..common import hash160
class p2pkh(addr_generator.base):
@check_data
def to_addr(self,data):
return CoinAddr(
self.proto,
self.proto.pubhash2addr( hash160(data.pubkey), p2sh=False ))
class legacy(p2pkh):
pass
class compressed(p2pkh):
pass
class segwit(addr_generator.base):
@check_data
def to_addr(self,data):
return CoinAddr(
self.proto,
self.proto.pubhash2segwitaddr( hash160(data.pubkey)) )
def to_segwit_redeem_script(self,data): # NB: returns hex
return self.proto.pubhash2redeem_script( hash160(data.pubkey) ).hex()
class bech32(addr_generator.base):
@check_data
def to_addr(self,data):
return CoinAddr(
self.proto,
self.proto.pubhash2bech32addr( hash160(data.pubkey) ))

24
mmgen/proto/eth/addrgen.py Executable file
View file

@ -0,0 +1,24 @@
#!/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
"""
proto.eth.addrgen: Ethereum address generation class for the MMGen suite
"""
from ...addrgen import addr_generator,check_data
from ...addr import CoinAddr
class ethereum(addr_generator.keccak):
@check_data
def to_addr(self,data):
return CoinAddr(
self.proto,
self.keccak_256(data.pubkey[1:]).hexdigest()[24:] )

37
mmgen/proto/xmr/addrgen.py Executable file
View file

@ -0,0 +1,37 @@
#!/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
"""
proto.xmr.addrgen: Monero address generation class for the MMGen suite
"""
from ...addrgen import addr_generator,check_data
from ...addr import CoinAddr,MoneroViewKey
class monero(addr_generator.keccak):
def b58enc(self,addr_bytes):
from ...baseconv import baseconv
enc = baseconv('b58').frombytes
l = len(addr_bytes)
a = ''.join([enc( addr_bytes[i*8:i*8+8], pad=11, tostr=True ) for i in range(l//8)])
b = enc( addr_bytes[l-l%8:], pad=7, tostr=True )
return a + b
@check_data
def to_addr(self,data):
step1 = self.proto.addr_fmt_to_ver_bytes['monero'] + data.pubkey
return CoinAddr(
proto = self.proto,
addr = self.b58enc( step1 + self.keccak_256(step1).digest()[:4]) )
@check_data
def to_viewkey(self,data):
return MoneroViewKey( data.viewkey_bytes.hex() )

33
mmgen/proto/zec/addrgen.py Executable file
View file

@ -0,0 +1,33 @@
#!/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
"""
proto.zec.addrgen: Zcash-Z address generation class for the MMGen suite
"""
from ...addrgen import addr_generator,check_data
from ...addr import CoinAddr,ZcashViewKey
from ..common import b58chk_encode
class zcash_z(addr_generator.base):
@check_data
def to_addr(self,data):
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(
self.proto.addr_fmt_to_ver_bytes['viewkey']
+ data.viewkey_bytes )
return ZcashViewKey( self.proto, ret )