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 test_avail(cls,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(backend,pubkey_type,desc='keygen backend'):
  64. from .util import is_int,qmsg,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. f'Configured backends: ' +
  71. ' '.join( f'{n}:{k}' for n,k in enumerate(backends,1) )
  72. )
  73. qmsg(f'Using backend {backends[int(backend)-1]!r} for public key generation')
  74. return True
  75. def check_backend(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. backend,
  80. pubkey_type,
  81. desc = '--keygen-backend parameter' )
  82. def KeyGenerator(proto,pubkey_type,backend=None,silent=False):
  83. """
  84. factory function returning a key generator backend for the specified pubkey type
  85. """
  86. assert pubkey_type in proto.pubkey_types, f'{pubkey_type!r}: invalid pubkey type for coin {proto.coin}'
  87. pubkey_type_cls = get_pubkey_type_cls(pubkey_type)
  88. from .opts import opt
  89. backend = backend or opt.keygen_backend
  90. if backend:
  91. _check_backend(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. ).test_avail(silent=silent)
  97. return getattr(pubkey_type_cls,backend_clsname)()