# Gas cost of a sha256 hash

I'm confused about the cost of the sha256 function, because my understanding of the cost from the yellow paper ( https://ethereum.github.io/yellowpaper/paper.pdf (Appendix E. Precompiled Contracts) ) doesn't match my experiments of executing the sha256 hash function in Remix.

Here's my understanding of how much sha256 should cost for a 'word' (a 256-bit input):

From the yellow paper:

We define `Ξ_{SHA256}` as a precompiled contract implementing the SHA2-256 hash function. Its gas usage is dependent on the input data size, a factor rounded up to the nearest number of words.

The gas requirement (`g_r`) is stated as:

`g_r = 60 + ( 12 * ( |I_d| / 32􏰛) )`

(where I've edited the notation to look nicer in markdown without latex).

Elsewhere in the paper, it defines `I_d` as:

`I_d`, the byte array that is the input data to this execution; if the execution agent is a transaction, this would be the transaction data.

So my interpretation of gas cost for a word of 256-bits (32-bytes) is:

`g_r = 60 + ( 12 * 32 / 32 ) = 60 + 12 = 72 gas`

However:

I've explored the gas costs of the following simple function in Remix:

``````function hash() public pure returns (uint256 a) {
a = 1234;
a = uint256(sha256(abi.encodePacked(a)));
}
``````

This has a transaction cost of `22789 gas` of which the execution cost is `1517 gas`.

Now, some of this will be extraneous storage costs to store `a` on the stack (and other stuff).

'Commenting out' the hashing line (`// a = uint256(sha256(abi.encodePacked(a)));`), for a very rough comparison, gives a transaction cost of `21486 gas` of which the execution cost is `214 gas`.

So a very approx. experimental cost of sha256 appears to be `1517 - 214 = 1303 gas`. I'm surprised at how high this cost is (given my understanding that sha256 should be just `72 gas`).

Any help would be appreciated in understanding the actual cost of sha256 :)

• Answered here I believe. – goodvibration Sep 21 at 20:54
• Thanks - this is helpful. I think it's nice to have sha256 addressed separately, as I hadn't thought to search "keccak" for a similar answer (I had "sha256" blinders on). Also, @Ismail has given some extra important information not contained in the other thread. – Michael Connor Sep 22 at 10:50

The Yellow paper only stablishes costs for opcodes of the EVM at a low level. The solidity compiler have to generate extra code to accomodate to the source code written at a high level.

Some of the details the compiler hides from user

• `abi.encodePacked` converts its parameters to a byte sequence in memory. It has to allocate memory and copy its parameters there.
• `sha256` is a precompiled contract. It has to make the call to the precompiled contract, check the result and copy the output. Making a contract call is 700 gas.

Another thing to consider is that the compiler by default generates unoptimized code and it can have many redundancies.

• Thanks! That's interesting; I hadn't appreciated precompiled contracts counted as a proper 'contract call'. So even if there was a low-level assembly implementation to call sha256 (instead of using solidity), there would still be a crude lower bound gas cost of 72 + 700? – Michael Connor Sep 22 at 10:38
• Yes, you will have to pay 700 gas for the call, and some more for copying the input and getting the output if you care about that. – Ismael Sep 22 at 19:33

Here's a cheaper implementation of sha256, using assembly, that I've written:

``````    function assemblyHash() public returns (bytes32 memory h) {
bytes32 memory inputs;
inputs = "0x1234";
inputs = "0x5678";
bool success;
assembly {
/*
gasLimit: calling with gas equal to not(0), as we have here, will send all available gas to the function being called. This removes the need to guess or upper-bound the amount of gas being sent yourself. As an alternative, we could have guessed the gas needed: with: sub(gas, 2000)
to: the sha256 precompile is at address 0x2: Sending the amount of gas currently available to us, after subtracting 2000;
value: 0 (no ether will be sent to the contract)
inputOffset: I believe this is just the input data
inputSize: hex input size = 0x40 = 2 x 32-bytes
outputOffset: where will the output be stored (in variable h in our case)
outputSize: sha256 outputs 256-bits = 32-bytes = 0x20 in hex
*/
success := call(not(0), 2, 0, inputs, 0x40, h, 0x20)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}
}
``````