← Files AgentBrokoARCHIVED FILE
.venv/Lib/site-packages/eth_keys/datatypes.py
12.1 KB · Sep 30, 2026 · 23:15 UTC
from abc import (
ABC,
abstractmethod,
)
import codecs
import collections
from typing import (
TYPE_CHECKING,
Any,
Tuple,
Type,
Union,
)
from eth_typing import (
ChecksumAddress,
)
from eth_utils import (
ValidationError,
big_endian_to_int,
encode_hex,
int_to_big_endian,
is_bytes,
is_string,
keccak,
to_checksum_address,
to_normalized_address,
)
from eth_keys.exceptions import (
BadSignature,
)
from eth_keys.utils.address import (
public_key_bytes_to_address,
)
from eth_keys.utils.numeric import (
int_to_byte,
)
from eth_keys.utils.padding import (
pad32,
)
from eth_keys.validation import (
validate_compressed_public_key_bytes,
validate_non_recoverable_signature_bytes,
validate_private_key_bytes,
validate_recoverable_signature_bytes,
validate_signature_r_or_s,
validate_signature_v,
validate_uncompressed_public_key_bytes,
)
if TYPE_CHECKING:
from eth_keys.backends.base import (
BaseECCBackend,
)
class LazyBackend:
def __init__(
self,
backend: "Union[BaseECCBackend, Type[BaseECCBackend], str, None]" = None,
) -> None:
from eth_keys.backends.base import ( # noqa: F811
BaseECCBackend,
)
if backend is None:
pass
elif isinstance(backend, BaseECCBackend):
pass
elif isinstance(backend, type) and issubclass(backend, BaseECCBackend):
backend = backend()
elif is_string(backend):
backend = self.get_backend(backend)
else:
raise ValueError(
"Unsupported format for ECC backend. Must be an instance or "
"subclass of `eth_keys.backends.BaseECCBackend` or a string of "
"the dot-separated import path for the desired backend class"
)
self.backend = backend
_backend: "BaseECCBackend" = None
@property
def backend(self) -> "BaseECCBackend":
if self._backend is None:
return self.get_backend()
else:
return self._backend
@backend.setter
def backend(self, value: "BaseECCBackend") -> None:
self._backend = value
@classmethod
def get_backend(cls, *args: Any, **kwargs: Any) -> "BaseECCBackend":
from eth_keys.backends import (
get_backend,
)
return get_backend(*args, **kwargs)
class BaseKey(collections.abc.Hashable):
_raw_key: bytes = None
def to_hex(self) -> str:
return "0x" + codecs.decode(codecs.encode(self._raw_key, "hex"), "ascii")
def to_bytes(self) -> bytes:
return self._raw_key
def __hash__(self) -> int:
return big_endian_to_int(keccak(self.to_bytes()))
def __str__(self) -> str:
return self.to_hex()
def __int__(self) -> int:
return big_endian_to_int(self._raw_key)
def __len__(self) -> int:
# TODO: this seems wrong.
return 64
def __getitem__(self, index: int) -> int:
return self._raw_key[index]
def __eq__(self, other: Any) -> bool:
if hasattr(other, "to_bytes"):
return self.to_bytes() == other.to_bytes()
elif is_bytes(other):
return self.to_bytes() == other
else:
return False
def __repr__(self) -> str:
return f"'{self.to_hex()}'"
def __index__(self) -> int:
return self.__int__()
def __hex__(self) -> str:
return self.to_hex()
class PublicKey(BaseKey, LazyBackend):
def __init__(
self,
public_key_bytes: bytes,
backend: "Union[BaseECCBackend, Type[BaseECCBackend], str, None]" = None,
) -> None:
validate_uncompressed_public_key_bytes(public_key_bytes)
self._raw_key = public_key_bytes
super().__init__(backend=backend)
@classmethod
def from_compressed_bytes(
cls,
compressed_public_key_bytes: bytes,
backend: "BaseECCBackend" = None,
) -> "PublicKey":
validate_compressed_public_key_bytes(compressed_public_key_bytes)
if backend is None:
backend = cls.get_backend()
uncompressed_key = backend.decompress_public_key_bytes(
compressed_public_key_bytes
)
return cls(uncompressed_key, backend)
@classmethod
def from_private(
cls,
private_key: "PrivateKey",
backend: "BaseECCBackend" = None,
) -> "PublicKey":
if backend is None:
backend = cls.get_backend()
return backend.private_key_to_public_key(private_key)
@classmethod
def recover_from_msg(
cls,
message: bytes,
signature: "Signature",
backend: "BaseECCBackend" = None,
) -> "PublicKey":
message_hash = keccak(message)
return cls.recover_from_msg_hash(message_hash, signature, backend)
@classmethod
def recover_from_msg_hash(
cls,
message_hash: bytes,
signature: "Signature",
backend: "BaseECCBackend" = None,
) -> "PublicKey":
if backend is None:
backend = cls.get_backend()
return backend.ecdsa_recover(message_hash, signature)
def verify_msg(
self,
message: bytes,
signature: "Signature",
) -> bool:
message_hash = keccak(message)
return self.verify_msg_hash(message_hash, signature)
def verify_msg_hash(
self,
message_hash: bytes,
signature: "Signature",
) -> bool:
return self.backend.ecdsa_verify(message_hash, signature, self)
def to_compressed_bytes(self) -> bytes:
return self.backend.compress_public_key_bytes(self.to_bytes())
#
# Ethereum address conversions
#
def to_checksum_address(self) -> ChecksumAddress:
return to_checksum_address(public_key_bytes_to_address(self.to_bytes()))
def to_address(self) -> str:
return to_normalized_address(public_key_bytes_to_address(self.to_bytes()))
def to_canonical_address(self) -> bytes:
return public_key_bytes_to_address(self.to_bytes())
class PrivateKey(BaseKey, LazyBackend):
def __init__(
self,
private_key_bytes: bytes,
backend: "Union[BaseECCBackend, Type[BaseECCBackend], str, None]" = None,
) -> None:
validate_private_key_bytes(private_key_bytes)
self._raw_key = private_key_bytes
super().__init__(backend=backend)
self.public_key: PublicKey = self.backend.private_key_to_public_key(self)
def sign_msg(self, message: bytes) -> "Signature":
message_hash = keccak(message)
return self.sign_msg_hash(message_hash)
def sign_msg_hash(self, message_hash: bytes) -> "Signature":
return self.backend.ecdsa_sign(message_hash, self)
def sign_msg_non_recoverable(self, message: bytes) -> "NonRecoverableSignature":
message_hash = keccak(message)
return self.sign_msg_hash_non_recoverable(message_hash)
def sign_msg_hash_non_recoverable(
self, message_hash: bytes
) -> "NonRecoverableSignature":
return self.backend.ecdsa_sign_non_recoverable(message_hash, self)
class BaseSignature(LazyBackend, ABC):
_r: int = None
_s: int = None
def __init__(
self,
rs: Tuple[int, int],
backend: "Union[BaseECCBackend, Type[BaseECCBackend], str, None]" = None,
) -> None:
for value in rs:
try:
validate_signature_r_or_s(value)
except ValidationError as error:
raise BadSignature(error) from error
self._r, self._s = rs
super().__init__(backend=backend)
@property
def r(self) -> int:
return self._r
@property
def s(self) -> int:
return self._s
@property
def rs(self) -> Tuple[int, int]:
return (self.r, self.s)
@abstractmethod
def to_bytes(self) -> bytes:
pass
def __bytes__(self) -> bytes:
return self.to_bytes()
def to_hex(self) -> str:
return encode_hex(self.to_bytes())
def __hash__(self) -> int:
return big_endian_to_int(keccak(self.to_bytes()))
def __str__(self) -> str:
return self.to_hex()
def __len__(self) -> int:
return len(bytes(self))
def __eq__(self, other: Any) -> bool:
if hasattr(other, "to_bytes"):
return self.to_bytes() == other.to_bytes()
elif is_bytes(other):
return self.to_bytes() == other
else:
return False
def __getitem__(self, index: int) -> int:
return self.to_bytes()[index]
def __repr__(self) -> str:
return f"'{self.to_hex()}'"
def __index__(self) -> int:
return self.__int__()
def __hex__(self) -> str:
return self.to_hex()
def __int__(self) -> int:
return big_endian_to_int(self.to_bytes())
def verify_msg(self, message: bytes, public_key: PublicKey) -> bool:
message_hash = keccak(message)
return self.verify_msg_hash(message_hash, public_key)
def verify_msg_hash(self, message_hash: bytes, public_key: PublicKey) -> bool:
return self.backend.ecdsa_verify(message_hash, self, public_key)
class Signature(BaseSignature):
_v: int = None
def __init__(
self,
signature_bytes: bytes = None,
vrs: Tuple[int, int, int] = None,
backend: "Union[BaseECCBackend, Type[BaseECCBackend], str, None]" = None,
) -> None:
if bool(signature_bytes) is bool(vrs):
raise TypeError("You must provide one of `signature_bytes` or `vrs`")
elif signature_bytes:
validate_recoverable_signature_bytes(signature_bytes)
r = big_endian_to_int(signature_bytes[0:32])
s = big_endian_to_int(signature_bytes[32:64])
v = ord(signature_bytes[64:65])
elif vrs:
(
v,
r,
s,
) = vrs
else:
raise TypeError("Invariant: unreachable code path")
super().__init__(rs=(r, s), backend=backend)
try:
self.v = v
except ValidationError as error:
raise BadSignature(str(error)) from error
#
# v
#
@property
def v(self) -> int:
return self._v
@v.setter
def v(self, value: int) -> None:
validate_signature_v(value)
self._v = value
@BaseSignature.r.setter # type: ignore
def r(self, value: int) -> None:
validate_signature_r_or_s(value)
self._r = value
@BaseSignature.s.setter # type: ignore
def s(self, value: int) -> None:
validate_signature_r_or_s(value)
self._s = value
@property
def vrs(self) -> Tuple[int, int, int]:
return (self.v, self.r, self.s)
def to_bytes(self) -> bytes:
vb = int_to_byte(self.v)
rb = pad32(int_to_big_endian(self.r))
sb = pad32(int_to_big_endian(self.s))
return b"".join((rb, sb, vb))
def recover_public_key_from_msg(self, message: bytes) -> PublicKey:
message_hash = keccak(message)
return self.recover_public_key_from_msg_hash(message_hash)
def recover_public_key_from_msg_hash(self, message_hash: bytes) -> PublicKey:
return self.backend.ecdsa_recover(message_hash, self)
def to_non_recoverable_signature(self) -> "NonRecoverableSignature":
return NonRecoverableSignature(rs=self.rs)
class NonRecoverableSignature(BaseSignature):
def __init__(
self,
signature_bytes: bytes = None,
rs: Tuple[int, int] = None,
backend: "Union[BaseECCBackend, Type[BaseECCBackend], str, None]" = None,
) -> None:
if signature_bytes is None and rs is None:
raise TypeError("You must provide one of `signature_bytes` or `vr`")
elif signature_bytes:
validate_non_recoverable_signature_bytes(signature_bytes)
r = big_endian_to_int(signature_bytes[0:32])
s = big_endian_to_int(signature_bytes[32:64])
elif rs:
r, s = rs
else:
raise Exception("Invariant: unreachable code path")
super().__init__(rs=(r, s), backend=backend)
def to_bytes(self) -> bytes:
return b"".join(pad32(int_to_big_endian(value)) for value in self.rs)
SHA-256: 0db756cac46977b1f1fa67622a3b53f9fffba67abffc16e1b35a1b7ca62289c7