From 94680db67df8621374e4527f60cba0dec4bf2851 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Tue, 4 Oct 2022 13:08:54 +0000 Subject: [PATCH] addrgen.py: modularize protocol-specific code --- mmgen/addr.py | 16 +----- mmgen/addrgen.py | 106 +++++++++---------------------------- mmgen/proto/btc/addrgen.py | 50 +++++++++++++++++ mmgen/proto/eth/addrgen.py | 24 +++++++++ mmgen/proto/xmr/addrgen.py | 37 +++++++++++++ mmgen/proto/zec/addrgen.py | 33 ++++++++++++ 6 files changed, 171 insertions(+), 95 deletions(-) create mode 100755 mmgen/proto/btc/addrgen.py create mode 100755 mmgen/proto/eth/addrgen.py create mode 100755 mmgen/proto/xmr/addrgen.py create mode 100755 mmgen/proto/zec/addrgen.py diff --git a/mmgen/addr.py b/mmgen/addr.py index 807d8cee..2eb4811c 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -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) diff --git a/mmgen/addrgen.py b/mmgen/addrgen.py index f3228ef5..9a66e65e 100755 --- a/mmgen/addrgen.py +++ b/mmgen/addrgen.py @@ -17,12 +17,9 @@ # along with this program. If not, see . """ -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) diff --git a/mmgen/proto/btc/addrgen.py b/mmgen/proto/btc/addrgen.py new file mode 100755 index 00000000..d4482856 --- /dev/null +++ b/mmgen/proto/btc/addrgen.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# 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) )) diff --git a/mmgen/proto/eth/addrgen.py b/mmgen/proto/eth/addrgen.py new file mode 100755 index 00000000..5e1dbac6 --- /dev/null +++ b/mmgen/proto/eth/addrgen.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# 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:] ) diff --git a/mmgen/proto/xmr/addrgen.py b/mmgen/proto/xmr/addrgen.py new file mode 100755 index 00000000..ccea038e --- /dev/null +++ b/mmgen/proto/xmr/addrgen.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# 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() ) diff --git a/mmgen/proto/zec/addrgen.py b/mmgen/proto/zec/addrgen.py new file mode 100755 index 00000000..680e510a --- /dev/null +++ b/mmgen/proto/zec/addrgen.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# 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 )