addr.py: move PubKey and PrivKey to key.py
This commit is contained in:
parent
e0352568db
commit
545406aea4
16 changed files with 134 additions and 97 deletions
|
|
@ -26,6 +26,7 @@ from .objmethods import MMGenObject
|
|||
from .obj import *
|
||||
from .baseconv import *
|
||||
from .protocol import hash160
|
||||
from .key import PrivKey,PubKey
|
||||
|
||||
class AddrGenerator(MMGenObject):
|
||||
def __new__(cls,proto,addr_type):
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ from .util import (
|
|||
from .protocol import init_proto
|
||||
from .obj import *
|
||||
from .seed import SeedID,is_seed_id
|
||||
from .key import PrivKey
|
||||
from .addrlist import KeyList,AddrListData,dmsg_sc
|
||||
from .passwdlist import PasswordList
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ addrlist.py: Address list classes for the MMGen suite
|
|||
from hashlib import sha256,sha512
|
||||
from .util import qmsg,qmsg_r,suf,make_chksum_N,Msg
|
||||
from .objmethods import MMGenObject,Hilite,InitErrors
|
||||
from .obj import MMGenListItem,ListItemAttr,MMGenDict,WalletPassword,PrivKey
|
||||
from .obj import MMGenListItem,ListItemAttr,MMGenDict,WalletPassword
|
||||
from .seed import SeedID
|
||||
from .key import PrivKey
|
||||
from .obj import MMGenID,MMGenAddrType,CoinAddr,AddrIdx,AddrListID,ViewKey
|
||||
|
||||
def dmsg_sc(desc,data):
|
||||
|
|
|
|||
113
mmgen/key.py
Executable file
113
mmgen/key.py
Executable file
|
|
@ -0,0 +1,113 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2022 The MMGen Project <mmgen@tuta.io>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
key.py: MMGen public and private key objects
|
||||
"""
|
||||
|
||||
from string import ascii_letters,digits
|
||||
from .objmethods import Hilite,InitErrors,MMGenObject
|
||||
from .obj import ImmutableAttr,get_obj,HexStr
|
||||
|
||||
class WifKey(str,Hilite,InitErrors):
|
||||
"""
|
||||
Initialize a WIF key, checking its well-formedness.
|
||||
The numeric validity of the private key it encodes is not checked.
|
||||
"""
|
||||
width = 53
|
||||
color = 'blue'
|
||||
def __new__(cls,proto,wif):
|
||||
if type(wif) == cls:
|
||||
return wif
|
||||
try:
|
||||
assert set(wif) <= set(ascii_letters+digits),'not an ascii alphanumeric string'
|
||||
proto.parse_wif(wif) # raises exception on error
|
||||
return str.__new__(cls,wif)
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,wif)
|
||||
|
||||
def is_wif(proto,s):
|
||||
return get_obj( WifKey, proto=proto, wif=s, silent=True, return_bool=True )
|
||||
|
||||
class PubKey(HexStr,MMGenObject): # TODO: add some real checks
|
||||
|
||||
def __new__(cls,s,privkey):
|
||||
try:
|
||||
me = HexStr.__new__(cls,s,case='lower')
|
||||
me.privkey = privkey
|
||||
me.compressed = privkey.compressed
|
||||
return me
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,s)
|
||||
|
||||
class PrivKey(str,Hilite,InitErrors,MMGenObject):
|
||||
"""
|
||||
Input: a) raw, non-preprocessed bytes; or b) WIF key.
|
||||
Output: preprocessed hexadecimal key, plus WIF key in 'wif' attribute
|
||||
For coins without a WIF format, 'wif' contains the preprocessed hex.
|
||||
The numeric validity of the resulting key is always checked.
|
||||
"""
|
||||
color = 'red'
|
||||
width = 64
|
||||
trunc_ok = False
|
||||
|
||||
compressed = ImmutableAttr(bool,typeconv=False)
|
||||
wif = ImmutableAttr(WifKey,typeconv=False)
|
||||
|
||||
# initialize with (priv_bin,compressed), WIF or self
|
||||
def __new__(cls,proto,s=None,compressed=None,wif=None,pubkey_type=None):
|
||||
if type(s) == cls:
|
||||
return s
|
||||
if wif:
|
||||
try:
|
||||
assert s == None,"'wif' and key hex args are mutually exclusive"
|
||||
assert set(wif) <= set(ascii_letters+digits),'not an ascii alphanumeric string'
|
||||
k = proto.parse_wif(wif) # raises exception on error
|
||||
me = str.__new__(cls,k.sec.hex())
|
||||
me.compressed = k.compressed
|
||||
me.pubkey_type = k.pubkey_type
|
||||
me.wif = str.__new__(WifKey,wif) # check has been done
|
||||
me.orig_hex = None
|
||||
if k.sec != proto.preprocess_key(k.sec,k.pubkey_type):
|
||||
from .exception import PrivateKeyError
|
||||
raise PrivateKeyError(
|
||||
f'{proto.cls_name} WIF key {me.wif!r} encodes private key with invalid value {me}')
|
||||
me.proto = proto
|
||||
return me
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,s,objname=f'{proto.coin} WIF key')
|
||||
else:
|
||||
try:
|
||||
assert s,'private key bytes data missing'
|
||||
assert pubkey_type is not None,"'pubkey_type' arg missing"
|
||||
assert len(s) == cls.width // 2, f'key length must be {cls.width // 2} bytes'
|
||||
if pubkey_type == 'password': # skip WIF creation and pre-processing for passwds
|
||||
me = str.__new__(cls,s.hex())
|
||||
else:
|
||||
assert compressed is not None, "'compressed' arg missing"
|
||||
assert type(compressed) == bool,(
|
||||
f"'compressed' must be of type bool, not {type(compressed).__name__}" )
|
||||
me = str.__new__(cls,proto.preprocess_key(s,pubkey_type).hex())
|
||||
me.wif = WifKey(proto,proto.hex2wif(me,pubkey_type,compressed))
|
||||
me.compressed = compressed
|
||||
me.pubkey_type = pubkey_type
|
||||
me.orig_hex = s.hex() # save the non-preprocessed key
|
||||
me.proto = proto
|
||||
return me
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,s)
|
||||
85
mmgen/obj.py
85
mmgen/obj.py
|
|
@ -62,8 +62,6 @@ def is_addrlist_id(s): return get_obj(AddrListID, sid=s, silent=True,return_
|
|||
|
||||
def is_mmgen_id(proto,s): return get_obj(MMGenID, proto=proto, id_str=s, silent=True,return_bool=True)
|
||||
def is_coin_addr(proto,s): return get_obj(CoinAddr, proto=proto, addr=s, silent=True,return_bool=True)
|
||||
def is_wif(proto,s): return get_obj(WifKey, proto=proto, wif=s, silent=True,return_bool=True)
|
||||
|
||||
# dict that keeps a list of keys for efficient lookup by index
|
||||
class IndexedDict(dict):
|
||||
|
||||
|
|
@ -435,89 +433,6 @@ class WalletPassword(HexStr): color,width,hexcase = 'blue',32,'lower'
|
|||
class MoneroViewKey(HexStr): color,width,hexcase = 'cyan',64,'lower' # FIXME - no checking performed
|
||||
class MMGenTxID(HexStr): color,width,hexcase = 'red',6,'upper'
|
||||
|
||||
class WifKey(str,Hilite,InitErrors):
|
||||
"""
|
||||
Initialize a WIF key, checking its well-formedness.
|
||||
The numeric validity of the private key it encodes is not checked.
|
||||
"""
|
||||
width = 53
|
||||
color = 'blue'
|
||||
def __new__(cls,proto,wif):
|
||||
if type(wif) == cls:
|
||||
return wif
|
||||
try:
|
||||
assert set(wif) <= set(ascii_letters+digits),'not an ascii alphanumeric string'
|
||||
proto.parse_wif(wif) # raises exception on error
|
||||
return str.__new__(cls,wif)
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,wif)
|
||||
|
||||
class PubKey(HexStr,MMGenObject): # TODO: add some real checks
|
||||
def __new__(cls,s,privkey):
|
||||
try:
|
||||
me = HexStr.__new__(cls,s,case='lower')
|
||||
me.privkey = privkey
|
||||
me.compressed = privkey.compressed
|
||||
return me
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,s)
|
||||
|
||||
class PrivKey(str,Hilite,InitErrors,MMGenObject):
|
||||
"""
|
||||
Input: a) raw, non-preprocessed bytes; or b) WIF key.
|
||||
Output: preprocessed hexadecimal key, plus WIF key in 'wif' attribute
|
||||
For coins without a WIF format, 'wif' contains the preprocessed hex.
|
||||
The numeric validity of the resulting key is always checked.
|
||||
"""
|
||||
color = 'red'
|
||||
width = 64
|
||||
trunc_ok = False
|
||||
|
||||
compressed = ImmutableAttr(bool,typeconv=False)
|
||||
wif = ImmutableAttr(WifKey,typeconv=False)
|
||||
|
||||
# initialize with (priv_bin,compressed), WIF or self
|
||||
def __new__(cls,proto,s=None,compressed=None,wif=None,pubkey_type=None):
|
||||
if type(s) == cls:
|
||||
return s
|
||||
if wif:
|
||||
try:
|
||||
assert s == None,"'wif' and key hex args are mutually exclusive"
|
||||
assert set(wif) <= set(ascii_letters+digits),'not an ascii alphanumeric string'
|
||||
k = proto.parse_wif(wif) # raises exception on error
|
||||
me = str.__new__(cls,k.sec.hex())
|
||||
me.compressed = k.compressed
|
||||
me.pubkey_type = k.pubkey_type
|
||||
me.wif = str.__new__(WifKey,wif) # check has been done
|
||||
me.orig_hex = None
|
||||
if k.sec != proto.preprocess_key(k.sec,k.pubkey_type):
|
||||
raise PrivateKeyError(
|
||||
f'{proto.cls_name} WIF key {me.wif!r} encodes private key with invalid value {me}')
|
||||
me.proto = proto
|
||||
return me
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,s,objname=f'{proto.coin} WIF key')
|
||||
else:
|
||||
try:
|
||||
assert s,'private key bytes data missing'
|
||||
assert pubkey_type is not None,"'pubkey_type' arg missing"
|
||||
assert len(s) == cls.width // 2, f'key length must be {cls.width // 2} bytes'
|
||||
if pubkey_type == 'password': # skip WIF creation and pre-processing for passwds
|
||||
me = str.__new__(cls,s.hex())
|
||||
else:
|
||||
assert compressed is not None, "'compressed' arg missing"
|
||||
assert type(compressed) == bool,(
|
||||
f"'compressed' must be of type bool, not {type(compressed).__name__}" )
|
||||
me = str.__new__(cls,proto.preprocess_key(s,pubkey_type).hex())
|
||||
me.wif = WifKey(proto,proto.hex2wif(me,pubkey_type,compressed))
|
||||
me.compressed = compressed
|
||||
me.pubkey_type = pubkey_type
|
||||
me.orig_hex = s.hex() # save the non-preprocessed key
|
||||
me.proto = proto
|
||||
return me
|
||||
except Exception as e:
|
||||
return cls.init_fail(e,s)
|
||||
|
||||
class AddrListID(str,Hilite,InitErrors,MMGenObject):
|
||||
width = 10
|
||||
trunc_ok = False
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@ from collections import namedtuple
|
|||
|
||||
from .exception import InvalidPasswdFormat
|
||||
from .util import ymsg,is_hex_str,is_int,keypress_confirm
|
||||
from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString,PrivKey
|
||||
from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString
|
||||
from .baseconv import baseconv,is_b32_str,is_b58_str
|
||||
from .key import PrivKey
|
||||
from .addr import MMGenPasswordType,AddrIdx,AddrListID,is_xmrseed,is_bip39_str
|
||||
from .addrlist import (
|
||||
AddrListChksum,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from collections import namedtuple
|
|||
|
||||
from .util import msg,ymsg,Msg,ydie
|
||||
from .devtools import *
|
||||
from .obj import CoinAddr,MMGenAddrType,PrivKey
|
||||
from .obj import CoinAddr,MMGenAddrType
|
||||
from .globalvars import g
|
||||
from .amt import BTCAmt,LTCAmt,BCHAmt,B2XAmt,XMRAmt
|
||||
from .altcoins.eth.obj import ETHAmt
|
||||
|
|
@ -178,9 +178,6 @@ class CoinProtocol(MMGenObject):
|
|||
def addr_type(self,id_str):
|
||||
return MMGenAddrType( proto=self, id_str=id_str )
|
||||
|
||||
def priv_key(self,s):
|
||||
return PrivKey( proto=self, s=s )
|
||||
|
||||
class Secp256k1(Base):
|
||||
"""
|
||||
Bitcoin and Ethereum protocols inherit from this class
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ tool.py: Routines for the 'mmgen-tool' utility
|
|||
from .protocol import hash160
|
||||
from .common import *
|
||||
from .crypto import *
|
||||
from .key import PrivKey
|
||||
from .seedsplit import MasterShareIdx
|
||||
from .addr import *
|
||||
from .addrlist import AddrList,KeyAddrList
|
||||
|
|
|
|||
|
|
@ -401,7 +401,8 @@ def parse_arg2():
|
|||
# begin execution
|
||||
from mmgen.protocol import init_proto
|
||||
from mmgen.altcoin import CoinInfo as ci
|
||||
from mmgen.obj import MMGenAddrType,PrivKey
|
||||
from mmgen.obj import MMGenAddrType
|
||||
from mmgen.key import PrivKey
|
||||
from mmgen.addr import KeyGenerator,AddrGenerator
|
||||
|
||||
addr_type = MMGenAddrType(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ tool_api_test.py: test the MMGen suite tool API
|
|||
|
||||
import sys,os
|
||||
from mmgen.common import *
|
||||
from mmgen.obj import PrivKey,CoinAddr
|
||||
from mmgen.key import PrivKey
|
||||
from mmgen.addr import CoinAddr
|
||||
|
||||
keys = [
|
||||
'118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492',
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from mmgen.protocol import *
|
|||
from mmgen.addr import *
|
||||
from mmgen.tx import *
|
||||
from mmgen.tw import *
|
||||
from mmgen.key import *
|
||||
from ..include.common import getrand
|
||||
|
||||
from collections import namedtuple
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ from mmgen.addr import *
|
|||
from mmgen.addrlist import *
|
||||
from mmgen.addrdata import *
|
||||
from mmgen.amt import *
|
||||
from mmgen.key import *
|
||||
|
||||
opts_data = {
|
||||
'sets': [('super_silent', True, 'silent', True)],
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ test.objtest_py_d.ot_btc_mainnet: BTC mainnet test vectors for MMGen data object
|
|||
from mmgen.obj import *
|
||||
from mmgen.addrlist import AddrIdxList
|
||||
from mmgen.seedsplit import *
|
||||
from mmgen.key import *
|
||||
from .ot_common import *
|
||||
|
||||
from mmgen.protocol import init_proto
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
|
|||
out.append(self._create_fake_unspent_entry(coinaddr,d['al_id'],idx,lbl,segwit=d['segwit']))
|
||||
|
||||
if non_mmgen_input:
|
||||
from mmgen.obj import PrivKey
|
||||
from mmgen.key import PrivKey
|
||||
privkey = PrivKey(
|
||||
self.proto,
|
||||
getrand(32),
|
||||
|
|
@ -417,7 +417,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
|
|||
return ad,tx_data
|
||||
|
||||
def _make_txcreate_cmdline(self,tx_data):
|
||||
from mmgen.obj import PrivKey
|
||||
from mmgen.key import PrivKey
|
||||
privkey = PrivKey(self.proto,getrand(32),compressed=True,pubkey_type='std')
|
||||
t = ('compressed','segwit')['S' in self.proto.mmtypes]
|
||||
from mmgen.addr import AddrGenerator,KeyGenerator
|
||||
|
|
|
|||
|
|
@ -185,7 +185,8 @@ if opt.list_names:
|
|||
)
|
||||
die(0,'\n{}\n {}'.format(yellow('Untested commands:'),'\n '.join(uc)))
|
||||
|
||||
from mmgen.tx import is_wif,is_coin_addr
|
||||
from mmgen.key import is_wif
|
||||
from mmgen.tx import is_coin_addr
|
||||
def is_wif_loc(s):
|
||||
return is_wif(proto,s)
|
||||
def is_coin_addr_loc(s):
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ NL = ('\n','\r\n')[g.platform=='win']
|
|||
def is_str(s):
|
||||
return type(s) == str
|
||||
|
||||
from mmgen.obj import is_wif,is_coin_addr
|
||||
from mmgen.key import is_wif
|
||||
from mmgen.obj import is_coin_addr
|
||||
def is_wif_loc(s):
|
||||
return is_wif(proto,s)
|
||||
def is_coin_addr_loc(s):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue