keygen.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2023 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. keygen: Public key generation initialization code for the MMGen suite
  20. """
  21. from collections import namedtuple
  22. from .key import PrivKey
  23. keygen_public_data = namedtuple(
  24. 'keygen_public_data', [
  25. 'pubkey',
  26. 'viewkey_bytes',
  27. 'pubkey_type',
  28. 'compressed' ])
  29. class keygen_base:
  30. def gen_data(self,privkey):
  31. assert isinstance(privkey,PrivKey)
  32. return keygen_public_data(
  33. self.to_pubkey(privkey),
  34. self.to_viewkey(privkey),
  35. privkey.pubkey_type,
  36. privkey.compressed )
  37. def to_viewkey(self,privkey):
  38. return None
  39. @classmethod
  40. def get_clsname(cls,cfg,silent=False):
  41. return cls.__name__
  42. backend_data = {
  43. 'std': {
  44. 'backends': ('libsecp256k1','python-ecdsa'),
  45. 'package': 'secp256k1',
  46. },
  47. 'monero': {
  48. 'backends': ('nacl','ed25519ll-djbec','ed25519'),
  49. 'package': 'xmr',
  50. },
  51. 'zcash_z': {
  52. 'backends': ('nacl',),
  53. 'package': 'zec',
  54. },
  55. }
  56. def get_backends(pubkey_type):
  57. return backend_data[pubkey_type]['backends']
  58. def get_pubkey_type_cls(pubkey_type):
  59. import importlib
  60. return getattr(
  61. importlib.import_module(f'mmgen.proto.{backend_data[pubkey_type]["package"]}.keygen'),
  62. 'backend' )
  63. def _check_backend(cfg,backend,pubkey_type,desc='keygen backend'):
  64. from .util import is_int,die
  65. assert is_int(backend), f'illegal value for {desc} (must be an integer)'
  66. backends = get_backends(pubkey_type)
  67. if not (1 <= int(backend) <= len(backends)):
  68. die(1,
  69. f'{backend}: {desc} out of range\n' +
  70. 'Configured backends: ' +
  71. ' '.join( f'{n}:{k}' for n,k in enumerate(backends,1) )
  72. )
  73. cfg._util.qmsg(f'Using backend {backends[int(backend)-1]!r} for public key generation')
  74. return True
  75. def check_backend(cfg,proto,backend,addr_type):
  76. from .addr import MMGenAddrType
  77. pubkey_type = MMGenAddrType(proto,addr_type or proto.dfl_mmtype).pubkey_type
  78. return _check_backend(
  79. cfg,
  80. backend,
  81. pubkey_type,
  82. desc = '--keygen-backend parameter' )
  83. def KeyGenerator(cfg,proto,pubkey_type,backend=None,silent=False):
  84. """
  85. factory function returning a key generator backend for the specified pubkey type
  86. """
  87. assert pubkey_type in proto.pubkey_types, f'{pubkey_type!r}: invalid pubkey type for coin {proto.coin}'
  88. pubkey_type_cls = get_pubkey_type_cls(pubkey_type)
  89. backend = backend or cfg.keygen_backend
  90. if backend:
  91. _check_backend( cfg, backend, pubkey_type )
  92. backend_id = backend_data[pubkey_type]['backends'][int(backend) - 1 if backend else 0]
  93. backend_clsname = getattr(
  94. pubkey_type_cls,
  95. backend_id.replace('-','_')
  96. ).get_clsname(cfg,silent=silent)
  97. return getattr(pubkey_type_cls,backend_clsname)(cfg)