| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- #!/usr/bin/env python3
- #
- # mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
- # Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
- # Licensed under the GNU General Public License, Version 3:
- # https://www.gnu.org/licenses
- # Public project repositories:
- # https://github.com/mmgen/mmgen-wallet
- # https://gitlab.com/mmgen/mmgen-wallet
- """
- proto.secp256k1.keygen: secp256k1 public key generation backends for the MMGen suite
- """
- from ...key import PubKey
- from ...keygen import keygen_base
- class backend:
- class libsecp256k1(keygen_base):
- production_safe = True
- def __init__(self,cfg):
- super().__init__(cfg)
- # catch ImportError to satisfy pylint when testing repo with unbuilt secp256k1 extension mod:
- try:
- from .secp256k1 import pubkey_gen
- self.pubkey_gen = pubkey_gen
- except ImportError:
- from ...util import die
- die(3,'libsecp256k1.keygen.backend: you shouldn’t be seeing this')
- def to_pubkey(self,privkey):
- return PubKey(
- s = self.pubkey_gen( privkey, int(privkey.compressed) ),
- compressed = privkey.compressed )
- @classmethod
- def get_clsname(cls,cfg,silent=False):
- try:
- from .secp256k1 import pubkey_gen
- if not pubkey_gen(bytes.fromhex('deadbeef'*8),1):
- from ...util import die
- die( 'ExtensionModuleError',
- 'Unable to execute pubkey_gen() from secp256k1 extension module' )
- return cls.__name__
- except ImportError as e:
- if not silent:
- from ...util import ymsg
- ymsg(str(e))
- cfg._util.qmsg('Using (slow) native Python ECDSA library for public key generation')
- return 'python_ecdsa'
- class python_ecdsa(keygen_base):
- production_safe = False
- def __init__(self,cfg):
- super().__init__(cfg)
- import ecdsa
- self.ecdsa = ecdsa
- def to_pubkey(self,privkey):
- """
- devdoc/guide_wallets.md:
- Uncompressed public keys start with 0x04; compressed public keys begin with 0x03 or
- 0x02 depending on whether they're greater or less than the midpoint of the curve.
- """
- def privnum2pubkey(numpriv,compressed=False):
- pk = self.ecdsa.SigningKey.from_secret_exponent(numpriv,curve=self.ecdsa.SECP256k1)
- # vk_bytes = x (32 bytes) + y (32 bytes) (unsigned big-endian)
- vk_bytes = pk.verifying_key.to_string()
- if compressed: # discard Y coord, replace with appropriate version byte
- # even y: <0, odd y: >0 -- https://bitcointalk.org/index.php?topic=129652.0
- return (b'\x03' if vk_bytes[-1] & 1 else b'\x02') + vk_bytes[:32]
- else:
- return b'\x04' + vk_bytes
- return PubKey(
- s = privnum2pubkey( int.from_bytes(privkey,'big'), compressed=privkey.compressed ),
- compressed = privkey.compressed )
|