Skip to content

core/vm: implement EIP 7883 - ModExp Gas Cost Increase #31606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var PrecompiledContractsByzantium = PrecompiledContracts{
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false, eip7823: false},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false, eip7823: false, eip7883: false},
common.BytesToAddress([]byte{0x6}): &bn256AddByzantium{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulByzantium{},
common.BytesToAddress([]byte{0x8}): &bn256PairingByzantium{},
Expand All @@ -79,7 +79,7 @@ var PrecompiledContractsIstanbul = PrecompiledContracts{
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false, eip7823: false},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false, eip7823: false, eip7883: false},
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
Expand All @@ -93,7 +93,7 @@ var PrecompiledContractsBerlin = PrecompiledContracts{
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true, eip7823: false},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false},
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
Expand All @@ -107,7 +107,7 @@ var PrecompiledContractsCancun = PrecompiledContracts{
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true, eip7823: false},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false},
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
Expand All @@ -122,7 +122,7 @@ var PrecompiledContractsPrague = PrecompiledContracts{
common.BytesToAddress([]byte{0x02}): &sha256hash{},
common.BytesToAddress([]byte{0x03}): &ripemd160hash{},
common.BytesToAddress([]byte{0x04}): &dataCopy{},
common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true, eip7823: false},
common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true, eip7823: false, eip7883: false},
common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{},
Expand All @@ -148,7 +148,7 @@ var PrecompiledContractsOsaka = PrecompiledContracts{
common.BytesToAddress([]byte{0x02}): &sha256hash{},
common.BytesToAddress([]byte{0x03}): &ripemd160hash{},
common.BytesToAddress([]byte{0x04}): &dataCopy{},
common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true, eip7823: true},
common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true, eip7823: true, eip7883: true},
common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{},
Expand All @@ -164,6 +164,7 @@ var PrecompiledContractsOsaka = PrecompiledContracts{
}

var (
PrecompiledAddressesOsaka []common.Address
PrecompiledAddressesPrague []common.Address
PrecompiledAddressesCancun []common.Address
PrecompiledAddressesBerlin []common.Address
Expand Down Expand Up @@ -191,6 +192,9 @@ func init() {
for k := range PrecompiledContractsPrague {
PrecompiledAddressesPrague = append(PrecompiledAddressesPrague, k)
}
for k := range PrecompiledContractsOsaka {
PrecompiledAddressesOsaka = append(PrecompiledAddressesOsaka, k)
}
}

func activePrecompiledContracts(rules params.Rules) PrecompiledContracts {
Expand Down Expand Up @@ -222,6 +226,8 @@ func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts {
// ActivePrecompiles returns the precompile addresses enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
switch {
case rules.IsOsaka:
return PrecompiledAddressesOsaka
case rules.IsPrague:
return PrecompiledAddressesPrague
case rules.IsCancun:
Expand Down Expand Up @@ -342,6 +348,7 @@ func (c *dataCopy) Run(in []byte) ([]byte, error) {
type bigModExp struct {
eip2565 bool
eip7823 bool
eip7883 bool
}

var (
Expand Down Expand Up @@ -417,7 +424,11 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
adjExpLen := new(big.Int)
if expLen.Cmp(big32) > 0 {
adjExpLen.Sub(expLen, big32)
adjExpLen.Lsh(adjExpLen, 3)
if c.eip7883 {
adjExpLen.Lsh(adjExpLen, 4)
} else {
adjExpLen.Lsh(adjExpLen, 3)
}
}
adjExpLen.Add(adjExpLen, big.NewInt(int64(msb)))
// Calculate the gas cost of the operation
Expand All @@ -427,19 +438,30 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
} else {
gas.Set(modLen)
}

maxLenOver32 := gas.Cmp(big32) > 0
if c.eip2565 {
// EIP-2565 has three changes
// EIP-2565 (Berlin fork) has three changes:
//
// 1. Different multComplexity (inlined here)
// in EIP-2565 (https://eips.ethereum.org/EIPS/eip-2565):
//
// def mult_complexity(x):
// ceiling(x/8)^2
//
//where is x is max(length_of_MODULUS, length_of_BASE)
// where is x is max(length_of_MODULUS, length_of_BASE)
gas.Add(gas, big7)
gas.Rsh(gas, 3)
gas.Mul(gas, gas)

var minPrice uint64 = 200
if c.eip7883 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this check is within the if c.eip2565 block, the two EIPs are effectively dependent on each other and cannot be toggled separately. Not sure if we need to be able to have them fully separate, but maybe it would be more appropriate to toggle them with a single setting.

minPrice = 500
if maxLenOver32 {
gas.Add(gas, gas)
}
}

if adjExpLen.Cmp(big1) > 0 {
gas.Mul(gas, adjExpLen)
}
Expand All @@ -448,18 +470,15 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
if gas.BitLen() > 64 {
return math.MaxUint64
}
// 3. Minimum price of 200 gas
if gas.Uint64() < 200 {
return 200
}
return gas.Uint64()
return max(minPrice, gas.Uint64())
}

// Pre-Berlin logic.
gas = modexpMultComplexity(gas)
if adjExpLen.Cmp(big1) > 0 {
gas.Mul(gas, adjExpLen)
}
gas.Div(gas, big20)

if gas.BitLen() > 64 {
return math.MaxUint64
}
Expand Down
8 changes: 6 additions & 2 deletions core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false},
common.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false, eip7883: false},
common.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true, eip7883: false},
common.BytesToAddress([]byte{0xf6}): &bigModExp{eip2565: true, eip7883: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
Expand Down Expand Up @@ -238,6 +239,9 @@ func BenchmarkPrecompiledModExp(b *testing.B) { benchJson("modexp", "05", b) }
func TestPrecompiledModExpEip2565(t *testing.T) { testJson("modexp_eip2565", "f5", t) }
func BenchmarkPrecompiledModExpEip2565(b *testing.B) { benchJson("modexp_eip2565", "f5", b) }

func TestPrecompiledModExpEip7883(t *testing.T) { testJson("modexp_eip7883", "f6", t) }
func BenchmarkPrecompiledModExpEip7883(b *testing.B) { benchJson("modexp_eip7883", "f6", b) }

// Tests the sample inputs from the elliptic curve addition EIP 213.
func TestPrecompiledBn256Add(t *testing.T) { testJson("bn256Add", "06", t) }
func BenchmarkPrecompiledBn256Add(b *testing.B) { benchJson("bn256Add", "06", b) }
Expand Down
Loading