Module tronpytool.common.key
Expand source code
import hashlib
import random
from collections.abc import ByteString, Hashable
from typing import Any, Union
import base58
import ecdsa # type: ignore
from Crypto.Hash import keccak
from tronpytool.exceptions import BadKey, BadSignature, BadAddress
def keccak256(data: bytes) -> bytes:
hasher = keccak.new(digest_bits=256)
hasher.update(data)
return hasher.digest()
def assure_bytes(value: Union[str, bytes]) -> bytes:
if isinstance(value, (str,)):
return bytes.fromhex(value)
if isinstance(value, (bytes,)):
return value
raise ValueError("bad bytes format")
def sha256(data: bytes) -> bytes:
hasher = hashlib.sha256()
hasher.update(data)
return hasher.digest()
def public_key_to_base58check_addr(pub_key: bytes) -> str:
primitive_addr = b"\x41" + keccak256(pub_key)[-20:]
addr = base58.b58encode_check(primitive_addr)
return addr.decode()
def public_key_to_addr(pub_key: bytes) -> bytes:
return b"\x41" + keccak256(pub_key)[-20:]
def to_base58check_address(raw_addr: Union[str, bytes]) -> str:
"""Convert hex address or base58check address to base58check address(and verify it)."""
if isinstance(raw_addr, (str,)):
if raw_addr[0] == "T" and len(raw_addr) == 34:
try:
# assert checked
base58.b58decode_check(raw_addr)
except ValueError:
raise BadAddress("bad base58check format")
return raw_addr
elif len(raw_addr) == 42:
if raw_addr.startswith("0x"): # eth address format
return base58.b58encode_check(b"\x41" + bytes.fromhex(raw_addr[2:])).decode()
else:
return base58.b58encode_check(bytes.fromhex(raw_addr)).decode()
elif raw_addr.startswith("0x") and len(raw_addr) == 44:
return base58.b58encode_check(bytes.fromhex(raw_addr[2:])).decode()
elif isinstance(raw_addr, (bytes, bytearray)):
if len(raw_addr) == 21 and int(raw_addr[0]) == 0x41:
return base58.b58encode_check(raw_addr).decode()
if len(raw_addr) == 20: # eth address format
return base58.b58encode_check(b"\x41" + raw_addr).decode()
return to_base58check_address(raw_addr.decode())
raise BadAddress(repr(raw_addr))
def to_hex_address(raw_addr: Union[str, bytes]) -> str:
addr = to_base58check_address(raw_addr)
return base58.b58decode_check(addr).hex()
def to_raw_address(raw_addr: Union[str, bytes]) -> bytes:
addr = to_base58check_address(raw_addr)
return base58.b58decode_check(addr)
def to_tvm_address(raw_addr: Union[str, bytes]) -> bytes:
return to_raw_address(raw_addr)[1:]
def is_base58check_address(value: str) -> bool:
return value[0] == "T" and len(base58.b58decode_check(value)) == 21
def is_hex_address(value: str) -> bool:
return value.startswith("41") and len(bytes.fromhex(value)) == 21
def is_address(value: str) -> bool:
return is_base58check_address(value) or is_hex_address(value)
class BaseKey(ByteString, Hashable):
_raw_key = None # type: bytes
# compatible with bytes.hex()
def hex(self) -> str:
"""
Key as a hex str.
:returns: A hex str.
"""
return self._raw_key.hex()
@classmethod
def fromhex(cls, hex_str: str) -> "BaseKey":
"""
Construct a key from a hex str.
:returns: The key object.
"""
return cls(bytes.fromhex(hex_str))
def to_bytes(self) -> bytes:
return self._raw_key
def __hash__(self) -> int:
return int.from_bytes(self._raw_key, "big")
def __str__(self) -> str:
return self.hex()
def __int__(self) -> int:
return int.from_bytes(self._raw_key, "big")
def __len__(self) -> int:
return len(self._raw_key)
# Must be typed with `ignore` due to
# https://github.com/python/mypy/issues/1237
def __getitem__(self, index: int) -> int: # type: ignore
return self._raw_key[index]
def __eq__(self, other: Any) -> bool:
if hasattr(other, "to_bytes"):
return self.to_bytes() == other.to_bytes()
elif isinstance(other, (bytes, bytearray)):
return self.to_bytes() == other
else:
return False
def __repr__(self) -> str:
return repr(self.hex())
def __index__(self) -> int:
return self.__int__()
def __hex__(self) -> str:
return self.hex()
class PublicKey(BaseKey):
"""The public key."""
def __init__(self, public_key_bytes: bytes):
try:
assert isinstance(public_key_bytes, (bytes,))
assert len(public_key_bytes) == 64
except AssertionError:
raise BadKey
self._raw_key = public_key_bytes
super().__init__()
@classmethod
def recover_from_msg(cls, message: bytes, signature: "Signature"):
"""Recover public key(address) from raw message and signature."""
return signature.recover_public_key_from_msg(message)
@classmethod
def recover_from_msg_hash(cls, message_hash: bytes, signature: "Signature"):
"""Recover public key(address) from message hash and signature."""
return signature.recover_public_key_from_msg_hash(message_hash)
def verify_msg(self, message: bytes, signature: "Signature") -> bool:
"""Verify message and signature."""
return signature.verify_msg(message, self)
def verify_msg_hash(self, message_hash: bytes, signature: "Signature") -> bool:
"""Verify message hash and signature."""
return signature.verify_msg_hash(message_hash, self)
# Address conversions
def to_base58check_address(self) -> str:
"""Get the base58check address of the public key."""
return public_key_to_base58check_addr(self._raw_key)
def to_hex_address(self) -> str:
return public_key_to_addr(self._raw_key).hex()
def to_address(self) -> bytes:
return public_key_to_addr(self._raw_key)
def to_tvm_address(self) -> bytes:
return public_key_to_addr(self._raw_key)[1:]
class PrivateKey(BaseKey):
"""The private key."""
_pubkey = None
def __init__(self, private_key_bytes: bytes):
try:
assert isinstance(private_key_bytes, (bytes,))
assert len(private_key_bytes) == 32
assert (
0
< int.from_bytes(private_key_bytes, "big")
< 115792089237316195423570985008687907852837564279074904382605163141518161494337
)
except AssertionError:
raise BadKey
self._raw_key = private_key_bytes
priv_key = ecdsa.SigningKey.from_string(self._raw_key, curve=ecdsa.SECP256k1)
self._pubkey = PublicKey(priv_key.get_verifying_key().to_string())
super().__init__()
@property
def public_key(self) -> "PublicKey":
return self._pubkey
def sign_msg(self, message: bytes) -> "Signature":
"""Sign a raw message."""
sk = ecdsa.SigningKey.from_string(self._raw_key, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256)
signature = sk.sign_deterministic(message)
# recover address to get rec_id
vks = ecdsa.VerifyingKey.from_public_key_recovery(
signature, message, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256
)
for v, pk in enumerate(vks):
if pk.to_string() == self._pubkey:
break
signature += bytes([v])
return Signature(signature)
def sign_msg_hash(self, message_hash: bytes) -> "Signature":
"""Sign a message hash(sha256)."""
sk = ecdsa.SigningKey.from_string(self._raw_key, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256)
signature = sk.sign_digest_deterministic(message_hash)
# recover address to get rec_id
vks = ecdsa.VerifyingKey.from_public_key_recovery_with_digest(
signature, message_hash, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256
)
for v, pk in enumerate(vks):
if pk.to_string() == self._pubkey:
break
signature += bytes([v])
return Signature(signature)
@classmethod
def random(cls) -> "PrivateKey":
"""Generate a random private key."""
return cls(bytes([random.randint(0, 255) for _ in range(32)]))
@classmethod
def from_passphrase(cls, passphrase: bytes) -> "PrivateKey":
"""Get a private key from sha256 of a passphrase."""
return cls(sha256(passphrase))
class Signature(ByteString):
"""The signature object."""
_raw_signature = None
def __init__(self, signature_bytes: bytes):
try:
assert isinstance(signature_bytes, (bytes,))
assert len(signature_bytes) == 65
assert signature_bytes[-1] in [0, 1]
except AssertionError:
raise BadSignature
self._raw_signature = signature_bytes
super().__init__()
def recover_public_key_from_msg(self, message: bytes) -> PublicKey:
"""Recover public key(address) from message and signature."""
vks = ecdsa.VerifyingKey.from_public_key_recovery(
self._raw_signature[:64], message, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256
)
return PublicKey(vks[self.v].to_string())
def recover_public_key_from_msg_hash(self, message_hash: bytes) -> PublicKey:
"""Recover public key(address) from message hash and signature."""
vks = ecdsa.VerifyingKey.from_public_key_recovery_with_digest(
self._raw_signature[:64], message_hash, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256
)
return PublicKey(vks[self.v].to_string())
def verify_msg(self, message: bytes, public_key: PublicKey) -> bool:
"""Verify message and signature."""
vk = ecdsa.VerifyingKey.from_string(public_key.to_bytes(), curve=ecdsa.SECP256k1)
return vk.verify(self._raw_signature[:64], message, hashfunc=hashlib.sha256)
def verify_msg_hash(self, message_hash: bytes, public_key: PublicKey) -> bool:
"""Verify message hash and signature."""
vk = ecdsa.VerifyingKey.from_string(public_key.to_bytes(), curve=ecdsa.SECP256k1)
return vk.verify_digest(self._raw_signature[:64], message_hash)
@property
def v(self) -> int:
return self._raw_signature[64]
def hex(self) -> str:
"""
Return signature as a hex str.
:returns: A hex str.
"""
return self._raw_signature.hex()
@classmethod
def fromhex(cls, hex_str: str) -> 'Signature':
"""Construct a Signature from hex str."""
return cls(bytes.fromhex(hex_str))
def to_bytes(self) -> bytes:
return self._raw_signature
def __hash__(self) -> int:
return int.from_bytes(self._raw_signature, "big")
def __str__(self) -> str:
return self.hex()
def __int__(self) -> int:
return int.from_bytes(self._raw_signature, "big")
def __len__(self) -> int:
return 65
def __getitem__(self, index: int) -> int: # type: ignore
return self._raw_signature[index]
def __eq__(self, other: Any) -> bool:
if hasattr(other, "to_bytes"):
return self.to_bytes() == other.to_bytes()
elif isinstance(other, (bytes, bytearray)):
return self.to_bytes() == other
else:
return False
def __repr__(self) -> str:
return repr(self.hex())
def __index__(self) -> int:
return self.__int__()
def __hex__(self) -> str:
return self.hex()
Functions
def assure_bytes(value: Union[str, bytes]) ‑> bytes
-
Expand source code
def assure_bytes(value: Union[str, bytes]) -> bytes: if isinstance(value, (str,)): return bytes.fromhex(value) if isinstance(value, (bytes,)): return value raise ValueError("bad bytes format")
def is_address(value: str) ‑> bool
-
Expand source code
def is_address(value: str) -> bool: return is_base58check_address(value) or is_hex_address(value)
def is_base58check_address(value: str) ‑> bool
-
Expand source code
def is_base58check_address(value: str) -> bool: return value[0] == "T" and len(base58.b58decode_check(value)) == 21
def is_hex_address(value: str) ‑> bool
-
Expand source code
def is_hex_address(value: str) -> bool: return value.startswith("41") and len(bytes.fromhex(value)) == 21
def keccak256(data: bytes) ‑> bytes
-
Expand source code
def keccak256(data: bytes) -> bytes: hasher = keccak.new(digest_bits=256) hasher.update(data) return hasher.digest()
def public_key_to_addr(pub_key: bytes) ‑> bytes
-
Expand source code
def public_key_to_addr(pub_key: bytes) -> bytes: return b"\x41" + keccak256(pub_key)[-20:]
def public_key_to_base58check_addr(pub_key: bytes) ‑> str
-
Expand source code
def public_key_to_base58check_addr(pub_key: bytes) -> str: primitive_addr = b"\x41" + keccak256(pub_key)[-20:] addr = base58.b58encode_check(primitive_addr) return addr.decode()
def sha256(data: bytes) ‑> bytes
-
Expand source code
def sha256(data: bytes) -> bytes: hasher = hashlib.sha256() hasher.update(data) return hasher.digest()
def to_base58check_address(raw_addr: Union[str, bytes]) ‑> str
-
Convert hex address or base58check address to base58check address(and verify it).
Expand source code
def to_base58check_address(raw_addr: Union[str, bytes]) -> str: """Convert hex address or base58check address to base58check address(and verify it).""" if isinstance(raw_addr, (str,)): if raw_addr[0] == "T" and len(raw_addr) == 34: try: # assert checked base58.b58decode_check(raw_addr) except ValueError: raise BadAddress("bad base58check format") return raw_addr elif len(raw_addr) == 42: if raw_addr.startswith("0x"): # eth address format return base58.b58encode_check(b"\x41" + bytes.fromhex(raw_addr[2:])).decode() else: return base58.b58encode_check(bytes.fromhex(raw_addr)).decode() elif raw_addr.startswith("0x") and len(raw_addr) == 44: return base58.b58encode_check(bytes.fromhex(raw_addr[2:])).decode() elif isinstance(raw_addr, (bytes, bytearray)): if len(raw_addr) == 21 and int(raw_addr[0]) == 0x41: return base58.b58encode_check(raw_addr).decode() if len(raw_addr) == 20: # eth address format return base58.b58encode_check(b"\x41" + raw_addr).decode() return to_base58check_address(raw_addr.decode()) raise BadAddress(repr(raw_addr))
def to_hex_address(raw_addr: Union[str, bytes]) ‑> str
-
Expand source code
def to_hex_address(raw_addr: Union[str, bytes]) -> str: addr = to_base58check_address(raw_addr) return base58.b58decode_check(addr).hex()
def to_raw_address(raw_addr: Union[str, bytes]) ‑> bytes
-
Expand source code
def to_raw_address(raw_addr: Union[str, bytes]) -> bytes: addr = to_base58check_address(raw_addr) return base58.b58decode_check(addr)
def to_tvm_address(raw_addr: Union[str, bytes]) ‑> bytes
-
Expand source code
def to_tvm_address(raw_addr: Union[str, bytes]) -> bytes: return to_raw_address(raw_addr)[1:]
Classes
class BaseKey
-
This unifies bytes and bytearray.
XXX Should add all their methods.
Expand source code
class BaseKey(ByteString, Hashable): _raw_key = None # type: bytes # compatible with bytes.hex() def hex(self) -> str: """ Key as a hex str. :returns: A hex str. """ return self._raw_key.hex() @classmethod def fromhex(cls, hex_str: str) -> "BaseKey": """ Construct a key from a hex str. :returns: The key object. """ return cls(bytes.fromhex(hex_str)) def to_bytes(self) -> bytes: return self._raw_key def __hash__(self) -> int: return int.from_bytes(self._raw_key, "big") def __str__(self) -> str: return self.hex() def __int__(self) -> int: return int.from_bytes(self._raw_key, "big") def __len__(self) -> int: return len(self._raw_key) # Must be typed with `ignore` due to # https://github.com/python/mypy/issues/1237 def __getitem__(self, index: int) -> int: # type: ignore return self._raw_key[index] def __eq__(self, other: Any) -> bool: if hasattr(other, "to_bytes"): return self.to_bytes() == other.to_bytes() elif isinstance(other, (bytes, bytearray)): return self.to_bytes() == other else: return False def __repr__(self) -> str: return repr(self.hex()) def __index__(self) -> int: return self.__int__() def __hex__(self) -> str: return self.hex()
Ancestors
- collections.abc.ByteString
- collections.abc.Sequence
- collections.abc.Reversible
- collections.abc.Collection
- collections.abc.Sized
- collections.abc.Iterable
- collections.abc.Container
- collections.abc.Hashable
Subclasses
Static methods
def fromhex(hex_str: str) ‑> BaseKey
-
Construct a key from a hex str.
:returns: The key object.
Expand source code
@classmethod def fromhex(cls, hex_str: str) -> "BaseKey": """ Construct a key from a hex str. :returns: The key object. """ return cls(bytes.fromhex(hex_str))
Methods
def hex(self) ‑> str
-
Key as a hex str.
:returns: A hex str.
Expand source code
def hex(self) -> str: """ Key as a hex str. :returns: A hex str. """ return self._raw_key.hex()
def to_bytes(self) ‑> bytes
-
Expand source code
def to_bytes(self) -> bytes: return self._raw_key
class PrivateKey (private_key_bytes: bytes)
-
The private key.
Expand source code
class PrivateKey(BaseKey): """The private key.""" _pubkey = None def __init__(self, private_key_bytes: bytes): try: assert isinstance(private_key_bytes, (bytes,)) assert len(private_key_bytes) == 32 assert ( 0 < int.from_bytes(private_key_bytes, "big") < 115792089237316195423570985008687907852837564279074904382605163141518161494337 ) except AssertionError: raise BadKey self._raw_key = private_key_bytes priv_key = ecdsa.SigningKey.from_string(self._raw_key, curve=ecdsa.SECP256k1) self._pubkey = PublicKey(priv_key.get_verifying_key().to_string()) super().__init__() @property def public_key(self) -> "PublicKey": return self._pubkey def sign_msg(self, message: bytes) -> "Signature": """Sign a raw message.""" sk = ecdsa.SigningKey.from_string(self._raw_key, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256) signature = sk.sign_deterministic(message) # recover address to get rec_id vks = ecdsa.VerifyingKey.from_public_key_recovery( signature, message, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 ) for v, pk in enumerate(vks): if pk.to_string() == self._pubkey: break signature += bytes([v]) return Signature(signature) def sign_msg_hash(self, message_hash: bytes) -> "Signature": """Sign a message hash(sha256).""" sk = ecdsa.SigningKey.from_string(self._raw_key, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256) signature = sk.sign_digest_deterministic(message_hash) # recover address to get rec_id vks = ecdsa.VerifyingKey.from_public_key_recovery_with_digest( signature, message_hash, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 ) for v, pk in enumerate(vks): if pk.to_string() == self._pubkey: break signature += bytes([v]) return Signature(signature) @classmethod def random(cls) -> "PrivateKey": """Generate a random private key.""" return cls(bytes([random.randint(0, 255) for _ in range(32)])) @classmethod def from_passphrase(cls, passphrase: bytes) -> "PrivateKey": """Get a private key from sha256 of a passphrase.""" return cls(sha256(passphrase))
Ancestors
- BaseKey
- collections.abc.ByteString
- collections.abc.Sequence
- collections.abc.Reversible
- collections.abc.Collection
- collections.abc.Sized
- collections.abc.Iterable
- collections.abc.Container
- collections.abc.Hashable
Static methods
def from_passphrase(passphrase: bytes) ‑> PrivateKey
-
Get a private key from sha256 of a passphrase.
Expand source code
@classmethod def from_passphrase(cls, passphrase: bytes) -> "PrivateKey": """Get a private key from sha256 of a passphrase.""" return cls(sha256(passphrase))
def random() ‑> PrivateKey
-
Generate a random private key.
Expand source code
@classmethod def random(cls) -> "PrivateKey": """Generate a random private key.""" return cls(bytes([random.randint(0, 255) for _ in range(32)]))
Instance variables
var public_key : PublicKey
-
Expand source code
@property def public_key(self) -> "PublicKey": return self._pubkey
Methods
def sign_msg(self, message: bytes) ‑> Signature
-
Sign a raw message.
Expand source code
def sign_msg(self, message: bytes) -> "Signature": """Sign a raw message.""" sk = ecdsa.SigningKey.from_string(self._raw_key, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256) signature = sk.sign_deterministic(message) # recover address to get rec_id vks = ecdsa.VerifyingKey.from_public_key_recovery( signature, message, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 ) for v, pk in enumerate(vks): if pk.to_string() == self._pubkey: break signature += bytes([v]) return Signature(signature)
def sign_msg_hash(self, message_hash: bytes) ‑> Signature
-
Sign a message hash(sha256).
Expand source code
def sign_msg_hash(self, message_hash: bytes) -> "Signature": """Sign a message hash(sha256).""" sk = ecdsa.SigningKey.from_string(self._raw_key, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256) signature = sk.sign_digest_deterministic(message_hash) # recover address to get rec_id vks = ecdsa.VerifyingKey.from_public_key_recovery_with_digest( signature, message_hash, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 ) for v, pk in enumerate(vks): if pk.to_string() == self._pubkey: break signature += bytes([v]) return Signature(signature)
Inherited members
class PublicKey (public_key_bytes: bytes)
-
The public key.
Expand source code
class PublicKey(BaseKey): """The public key.""" def __init__(self, public_key_bytes: bytes): try: assert isinstance(public_key_bytes, (bytes,)) assert len(public_key_bytes) == 64 except AssertionError: raise BadKey self._raw_key = public_key_bytes super().__init__() @classmethod def recover_from_msg(cls, message: bytes, signature: "Signature"): """Recover public key(address) from raw message and signature.""" return signature.recover_public_key_from_msg(message) @classmethod def recover_from_msg_hash(cls, message_hash: bytes, signature: "Signature"): """Recover public key(address) from message hash and signature.""" return signature.recover_public_key_from_msg_hash(message_hash) def verify_msg(self, message: bytes, signature: "Signature") -> bool: """Verify message and signature.""" return signature.verify_msg(message, self) def verify_msg_hash(self, message_hash: bytes, signature: "Signature") -> bool: """Verify message hash and signature.""" return signature.verify_msg_hash(message_hash, self) # Address conversions def to_base58check_address(self) -> str: """Get the base58check address of the public key.""" return public_key_to_base58check_addr(self._raw_key) def to_hex_address(self) -> str: return public_key_to_addr(self._raw_key).hex() def to_address(self) -> bytes: return public_key_to_addr(self._raw_key) def to_tvm_address(self) -> bytes: return public_key_to_addr(self._raw_key)[1:]
Ancestors
- BaseKey
- collections.abc.ByteString
- collections.abc.Sequence
- collections.abc.Reversible
- collections.abc.Collection
- collections.abc.Sized
- collections.abc.Iterable
- collections.abc.Container
- collections.abc.Hashable
Static methods
def recover_from_msg(message: bytes, signature: Signature)
-
Recover public key(address) from raw message and signature.
Expand source code
@classmethod def recover_from_msg(cls, message: bytes, signature: "Signature"): """Recover public key(address) from raw message and signature.""" return signature.recover_public_key_from_msg(message)
def recover_from_msg_hash(message_hash: bytes, signature: Signature)
-
Recover public key(address) from message hash and signature.
Expand source code
@classmethod def recover_from_msg_hash(cls, message_hash: bytes, signature: "Signature"): """Recover public key(address) from message hash and signature.""" return signature.recover_public_key_from_msg_hash(message_hash)
Methods
def to_address(self) ‑> bytes
-
Expand source code
def to_address(self) -> bytes: return public_key_to_addr(self._raw_key)
def to_base58check_address(self) ‑> str
-
Get the base58check address of the public key.
Expand source code
def to_base58check_address(self) -> str: """Get the base58check address of the public key.""" return public_key_to_base58check_addr(self._raw_key)
def to_hex_address(self) ‑> str
-
Expand source code
def to_hex_address(self) -> str: return public_key_to_addr(self._raw_key).hex()
def to_tvm_address(self) ‑> bytes
-
Expand source code
def to_tvm_address(self) -> bytes: return public_key_to_addr(self._raw_key)[1:]
def verify_msg(self, message: bytes, signature: Signature) ‑> bool
-
Verify message and signature.
Expand source code
def verify_msg(self, message: bytes, signature: "Signature") -> bool: """Verify message and signature.""" return signature.verify_msg(message, self)
def verify_msg_hash(self, message_hash: bytes, signature: Signature) ‑> bool
-
Verify message hash and signature.
Expand source code
def verify_msg_hash(self, message_hash: bytes, signature: "Signature") -> bool: """Verify message hash and signature.""" return signature.verify_msg_hash(message_hash, self)
Inherited members
class Signature (signature_bytes: bytes)
-
The signature object.
Expand source code
class Signature(ByteString): """The signature object.""" _raw_signature = None def __init__(self, signature_bytes: bytes): try: assert isinstance(signature_bytes, (bytes,)) assert len(signature_bytes) == 65 assert signature_bytes[-1] in [0, 1] except AssertionError: raise BadSignature self._raw_signature = signature_bytes super().__init__() def recover_public_key_from_msg(self, message: bytes) -> PublicKey: """Recover public key(address) from message and signature.""" vks = ecdsa.VerifyingKey.from_public_key_recovery( self._raw_signature[:64], message, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 ) return PublicKey(vks[self.v].to_string()) def recover_public_key_from_msg_hash(self, message_hash: bytes) -> PublicKey: """Recover public key(address) from message hash and signature.""" vks = ecdsa.VerifyingKey.from_public_key_recovery_with_digest( self._raw_signature[:64], message_hash, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 ) return PublicKey(vks[self.v].to_string()) def verify_msg(self, message: bytes, public_key: PublicKey) -> bool: """Verify message and signature.""" vk = ecdsa.VerifyingKey.from_string(public_key.to_bytes(), curve=ecdsa.SECP256k1) return vk.verify(self._raw_signature[:64], message, hashfunc=hashlib.sha256) def verify_msg_hash(self, message_hash: bytes, public_key: PublicKey) -> bool: """Verify message hash and signature.""" vk = ecdsa.VerifyingKey.from_string(public_key.to_bytes(), curve=ecdsa.SECP256k1) return vk.verify_digest(self._raw_signature[:64], message_hash) @property def v(self) -> int: return self._raw_signature[64] def hex(self) -> str: """ Return signature as a hex str. :returns: A hex str. """ return self._raw_signature.hex() @classmethod def fromhex(cls, hex_str: str) -> 'Signature': """Construct a Signature from hex str.""" return cls(bytes.fromhex(hex_str)) def to_bytes(self) -> bytes: return self._raw_signature def __hash__(self) -> int: return int.from_bytes(self._raw_signature, "big") def __str__(self) -> str: return self.hex() def __int__(self) -> int: return int.from_bytes(self._raw_signature, "big") def __len__(self) -> int: return 65 def __getitem__(self, index: int) -> int: # type: ignore return self._raw_signature[index] def __eq__(self, other: Any) -> bool: if hasattr(other, "to_bytes"): return self.to_bytes() == other.to_bytes() elif isinstance(other, (bytes, bytearray)): return self.to_bytes() == other else: return False def __repr__(self) -> str: return repr(self.hex()) def __index__(self) -> int: return self.__int__() def __hex__(self) -> str: return self.hex()
Ancestors
- collections.abc.ByteString
- collections.abc.Sequence
- collections.abc.Reversible
- collections.abc.Collection
- collections.abc.Sized
- collections.abc.Iterable
- collections.abc.Container
Static methods
def fromhex(hex_str: str) ‑> Signature
-
Construct a Signature from hex str.
Expand source code
@classmethod def fromhex(cls, hex_str: str) -> 'Signature': """Construct a Signature from hex str.""" return cls(bytes.fromhex(hex_str))
Instance variables
var v : int
-
Expand source code
@property def v(self) -> int: return self._raw_signature[64]
Methods
def hex(self) ‑> str
-
Return signature as a hex str.
:returns: A hex str.
Expand source code
def hex(self) -> str: """ Return signature as a hex str. :returns: A hex str. """ return self._raw_signature.hex()
def recover_public_key_from_msg(self, message: bytes) ‑> PublicKey
-
Recover public key(address) from message and signature.
Expand source code
def recover_public_key_from_msg(self, message: bytes) -> PublicKey: """Recover public key(address) from message and signature.""" vks = ecdsa.VerifyingKey.from_public_key_recovery( self._raw_signature[:64], message, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 ) return PublicKey(vks[self.v].to_string())
def recover_public_key_from_msg_hash(self, message_hash: bytes) ‑> PublicKey
-
Recover public key(address) from message hash and signature.
Expand source code
def recover_public_key_from_msg_hash(self, message_hash: bytes) -> PublicKey: """Recover public key(address) from message hash and signature.""" vks = ecdsa.VerifyingKey.from_public_key_recovery_with_digest( self._raw_signature[:64], message_hash, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256 ) return PublicKey(vks[self.v].to_string())
def to_bytes(self) ‑> bytes
-
Expand source code
def to_bytes(self) -> bytes: return self._raw_signature
def verify_msg(self, message: bytes, public_key: PublicKey) ‑> bool
-
Verify message and signature.
Expand source code
def verify_msg(self, message: bytes, public_key: PublicKey) -> bool: """Verify message and signature.""" vk = ecdsa.VerifyingKey.from_string(public_key.to_bytes(), curve=ecdsa.SECP256k1) return vk.verify(self._raw_signature[:64], message, hashfunc=hashlib.sha256)
def verify_msg_hash(self, message_hash: bytes, public_key: PublicKey) ‑> bool
-
Verify message hash and signature.
Expand source code
def verify_msg_hash(self, message_hash: bytes, public_key: PublicKey) -> bool: """Verify message hash and signature.""" vk = ecdsa.VerifyingKey.from_string(public_key.to_bytes(), curve=ecdsa.SECP256k1) return vk.verify_digest(self._raw_signature[:64], message_hash)