Skip to content

Commit fdc4eb1

Browse files
jwasingerMariusVanDerWijdenfjl
authored andcommitted
core/vm: implement EIP 7883 - ModExp Gas Cost Increase (ethereum#31606)
https://eips.ethereum.org/EIPS/eip-7883 --------- Co-authored-by: MariusVanDerWijden <[email protected]> Co-authored-by: Felix Lange <[email protected]>
1 parent 1f6df13 commit fdc4eb1

File tree

3 files changed

+154
-23
lines changed

3 files changed

+154
-23
lines changed

core/vm/contracts.go

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
6565
common.BytesToAddress([]byte{2}): &sha256hash{},
6666
common.BytesToAddress([]byte{3}): &ripemd160hash{},
6767
common.BytesToAddress([]byte{4}): &dataCopy{},
68-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false, eip7823: false},
68+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false, eip7823: false, eip7883: false},
6969
common.BytesToAddress([]byte{6}): &bn256AddByzantium{},
7070
common.BytesToAddress([]byte{7}): &bn256ScalarMulByzantium{},
7171
common.BytesToAddress([]byte{8}): &bn256PairingByzantium{},
@@ -78,7 +78,7 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
7878
common.BytesToAddress([]byte{2}): &sha256hash{},
7979
common.BytesToAddress([]byte{3}): &ripemd160hash{},
8080
common.BytesToAddress([]byte{4}): &dataCopy{},
81-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false, eip7823: false},
81+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false, eip7823: false, eip7883: false},
8282
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
8383
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
8484
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: false},
@@ -92,7 +92,7 @@ var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
9292
common.BytesToAddress([]byte{2}): &sha256hash{},
9393
common.BytesToAddress([]byte{3}): &ripemd160hash{},
9494
common.BytesToAddress([]byte{4}): &dataCopy{},
95-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: false},
95+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false},
9696
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
9797
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
9898
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: false},
@@ -106,7 +106,7 @@ var PrecompiledContractsArchimedes = map[common.Address]PrecompiledContract{
106106
common.BytesToAddress([]byte{2}): &sha256hashDisabled{},
107107
common.BytesToAddress([]byte{3}): &ripemd160hashDisabled{},
108108
common.BytesToAddress([]byte{4}): &dataCopy{},
109-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: false},
109+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false},
110110
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
111111
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
112112
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: true},
@@ -120,7 +120,7 @@ var PrecompiledContractsBernoulli = map[common.Address]PrecompiledContract{
120120
common.BytesToAddress([]byte{2}): &sha256hash{},
121121
common.BytesToAddress([]byte{3}): &ripemd160hashDisabled{},
122122
common.BytesToAddress([]byte{4}): &dataCopy{},
123-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: false},
123+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false},
124124
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
125125
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
126126
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: true},
@@ -134,7 +134,7 @@ var PrecompiledContractsEuclidV2 = map[common.Address]PrecompiledContract{
134134
common.BytesToAddress([]byte{2}): &sha256hash{},
135135
common.BytesToAddress([]byte{3}): &ripemd160hashDisabled{},
136136
common.BytesToAddress([]byte{4}): &dataCopy{},
137-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: false},
137+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false},
138138
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
139139
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
140140
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: true},
@@ -149,7 +149,7 @@ var PrecompiledContractsFeynman = map[common.Address]PrecompiledContract{
149149
common.BytesToAddress([]byte{2}): &sha256hash{},
150150
common.BytesToAddress([]byte{3}): &ripemd160hashDisabled{},
151151
common.BytesToAddress([]byte{4}): &dataCopy{},
152-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: true},
152+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true, eip7823: true, eip7883: true},
153153
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
154154
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
155155
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: false},
@@ -351,6 +351,7 @@ func (c *dataCopy) Run(in []byte) ([]byte, error) {
351351
type bigModExp struct {
352352
eip2565 bool
353353
eip7823 bool
354+
eip7883 bool
354355
}
355356

356357
var (
@@ -431,40 +432,59 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
431432
adjExpLen := new(big.Int)
432433
if expLen.Cmp(big32) > 0 {
433434
adjExpLen.Sub(expLen, big32)
434-
adjExpLen.Mul(big8, adjExpLen)
435+
if c.eip7883 {
436+
adjExpLen.Lsh(adjExpLen, 4)
437+
} else {
438+
adjExpLen.Lsh(adjExpLen, 3)
439+
}
435440
}
436441
adjExpLen.Add(adjExpLen, big.NewInt(int64(msb)))
437442
// Calculate the gas cost of the operation
438-
gas := new(big.Int).Set(math.BigMax(modLen, baseLen))
443+
gas := new(big.Int)
444+
if modLen.Cmp(baseLen) < 0 {
445+
gas.Set(baseLen)
446+
} else {
447+
gas.Set(modLen)
448+
}
449+
450+
maxLenOver32 := gas.Cmp(big32) > 0
439451
if c.eip2565 {
440-
// EIP-2565 has three changes
452+
// EIP-2565 (Berlin fork) has three changes:
453+
//
441454
// 1. Different multComplexity (inlined here)
442455
// in EIP-2565 (https://eips.ethereum.org/EIPS/eip-2565):
443456
//
444457
// def mult_complexity(x):
445458
// ceiling(x/8)^2
446459
//
447-
//where is x is max(length_of_MODULUS, length_of_BASE)
448-
gas = gas.Add(gas, big7)
449-
gas = gas.Div(gas, big8)
460+
// where is x is max(length_of_MODULUS, length_of_BASE)
461+
gas.Add(gas, big7)
462+
gas.Rsh(gas, 3)
450463
gas.Mul(gas, gas)
451464

452-
gas.Mul(gas, math.BigMax(adjExpLen, big1))
465+
var minPrice uint64 = 200
466+
if c.eip7883 {
467+
minPrice = 500
468+
if maxLenOver32 {
469+
gas.Add(gas, gas)
470+
}
471+
}
472+
473+
if adjExpLen.Cmp(big1) > 0 {
474+
gas.Mul(gas, adjExpLen)
475+
}
453476
// 2. Different divisor (`GQUADDIVISOR`) (3)
454477
gas.Div(gas, big3)
455478
if gas.BitLen() > 64 {
456479
return math.MaxUint64
457480
}
458-
// 3. Minimum price of 200 gas
459-
if gas.Uint64() < 200 {
460-
return 200
461-
}
462-
return gas.Uint64()
481+
return max(minPrice, gas.Uint64())
463482
}
483+
484+
// Pre-Berlin logic.
464485
gas = modexpMultComplexity(gas)
465486
gas.Mul(gas, math.BigMax(adjExpLen, big1))
466487
gas.Div(gas, big20)
467-
468488
if gas.BitLen() > 64 {
469489
return math.MaxUint64
470490
}
@@ -482,7 +502,7 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
482502
expLen = expLenBigInt.Uint64()
483503
modLen = modLenBigInt.Uint64()
484504
)
485-
if !c.eip7823 {
505+
if !c.eip7823 && !c.eip7883 {
486506
// Check that all inputs are `u256` (32 - bytes) or less, revert otherwise
487507
var lenLimit = new(big.Int).SetInt64(32)
488508
if baseLenBigInt.Cmp(lenLimit) > 0 || expLenBigInt.Cmp(lenLimit) > 0 || modLenBigInt.Cmp(lenLimit) > 0 {

core/vm/contracts_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
5050
common.BytesToAddress([]byte{2}): &sha256hash{},
5151
common.BytesToAddress([]byte{3}): &ripemd160hash{},
5252
common.BytesToAddress([]byte{4}): &dataCopy{},
53-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false},
54-
common.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true},
53+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false, eip7883: false},
54+
common.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true, eip7883: false},
55+
common.BytesToAddress([]byte{0xf6}): &bigModExp{eip2565: true, eip7883: true},
5556
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
5657
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
5758
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
@@ -244,6 +245,9 @@ func BenchmarkPrecompiledModExp(b *testing.B) { benchJson("modexp", "05", b) }
244245
func TestPrecompiledModExpEip2565(t *testing.T) { testJson("modexp_eip2565", "f5", t) }
245246
func BenchmarkPrecompiledModExpEip2565(b *testing.B) { benchJson("modexp_eip2565", "f5", b) }
246247

248+
func TestPrecompiledModExpEip7883(t *testing.T) { testJson("modexp_eip7883", "f6", t) }
249+
func BenchmarkPrecompiledModExpEip7883(b *testing.B) { benchJson("modexp_eip7883", "f6", b) }
250+
247251
// Tests the sample inputs from the elliptic curve addition EIP 213.
248252
func TestPrecompiledBn256Add(t *testing.T) { testJson("bn256Add", "06", t) }
249253
func BenchmarkPrecompiledBn256Add(b *testing.B) { benchJson("bn256Add", "06", b) }

0 commit comments

Comments
 (0)