Coverage for src / ethereum_types / numeric.py: 100%
451 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-06-08 11:25 -0400
« prev ^ index » next coverage.py v7.14.0, created at 2026-06-08 11:25 -0400
1"""
2Numeric types (mostly integers.)
3"""
5from abc import abstractmethod
6from numbers import Integral
7from types import NotImplementedType
8from typing import (
9 ClassVar,
10 Final,
11 Literal,
12 Optional,
13 Sized,
14 SupportsInt,
15 Tuple,
16 Type,
17 Union,
18 cast,
19)
21from mypy_extensions import mypyc_attr
22from typing_extensions import Self, TypeAlias, override
24from .bytes import Bytes, Bytes1, Bytes4, Bytes8, Bytes32, Bytes64
26_BytesLike: TypeAlias = Union[bytes, bytearray, memoryview]
29def _max_value(bits: int) -> int:
30 assert bits >= 0
31 value = (2**bits) - 1
32 return cast("int", value) # 2**-1 == 0.5
35@mypyc_attr(acyclic=True)
36class Unsigned:
37 """
38 Base of integer types.
39 """
41 __slots__ = ("_number",)
42 _number: Final[int]
44 def __init__(self, value: SupportsInt) -> None:
45 int_value = int(value)
46 if not self._in_range(int_value):
47 raise OverflowError
48 self._number = int_value
50 def __complex__(self) -> complex:
51 return complex(self._number)
53 def __bool__(self) -> bool:
54 return bool(self._number)
56 @property
57 def real(self) -> Self:
58 return self
60 @property
61 def imag(self) -> Self:
62 return type(self)(0)
64 def conjugate(self) -> Self:
65 return self
67 def __float__(self) -> float:
68 return float(self._number)
70 @property
71 def numerator(self) -> int:
72 return self._number.numerator
74 @property
75 def denominator(self) -> int:
76 return 1
78 def __index__(self) -> int:
79 return self._number
81 @abstractmethod
82 def _in_range(self, value: int) -> bool:
83 raise NotImplementedError
85 def __abs__(self) -> Self:
86 return type(self)(self)
88 def __radd__(self, left: Self) -> Self:
89 return self.__add__(left)
91 def __add__(self, right: Self) -> Self:
92 class_ = type(self)
93 if not isinstance(right, class_):
94 return NotImplemented
95 return class_(self._number + right._number)
97 def __iadd__(self, right: Self) -> Self:
98 class_ = type(self)
99 if not isinstance(right, class_):
100 return NotImplemented
101 return class_(self._number + right._number)
103 def __sub__(self, right: Self) -> Self:
104 class_ = type(self)
105 if not isinstance(right, class_):
106 return NotImplemented
108 if self._number < right._number:
109 raise OverflowError
111 return class_(self._number - right._number)
113 def __rsub__(self, left: Self) -> Self:
114 class_ = type(self)
115 if not isinstance(left, class_):
116 return NotImplemented
118 if self._number > left._number:
119 raise OverflowError
121 return class_(left._number - self._number)
123 def __isub__(self, right: Self) -> Self:
124 class_ = type(self)
125 if not isinstance(right, class_):
126 return NotImplemented
127 if right._number > self._number:
128 raise OverflowError
129 return class_(self._number - right._number)
131 def __mul__(self, right: Self) -> Self:
132 class_ = type(self)
133 if not isinstance(right, class_):
134 return NotImplemented
135 return class_(self._number * right._number)
137 def __rmul__(self, left: Self) -> Self:
138 return self.__mul__(left)
140 def __imul__(self, right: Self) -> Self:
141 class_ = type(self)
142 if not isinstance(right, class_):
143 return NotImplemented
144 return class_(self._number * right._number)
146 def __truediv__(self, other: Self) -> float:
147 class_ = type(self)
148 if not isinstance(other, class_):
149 return NotImplemented
150 return self._number.__truediv__(other._number)
152 def __rtruediv__(self, other: Self) -> float:
153 class_ = type(self)
154 if not isinstance(other, class_):
155 return NotImplemented
156 return self._number.__rtruediv__(other._number)
158 def __floordiv__(self, right: Self) -> Self:
159 class_ = type(self)
160 if not isinstance(right, class_):
161 return NotImplemented
163 return class_(self._number.__floordiv__(right._number))
165 def __rfloordiv__(self, left: Self) -> Self:
166 class_ = type(self)
167 if not isinstance(left, class_):
168 return NotImplemented
170 return class_(self._number.__rfloordiv__(left._number))
172 def __ifloordiv__(self, right: Self) -> Self:
173 class_ = type(self)
174 if not isinstance(right, class_):
175 return NotImplemented
176 return class_(self._number // right._number)
178 def __mod__(self, right: Self) -> Self:
179 class_ = type(self)
180 if not isinstance(right, class_):
181 return NotImplemented
183 return class_(self._number % right._number)
185 def __rmod__(self, left: Self) -> Self:
186 class_ = type(self)
187 if not isinstance(left, class_):
188 return NotImplemented
190 return class_(self._number.__rmod__(left._number))
192 def __imod__(self, right: Self) -> Self:
193 class_ = type(self)
194 if not isinstance(right, class_):
195 return NotImplemented
196 return class_(self._number % right._number)
198 def __divmod__(self, right: Self) -> Tuple[Self, Self]:
199 class_ = type(self)
200 if not isinstance(right, class_):
201 return NotImplemented
203 result = self._number.__divmod__(right._number)
204 return (
205 class_(result[0]),
206 class_(result[1]),
207 )
209 def __rdivmod__(
210 self, left: Self
211 ) -> Union[Tuple[Self, Self], NotImplementedType]:
212 class_ = type(self)
213 if not isinstance(left, class_):
214 # No idea why mypy is assuming this is an Any...
215 return NotImplemented # type: ignore[no-any-return]
217 result = self._number.__rdivmod__(left._number)
218 return (
219 class_(result[0]),
220 class_(result[1]),
221 )
223 def __pow__(self, right: Self, modulo: Optional[Self] = None) -> Self:
224 class_ = type(self)
225 modulo_int = None
226 if modulo is not None:
227 if not isinstance(modulo, class_):
228 return NotImplemented
229 modulo_int = modulo._number
231 if not isinstance(right, class_):
232 return NotImplemented
234 return class_(self._number.__pow__(right._number, modulo_int))
236 def __rpow__(self, left: Self) -> Self:
237 class_ = type(self)
238 if not isinstance(left, class_):
239 return NotImplemented
241 return class_(self._number.__rpow__(left._number))
243 def __ipow__(self, right: Self, modulo: Optional[Self] = None) -> Self:
244 class_ = type(self)
245 modulo_int = None
246 if modulo is not None:
247 if not isinstance(modulo, class_):
248 raise TypeError
249 modulo_int = modulo._number
251 if not isinstance(right, class_):
252 return NotImplemented
254 return class_(self._number.__pow__(right._number, modulo_int))
256 def __xor__(self, right: Self) -> Self:
257 class_ = type(self)
258 if not isinstance(right, class_):
259 return NotImplemented
261 return class_(self._number.__xor__(right._number))
263 def __rxor__(self, left: Self) -> Self:
264 class_ = type(self)
265 if not isinstance(left, class_):
266 return NotImplemented
268 return class_(self._number.__rxor__(left._number))
270 def __ixor__(self, right: Self) -> Self:
271 class_ = type(self)
272 if not isinstance(right, class_):
273 return NotImplemented
275 return class_(self._number.__xor__(right._number))
277 def __and__(self, other: Self) -> Self:
278 class_ = type(self)
279 if not isinstance(other, class_):
280 return NotImplemented
282 return class_(self._number.__and__(other._number))
284 def __rand__(self, other: Self) -> Self:
285 class_ = type(self)
286 if not isinstance(other, class_):
287 return NotImplemented
289 return class_(self._number.__rand__(other._number))
291 def __or__(self, other: Self) -> Self:
292 class_ = type(self)
293 if not isinstance(other, class_):
294 return NotImplemented
296 return class_(self._number.__or__(other._number))
298 def __ror__(self, other: Self) -> Self:
299 class_ = type(self)
300 if not isinstance(other, class_):
301 return NotImplemented
303 return class_(self._number.__ror__(other._number))
305 def __neg__(self) -> int:
306 return -self._number
308 def __pos__(self) -> Self:
309 return type(self)(self._number)
311 def __invert__(self) -> Self:
312 # TODO: How should this behave?
313 raise NotImplementedError
315 def __floor__(self) -> Self:
316 return type(self)(self)
318 def __ceil__(self) -> Self:
319 return type(self)(self)
321 def __int__(self) -> int:
322 return self._number
324 @override
325 def __eq__(self, other: object) -> bool:
326 # Unlike the other comparison dunder methods (eg. `__lt__`, `__ge__`,
327 # etc.), `__eq__` is expected to work with any object, so mypy doesn't
328 # detect comparisons between `Uint` and `int` as errors. Instead of
329 # throwing a `TypeError` at runtime, we try to behave sanely and
330 # soundly by converting `other` to an integer if possible, then
331 # comparing.
332 if isinstance(other, Unsigned):
333 return self._number == other._number
334 elif isinstance(other, SupportsInt):
335 other_int = int(other)
336 if other != other_int:
337 # If `other` doesn't equal `int(other)`, `self` definitely
338 # doesn't equal `other` since `self` has to be an integer.
339 return False
340 return self._number == other_int
341 return NotImplemented
343 def __le__(self, other: Self) -> bool:
344 class_ = type(self)
345 if not isinstance(other, class_):
346 return NotImplemented
348 return self._number <= other._number
350 def __ge__(self, other: Self) -> bool:
351 class_ = type(self)
352 if not isinstance(other, class_):
353 return NotImplemented
355 return self._number >= other._number
357 def __lt__(self, other: Self) -> bool:
358 class_ = type(self)
359 if not isinstance(other, class_):
360 return NotImplemented
362 return self._number < other._number
364 def __gt__(self, other: Self) -> bool:
365 class_ = type(self)
366 if not isinstance(other, class_):
367 return NotImplemented
369 return self._number > other._number
371 def __round__(self, ndigits: Optional[int] = None) -> Self:
372 return type(self)(self)
374 def __trunc__(self) -> Self:
375 return type(self)(self)
377 def __rshift__(self, right: Self) -> Self:
378 class_ = type(self)
379 if not isinstance(right, class_):
380 return NotImplemented
382 return class_(self._number >> right._number)
384 def __rrshift__(self, left: Self) -> Self:
385 class_ = type(self)
386 if not isinstance(left, class_):
387 return NotImplemented
389 return class_(self._number.__rrshift__(left._number))
391 def __lshift__(self, right: Self) -> Self:
392 class_ = type(self)
393 if not isinstance(right, class_):
394 return NotImplemented
396 return class_(self._number << right._number)
398 def __rlshift__(self, left: Self) -> Self:
399 class_ = type(self)
400 if not isinstance(left, class_):
401 return NotImplemented
403 return class_(self._number.__rlshift__(left._number))
405 @override
406 def __hash__(self) -> int:
407 return hash(self._number)
409 @override
410 def __repr__(self) -> str:
411 return f"{type(self).__name__}({self._number})"
413 @override
414 def __str__(self) -> str:
415 return str(self._number)
417 def to_be_bytes64(self) -> Bytes64:
418 """
419 Converts this unsigned integer into its big endian representation with
420 exactly 64 bytes.
421 """
422 return Bytes64(self._number.to_bytes(64, "big"))
424 def to_be_bytes32(self) -> Bytes32:
425 """
426 Converts this unsigned integer into its big endian representation
427 with exactly 32 bytes.
428 """
429 return Bytes32(self._number.to_bytes(32, "big"))
431 def to_bytes1(self) -> Bytes1:
432 """
433 Converts this unsigned integer into a byte sequence with exactly 1
434 bytes.
435 """
436 return Bytes1(self._number.to_bytes(1, "little"))
438 def to_le_bytes4(self) -> "Bytes4":
439 """
440 Converts this unsigned integer into its little endian representation,
441 with exactly 4 bytes.
442 """
443 return Bytes4(self._number.to_bytes(4, "little"))
445 def to_be_bytes4(self) -> "Bytes4":
446 """
447 Converts this unsigned integer into its big endian representation, with
448 exactly 4 bytes.
449 """
450 return Bytes4(self._number.to_bytes(4, "big"))
452 def to_le_bytes8(self) -> "Bytes8":
453 """
454 Converts this fixed sized unsigned integer into its little endian
455 representation, with exactly 8 bytes.
456 """
457 return Bytes8(self._number.to_bytes(8, "little"))
459 def to_be_bytes8(self) -> "Bytes8":
460 """
461 Converts this unsigned integer into its big endian representation, with
462 exactly 8 bytes.
463 """
464 return Bytes8(self._number.to_bytes(8, "big"))
466 def to_bytes(
467 self,
468 length: Optional[Self] = None,
469 byteorder: Literal["big", "little"] = "big",
470 ) -> Bytes:
471 """
472 Return an array of bytes representing an integer.
473 """
474 length_int = 1 if length is None else int(length)
475 return self._number.to_bytes(length=length_int, byteorder=byteorder)
477 def to_be_bytes(self) -> "Bytes":
478 """
479 Converts this unsigned integer into its big endian representation,
480 without padding.
481 """
482 bit_length = self._number.bit_length()
483 byte_length = (bit_length + 7) // 8
484 return self._number.to_bytes(byte_length, "big")
486 def to_le_bytes(self) -> "Bytes":
487 """
488 Converts this unsigned integer into its little endian representation,
489 without padding.
490 """
491 bit_length = self._number.bit_length()
492 number_bytes = (bit_length + 7) // 8
493 return self._number.to_bytes(number_bytes, "little")
495 def to_le_bytes32(self) -> Bytes32:
496 """
497 Converts this unsigned integer into its little endian representation
498 with exactly 32 bytes.
499 """
500 return Bytes32(self._number.to_bytes(32, "little"))
502 def to_le_bytes64(self) -> Bytes64:
503 """
504 Converts this unsigned integer into its little endian representation
505 with exactly 64 bytes.
506 """
507 return Bytes64(self._number.to_bytes(64, "little"))
509 def bit_length(self) -> "Uint":
510 """
511 Minimum number of bits required to represent this number in binary.
512 """
513 return Uint(self._number.bit_length())
516@mypyc_attr(acyclic=True)
517class Uint(Unsigned):
518 """
519 Unsigned integer of arbitrary size.
520 """
522 @classmethod
523 def from_be_bytes(cls: Type[Self], buffer: _BytesLike) -> Self:
524 """
525 Converts a sequence of bytes into an arbitrarily sized unsigned integer
526 from its big endian representation.
527 """
528 return cls(int.from_bytes(buffer, "big"))
530 @classmethod
531 def from_le_bytes(cls: Type[Self], buffer: _BytesLike) -> Self:
532 """
533 Converts a sequence of bytes into an arbitrarily sized unsigned integer
534 from its little endian representation.
535 """
536 return cls(int.from_bytes(buffer, "little"))
538 @override
539 def _in_range(self, value: int) -> bool:
540 return value >= 0
543Integral.register(Uint)
546def ulen(sized: Sized, /) -> Uint:
547 """
548 Return the number of items in a container, as a `Uint`.
549 """
550 return Uint(len(sized))
553@mypyc_attr(acyclic=True)
554class FixedUnsigned(Unsigned):
555 """
556 Superclass for fixed size unsigned integers. Not intended to be used
557 directly, but rather to be subclassed.
558 """
560 MAX_VALUE: ClassVar[Self]
561 """
562 Largest value that can be represented by this integer type.
563 """
565 @classmethod
566 def from_be_bytes(cls: Type[Self], buffer: _BytesLike) -> Self:
567 """
568 Converts a sequence of bytes into a fixed sized unsigned integer
569 from its big endian representation.
570 """
571 bits = cls.MAX_VALUE._number.bit_length()
572 byte_count = (bits + 7) // 8
573 if len(buffer) > byte_count:
574 message = f"expected at most {byte_count} but got {len(buffer)}"
575 raise ValueError(message)
577 return cls(int.from_bytes(buffer, "big"))
579 @classmethod
580 def from_le_bytes(cls: Type[Self], buffer: _BytesLike) -> Self:
581 """
582 Converts a sequence of bytes into a fixed sized unsigned integer
583 from its little endian representation.
584 """
585 bits = cls.MAX_VALUE._number.bit_length()
586 byte_count = (bits + 7) // 8
587 if len(buffer) > byte_count:
588 message = f"expected at most {byte_count} but got {len(buffer)}"
589 raise ValueError(message)
591 return cls(int.from_bytes(buffer, "little"))
593 @classmethod
594 def from_signed(cls: Type[Self], value: int) -> Self:
595 """
596 Creates an unsigned integer representing `value` using two's
597 complement.
598 """
599 if value >= (cls.MAX_VALUE._number // 2 + 1):
600 raise OverflowError
602 if value >= 0:
603 return cls(value)
605 if value < (-cls.MAX_VALUE // 2):
606 raise OverflowError
608 return cls(value & cls.MAX_VALUE._number)
610 @override
611 def _in_range(self, value: int) -> bool:
612 return value >= 0 and value <= self.MAX_VALUE._number
614 def wrapping_add(self, right: Self) -> Self:
615 """
616 Return a new instance containing `self + right (mod N)`.
617 """
618 class_ = type(self)
619 if not isinstance(right, class_):
620 raise TypeError
622 # This is a fast way of ensuring that the result is < (2 ** 256)
623 return class_((self._number + right._number) & self.MAX_VALUE._number)
625 def wrapping_sub(self, right: Self) -> Self:
626 """
627 Return a new instance containing `self - right (mod N)`.
628 """
629 class_ = type(self)
630 if not isinstance(right, class_):
631 raise TypeError
633 # This is a fast way of ensuring that the result is < (2 ** 256)
634 return class_((self._number - right._number) & self.MAX_VALUE._number)
636 def wrapping_mul(self, right: Self) -> Self:
637 """
638 Return a new instance containing `self * right (mod N)`.
639 """
640 class_ = type(self)
641 if not isinstance(right, class_):
642 raise TypeError
644 # This is a fast way of ensuring that the result is < (2 ** 256)
645 return class_((self._number * right._number) & self.MAX_VALUE._number)
647 def wrapping_pow(self, right: Self, modulo: Optional[Self] = None) -> Self:
648 """
649 Return a new instance containing `self ** right (mod modulo)`.
651 If omitted, `modulo` defaults to `Uint(self.MAX_VALUE) + 1`.
652 """
653 class_ = type(self)
654 modulo_int = None
655 if modulo is not None:
656 if not isinstance(modulo, class_):
657 raise TypeError
658 modulo_int = modulo._number
660 if not isinstance(right, class_):
661 raise TypeError
663 # This is a fast way of ensuring that the result is < (2 ** 256)
664 return class_(
665 self._number.__pow__(right._number, modulo_int)
666 & self.MAX_VALUE._number
667 )
669 @override
670 def __invert__(self: Self) -> Self:
671 return type(self)(
672 int.__invert__(self._number) & self.MAX_VALUE._number
673 )
675 def to_signed(self) -> int:
676 """
677 Decodes a signed integer from its two's complement representation.
678 """
679 bits = self.MAX_VALUE._number.bit_length()
680 bits = 8 * ((bits + 7) // 8)
681 if self._number.bit_length() < bits:
682 # This means that the sign bit is 0
683 return int(self)
685 # -1 * (2's complement of value)
686 return int(self) - (self.MAX_VALUE._number + 1)
689@mypyc_attr(acyclic=True)
690class U256(FixedUnsigned):
691 """
692 Unsigned integer, which can represent `0` to `2 ** 256 - 1`, inclusive.
693 """
695 MAX_VALUE: ClassVar["U256"]
696 """
697 Largest value that can be represented by this integer type.
698 """
701Integral.register(U256)
704@mypyc_attr(acyclic=True)
705class _U256(U256):
706 @override
707 def _in_range(self, value: int) -> bool:
708 return True
711U256.MAX_VALUE = _U256(_max_value(256))
712U256.MAX_VALUE = U256(_max_value(256))
715@mypyc_attr(acyclic=True)
716class U8(FixedUnsigned):
717 """
718 Unsigned positive integer, which can represent `0` to `2 ** 8 - 1`,
719 inclusive.
720 """
722 MAX_VALUE: ClassVar["U8"]
723 """
724 Largest value that can be represented by this integer type.
725 """
728Integral.register(U8)
731@mypyc_attr(acyclic=True)
732class _U8(U8):
733 @override
734 def _in_range(self, value: int) -> bool:
735 return True
738U8.MAX_VALUE = _U8(_max_value(8))
739U8.MAX_VALUE = U8(_max_value(8))
742@mypyc_attr(acyclic=True)
743class U16(FixedUnsigned):
744 """
745 Unsigned positive integer, which can represent `0` to `2 ** 16 - 1`,
746 inclusive.
747 """
749 MAX_VALUE: ClassVar["U16"]
750 """
751 Largest value that can be represented by this integer type.
752 """
755Integral.register(U16)
758@mypyc_attr(acyclic=True)
759class _U16(U16):
760 @override
761 def _in_range(self, value: int) -> bool:
762 return True
765U16.MAX_VALUE = _U16(_max_value(16))
766U16.MAX_VALUE = U16(_max_value(16))
769@mypyc_attr(acyclic=True)
770class U32(FixedUnsigned):
771 """
772 Unsigned positive integer, which can represent `0` to `2 ** 32 - 1`,
773 inclusive.
774 """
776 MAX_VALUE: ClassVar["U32"]
777 """
778 Largest value that can be represented by this integer type.
779 """
782Integral.register(U32)
785@mypyc_attr(acyclic=True)
786class _U32(U32):
787 @override
788 def _in_range(self, value: int) -> bool:
789 return True
792U32.MAX_VALUE = _U32(_max_value(32))
793U32.MAX_VALUE = U32(_max_value(32))
796@mypyc_attr(acyclic=True)
797class U64(FixedUnsigned):
798 """
799 Unsigned positive integer, which can represent `0` to `2 ** 64 - 1`,
800 inclusive.
801 """
803 MAX_VALUE: ClassVar["U64"]
804 """
805 Largest value that can be represented by this integer type.
806 """
809Integral.register(U64)
812@mypyc_attr(acyclic=True)
813class _U64(U64):
814 @override
815 def _in_range(self, value: int) -> bool:
816 return True
819U64.MAX_VALUE = _U64(_max_value(64))
820U64.MAX_VALUE = U64(_max_value(64))