From 83030aeb44927178275b9f5998725007a4ba47d5 Mon Sep 17 00:00:00 2001 From: Holger Drewes Date: Thu, 27 Nov 2025 13:51:44 +0100 Subject: [PATCH 1/6] Remove redundant modulo length check for msmg1 precompile --- packages/evm/src/precompiles/0c-bls12-g1msm.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/evm/src/precompiles/0c-bls12-g1msm.ts b/packages/evm/src/precompiles/0c-bls12-g1msm.ts index c4e8e5169e3..b3bcc916840 100644 --- a/packages/evm/src/precompiles/0c-bls12-g1msm.ts +++ b/packages/evm/src/precompiles/0c-bls12-g1msm.ts @@ -42,15 +42,6 @@ export async function precompile0c(opts: PrecompileInput): Promise { return OOGResult(opts.gasLimit) } - if (inputData.length % 160 !== 0) { - if (opts._debug !== undefined) { - opts._debug(`${pName} failed: Invalid input length length=${inputData.length}`) - } - return EVMErrorResult( - new EVMError(EVMError.errorMessages.BLS_12_381_INVALID_INPUT_LENGTH), - opts.gasLimit, - ) - } if (!moduloLengthCheck(opts, 160, pName)) { return EVMErrorResult( new EVMError(EVMError.errorMessages.BLS_12_381_INVALID_INPUT_LENGTH), From e83979f3469745bd083127718861db2ffec6e766 Mon Sep 17 00:00:00 2001 From: Holger Drewes Date: Thu, 27 Nov 2025 14:03:54 +0100 Subject: [PATCH 2/6] Addition note on coverage command how to include specific files --- packages/vm/DEVELOPER.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/DEVELOPER.md b/packages/vm/DEVELOPER.md index 423fdfa6fac..09afe59b929 100644 --- a/packages/vm/DEVELOPER.md +++ b/packages/vm/DEVELOPER.md @@ -202,7 +202,7 @@ It is also possible to only run the tests from the skip lists: The following command shows an example of how to get coverage for a set of the official spec test files: ```bash -VITE_CUSTOM_TESTS_PATH=../execution-spec-tests/fusaka-devnet-5/state_tests/osaka/eip7951_p256verify_precompiles VITE_FORK=Osaka npx vitest watch --coverage --coverage.reporter=html --ui --coverage.allowExternal test/tester/state.spec.ts +VITE_CUSTOM_TESTS_PATH=../execution-spec-tests/fusaka-devnet-5/state_tests/osaka/eip7951_p256verify_precompiles VITE_FORK=Osaka npx vitest watch --coverage --coverage.reporter=html --ui --coverage.allowExternal --coverage.include=evm/src/precompiles/0c-bls12-g1msm.ts [--coverage.include=evm/src/precompiles/index.ts] test/tester/state.spec.ts ``` This can be useful to identify gaps in the coverage of the official spec tests and see where additional tests are needed. From 9ecdf437b57a8897f549963968e444b651b03457 Mon Sep 17 00:00:00 2001 From: Holger Drewes Date: Thu, 27 Nov 2025 14:08:39 +0100 Subject: [PATCH 3/6] Remove unused BLS mul operations + type adjustment (backwards compatible) (left-overs from EIP evolution) --- packages/evm/src/precompiles/bls12_381/mcl.ts | 20 ---------------- .../evm/src/precompiles/bls12_381/noble.ts | 24 ------------------- packages/evm/src/types.ts | 2 -- 3 files changed, 46 deletions(-) diff --git a/packages/evm/src/precompiles/bls12_381/mcl.ts b/packages/evm/src/precompiles/bls12_381/mcl.ts index 65ed1389352..993a47cae5c 100644 --- a/packages/evm/src/precompiles/bls12_381/mcl.ts +++ b/packages/evm/src/precompiles/bls12_381/mcl.ts @@ -234,16 +234,6 @@ export class MCLBLS implements EVMBLSInterface { return BLS12_381_FromG1Point(result) } - mulG1(input: Uint8Array): Uint8Array { - // convert input to G1 points, add them, and convert the output to a Uint8Array. - const p = BLS12_381_ToG1Point(input.subarray(0, BLS_G1_POINT_BYTE_LENGTH), this._mcl) - const frPoint = BLS12_381_ToFrPoint(input.subarray(BLS_G1_POINT_BYTE_LENGTH, 160), this._mcl) - - const result = this._mcl.mul(p, frPoint) - - return BLS12_381_FromG1Point(result) - } - addG2(input: Uint8Array): Uint8Array { // convert input to G1 points, add them, and convert the output to a Uint8Array. const p1 = BLS12_381_ToG2Point(input.subarray(0, BLS_G2_POINT_BYTE_LENGTH), this._mcl, false) @@ -258,16 +248,6 @@ export class MCLBLS implements EVMBLSInterface { return BLS12_381_FromG2Point(result) } - mulG2(input: Uint8Array): Uint8Array { - // convert input to G2 point/Fr point, add them, and convert the output to a Uint8Array. - const p = BLS12_381_ToG2Point(input.subarray(0, BLS_G2_POINT_BYTE_LENGTH), this._mcl) - const frPoint = BLS12_381_ToFrPoint(input.subarray(BLS_G2_POINT_BYTE_LENGTH, 288), this._mcl) - - const result = this._mcl.mul(p, frPoint) - - return BLS12_381_FromG2Point(result) - } - mapFPtoG1(input: Uint8Array): Uint8Array { // convert input to Fp1 point const Fp1Point = BLS12_381_ToFpPoint(input.subarray(0, 64), this._mcl) diff --git a/packages/evm/src/precompiles/bls12_381/noble.ts b/packages/evm/src/precompiles/bls12_381/noble.ts index 1ce87346b1d..8006d179449 100644 --- a/packages/evm/src/precompiles/bls12_381/noble.ts +++ b/packages/evm/src/precompiles/bls12_381/noble.ts @@ -172,18 +172,6 @@ export class NobleBLS implements EVMBLSInterface { return result } - mulG1(input: Uint8Array): Uint8Array { - // convert input to G1 points, add them, and convert the output to a Uint8Array. - const p = BLS12_381_ToG1Point(input.subarray(0, BLS_G1_POINT_BYTE_LENGTH)) - const scalar = BLS12_381_ToFrPoint(input.subarray(BLS_G1_POINT_BYTE_LENGTH, 160)) - - if (scalar === BIGINT_0) { - return BLS_G1_INFINITY_POINT_BYTES - } - const result = p.multiplyUnsafe(scalar) - return BLS12_381_FromG1Point(result.toAffine()) - } - addG2(input: Uint8Array): Uint8Array { const p1 = BLS12_381_ToG2Point(input.subarray(0, BLS_G2_POINT_BYTE_LENGTH), false) const p2 = BLS12_381_ToG2Point( @@ -196,18 +184,6 @@ export class NobleBLS implements EVMBLSInterface { return result } - mulG2(input: Uint8Array): Uint8Array { - // convert input to G2 point/Fr point, add them, and convert the output to a Uint8Array. - const p = BLS12_381_ToG2Point(input.subarray(0, BLS_G2_POINT_BYTE_LENGTH)) - const scalar = BLS12_381_ToFrPoint(input.subarray(BLS_G2_POINT_BYTE_LENGTH, 288)) - - if (scalar === BIGINT_0) { - return BLS_G2_INFINITY_POINT_BYTES - } - const result = p.multiplyUnsafe(scalar) - return BLS12_381_FromG2Point(result.toAffine()) - } - mapFPtoG1(input: Uint8Array): Uint8Array { // convert input to Fp1 point const FP = BLS12_381_ToFpPoint(input.subarray(0, 64)) diff --git a/packages/evm/src/types.ts b/packages/evm/src/types.ts index 81e7ead369c..ea2f8ed6c95 100644 --- a/packages/evm/src/types.ts +++ b/packages/evm/src/types.ts @@ -443,9 +443,7 @@ export interface ExecResult { export type EVMBLSInterface = { init?(): void addG1(input: Uint8Array): Uint8Array - mulG1(input: Uint8Array): Uint8Array addG2(input: Uint8Array): Uint8Array - mulG2(input: Uint8Array): Uint8Array mapFPtoG1(input: Uint8Array): Uint8Array mapFP2toG2(input: Uint8Array): Uint8Array msmG1(input: Uint8Array): Uint8Array From de9b104968fb90e9843f219e0121a984089c4e2c Mon Sep 17 00:00:00 2001 From: Holger Drewes Date: Thu, 27 Nov 2025 14:45:13 +0100 Subject: [PATCH 4/6] Remove BLS BigInt(0) gas fallbacks (do not make sense + distort coverage) --- packages/evm/src/precompiles/0b-bls12-g1add.ts | 2 +- packages/evm/src/precompiles/0c-bls12-g1msm.ts | 2 +- packages/evm/src/precompiles/0d-bls12-g2add.ts | 2 +- packages/evm/src/precompiles/0e-bls12-g2msm.ts | 2 +- packages/evm/src/precompiles/0f-bls12-pairing.ts | 2 +- packages/evm/src/precompiles/10-bls12-map-fp-to-g1.ts | 2 +- packages/evm/src/precompiles/11-bls12-map-fp2-to-g2.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/evm/src/precompiles/0b-bls12-g1add.ts b/packages/evm/src/precompiles/0b-bls12-g1add.ts index f1a620db89d..2427bab54f8 100644 --- a/packages/evm/src/precompiles/0b-bls12-g1add.ts +++ b/packages/evm/src/precompiles/0b-bls12-g1add.ts @@ -16,7 +16,7 @@ export async function precompile0b(opts: PrecompileInput): Promise { const bls = (opts._EVM as EVM)['_bls']! // note: the gas used is constant; even if the input is incorrect. - const gasUsed = opts.common.param('bls12381G1AddGas') ?? BigInt(0) + const gasUsed = opts.common.param('bls12381G1AddGas') if (!gasLimitCheck(opts, gasUsed, pName)) { return OOGResult(opts.gasLimit) } diff --git a/packages/evm/src/precompiles/0c-bls12-g1msm.ts b/packages/evm/src/precompiles/0c-bls12-g1msm.ts index b3bcc916840..d6364a27684 100644 --- a/packages/evm/src/precompiles/0c-bls12-g1msm.ts +++ b/packages/evm/src/precompiles/0c-bls12-g1msm.ts @@ -35,7 +35,7 @@ export async function precompile0c(opts: PrecompileInput): Promise { // on this eventually to be "floored" pair number should happen before the input length modulo // validation (same for g2msm) const numPairs = Math.floor(inputData.length / 160) - const gasUsedPerPair = opts.common.param('bls12381G1MulGas') ?? BigInt(0) + const gasUsedPerPair = opts.common.param('bls12381G1MulGas') const gasUsed = msmGasUsed(numPairs, gasUsedPerPair, BLS_GAS_DISCOUNT_PAIRS_G1) if (!gasLimitCheck(opts, gasUsed, pName)) { diff --git a/packages/evm/src/precompiles/0d-bls12-g2add.ts b/packages/evm/src/precompiles/0d-bls12-g2add.ts index 93946b595e0..3819a320b86 100644 --- a/packages/evm/src/precompiles/0d-bls12-g2add.ts +++ b/packages/evm/src/precompiles/0d-bls12-g2add.ts @@ -16,7 +16,7 @@ export async function precompile0d(opts: PrecompileInput): Promise { const bls = (opts._EVM as EVM)['_bls']! // note: the gas used is constant; even if the input is incorrect. - const gasUsed = opts.common.param('bls12381G2AddGas') ?? BigInt(0) + const gasUsed = opts.common.param('bls12381G2AddGas') if (!gasLimitCheck(opts, gasUsed, pName)) { return OOGResult(opts.gasLimit) } diff --git a/packages/evm/src/precompiles/0e-bls12-g2msm.ts b/packages/evm/src/precompiles/0e-bls12-g2msm.ts index 0b71ba4af76..ee7f4f25e15 100644 --- a/packages/evm/src/precompiles/0e-bls12-g2msm.ts +++ b/packages/evm/src/precompiles/0e-bls12-g2msm.ts @@ -30,7 +30,7 @@ export async function precompile0e(opts: PrecompileInput): Promise { } const numPairs = Math.floor(opts.data.length / 288) - const gasUsedPerPair = opts.common.param('bls12381G2MulGas') ?? BigInt(0) + const gasUsedPerPair = opts.common.param('bls12381G2MulGas') const gasUsed = msmGasUsed(numPairs, gasUsedPerPair, BLS_GAS_DISCOUNT_PAIRS_G2) if (!gasLimitCheck(opts, gasUsed, pName)) { diff --git a/packages/evm/src/precompiles/0f-bls12-pairing.ts b/packages/evm/src/precompiles/0f-bls12-pairing.ts index 63e1124dfc8..824e943077a 100644 --- a/packages/evm/src/precompiles/0f-bls12-pairing.ts +++ b/packages/evm/src/precompiles/0f-bls12-pairing.ts @@ -15,7 +15,7 @@ export async function precompile0f(opts: PrecompileInput): Promise { const pName = getPrecompileName('11') const bls = (opts._EVM as EVM)['_bls']! - const baseGas = opts.common.param('bls12381PairingBaseGas') ?? BigInt(0) + const baseGas = opts.common.param('bls12381PairingBaseGas') // TODO: confirm that this is not a thing for the other precompiles if (opts.data.length === 0) { diff --git a/packages/evm/src/precompiles/10-bls12-map-fp-to-g1.ts b/packages/evm/src/precompiles/10-bls12-map-fp-to-g1.ts index 42690e00076..f8dcebd6368 100644 --- a/packages/evm/src/precompiles/10-bls12-map-fp-to-g1.ts +++ b/packages/evm/src/precompiles/10-bls12-map-fp-to-g1.ts @@ -16,7 +16,7 @@ export async function precompile10(opts: PrecompileInput): Promise { const bls = (opts._EVM as EVM)['_bls']! // note: the gas used is constant; even if the input is incorrect. - const gasUsed = opts.common.param('bls12381MapG1Gas') ?? BigInt(0) + const gasUsed = opts.common.param('bls12381MapG1Gas') if (!gasLimitCheck(opts, gasUsed, pName)) { return OOGResult(opts.gasLimit) } diff --git a/packages/evm/src/precompiles/11-bls12-map-fp2-to-g2.ts b/packages/evm/src/precompiles/11-bls12-map-fp2-to-g2.ts index 8cb7aded655..7b81dc171b6 100644 --- a/packages/evm/src/precompiles/11-bls12-map-fp2-to-g2.ts +++ b/packages/evm/src/precompiles/11-bls12-map-fp2-to-g2.ts @@ -16,7 +16,7 @@ export async function precompile11(opts: PrecompileInput): Promise { const bls = (opts._EVM as EVM)['_bls']! // note: the gas used is constant; even if the input is incorrect. - const gasUsed = opts.common.param('bls12381MapG2Gas') ?? BigInt(0) + const gasUsed = opts.common.param('bls12381MapG2Gas') if (!gasLimitCheck(opts, gasUsed, pName)) { return OOGResult(opts.gasLimit) } From d8dcb5b415f9c6f8006ceedbd4478672aa5a3783 Mon Sep 17 00:00:00 2001 From: Holger Drewes Date: Thu, 27 Nov 2025 14:47:00 +0100 Subject: [PATCH 5/6] Small DEBUG note on coverage docs --- packages/vm/DEVELOPER.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vm/DEVELOPER.md b/packages/vm/DEVELOPER.md index 09afe59b929..73b5ec7c860 100644 --- a/packages/vm/DEVELOPER.md +++ b/packages/vm/DEVELOPER.md @@ -202,12 +202,12 @@ It is also possible to only run the tests from the skip lists: The following command shows an example of how to get coverage for a set of the official spec test files: ```bash -VITE_CUSTOM_TESTS_PATH=../execution-spec-tests/fusaka-devnet-5/state_tests/osaka/eip7951_p256verify_precompiles VITE_FORK=Osaka npx vitest watch --coverage --coverage.reporter=html --ui --coverage.allowExternal --coverage.include=evm/src/precompiles/0c-bls12-g1msm.ts [--coverage.include=evm/src/precompiles/index.ts] test/tester/state.spec.ts +DEBUG=ethjs,dummy:* VITE_CUSTOM_TESTS_PATH=../execution-spec-tests/fusaka-devnet-5/state_tests/osaka/eip7951_p256verify_precompiles VITE_FORK=Osaka npx vitest watch --coverage --coverage.reporter=html --ui --coverage.allowExternal --coverage.include=evm/src/precompiles/0c-bls12-g1msm.ts [--coverage.include=evm/src/precompiles/index.ts] test/tester/state.spec.ts ``` This can be useful to identify gaps in the coverage of the official spec tests and see where additional tests are needed. -The specific command stays in "watch" mode and opens a specific UI to see coverage also for EVM files (this needs the `coverage.allowExternal` flag to be set). +The specific command stays in "watch" mode and opens a specific UI to see coverage also for EVM files (this needs the `coverage.allowExternal` flag to be set). The `DEBUG` part can be helpful to not have coverage being distorted by non-debug calls artificially lowering the coverage. ### Coverage Reporting From 3ae31e9c3d69dd2ba10b42e6aeeae73fbc6be0b2 Mon Sep 17 00:00:00 2001 From: Holger Drewes Date: Thu, 27 Nov 2025 14:55:43 +0100 Subject: [PATCH 6/6] Minor --- packages/evm/src/precompiles/0f-bls12-pairing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/evm/src/precompiles/0f-bls12-pairing.ts b/packages/evm/src/precompiles/0f-bls12-pairing.ts index 824e943077a..6a78ea90f0b 100644 --- a/packages/evm/src/precompiles/0f-bls12-pairing.ts +++ b/packages/evm/src/precompiles/0f-bls12-pairing.ts @@ -28,7 +28,7 @@ export async function precompile0f(opts: PrecompileInput): Promise { ) } - const gasUsedPerPair = opts.common.param('bls12381PairingPerPairGas') ?? BigInt(0) + const gasUsedPerPair = opts.common.param('bls12381PairingPerPairGas') // TODO: For this precompile it is the only exception that the length check is placed before the // gas check. I will keep it there to not side-change the existing implementation, but we should