Skip to content

Conversation

@chfast
Copy link
Member

@chfast chfast commented Jan 14, 2026

Use the Newton–Raphson method to compute the modular inverse of the odd part of the modulus in the modexp for even modulus. This reuses the inv_mod() procedure from ModArith to compute initial 64-bit value of the inversion.

Benchmarks of modified modexp cases with big k in the decomposition to mod_odd * 2^k:

                                                  │     before       │            after                        │
                                                  │      gas/s       │     gas/s      vs base                  │
modexp<expmod_execute>/mod_len:8/exp_bits:33-14         722.7M ±  0%    870.1M ±  0%    +20.39% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:16/exp_bits:33-14        863.9M ±  0%    868.3M ±  0%     +0.50% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:24/exp_bits:33-14        206.1M ±  0%    217.0M ±  0%     +5.24% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:32/exp_bits:33-14        217.7M ±  0%    218.1M ±  0%     +0.16% (p=0.034 n=11)
modexp<expmod_execute>/mod_len:40/exp_bits:11-14        136.5M ±  0%    181.0M ±  0%    +32.65% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:48/exp_bits:8-14         211.5M ±  0%    237.4M ±  0%    +12.24% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:56/exp_bits:6-14         210.2M ±  0%    296.2M ±  0%    +40.89% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:64/exp_bits:5-14         33.74M ±  0%   324.07M ±  0%   +860.53% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:72/exp_bits:4-14         76.66M ±  0%   116.36M ±  0%    +51.79% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:80/exp_bits:4-14         91.70M ±  0%   139.26M ±  0%    +51.87% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:88/exp_bits:4-14         70.52M ±  0%   167.91M ±  0%   +138.11% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:96/exp_bits:4-14         171.1M ±  0%    192.2M ±  0%    +12.30% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:112/exp_bits:4-14        106.2M ±  0%    239.8M ± 16%   +125.91% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:136/exp_bits:3-14        53.91M ±  0%    86.57M ±  0%    +60.58% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:192/exp_bits:2-14        83.53M ±  0%   107.25M ±  0%    +28.39% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:200/exp_bits:2-14        2.302M ±  0%   95.886M ±  0%  +4065.86% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:256/exp_bits:2-14        50.46M ±  0%   180.23M ±  1%   +257.16% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:264/exp_bits:2-14        3.710M ±  0%   12.260M ±  1%   +230.45% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:504/exp_bits:2-14        10.74M ±  0%    43.81M ±  1%   +307.90% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:512/exp_bits:2-14        25.28M ±  0%    48.86M ±  1%    +93.28% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:520/exp_bits:2-14        11.43M ±  0%    46.62M ±  0%   +307.95% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:1016/exp_bits:2-14       43.47M ±  0%   175.31M ±  0%   +303.26% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:1024/exp_bits:2-14       145.6M ± 81%    190.8M ± 12%    +31.10% (p=0.000 n=11)
geomean                                                 69.00M          150.5M         +118.12%

Copilot AI review requested due to automatic review settings January 14, 2026 11:20
@codecov
Copy link

codecov bot commented Jan 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.64%. Comparing base (67adeb2) to head (3e6f68d).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1420      +/-   ##
==========================================
- Coverage   81.64%   81.64%   -0.01%     
==========================================
  Files         152      152              
  Lines       13550    13548       -2     
  Branches     3217     3217              
==========================================
- Hits        11063    11061       -2     
  Misses        343      343              
  Partials     2144     2144              
Flag Coverage Δ
eest-develop 91.10% <100.00%> (-0.01%) ⬇️
eest-develop-gmp 29.07% <100.00%> (-0.02%) ⬇️
eest-legacy 15.37% <0.00%> (+<0.01%) ⬆️
eest-legacy-silkpre 24.41% <80.00%> (-0.02%) ⬇️
evmone-unittests 76.17% <60.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
core 94.38% <100.00%> (-0.01%) ⬇️
tooling 83.63% <ø> (ø)
tests 73.52% <ø> (ø)
Files with missing lines Coverage Δ
lib/evmone_precompiles/modexp.cpp 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@chfast chfast requested review from Copilot and rodiazet and removed request for Copilot January 14, 2026 11:25
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes the modular inverse computation in the modexp precompile by replacing a bit-by-bit algorithm with the Newton-Raphson method. The change significantly improves performance for modexp operations with even moduli, especially when the power-of-two factor is large.

Changes:

  • Replaced the iterative bit-by-bit modular inversion algorithm with Newton-Raphson doubling method
  • Reuses the existing inv_mod() function from ModArith to compute an initial 64-bit inverse
  • Added documentation note about the return value potentially exceeding k bits

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Use the Newton–Raphson method to compute the modular inverse of the
odd part of the modulus in the modexp for even modulus.
This reuses the inv_mod() procedure from ModArith to compute initial
64-bit value of the inversion.

Benchmarks of modified modexp cases with big `k` in the decomposition
to `mod_odd * 2^k`:

```
                                                  │     before       │            after                        │
                                                  │      gas/s       │     gas/s      vs base                  │
modexp<expmod_execute>/mod_len:8/exp_bits:33-14         722.7M ±  0%    870.1M ±  0%    +20.39% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:16/exp_bits:33-14        863.9M ±  0%    868.3M ±  0%     +0.50% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:24/exp_bits:33-14        206.1M ±  0%    217.0M ±  0%     +5.24% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:32/exp_bits:33-14        217.7M ±  0%    218.1M ±  0%     +0.16% (p=0.034 n=11)
modexp<expmod_execute>/mod_len:40/exp_bits:11-14        136.5M ±  0%    181.0M ±  0%    +32.65% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:48/exp_bits:8-14         211.5M ±  0%    237.4M ±  0%    +12.24% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:56/exp_bits:6-14         210.2M ±  0%    296.2M ±  0%    +40.89% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:64/exp_bits:5-14         33.74M ±  0%   324.07M ±  0%   +860.53% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:72/exp_bits:4-14         76.66M ±  0%   116.36M ±  0%    +51.79% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:80/exp_bits:4-14         91.70M ±  0%   139.26M ±  0%    +51.87% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:88/exp_bits:4-14         70.52M ±  0%   167.91M ±  0%   +138.11% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:96/exp_bits:4-14         171.1M ±  0%    192.2M ±  0%    +12.30% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:112/exp_bits:4-14        106.2M ±  0%    239.8M ± 16%   +125.91% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:136/exp_bits:3-14        53.91M ±  0%    86.57M ±  0%    +60.58% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:192/exp_bits:2-14        83.53M ±  0%   107.25M ±  0%    +28.39% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:200/exp_bits:2-14        2.302M ±  0%   95.886M ±  0%  +4065.86% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:256/exp_bits:2-14        50.46M ±  0%   180.23M ±  1%   +257.16% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:264/exp_bits:2-14        3.710M ±  0%   12.260M ±  1%   +230.45% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:504/exp_bits:2-14        10.74M ±  0%    43.81M ±  1%   +307.90% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:512/exp_bits:2-14        25.28M ±  0%    48.86M ±  1%    +93.28% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:520/exp_bits:2-14        11.43M ±  0%    46.62M ±  0%   +307.95% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:1016/exp_bits:2-14       43.47M ±  0%   175.31M ±  0%   +303.26% (p=0.000 n=11)
modexp<expmod_execute>/mod_len:1024/exp_bits:2-14       145.6M ± 81%    190.8M ± 12%    +31.10% (p=0.000 n=11)
geomean                                                 69.00M          150.5M         +118.12%

```
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.

2 participants