Skip to content

Commit

Permalink
Fix Blake2F gas + output calculation on non-zero aligned inputs (#3201)
Browse files Browse the repository at this point in the history
* refactor(precompiles/09-blake2f.ts): improve readability and performance by using DataView with byteOffset instead of subarray

The changes in this commit refactor the code in the `precompile09` function in the `09-blake2f.ts` file. The changes improve the readability and performance of the code by using the `DataView` constructor with `byteOffset` instead of using `subarray` to create new `DataView` instances.

Before the changes:
- The `rounds`, `hRaw`, `mRaw`, and `tRaw` variables were created using `subarray` to extract specific parts of the `data` array buffer.
- The `subarray` method was used with specific indices to create new `DataView` instances.

After the changes:
- The `rounds`, `hRaw`, `mRaw`, and `tRaw` variables are created using the `DataView` constructor with `byteOffset` to directly access the desired parts of the `data` array buffer.
- The `DataView` constructor is used with the appropriate `byteOffset` values to create new `DataView` instances.

These changes improve the readability of the code by making it clearer which parts of the `data` array buffer are being accessed. Additionally, using `DataView` with `byteOffset` instead of `subarray` can improve performance by avoiding unnecessary memory allocations.

* evm: add blake2f test

* evm: blake2f test: add extra comment

* evm: fix blake2f "it.only"

---------

Co-authored-by: Jochem Brouwer <jochembrouwer96@gmail.com>
  • Loading branch information
kchojn and jochem-brouwer authored Dec 16, 2023
1 parent 44e069e commit a58c6cb
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 5 deletions.
8 changes: 4 additions & 4 deletions packages/evm/src/precompiles/09-blake2f.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,10 @@ export function precompile09(opts: PrecompileInput): ExecResult {
}
}

const rounds = new DataView(data.subarray(0, 4).buffer).getUint32(0)
const hRaw = new DataView(data.buffer, 4, 64)
const mRaw = new DataView(data.buffer, 68, 128)
const tRaw = new DataView(data.buffer, 196, 16)
const rounds = new DataView(data.buffer, data.byteOffset).getUint32(0)
const hRaw = new DataView(data.buffer, data.byteOffset + 4, 64)
const mRaw = new DataView(data.buffer, data.byteOffset + 68, 128)
const tRaw = new DataView(data.buffer, data.byteOffset + 196, 16)
// final
const f = lastByte === 1

Expand Down
36 changes: 35 additions & 1 deletion packages/evm/test/precompiles/09-blake2f.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Chain, Common, Hardfork } from '@ethereumjs/common'
import { bytesToHex, hexToBytes } from '@ethereumjs/util'
import { Address, bytesToHex, hexToBytes } from '@ethereumjs/util'
import { assert, describe, it } from 'vitest'

import { EVM, getActivePrecompiles } from '../../src/index.js'
Expand Down Expand Up @@ -114,4 +114,38 @@ describe('Precompiles: BLAKE2F', () => {
assert.equal(result.exceptionError?.error, t.expectedError, 'should generate expected error')
})
}

it('should also work on non-zero aligned inputs', async () => {
const addr = Address.zero()
// Blake2f calldata from https://etherscan.io/tx/0x4f2e13a0a3f14033630ab2b8cdad09d316826375f761ded5b31253bb42e0a476
// (This tx calls into Blake2f multiple times, but one of them is taken)
const calldata =
'0x0000000c28c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b3dd8338ed89de6791854126751ac933302810c04147014e9eb472e4dbc09d3c96abb531c9ae39c9e6c454cb83913d688795e237837d30258d11ea7c75201003000454cb83913d688795e237837d30258d11ea7c752011af5b8015c64d39ab44c60ead8317f9f5a9b6c4c01000000000100ca9a3b000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000'

// This code:
// -> Copies the CALLDATA into memory, but at offset 0x20 (32)
// -> Calls Blake2F with this data (so, with the calldata)
// -> Returns the data from Blake2F
const code = '0x366000602037' + '600080366020600060095AF1593D6000593E3D90F3'
await evm.stateManager.putContractCode(addr, hexToBytes(code))

const res = await evm.runCall({
data: hexToBytes(calldata),
to: addr,
})

/*
Note: this value is retrieved from infura by calling directly into Blake2F with the above `calldata`:
curl https://mainnet.infura.io/v3/API_KEY_HERE \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_call","params": [{"to": "0x0000000000000000000000000000000000000009","data": "0x0000000c28c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b3dd8338ed89de6791854126751ac933302810c04147014e9eb472e4dbc09d3c96abb531c9ae39c9e6c454cb83913d688795e237837d30258d11ea7c75201003000454cb83913d688795e237837d30258d11ea7c752011af5b8015c64d39ab44c60ead8317f9f5a9b6c4c01000000000100ca9a3b000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000"}, "latest"],"id":1}'
*/

const expected =
'0x772acbd3f30b0c3f5f53e8b836ab406f7d8d46fd4b27e2ce2ecd67dbf18c958741e2c49d1f1b1a463907a484f970c057dab9684062b82fda69e8a0057e14766f'

assert.equal(bytesToHex(res.execResult.returnValue), expected)
})
})

0 comments on commit a58c6cb

Please sign in to comment.