coin.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2022 The MMGen Project <mmgen@tuta.io>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. tool/coin.py: Cryptocoin routines for the 'mmgen-tool' utility
  20. """
  21. from collections import namedtuple
  22. generator_data = namedtuple('generator_data',['kg','ag'])
  23. from .common import tool_cmd_base
  24. from ..protocol import init_proto,init_genonly_altcoins,hash160
  25. from ..key import PrivKey
  26. from ..addr import KeyGenerator,AddrGenerator,MMGenAddrType,CoinAddr
  27. class tool_cmd(tool_cmd_base):
  28. """
  29. cryptocoin key/address utilities
  30. May require use of the '--coin', '--type' and/or '--testnet' options
  31. Examples:
  32. mmgen-tool --coin=ltc --type=bech32 wif2addr <wif key>
  33. mmgen-tool --coin=zec --type=zcash_z randpair
  34. """
  35. def __init__(self,proto=None,mmtype=None):
  36. if proto:
  37. self.proto = proto
  38. else:
  39. from ..protocol import init_proto_from_opts
  40. self.proto = init_proto_from_opts()
  41. from ..opts import opt
  42. self.mmtype = MMGenAddrType(
  43. self.proto,
  44. mmtype or opt.type or self.proto.dfl_mmtype )
  45. from ..globalvars import g
  46. if g.token:
  47. self.proto.tokensym = g.token.upper()
  48. def _init_generators(self,arg=None):
  49. return generator_data(
  50. kg = KeyGenerator( self.proto, self.mmtype.pubkey_type ),
  51. ag = AddrGenerator( self.proto, self.mmtype ),
  52. )
  53. def randwif(self):
  54. "generate a random private key in WIF format"
  55. from ..crypto import get_random
  56. return PrivKey(
  57. self.proto,
  58. get_random(32),
  59. pubkey_type = self.mmtype.pubkey_type,
  60. compressed = self.mmtype.compressed ).wif
  61. def randpair(self):
  62. "generate a random private key/address pair"
  63. gd = self._init_generators()
  64. from ..crypto import get_random
  65. privkey = PrivKey(
  66. self.proto,
  67. get_random(32),
  68. pubkey_type = self.mmtype.pubkey_type,
  69. compressed = self.mmtype.compressed )
  70. return (
  71. privkey.wif,
  72. gd.ag.to_addr( gd.kg.gen_data(privkey) ))
  73. def wif2hex(self,wifkey:'sstr'):
  74. "convert a private key from WIF to hex format"
  75. return PrivKey(
  76. self.proto,
  77. wif = wifkey ).hex()
  78. def hex2wif(self,privhex:'sstr'):
  79. "convert a private key from hex to WIF format"
  80. return PrivKey(
  81. self.proto,
  82. bytes.fromhex(privhex),
  83. pubkey_type = self.mmtype.pubkey_type,
  84. compressed = self.mmtype.compressed ).wif
  85. def wif2addr(self,wifkey:'sstr'):
  86. "generate a coin address from a key in WIF format"
  87. gd = self._init_generators()
  88. privkey = PrivKey(
  89. self.proto,
  90. wif = wifkey )
  91. return gd.ag.to_addr( gd.kg.gen_data(privkey) )
  92. def wif2redeem_script(self,wifkey:'sstr'): # new
  93. "convert a WIF private key to a Segwit P2SH-P2WPKH redeem script"
  94. assert self.mmtype.name == 'segwit','This command is meaningful only for --type=segwit'
  95. gd = self._init_generators()
  96. privkey = PrivKey(
  97. self.proto,
  98. wif = wifkey )
  99. return gd.ag.to_segwit_redeem_script( gd.kg.gen_data(privkey) )
  100. def wif2segwit_pair(self,wifkey:'sstr'):
  101. "generate both a Segwit P2SH-P2WPKH redeem script and address from WIF"
  102. assert self.mmtype.name == 'segwit','This command is meaningful only for --type=segwit'
  103. gd = self._init_generators()
  104. data = gd.kg.gen_data(PrivKey(
  105. self.proto,
  106. wif = wifkey ))
  107. return (
  108. gd.ag.to_segwit_redeem_script(data),
  109. gd.ag.to_addr(data) )
  110. def privhex2addr(self,privhex:'sstr',output_pubhex=False):
  111. "generate coin address from raw private key data in hexadecimal format"
  112. gd = self._init_generators()
  113. pk = PrivKey(
  114. self.proto,
  115. bytes.fromhex(privhex),
  116. compressed = self.mmtype.compressed,
  117. pubkey_type = self.mmtype.pubkey_type )
  118. data = gd.kg.gen_data(pk)
  119. return data.pubkey.hex() if output_pubhex else gd.ag.to_addr(data)
  120. def privhex2pubhex(self,privhex:'sstr'): # new
  121. "generate a hex public key from a hex private key"
  122. return self.privhex2addr(privhex,output_pubhex=True)
  123. def pubhex2addr(self,pubkeyhex:'sstr'):
  124. "convert a hex pubkey to an address"
  125. pubkey = bytes.fromhex(pubkeyhex)
  126. if self.mmtype.name == 'segwit':
  127. return self.proto.pubkey2segwitaddr( pubkey )
  128. else:
  129. return self.pubhash2addr( hash160(pubkey).hex() )
  130. def pubhex2redeem_script(self,pubkeyhex:'sstr'): # new
  131. "convert a hex pubkey to a Segwit P2SH-P2WPKH redeem script"
  132. assert self.mmtype.name == 'segwit','This command is meaningful only for --type=segwit'
  133. return self.proto.pubkey2redeem_script( bytes.fromhex(pubkeyhex) ).hex()
  134. def redeem_script2addr(self,redeem_scripthex:'sstr'): # new
  135. "convert a Segwit P2SH-P2WPKH redeem script to an address"
  136. assert self.mmtype.name == 'segwit', 'This command is meaningful only for --type=segwit'
  137. assert redeem_scripthex[:4] == '0014', f'{redeem_scripthex!r}: invalid redeem script'
  138. assert len(redeem_scripthex) == 44, f'{len(redeem_scripthex)//2} bytes: invalid redeem script length'
  139. return self.pubhash2addr( hash160(bytes.fromhex(redeem_scripthex)).hex() )
  140. def pubhash2addr(self,pubhashhex:'sstr'):
  141. "convert public key hash to address"
  142. pubhash = bytes.fromhex(pubhashhex)
  143. if self.mmtype.name == 'bech32':
  144. return self.proto.pubhash2bech32addr( pubhash )
  145. else:
  146. return self.proto.pubhash2addr( pubhash, self.mmtype.addr_fmt=='p2sh' )
  147. def addr2pubhash(self,addr:'sstr'):
  148. "convert coin address to public key hash"
  149. from ..tx import addr2pubhash
  150. return addr2pubhash( self.proto, CoinAddr(self.proto,addr) )
  151. def addr2scriptpubkey(self,addr:'sstr'):
  152. "convert coin address to scriptPubKey"
  153. from ..tx import addr2scriptPubKey
  154. return addr2scriptPubKey( self.proto, CoinAddr(self.proto,addr) )
  155. def scriptpubkey2addr(self,hexstr:'sstr'):
  156. "convert scriptPubKey to coin address"
  157. from ..tx import scriptPubKey2addr
  158. return scriptPubKey2addr( self.proto, hexstr )[0]