Skip to content

Conversation

@chfast
Copy link
Member

@chfast chfast commented Jul 31, 2025

Optimize the gas calculation for the modexp precompile by avoiding big.Int. The implementation is ported from evmone: https://github.com/ipsilon/evmone/blob/2cbfad3d5eda9bd920f1174088fe48d41f9edcd7/test/state/precompiles.cpp#L102

This has been additionally tested but executing all tests from the precompiles fuzzing corpus. However, this implementation has not been directly fuzzed.

@chfast chfast force-pushed the chfast/modexp_gas_opt branch from 0ff8a01 to ded9d74 Compare August 12, 2025 13:55
@chfast chfast requested a review from yperbasis August 12, 2025 13:55
if !allZero(header[0:28]) || !allZero(header[32:32+28]) || !allZero(header[64:64+28]) {
// Except for the case where both base and mod are zeros.
if allZero(header[0:32]) && allZero(header[64:96]) {
return minGas
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't right for Fusaka because MultComplexity won't be 0 even when both base and mod are zeros.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm on it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is hidden (i.e. not testable) because of the EIP-7823 (modexp length limits) applied later in the Run() function. In other words: we compute incorrect (by EIP-7883) gas cost here, but it does not matter because the execution ends with an error (by EIP-7823).

This is an argument to move EIP-7823 implementation from Run() to RequiredGas().

For now, I'm correcting the implementation.

Optimize the gas calculation for the modexp precompile by avoiding
big.Int. The implementation is ported from evmone:
https://github.com/ipsilon/evmone/blob/2cbfad3d5eda9bd920f1174088fe48d41f9edcd7/test/state/precompiles.cpp#L102

This has been additionally tested by executing all tests from the
precompiles fuzzing corpus. However, this implementation has not been
directly fuzzed.
@chfast chfast force-pushed the chfast/modexp_gas_opt branch from ded9d74 to 1131587 Compare August 15, 2025 10:27
for i := 0; i < len(expHeadExplicitBytes); i++ {
expByte := expHeadExplicitBytes[i]
if expByte != 0 {
expTopByteBitWidth := 8 - uint32(bits.LeadingZeros8(expByte))
Copy link
Member

@yperbasis yperbasis Aug 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering whether it is more performant to pad the input to 32 bytes and use uint256.BitLen instead of going byte by byte

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case this made it slower so I'm not going to change it now. However, I used uint256 for initial lengths and the performance has improved by up to 4% in the full benchmarks.

@chfast
Copy link
Member Author

chfast commented Aug 15, 2025

Final benchmarks:

                                                         │  main.txt   │             uint256.txt             │
                                                         │   mgas/s    │   mgas/s     vs base                │
PrecompiledModExpEip2565/eip_example1-Gas=1360              67.37 ± 1%    68.40 ± 1%    +1.53% (p=0.001 n=9)
PrecompiledModExpEip2565/eip_example2-Gas=1360             3.168k ± 2%   9.890k ± 1%  +212.18% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-1-square-Gas=200          191.9 ± 1%    273.8 ± 1%   +42.68% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-1-qube-Gas=200            147.2 ± 1%    191.3 ± 1%   +29.96% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-1-pow0x10001-Gas=341      54.00 ± 1%    56.19 ± 2%    +4.06% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-2-square-Gas=200          127.9 ± 1%    158.8 ± 1%   +24.16% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-2-qube-Gas=200            86.77 ± 0%   100.10 ± 1%   +15.36% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-2-pow0x10001-Gas=1365     108.5 ± 0%    111.7 ± 1%    +2.95% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-3-square-Gas=341          112.5 ± 1%    126.8 ± 1%   +12.71% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-3-qube-Gas=341            62.47 ± 0%    66.75 ± 0%    +6.85% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-3-pow0x10001-Gas=5461     163.7 ± 1%    167.2 ± 0%    +2.14% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-4-square-Gas=1365         179.0 ± 0%    188.8 ± 0%    +5.47% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-4-qube-Gas=1365           79.14 ± 0%    81.29 ± 0%    +2.72% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-4-pow0x10001-Gas=21845    210.0 ± 0%    213.3 ± 0%    +1.57% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-5-square-Gas=5461         253.5 ± 0%    259.2 ± 1%    +2.25% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-5-qube-Gas=5461           111.2 ± 1%    112.9 ± 1%    +1.53% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-5-pow0x10001-Gas=87381    279.6 ± 1%    281.4 ± 1%    +0.64% (p=0.008 n=9)
PrecompiledModExpEip2565/marius-1-even-Gas=2057             39.00 ± 1%    39.86 ± 1%    +2.21% (p=0.000 n=9)
PrecompiledModExpEip2565/guido-1-even-Gas=2298              63.22 ± 1%    64.37 ± 1%    +1.82% (p=0.000 n=9)
PrecompiledModExpEip2565/guido-2-even-Gas=2300              39.50 ± 1%    40.60 ± 1%    +2.78% (p=0.000 n=9)
PrecompiledModExpEip2565/guido-3-even-Gas=5400              296.9 ± 0%    304.0 ± 0%    +2.39% (p=0.000 n=9)
PrecompiledModExpEip2565/guido-4-even-Gas=1026             1.648k ± 1%   3.872k ± 0%  +134.95% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-1-base-heavy-Gas=200        54.73 ± 1%    60.96 ± 1%   +11.38% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-1-exp-heavy-Gas=215         15.06 ± 1%    15.81 ± 1%    +4.98% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-1-balanced-Gas=200          21.09 ± 1%    22.47 ± 1%    +6.54% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-2-base-heavy-Gas=867        67.52 ± 1%    70.19 ± 0%    +3.95% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-2-exp-heavy-Gas=852         38.25 ± 1%    40.23 ± 1%    +5.18% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-2-balanced-Gas=996          31.58 ± 1%    33.27 ± 1%    +5.35% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-3-base-heavy-Gas=677        58.26 ± 1%    61.52 ± 1%    +5.60% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-3-exp-heavy-Gas=765         50.57 ± 1%    52.66 ± 2%    +4.13% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-3-balanced-Gas=1360         64.78 ± 1%    67.26 ± 0%    +3.83% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-8-exp-648-Gas=215              13.75 ± 1%    14.41 ± 1%    +4.80% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-8-exp-896-Gas=298              15.61 ± 1%    16.23 ± 0%    +3.97% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-32-Gas=200              22.04 ± 1%    23.54 ± 1%    +6.81% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-36-Gas=200              19.82 ± 1%    21.16 ± 1%    +6.76% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-40-Gas=208              18.63 ± 1%    19.83 ± 1%    +6.44% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-64-Gas=336              19.41 ± 1%    20.31 ± 1%    +4.64% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-65-Gas=341              26.38 ± 1%    27.64 ± 1%    +4.78% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-128-Gas=677             51.66 ± 1%    54.52 ± 1%    +5.54% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-256-exp-2-Gas=341              62.62 ± 1%    67.34 ± 1%    +7.54% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-264-exp-2-Gas=363              63.63 ± 0%    68.66 ± 0%    +7.91% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-1024-exp-2-Gas=5461            132.7 ± 0%    134.6 ± 0%    +1.43% (p=0.000 n=9)
PrecompiledModExpEip2565/pawel-1-exp-heavy-Gas=298          15.39 ± 1%    16.23 ± 2%    +5.46% (p=0.000 n=9)
PrecompiledModExpEip2565/pawel-2-exp-heavy-Gas=425          30.70 ± 0%    32.22 ± 1%    +4.95% (p=0.000 n=9)
PrecompiledModExpEip2565/pawel-3-exp-heavy-Gas=501          36.36 ± 1%    38.66 ± 1%    +6.33% (p=0.000 n=9)
PrecompiledModExpEip2565/pawel-4-exp-heavy-Gas=506          38.74 ± 1%    40.89 ± 1%    +5.55% (p=0.000 n=9)
geomean                                                     68.17         75.65        +10.97%


                                                         │  main.txt   │            uint256.txt            │
                                                         │  allocs/op  │ allocs/op   vs base               │
PrecompiledModExpEip2565/eip_example1-Gas=1360              34.00 ± 0%   27.00 ± 0%  -20.59% (p=0.000 n=9)
PrecompiledModExpEip2565/eip_example2-Gas=1360             10.000 ± 0%   3.000 ± 0%  -70.00% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-1-square-Gas=200         15.000 ± 0%   7.000 ± 0%  -53.33% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-1-qube-Gas=200           16.000 ± 0%   8.000 ± 0%  -50.00% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-1-pow0x10001-Gas=341      19.00 ± 0%   11.00 ± 0%  -42.11% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-2-square-Gas=200         15.000 ± 0%   7.000 ± 0%  -53.33% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-2-qube-Gas=200           16.000 ± 0%   8.000 ± 0%  -50.00% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-2-pow0x10001-Gas=1365     19.00 ± 0%   11.00 ± 0%  -42.11% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-3-square-Gas=341         15.000 ± 0%   7.000 ± 0%  -53.33% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-3-qube-Gas=341           16.000 ± 0%   8.000 ± 0%  -50.00% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-3-pow0x10001-Gas=5461     19.00 ± 0%   11.00 ± 0%  -42.11% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-4-square-Gas=1365        15.000 ± 0%   7.000 ± 0%  -53.33% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-4-qube-Gas=1365          17.000 ± 0%   9.000 ± 0%  -47.06% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-4-pow0x10001-Gas=21845    20.00 ± 0%   12.00 ± 0%  -40.00% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-5-square-Gas=5461        16.000 ± 0%   8.000 ± 0%  -50.00% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-5-qube-Gas=5461           18.00 ± 0%   10.00 ± 0%  -44.44% (p=0.000 n=9)
PrecompiledModExpEip2565/nagydani-5-pow0x10001-Gas=87381    36.00 ± 0%   28.00 ± 0%  -22.22% (p=0.000 n=9)
PrecompiledModExpEip2565/marius-1-even-Gas=2057             49.00 ± 0%   40.00 ± 0%  -18.37% (p=0.000 n=9)
PrecompiledModExpEip2565/guido-1-even-Gas=2298              52.00 ± 0%   43.00 ± 0%  -17.31% (p=0.000 n=9)
PrecompiledModExpEip2565/guido-2-even-Gas=2300              49.00 ± 0%   41.00 ± 0%  -16.33% (p=0.000 n=9)
PrecompiledModExpEip2565/guido-3-even-Gas=5400             16.000 ± 0%   9.000 ± 0%  -43.75% (p=0.000 n=9)
PrecompiledModExpEip2565/guido-4-even-Gas=1026             15.000 ± 0%   6.000 ± 0%  -60.00% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-1-base-heavy-Gas=200       15.000 ± 0%   8.000 ± 0%  -46.67% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-1-exp-heavy-Gas=215         34.00 ± 0%   25.00 ± 0%  -26.47% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-1-balanced-Gas=200         16.000 ± 0%   9.000 ± 0%  -43.75% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-2-base-heavy-Gas=867       16.000 ± 0%   9.000 ± 0%  -43.75% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-2-exp-heavy-Gas=852         33.00 ± 0%   25.00 ± 0%  -24.24% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-2-balanced-Gas=996          20.00 ± 0%   12.00 ± 0%  -40.00% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-3-base-heavy-Gas=677        33.00 ± 0%   25.00 ± 0%  -24.24% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-3-exp-heavy-Gas=765         32.00 ± 0%   25.00 ± 0%  -21.88% (p=0.000 n=9)
PrecompiledModExpEip2565/marcin-3-balanced-Gas=1360         32.00 ± 0%   25.00 ± 0%  -21.88% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-8-exp-648-Gas=215              47.00 ± 0%   38.00 ± 0%  -19.15% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-8-exp-896-Gas=298              47.00 ± 0%   38.00 ± 0%  -19.15% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-32-Gas=200              18.00 ± 0%   10.00 ± 0%  -44.44% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-36-Gas=200              19.00 ± 0%   11.00 ± 0%  -42.11% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-40-Gas=208              17.00 ± 0%   10.00 ± 0%  -41.18% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-64-Gas=336              17.00 ± 0%   10.00 ± 0%  -41.18% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-65-Gas=341              49.00 ± 0%   41.00 ± 0%  -16.33% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-32-exp-128-Gas=677             49.00 ± 0%   41.00 ± 0%  -16.33% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-256-exp-2-Gas=341             16.000 ± 0%   8.000 ± 0%  -50.00% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-264-exp-2-Gas=363             15.000 ± 0%   8.000 ± 0%  -46.67% (p=0.000 n=9)
PrecompiledModExpEip2565/mod-1024-exp-2-Gas=5461            19.00 ± 0%   11.00 ± 0%  -42.11% (p=0.000 n=9)
PrecompiledModExpEip2565/pawel-1-exp-heavy-Gas=298          49.00 ± 0%   40.00 ± 0%  -18.37% (p=0.000 n=9)
PrecompiledModExpEip2565/pawel-2-exp-heavy-Gas=425          51.00 ± 0%   42.00 ± 0%  -17.65% (p=0.000 n=9)
PrecompiledModExpEip2565/pawel-3-exp-heavy-Gas=501          49.00 ± 0%   42.00 ± 0%  -14.29% (p=0.000 n=9)
PrecompiledModExpEip2565/pawel-4-exp-heavy-Gas=506          50.00 ± 0%   42.00 ± 0%  -16.00% (p=0.000 n=9)
geomean                                                     23.82        14.71       -38.23%

@yperbasis yperbasis merged commit a3a845f into main Aug 19, 2025
12 of 15 checks passed
@yperbasis yperbasis deleted the chfast/modexp_gas_opt branch August 19, 2025 10:11
NazariiDenha pushed a commit that referenced this pull request Oct 24, 2025
Optimize the gas calculation for the modexp precompile by avoiding
big.Int. The implementation is ported from evmone:
https://github.com/ipsilon/evmone/blob/2cbfad3d5eda9bd920f1174088fe48d41f9edcd7/test/state/precompiles.cpp#L102

This has been additionally tested but executing all tests from the
precompiles fuzzing corpus. However, this implementation has not been
directly fuzzed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants