diff --git a/setup.cfg b/setup.cfg index 6e006a2165..4512b19f57 100644 --- a/setup.cfg +++ b/setup.cfg @@ -109,7 +109,7 @@ packages = package_dir = =src -python_requires = >=3.10 +python_requires = >=3.11 install_requires = pycryptodome>=3,<4 coincurve>=20,<21 diff --git a/src/ethereum/crypto/elliptic_curve.py b/src/ethereum/crypto/elliptic_curve.py index 3e5e5dbdc3..01aa56323c 100644 --- a/src/ethereum/crypto/elliptic_curve.py +++ b/src/ethereum/crypto/elliptic_curve.py @@ -3,7 +3,7 @@ ^^^^^^^^^^^^^^^ """ -from typing import Generic, Type, TypeVar +from typing import Generic, Type, TypeVar, Self import coincurve from ethereum_types.bytes import Bytes @@ -17,7 +17,6 @@ ) F = TypeVar("F", bound=Field) -T = TypeVar("T", bound="EllipticCurve") def secp256k1_recover(r: U256, s: U256, v: U256, msg_hash: Hash32) -> Bytes: @@ -69,7 +68,7 @@ class EllipticCurve(Generic[F]): x: F y: F - def __new__(cls: Type[T], x: F, y: F) -> T: + def __new__(cls, x: F, y: F) -> Self: """ Make new point on the curve. The point is not checked to see if it is on the curve. @@ -104,7 +103,7 @@ def __str__(self) -> str: return str((self.x, self.y)) @classmethod - def point_at_infinity(cls: Type[T]) -> T: + def point_at_infinity(cls) -> Self: """ Return the point at infinity. This is the identity element of the group operation. @@ -114,7 +113,7 @@ def point_at_infinity(cls: Type[T]) -> T: """ return cls.__new__(cls, cls.FIELD.zero(), cls.FIELD.zero()) - def double(self: T) -> T: + def double(self) -> Self: """ Add a point to itself. """ @@ -126,7 +125,7 @@ def double(self: T) -> T: new_y = lam * (x - new_x) - y return self.__new__(type(self), new_x, new_y) - def __add__(self: T, other: T) -> T: + def __add__(self, other: Self) -> Self: """ Add two points together. """ @@ -146,7 +145,7 @@ def __add__(self: T, other: T) -> T: y = lam * (self_x - x) - self_y return self.__new__(type(self), x, y) - def mul_by(self: T, n: int) -> T: + def mul_by(self, n: int) -> Self: """ Multiply `self` by `n` using the double and add algorithm. """ diff --git a/src/ethereum/crypto/finite_field.py b/src/ethereum/crypto/finite_field.py index 1e1fc6d5df..bc95cbf1ff 100644 --- a/src/ethereum/crypto/finite_field.py +++ b/src/ethereum/crypto/finite_field.py @@ -5,13 +5,11 @@ # flake8: noqa: D102, D105 -from typing import Iterable, List, Tuple, Type, TypeVar, cast +from typing import Iterable, List, Tuple, Type, TypeVar, Self, cast from ethereum_types.bytes import Bytes, Bytes32 from typing_extensions import Protocol -F = TypeVar("F", bound="Field") - class Field(Protocol): """ @@ -21,52 +19,64 @@ class Field(Protocol): __slots__ = () @classmethod - def zero(cls: Type[F]) -> F: + def zero(cls) -> Self: + """Returns the additive identity (0) of the field.""" ... @classmethod - def from_int(cls: Type[F], n: int) -> F: + def from_int(cls, n: int) -> Self: + """Constructs a field element from an integer.""" ... - def __radd__(self: F, left: F) -> F: + def __radd__(self, left: Self) -> Self: + """Reverse addition (left + self).""" ... - def __add__(self: F, right: F) -> F: + def __add__(self, right: Self) -> Self: + """Field addition (self + right).""" ... - def __iadd__(self: F, right: F) -> F: + def __iadd__(self, right: Self) -> Self: + """In-place addition (self += right).""" ... - def __sub__(self: F, right: F) -> F: + def __sub__(self, right: Self) -> Self: + """Field subtraction (self - right).""" ... - def __rsub__(self: F, left: F) -> F: + def __rsub__(self, left: Self) -> Self: + """Reverse subtraction (left - self).""" ... - def __mul__(self: F, right: F) -> F: + def __mul__(self, right: Self) -> Self: + """Field multiplication (self * right).""" ... - def __rmul__(self: F, left: F) -> F: + def __rmul__(self, left: Self) -> Self: + """Reverse multiplication (left * self).""" ... - def __imul__(self: F, right: F) -> F: + def __imul__(self, right: Self) -> Self: + """In-place multiplication (self *= right).""" ... - def __pow__(self: F, exponent: int) -> F: + def __pow__(self, exponent: int) -> Self: + """Field exponentiation (self ** exponent).""" ... - def __ipow__(self: F, right: int) -> F: + def __ipow__(self, right: int) -> Self: + """In-place exponentiation (self **= right).""" ... - def __neg__(self: F) -> F: + def __neg__(self) -> Self: + """Additive inverse (-self).""" ... - def __truediv__(self: F, right: F) -> F: + def __truediv__(self, right: Self) -> Self: + """Field division (self / right).""" ... -T = TypeVar("T", bound="PrimeField") - class PrimeField(int, Field): """ @@ -78,85 +88,83 @@ class PrimeField(int, Field): PRIME: int @classmethod - def from_be_bytes(cls: Type[T], buffer: "Bytes") -> T: + def from_be_bytes(cls, buffer: Bytes) -> Self: """ - Converts a sequence of bytes into a element of the field. + Converts a sequence of bytes into an element of the field. Parameters ---------- buffer : Bytes to decode. Returns ------- - self : `T` - Unsigned integer decoded from `buffer`. + The decoded field element. """ return cls(int.from_bytes(buffer, "big")) @classmethod - def zero(cls: Type[T]) -> T: + def zero(cls) -> Self: + """Returns the additive identity (0) of the field.""" return cls.__new__(cls, 0) @classmethod - def from_int(cls: Type[T], n: int) -> T: + def from_int(cls, n: int) -> Self: + """Constructs a field element from an integer.""" return cls(n) - def __new__(cls: Type[T], value: int) -> T: + def __new__(cls, value: int) -> Self: return int.__new__(cls, value % cls.PRIME) - def __radd__(self: T, left: T) -> T: # type: ignore[override] + def __radd__(self, left: Self) -> Self: # type: ignore[override] return self.__add__(left) - def __add__(self: T, right: T) -> T: # type: ignore[override] + def __add__(self, right: Self) -> Self: # type: ignore[override] if not isinstance(right, int): return NotImplemented - return self.__new__(type(self), int.__add__(self, right)) - def __iadd__(self: T, right: T) -> T: # type: ignore[override] + def __iadd__(self, right: Self) -> Self: # type: ignore[override] return self.__add__(right) - def __sub__(self: T, right: T) -> T: # type: ignore[override] + def __sub__(self, right: Self) -> Self: # type: ignore[override] if not isinstance(right, int): return NotImplemented - return self.__new__(type(self), int.__sub__(self, right)) - def __rsub__(self: T, left: T) -> T: # type: ignore[override] + def __rsub__(self, left: Self) -> Self: # type: ignore[override] if not isinstance(left, int): return NotImplemented - return self.__new__(type(self), int.__rsub__(self, left)) - def __mul__(self: T, right: T) -> T: # type: ignore[override] + def __mul__(self, right: Self) -> Self: # type: ignore[override] if not isinstance(right, int): return NotImplemented - return self.__new__(type(self), int.__mul__(self, right)) - def __rmul__(self: T, left: T) -> T: # type: ignore[override] + def __rmul__(self, left: Self) -> Self: # type: ignore[override] return self.__mul__(left) - def __imul__(self: T, right: T) -> T: # type: ignore[override] + def __imul__(self, right: Self) -> Self: # type: ignore[override] return self.__mul__(right) + # Disabled operations __floordiv__ = None # type: ignore __rfloordiv__ = None # type: ignore __ifloordiv__ = None __divmod__ = None # type: ignore __rdivmod__ = None # type: ignore - def __pow__(self: T, exponent: int) -> T: # type: ignore[override] - # For reasons that are unclear, self must be cast to int here under - # PyPy. + def __pow__(self, exponent: int) -> Self: # type: ignore[override] + """Modular exponentiation (self ** exponent % PRIME).""" return self.__new__( type(self), int.__pow__(int(self), exponent, self.PRIME) ) __rpow__ = None # type: ignore - def __ipow__(self: T, right: int) -> T: # type: ignore[override] + def __ipow__(self, right: int) -> Self: # type: ignore[override] return self.__pow__(right) + # Disabled bitwise operations __and__ = None # type: ignore __or__ = None # type: ignore __xor__ = None # type: ignore @@ -167,30 +175,29 @@ def __ipow__(self: T, right: int) -> T: # type: ignore[override] __irshift__ = None __ilshift__ = None - def __neg__(self: T) -> T: + def __neg__(self) -> Self: + """Additive inverse (-self).""" return self.__new__(type(self), int.__neg__(self)) - def __truediv__(self: T, right: T) -> T: # type: ignore[override] + def __truediv__(self, right: Self) -> Self: # type: ignore[override] + """Field division (self / right).""" return self * right.multiplicative_inverse() - def multiplicative_inverse(self: T) -> T: + def multiplicative_inverse(self) -> Self: + """Returns the multiplicative inverse (self ** -1).""" return self ** (-1) - def to_be_bytes32(self) -> "Bytes32": + def to_be_bytes32(self) -> Bytes32: """ - Converts this arbitrarily sized unsigned integer into its big endian - representation with exactly 32 bytes. + Converts this field element to big-endian bytes representation. Returns ------- - big_endian : `Bytes32` - Big endian (most significant bits first) representation. + Bytes32 + Big-endian representation with exactly 32 bytes. """ return Bytes32(self.to_bytes(32, "big")) -U = TypeVar("U", bound="GaloisField") - - class GaloisField(tuple, Field): """ Superclass for defining finite fields. Not intended to be used @@ -200,74 +207,69 @@ class GaloisField(tuple, Field): tuple of the non-leading coefficients of the defining polynomial. For example `x^3 + 2x^2 + 3x + 4` is `(2, 3, 4)`. - In practice the polynomial is likely to be sparse and you should overload - the `__mul__()` function to take advantage of this fact. """ __slots__ = () PRIME: int MODULUS: Tuple[int, ...] - FROBENIUS_COEFFICIENTS: Tuple["GaloisField", ...] + FROBENIUS_COEFFICIENTS: Tuple[Self, ...] @classmethod - def zero(cls: Type[U]) -> U: + def zero(cls) -> Self: + """Returns the additive identity (0) of the field.""" return cls.__new__(cls, [0] * len(cls.MODULUS)) @classmethod - def from_int(cls: Type[U], n: int) -> U: + def from_int(cls, n: int) -> Self: + """Constructs a field element from an integer.""" return cls.__new__(cls, [n] + [0] * (len(cls.MODULUS) - 1)) - def __new__(cls: Type[U], iterable: Iterable[int]) -> U: + def __new__(cls, iterable: Iterable[int]) -> Self: self = tuple.__new__(cls, (x % cls.PRIME for x in iterable)) assert len(self) == len(cls.MODULUS) return self - def __add__(self: U, right: U) -> U: # type: ignore[override] + def __add__(self, right: Self) -> Self: # type: ignore[override] + """Field addition (self + right).""" if not isinstance(right, type(self)): return NotImplemented return self.__new__( type(self), - ( - x + y - for (x, y) in cast(Iterable[Tuple[int, int]], zip(self, right)) - ), + (x + y for (x, y) in zip(self, right)), ) - def __radd__(self: U, left: U) -> U: + def __radd__(self, left: Self) -> Self: + """Reverse addition (left + self).""" return self.__add__(left) - def __iadd__(self: U, right: U) -> U: # type: ignore[override] + def __iadd__(self, right: Self) -> Self: # type: ignore[override] + """In-place addition (self += right).""" return self.__add__(right) - def __sub__(self: U, right: U) -> U: + def __sub__(self, right: Self) -> Self: + """Field subtraction (self - right).""" if not isinstance(right, type(self)): return NotImplemented - x: int - y: int return self.__new__( type(self), - ( - x - y - for (x, y) in cast(Iterable[Tuple[int, int]], zip(self, right)) - ), + (x - y for (x, y) in zip(self, right)), ) - def __rsub__(self: U, left: U) -> U: + def __rsub__(self, left: Self) -> Self: + """Reverse subtraction (left - self).""" if not isinstance(left, type(self)): return NotImplemented return self.__new__( type(self), - ( - x - y - for (x, y) in cast(Iterable[Tuple[int, int]], zip(left, self)) - ), + (x - y for (x, y) in zip(left, self)), ) - def __mul__(self: U, right: U) -> U: # type: ignore[override] + def __mul__(self, right: Self) -> Self: # type: ignore[override] + """Field multiplication (self * right).""" modulus = self.MODULUS degree = len(modulus) prime = self.PRIME @@ -281,43 +283,40 @@ def __mul__(self: U, right: U) -> U: # type: ignore[override] for j in range(i - degree, i): mul[j] -= (mul[i] * modulus[degree - (i - j)]) % prime - return self.__new__( - type(self), - mul[:degree], - ) + return self.__new__(type(self), mul[:degree]) - def __rmul__(self: U, left: U) -> U: # type: ignore[override] + def __rmul__(self, left: Self) -> Self: # type: ignore[override] + """Reverse multiplication (left * self).""" return self.__mul__(left) - def __imul__(self: U, right: U) -> U: # type: ignore[override] + def __imul__(self, right: Self) -> Self: # type: ignore[override] + """In-place multiplication (self *= right).""" return self.__mul__(right) - def __truediv__(self: U, right: U) -> U: + def __truediv__(self, right: Self) -> Self: + """Field division (self / right).""" return self * right.multiplicative_inverse() - def __neg__(self: U) -> U: + def __neg__(self) -> Self: + """Additive inverse (-self).""" return self.__new__(type(self), (-a for a in self)) - def scalar_mul(self: U, x: int) -> U: + def scalar_mul(self, x: int) -> Self: """ - Multiply a field element by a integer. This is faster than using - `from_int()` and field multiplication. + Multiply a field element by an integer. + Faster than using `from_int()` and field multiplication. """ return self.__new__(type(self), (x * n for n in self)) - def deg(self: U) -> int: - """ - This is a support function for `multiplicative_inverse()`. - """ + def deg(self) -> int: + """Returns the degree of the polynomial representation.""" for i in range(len(self.MODULUS) - 1, -1, -1): if self[i] != 0: return i raise ValueError("deg() does not support zero") - def multiplicative_inverse(self: U) -> U: - """ - Calculate the multiplicative inverse. Uses the Euclidean algorithm. - """ + def multiplicative_inverse(self) -> Self: + """Calculate the multiplicative inverse using Euclidean algorithm.""" x2: List[int] p = self.PRIME x1, f1 = list(self.MODULUS), [0] * len(self) @@ -341,7 +340,7 @@ def multiplicative_inverse(self: U) -> U: ans = f2 q = pow(x2[0], -1, self.PRIME) for i in range(len(ans)): - ans *= q + ans[i] *= q break if d1 < d2: q = x2[d2] * pow(x1[d1], -1, self.PRIME) @@ -359,7 +358,8 @@ def multiplicative_inverse(self: U) -> U: d1 -= 1 return self.__new__(type(self), ans) - def __pow__(self: U, exponent: int) -> U: + def __pow__(self, exponent: int) -> Self: + """Field exponentiation (self ** exponent).""" degree = len(self.MODULUS) if exponent < 0: self = self.multiplicative_inverse() @@ -374,11 +374,12 @@ def __pow__(self: U, exponent: int) -> U: exponent //= 2 return res - def __ipow__(self: U, right: int) -> U: + def __ipow__(self, right: int) -> Self: + """In-place exponentiation (self **= right).""" return self.__pow__(right) @classmethod - def calculate_frobenius_coefficients(cls: Type[U]) -> Tuple[U, ...]: + def calculate_frobenius_coefficients(cls) -> Tuple[Self, ...]: """ Calculate the coefficients needed by `frobenius()`. """ @@ -389,15 +390,12 @@ def calculate_frobenius_coefficients(cls: Type[U]) -> Tuple[U, ...]: coefficients.append(cls.__new__(cls, x) ** cls.PRIME) return tuple(coefficients) - def frobenius(self: U) -> U: + def frobenius(self) -> Self: """ - Returns `self ** p`. This function is known as the Frobenius - endomorphism and has many special mathematical properties. In - particular it is extremely cheap to compute compared to other - exponentiations. + Returns `self ** p` (Frobenius endomorphism). + Extremely cheap to compute compared to other exponentiations. """ ans = self.from_int(0) - a: int for i, a in enumerate(self): - ans += cast(U, self.FROBENIUS_COEFFICIENTS[i]).scalar_mul(a) + ans += self.FROBENIUS_COEFFICIENTS[i].scalar_mul(a) return ans diff --git a/src/ethereum_optimized/state_db.py b/src/ethereum_optimized/state_db.py index d9c9ced6be..e63a7d73ed 100644 --- a/src/ethereum_optimized/state_db.py +++ b/src/ethereum_optimized/state_db.py @@ -15,7 +15,7 @@ import logging from dataclasses import dataclass from importlib import import_module -from typing import Any, ClassVar, Dict, List, Optional, Set, cast +from typing import Any, ClassVar, Dict, List, Optional, Set, Self, cast try: import rust_pyspec_glue @@ -105,8 +105,12 @@ def __eq__(self, other: object) -> bool: return NotImplemented return state_root(self) == state_root(other) - def __enter__(self) -> "State": - """Support with statements""" + def __enter__(self) -> Self: + """Support with statements + Note: Uses `typing.Self` (PEP 673) for methods returning instances + of this class. Future methods that return `self` should also + use `-> Self`. + """ return self def __exit__(self, *args: Any) -> None: