Skip to content

Commit 17e68c3

Browse files
authored
[ETCM-910] ModExp gas cost change (#1013)
* [ETCM-910] ModExp gas cost change * [ETCM-910] ModExp gas cost unit tests * [ETCM-910] PR remarks applied * [ETCM-910] Apply PR remarks * [ETCM-910] Apply PR remarks
1 parent 8dde788 commit 17e68c3

File tree

3 files changed

+164
-32
lines changed

3 files changed

+164
-32
lines changed

src/main/scala/io/iohk/ethereum/vm/BlockchainConfigForEvm.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ object BlockchainConfigForEvm {
5656

5757
object EtcForks extends Enumeration {
5858
type EtcFork = Value
59-
val BeforeAtlantis, Atlantis, Agharta, Phoenix = Value
59+
val BeforeAtlantis, Atlantis, Agharta, Phoenix, Magneto = Value
6060
}
6161

6262
object EthForks extends Enumeration {
6363
type EthFork = Value
64-
val BeforeByzantium, Byzantium, Constantinople, Petersburg, Istanbul = Value
64+
val BeforeByzantium, Byzantium, Constantinople, Petersburg, Istanbul, Berlin = Value
6565
}
6666

6767
def apply(blockchainConfig: BlockchainConfig): BlockchainConfigForEvm = {

src/main/scala/io/iohk/ethereum/vm/PrecompiledContracts.scala

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,13 @@ object PrecompiledContracts {
165165

166166
private val lengthBytes = 32
167167
private val totalLengthBytes = 3 * lengthBytes
168-
private val GQUADDIVISOR = 20
169168

170169
def exec(inputData: ByteString): Option[ByteString] = {
171170
val baseLength = getLength(inputData, 0)
172171
val expLength = getLength(inputData, 1)
173172
val modLength = getLength(inputData, 2)
174173

175-
val result =
174+
val result = {
176175
if (baseLength == 0 && modLength == 0)
177176
BigInt(0)
178177
else {
@@ -187,6 +186,7 @@ object PrecompiledContracts {
187186
base.modPow(exp, mod)
188187
}
189188
}
189+
}
190190
Some(ByteString(ByteUtils.bigIntegerToBytes(result.bigInteger, modLength)))
191191
}
192192

@@ -201,58 +201,84 @@ object PrecompiledContracts {
201201
safeAdd(safeAdd(totalLengthBytes, baseLength), expLength)
202202
)
203203

204-
val multComplexity = getMultComplexity(math.max(baseLength, modLength))
204+
if (ethFork >= EthForks.Berlin || etcFork >= EtcForks.Magneto)
205+
PostEIP2565Cost.calculate(baseLength, modLength, expLength, expBytes)
206+
else
207+
PostEIP198Cost.calculate(baseLength, modLength, expLength, expBytes)
208+
}
205209

206-
val adjExpLen = adjExpLength(expBytes, expLength)
210+
//Spec: https://eips.ethereum.org/EIPS/eip-198
211+
object PostEIP198Cost {
212+
private val GQUADDIVISOR = 20
207213

208-
multComplexity * math.max(adjExpLen, 1) / GQUADDIVISOR
209-
}
214+
def calculate(baseLength: Int, modLength: Int, expLength: Int, expBytes: ByteString): BigInt = {
215+
val multComplexity = getMultComplexity(math.max(baseLength, modLength))
216+
val adjusted = adjustExpLength(expBytes, expLength)
217+
multComplexity * math.max(adjusted, 1) / GQUADDIVISOR
218+
}
210219

211-
private def adjExpLength(expBytes: ByteString, expLength: Int): Long = {
212-
val expHead =
213-
if (expLength <= lengthBytes)
214-
expBytes.padToByteString(expLength, 0.toByte)
220+
private def getMultComplexity(x: BigInt): BigInt = {
221+
val x2 = x * x
222+
if (x <= 64)
223+
x2
224+
else if (x <= 1024)
225+
x2 / 4 + 96 * x - 3072
215226
else
216-
expBytes.take(lengthBytes).padToByteString(lengthBytes, 0.toByte)
227+
x2 / 16 + 480 * x - 199680
228+
}
229+
}
217230

218-
val highestBitIndex = math.max(ByteUtils.toBigInt(expHead).bitLength - 1, 0)
231+
//Spec: https://eips.ethereum.org/EIPS/eip-2565
232+
object PostEIP2565Cost {
233+
private val GQUADDIVISOR = 3
219234

220-
if (expLength <= lengthBytes) {
221-
highestBitIndex
222-
} else {
223-
8L * (expLength - lengthBytes) + highestBitIndex
235+
def calculate(baseLength: Int, modLength: Int, expLength: Int, expBytes: ByteString): BigInt = {
236+
val multComplexity = getMultComplexity(math.max(baseLength, modLength))
237+
val adjusted = adjustExpLength(expBytes, expLength)
238+
val r = multComplexity * math.max(adjusted, 1) / GQUADDIVISOR
239+
if (r <= 200) 200
240+
else r
224241
}
225-
}
226242

227-
private def getLength(bytes: ByteString, position: Int): Int = {
228-
val start = position * lengthBytes
229-
safeInt(ByteUtils.toBigInt(bytes.slice(start, start + lengthBytes)))
243+
// ceiling(x/8)^2
244+
private def getMultComplexity(x: BigInt): BigInt =
245+
((x + 7) / 8).pow(2)
230246
}
231247

232248
private def getNumber(bytes: ByteString, offset: Int, length: Int): BigInt = {
233249
val number = bytes.slice(offset, safeAdd(offset, length)).padToByteString(length, 0.toByte)
234250
ByteUtils.toBigInt(number)
235251
}
236252

253+
private def safeAdd(a: Int, b: Int): Int = {
254+
safeInt(BigInt(a) + BigInt(b))
255+
}
256+
237257
private def safeInt(value: BigInt): Int =
238258
if (value.isValidInt)
239259
value.toInt
240260
else
241261
Integer.MAX_VALUE
242262

243-
private def safeAdd(a: Int, b: Int): Int = {
244-
safeInt(BigInt(a) + BigInt(b))
263+
private def getLength(bytes: ByteString, position: Int): Int = {
264+
val start = position * lengthBytes
265+
safeInt(ByteUtils.toBigInt(bytes.slice(start, start + lengthBytes)))
245266
}
246267

247-
private def getMultComplexity(x: BigInt): BigInt = {
248-
val x2 = x * x
268+
private def adjustExpLength(expBytes: ByteString, expLength: Int): Long = {
269+
val expHead =
270+
if (expLength <= lengthBytes)
271+
expBytes.padToByteString(expLength, 0.toByte)
272+
else
273+
expBytes.take(lengthBytes).padToByteString(lengthBytes, 0.toByte)
249274

250-
if (x <= 64)
251-
x2
252-
else if (x <= 1024)
253-
x2 / 4 + 96 * x - 3072
254-
else
255-
x2 / 16 + 480 * x - 199680
275+
val highestBitIndex = math.max(ByteUtils.toBigInt(expHead).bitLength - 1, 0)
276+
277+
if (expLength <= lengthBytes) {
278+
highestBitIndex
279+
} else {
280+
8L * (expLength - lengthBytes) + highestBitIndex
281+
}
256282
}
257283
}
258284

0 commit comments

Comments
 (0)