Skip to content

Commit

Permalink
Several EVM Precompile Clean-Ups & Renamings (#3655)
Browse files Browse the repository at this point in the history
* Rename EVM bn254 precompiles (EC based name too generic, not consistent with bls12)

* Additional EC* precompile renaming

* Small fix

* Bring precompileEntries array in the correct order

* Even more ordering

* Some precompile name DRYing

* Undo confused-state hex resorting

* Another confusion: keep the SHA256 name

* Rename ec*Gas params to bn254*Gas

* Lower-case bls12381*Gas param names
  • Loading branch information
holgerd77 committed Sep 12, 2024
1 parent 47051db commit 4da6647
Show file tree
Hide file tree
Showing 32 changed files with 255 additions and 190 deletions.
6 changes: 3 additions & 3 deletions packages/common/test/data/paramsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const paramsTest: ParamsDict = {
*/
609: {
// gasPrices
ecAddGas: 500, // Gas costs for curve addition precompile
bn254AddGas: 500, // Gas costs for curve addition precompile
// pow
minerReward: '3000000000000000000', // the amount a miner get rewarded for mining a block
},
Expand All @@ -38,13 +38,13 @@ export const paramsTest: ParamsDict = {
*/
1679: {
// gasPrices
ecAddGas: 150, // Gas costs for curve addition precompile
bn254AddGas: 150, // Gas costs for curve addition precompile
},
/**
* BLS12-381 precompiles
*/
2537: {
// gasPrices
Bls12381G1AddGas: 500, // Gas cost of a single BLS12-381 G1 addition precompile-call
bls12381G1AddGas: 500, // Gas cost of a single BLS12-381 G1 addition precompile-call
},
}
30 changes: 15 additions & 15 deletions packages/common/test/params.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,42 @@ describe('[Common]: Parameter instantiation / params option / Updates', () => {
it('Param option', () => {
const c = new Common({ chain: Mainnet, params: paramsTest })
let msg = 'Should also work with parameters passed with params option'
assert.equal(c.param('ecAddGas'), BigInt(150), msg)
assert.equal(c.param('bn254AddGas'), BigInt(150), msg)

const params = {
1679: {
ecAddGas: 250,
bn254AddGas: 250,
},
}
c.updateParams(params)
msg = 'Should update parameter on updateParams() and properly rebuild cache'
assert.equal(c.param('ecAddGas'), BigInt(250), msg)
assert.equal(c.param('bn254AddGas'), BigInt(250), msg)

c.resetParams(params)
msg = 'Should reset all parameters on resetParams() and properly rebuild cache'
assert.equal(c.param('ecAddGas'), BigInt(250), msg)
assert.equal(c.param('bn254AddGas'), BigInt(250), msg)
assert.throws(() => {
c.param('ecMulGas'), BigInt(250)
c.param('bn254MulGas'), BigInt(250)
})

msg = 'Should not side-manipulate the original params file during updating internally'
assert.equal(paramsTest['1679']['ecAddGas'], 150)
assert.equal(paramsTest['1679']['bn254AddGas'], 150)
})
})

describe('[Common]: Parameter access for param(), paramByHardfork()', () => {
it('Basic usage', () => {
const c = new Common({ chain: Mainnet, params: paramsTest, eips: [2537] })
let msg = 'Should return correct value when HF directly provided'
assert.equal(c.paramByHardfork('ecAddGas', 'byzantium'), BigInt(500), msg)
assert.equal(c.paramByHardfork('bn254AddGas', 'byzantium'), BigInt(500), msg)

msg = 'Should return correct value for HF set in class'
c.setHardfork(Hardfork.Byzantium)
assert.equal(c.param('ecAddGas'), BigInt(500), msg)
assert.equal(c.param('bn254AddGas'), BigInt(500), msg)
c.setHardfork(Hardfork.Istanbul)
assert.equal(c.param('ecAddGas'), BigInt(150), msg)
assert.equal(c.param('bn254AddGas'), BigInt(150), msg)
c.setHardfork(Hardfork.MuirGlacier)
assert.equal(c.param('ecAddGas'), BigInt(150), msg)
assert.equal(c.param('bn254AddGas'), BigInt(150), msg)

assert.throws(() => {
c.paramByHardfork('notExistingValue', 'byzantium')
Expand All @@ -55,7 +55,7 @@ describe('[Common]: Parameter access for param(), paramByHardfork()', () => {
// To run please manually add an "ecAdd" entry with value 12345 to EIP2537 config
// and uncomment the test
msg = 'EIP config should take precedence over HF config'
assert.equal(c.param('ecAddGas'), 12345, msg)
assert.equal(c.param('bn254AddGas'), 12345, msg)
*/
})

Expand All @@ -64,7 +64,7 @@ describe('[Common]: Parameter access for param(), paramByHardfork()', () => {

c.setHardfork(Hardfork.Byzantium)
assert.equal(
c.param('ecAddGas'),
c.param('bn254AddGas'),
BigInt(500),
'Should return correct value for HF set in class',
)
Expand Down Expand Up @@ -123,12 +123,12 @@ describe('[Common]: Parameter access for param(), paramByHardfork()', () => {

const UNSUPPORTED_EIP = 1000000
const f = function () {
c.paramByEIP('Bls12381G1AddGas', UNSUPPORTED_EIP)
c.paramByEIP('bls12381G1AddGas', UNSUPPORTED_EIP)
}
let msg = 'Should throw for using paramByEIP() with an unsupported EIP'
assert.throws(f, /not supported$/, undefined, msg)

msg = 'Should return Bls12381G1AddGas gas price for EIP2537'
assert.equal(c.paramByEIP('Bls12381G1AddGas', 2537), BigInt(500), msg)
msg = 'Should return bls12381G1AddGas gas price for EIP2537'
assert.equal(c.paramByEIP('bls12381G1AddGas', 2537), BigInt(500), msg)
})
})
32 changes: 16 additions & 16 deletions packages/evm/src/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,10 @@ export const paramsEVM: ParamsDict = {
609: {
// gasPrices
modexpGquaddivisorGas: 20, // Gquaddivisor from modexp precompile for gas calculation
ecAddGas: 500, // Gas costs for curve addition precompile
ecMulGas: 40000, // Gas costs for curve multiplication precompile
ecPairingGas: 100000, // Base gas costs for curve pairing precompile
ecPairingWordGas: 80000, // Gas costs regarding curve pairing precompile input length
bn254AddGas: 500, // Gas costs for curve addition precompile
bn254MulGas: 40000, // Gas costs for curve multiplication precompile
bn254PairingGas: 100000, // Base gas costs for curve pairing precompile
bn254PairingWordGas: 80000, // Gas costs regarding curve pairing precompile input length
revertGas: 0, // Base fee of the REVERT opcode
staticcallGas: 700, // Base fee of the STATICCALL opcode
returndatasizeGas: 2, // Base fee of the RETURNDATASIZE opcode
Expand Down Expand Up @@ -183,10 +183,10 @@ export const paramsEVM: ParamsDict = {
1679: {
// gasPrices
blake2RoundGas: 1, // Gas cost per round for the Blake2 F precompile
ecAddGas: 150, // Gas costs for curve addition precompile
ecMulGas: 6000, // Gas costs for curve multiplication precompile
ecPairingGas: 45000, // Base gas costs for curve pairing precompile
ecPairingWordGas: 34000, // Gas costs regarding curve pairing precompile input length
bn254AddGas: 150, // Gas costs for curve addition precompile
bn254MulGas: 6000, // Gas costs for curve multiplication precompile
bn254PairingGas: 45000, // Base gas costs for curve pairing precompile
bn254PairingWordGas: 34000, // Gas costs regarding curve pairing precompile input length
sstoreSentryEIP2200Gas: 2300, // Minimum gas required to be present for an SSTORE call, not consumed
sstoreNoopEIP2200Gas: 800, // Once per SSTORE operation if the value doesn't change
sstoreDirtyEIP2200Gas: 800, // Once per SSTORE operation if a dirty value is changed
Expand Down Expand Up @@ -234,14 +234,14 @@ export const paramsEVM: ParamsDict = {
*/
2537: {
// gasPrices
Bls12381G1AddGas: 500, // Gas cost of a single BLS12-381 G1 addition precompile-call
Bls12381G1MulGas: 12000, // Gas cost of a single BLS12-381 G1 multiplication precompile-call
Bls12381G2AddGas: 800, // Gas cost of a single BLS12-381 G2 addition precompile-call
Bls12381G2MulGas: 45000, // Gas cost of a single BLS12-381 G2 multiplication precompile-call
Bls12381PairingBaseGas: 65000, // Base gas cost of BLS12-381 pairing check
Bls12381PairingPerPairGas: 43000, // Per-pair gas cost of BLS12-381 pairing check
Bls12381MapG1Gas: 5500, // Gas cost of BLS12-381 map field element to G1
Bls12381MapG2Gas: 75000, // Gas cost of BLS12-381 map field element to G2
bls12381G1AddGas: 500, // Gas cost of a single BLS12-381 G1 addition precompile-call
bls12381G1MulGas: 12000, // Gas cost of a single BLS12-381 G1 multiplication precompile-call
bls12381G2AddGas: 800, // Gas cost of a single BLS12-381 G2 addition precompile-call
bls12381G2MulGas: 45000, // Gas cost of a single BLS12-381 G2 multiplication precompile-call
bls12381PairingBaseGas: 65000, // Base gas cost of BLS12-381 pairing check
bls12381PairingPerPairGas: 43000, // Per-pair gas cost of BLS12-381 pairing check
bls12381MapG1Gas: 5500, // Gas cost of BLS12-381 map field element to G1
bls12381MapG2Gas: 75000, // Gas cost of BLS12-381 map field element to G2
},
/**
. * Gas cost increases for state access opcodes
Expand Down
13 changes: 8 additions & 5 deletions packages/evm/src/precompiles/01-ecrecover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ import { OOGResult } from '../evm.js'

import { gasLimitCheck } from './util.js'

import { getPrecompileName } from './index.js'

import type { ExecResult } from '../types.js'
import type { PrecompileInput } from './types.js'

export function precompile01(opts: PrecompileInput): ExecResult {
const pName = getPrecompileName('01')
const ecrecoverFunction = opts.common.customCrypto.ecrecover ?? ecrecover
const gasUsed = opts.common.param('ecRecoverGas')
if (!gasLimitCheck(opts, gasUsed, 'ECRECOVER (0x01)')) {
if (!gasLimitCheck(opts, gasUsed, pName)) {
return OOGResult(opts.gasLimit)
}

Expand All @@ -34,7 +37,7 @@ export function precompile01(opts: PrecompileInput): ExecResult {
// However, this should throw, only 27 and 28 is allowed as input
if (vBigInt !== BIGINT_27 && vBigInt !== BIGINT_28) {
if (opts._debug !== undefined) {
opts._debug(`ECRECOVER (0x01) failed: v neither 27 nor 28`)
opts._debug(`${pName} failed: v neither 27 nor 28`)
}
return {
executionGasUsed: gasUsed,
Expand All @@ -49,15 +52,15 @@ export function precompile01(opts: PrecompileInput): ExecResult {
try {
if (opts._debug !== undefined) {
opts._debug(
`ECRECOVER (0x01): PK recovery with msgHash=${bytesToHex(msgHash)} v=${bytesToHex(
`${pName}: PK recovery with msgHash=${bytesToHex(msgHash)} v=${bytesToHex(
v,
)} r=${bytesToHex(r)}s=${bytesToHex(s)}}`,
)
}
publicKey = ecrecoverFunction(msgHash, bytesToBigInt(v), r, s)
} catch (e: any) {
if (opts._debug !== undefined) {
opts._debug(`ECRECOVER (0x01) failed: PK recovery failed`)
opts._debug(`${pName} failed: PK recovery failed`)
}
return {
executionGasUsed: gasUsed,
Expand All @@ -66,7 +69,7 @@ export function precompile01(opts: PrecompileInput): ExecResult {
}
const address = setLengthLeft(publicToAddress(publicKey), 32)
if (opts._debug !== undefined) {
opts._debug(`ECRECOVER (0x01) return address=${bytesToHex(address)}`)
opts._debug(`${pName} return address=${bytesToHex(address)}`)
}
return {
executionGasUsed: gasUsed,
Expand Down
7 changes: 5 additions & 2 deletions packages/evm/src/precompiles/02-sha256.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@ import { OOGResult } from '../evm.js'

import { gasLimitCheck } from './util.js'

import { getPrecompileName } from './index.js'

import type { ExecResult } from '../types.js'
import type { PrecompileInput } from './types.js'

export function precompile02(opts: PrecompileInput): ExecResult {
const pName = getPrecompileName('02')
const data = opts.data
const sha256Function = opts.common.customCrypto.sha256 ?? sha256
let gasUsed = opts.common.param('sha256Gas')
gasUsed += opts.common.param('sha256WordGas') * BigInt(Math.ceil(data.length / 32))

if (!gasLimitCheck(opts, gasUsed, 'KECCAK256 (0x02)')) {
if (!gasLimitCheck(opts, gasUsed, pName)) {
return OOGResult(opts.gasLimit)
}

const hash = sha256Function(data)
if (opts._debug !== undefined) {
opts._debug(`KECCAK256 (0x02) return hash=${bytesToHex(hash)}`)
opts._debug(`${pName} return hash=${bytesToHex(hash)}`)
}

return {
Expand Down
7 changes: 5 additions & 2 deletions packages/evm/src/precompiles/03-ripemd160.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@ import { OOGResult } from '../evm.js'

import { gasLimitCheck } from './util.js'

import { getPrecompileName } from './index.js'

import type { ExecResult } from '../types.js'
import type { PrecompileInput } from './types.js'

export function precompile03(opts: PrecompileInput): ExecResult {
const pName = getPrecompileName('03')
const data = opts.data

let gasUsed = opts.common.param('ripemd160Gas')
gasUsed += opts.common.param('ripemd160WordGas') * BigInt(Math.ceil(data.length / 32))

if (!gasLimitCheck(opts, gasUsed, 'RIPEMD160 (0x03)')) {
if (!gasLimitCheck(opts, gasUsed, pName)) {
return OOGResult(opts.gasLimit)
}

const hash = setLengthLeft(ripemd160(data), 32)
if (opts._debug !== undefined) {
opts._debug(`RIPEMD160 (0x03) return hash=${bytesToHex(hash)}`)
opts._debug(`${pName} return hash=${bytesToHex(hash)}`)
}

return {
Expand Down
7 changes: 5 additions & 2 deletions packages/evm/src/precompiles/04-identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,23 @@ import { OOGResult } from '../evm.js'

import { gasLimitCheck } from './util.js'

import { getPrecompileName } from './index.js'

import type { ExecResult } from '../types.js'
import type { PrecompileInput } from './types.js'

export function precompile04(opts: PrecompileInput): ExecResult {
const pName = getPrecompileName('04')
const data = opts.data

let gasUsed = opts.common.param('identityGas')
gasUsed += opts.common.param('identityWordGas') * BigInt(Math.ceil(data.length / 32))
if (!gasLimitCheck(opts, gasUsed, 'IDENTITY (0x04)')) {
if (!gasLimitCheck(opts, gasUsed, pName)) {
return OOGResult(opts.gasLimit)
}

if (opts._debug !== undefined) {
opts._debug(`IDENTITY (0x04) return data=${short(opts.data)}`)
opts._debug(`${pName} return data=${short(opts.data)}`)
}

return {
Expand Down
11 changes: 7 additions & 4 deletions packages/evm/src/precompiles/05-modexp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { OOGResult } from '../evm.js'

import { gasLimitCheck } from './util.js'

import { getPrecompileName } from './index.js'

import type { ExecResult } from '../types.js'
import type { PrecompileInput } from './types.js'

Expand Down Expand Up @@ -104,6 +106,7 @@ export function expMod(a: bigint, power: bigint, modulo: bigint) {
}

export function precompile05(opts: PrecompileInput): ExecResult {
const pName = getPrecompileName('05')
const data = opts.data.length < 96 ? setLengthRight(opts.data, 96) : opts.data

let adjustedELen = getAdjustedExponentLength(data)
Expand Down Expand Up @@ -137,7 +140,7 @@ export function precompile05(opts: PrecompileInput): ExecResult {
gasUsed = BIGINT_200
}
}
if (!gasLimitCheck(opts, gasUsed, 'MODEXP (0x05)')) {
if (!gasLimitCheck(opts, gasUsed, pName)) {
return OOGResult(opts.gasLimit)
}

Expand All @@ -150,14 +153,14 @@ export function precompile05(opts: PrecompileInput): ExecResult {

if (bLen > maxSize || eLen > maxSize || mLen > maxSize) {
if (opts._debug !== undefined) {
opts._debug(`MODEXP (0x05) failed: OOG`)
opts._debug(`${pName} failed: OOG`)
}
return OOGResult(opts.gasLimit)
}

if (mEnd > maxInt) {
if (opts._debug !== undefined) {
opts._debug(`MODEXP (0x05) failed: OOG`)
opts._debug(`${pName} failed: OOG`)
}
return OOGResult(opts.gasLimit)
}
Expand All @@ -180,7 +183,7 @@ export function precompile05(opts: PrecompileInput): ExecResult {

const res = setLengthLeft(R, Number(mLen))
if (opts._debug !== undefined) {
opts._debug(`MODEXP (0x05) return value=${bytesToHex(res)}`)
opts._debug(`${pName} return value=${bytesToHex(res)}`)
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import { EvmErrorResult, OOGResult } from '../evm.js'

import { gasLimitCheck } from './util.js'

import { getPrecompileName } from './index.js'

import type { EVM } from '../evm.js'
import type { ExecResult } from '../types.js'
import type { PrecompileInput } from './types.js'

export function precompile06(opts: PrecompileInput): ExecResult {
const gasUsed = opts.common.param('ecAddGas')
if (!gasLimitCheck(opts, gasUsed, 'ECADD (0x06)')) {
const pName = getPrecompileName('06')
const gasUsed = opts.common.param('bn254AddGas')
if (!gasLimitCheck(opts, gasUsed, pName)) {
return OOGResult(opts.gasLimit)
}

Expand All @@ -23,21 +26,21 @@ export function precompile06(opts: PrecompileInput): ExecResult {
returnData = (opts._EVM as EVM)['_bn254'].add(input)
} catch (e: any) {
if (opts._debug !== undefined) {
opts._debug(`ECADD (0x06) failed: ${e.message}`)
opts._debug(`${pName} failed: ${e.message}`)
}
return EvmErrorResult(e, opts.gasLimit)
}

// check ecadd success or failure by comparing the output length
if (returnData.length !== 64) {
if (opts._debug !== undefined) {
opts._debug(`ECADD (0x06) failed: OOG`)
opts._debug(`${pName} failed: OOG`)
}
return OOGResult(opts.gasLimit)
}

if (opts._debug !== undefined) {
opts._debug(`ECADD (0x06) return value=${bytesToHex(returnData)}`)
opts._debug(`${pName} return value=${bytesToHex(returnData)}`)
}

return {
Expand Down
Loading

0 comments on commit 4da6647

Please sign in to comment.