Skip to content

Spec

Documentation for tests/osaka/eip7883_modexp_gas_increase/spec.py@98848dfe.

Defines EIP-7883 specification constants and functions.

Spec dataclass

Constants and helpers for the ModExp gas cost calculation.

Source code in tests/osaka/eip7883_modexp_gas_increase/spec.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
@dataclass(frozen=True)
class Spec:
    """Constants and helpers for the ModExp gas cost calculation."""

    MODEXP_ADDRESS = 0x05
    MIN_GAS = 200

    LARGE_BASE_MODULUS_MULTIPLIER = 1
    MAX_LENGTH_THRESHOLD = 32
    EXPONENT_BYTE_MULTIPLIER = 8
    MAX_LENGTH_BYTES = 1024

    WORD_SIZE = 8
    EXPONENT_THRESHOLD = 32
    GAS_DIVISOR = 3

    # Arbitrary Test Constants
    modexp_input = ModExpInput(
        base="e8e77626586f73b955364c7b4bbf0bb7f7685ebd40e852b164633a4acbd3244c0001020304050607",
        exponent="01ffffff",
        modulus="f01681d2220bfea4bb888a5543db8c0916274ddb1ea93b144c042c01d8164c950001020304050607",
    )
    modexp_expected = bytes.fromhex(
        "1abce71dc2205cce4eb6934397a88136f94641342e283cbcd30e929e85605c6718ed67f475192ffd"
    )
    modexp_error = bytes()

    @classmethod
    def calculate_multiplication_complexity(cls, base_length: int, modulus_length: int) -> int:
        """Calculate the multiplication complexity of the ModExp precompile."""
        max_length = max(base_length, modulus_length)
        words = ceiling_division(max_length, cls.WORD_SIZE)
        if max_length <= cls.MAX_LENGTH_THRESHOLD:
            return words**2
        return cls.LARGE_BASE_MODULUS_MULTIPLIER * words**2

    @classmethod
    def calculate_iteration_count(cls, modexp_input: ModExpInput) -> int:
        """
        Calculate the iteration count of the ModExp precompile.
        This handles length mismatch cases by using declared lengths from the raw input
        and only the first 32 bytes of exponent data for iteration calculation.
        """
        _, exponent_length, _ = modexp_input.get_declared_lengths()
        exponent_head = modexp_input.get_exponent_head()
        if exponent_length <= cls.EXPONENT_THRESHOLD and exponent_head == 0:
            iteration_count = 0
        elif exponent_length <= cls.EXPONENT_THRESHOLD:
            iteration_count = exponent_head.bit_length() - 1 if exponent_head > 0 else 0
        else:
            # For large exponents: length_part + bits from first 32 bytes
            length_part = cls.EXPONENT_BYTE_MULTIPLIER * (exponent_length - 32)
            bits_part = exponent_head.bit_length() - 1 if exponent_head > 0 else 0
            iteration_count = length_part + bits_part
        return max(iteration_count, 1)

    @classmethod
    def calculate_gas_cost(cls, modexp_input: ModExpInput) -> int:
        """
        Calculate the ModExp gas cost according to EIP-2565 specification, overridden by the
        constants within `Spec7883` when calculating for the EIP-7883 specification.
        """
        base_length, _, modulus_length = modexp_input.get_declared_lengths()
        multiplication_complexity = cls.calculate_multiplication_complexity(
            base_length, modulus_length
        )
        iteration_count = cls.calculate_iteration_count(modexp_input)
        return max(cls.MIN_GAS, (multiplication_complexity * iteration_count // cls.GAS_DIVISOR))

Spec7883 dataclass

Bases: Spec

Constants and helpers for the ModExp gas cost increase EIP. These override the original Spec class variables for EIP-7883.

Source code in tests/osaka/eip7883_modexp_gas_increase/spec.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
@dataclass(frozen=True)
class Spec7883(Spec):
    """
    Constants and helpers for the ModExp gas cost increase EIP.
    These override the original Spec class variables for EIP-7883.
    """

    MODEXP_ADDRESS = 0x05
    MIN_GAS = 500

    LARGE_BASE_MODULUS_MULTIPLIER = 2
    EXPONENT_BYTE_MULTIPLIER = 16
    GAS_DIVISOR = 1  # Overrides the original Spec class GAS_DIVISOR

    @classmethod
    def calculate_multiplication_complexity(cls, base_length: int, modulus_length: int) -> int:
        """Calculate the multiplication complexity of the ModExp precompile for EIP-7883."""
        max_length = max(base_length, modulus_length)
        words = ceiling_division(max_length, cls.WORD_SIZE)
        complexity = 16
        if max_length > cls.MAX_LENGTH_THRESHOLD:
            complexity = cls.LARGE_BASE_MODULUS_MULTIPLIER * words**2
        return complexity