1

Is there a way to use inline assembly keccak256(p, n) work like the Solidity keccak256(p)? I imagine there would be a neutral input I could give for either p or n to make that happen?

Ahmed Ihsan Tawfeeq
  • 4,524
  • 2
  • 19
  • 47

1 Answers1

3

From this answer, we know that we need the pointer and the length of the data to use inline assembly keccak256(p, n). Therefore, when using inline assembly keccak256 you need to indicate the length of the input to use a neutral input.

For this example I will use bytes since according to the docs the keccak256 function receives bytes. If you use a different variable type, such as uint you need to convert it into bytes. So, note that the function should be modified depending on your input.

Hence, one option to make a general function could be the following:

  • We need to load the length (first 32 bytes) using mload(_a).
  • We need to load the data using add(_data, 0x20). Just to clarify, 0x20 is 32 bytes in hex.

Thus, inline assembly keccak256(p, n) will have the following parameters:

keccak256(add(_a, 0x20), mload(_a))

You can test on Remix the following functions:

function solidityKeccak (bytes memory _input) public pure returns (bytes32) {
    return keccak256(abi.encodePacked(_input));
}

function assemblyKeccak (bytes memory _input) public pure returns (bytes32 x) { assembly { x := keccak256(add(_input, 0x20), mload(_input)) } }


Example with a storage reference:

Code to test on Remix:

// For dynamic array variables, this slot contains the length.
bytes example = hex"0000000000000000000000000000000000000000000000000000000000001234"; // Storage slot #0

function assemblyKeccakStorage () public view returns (bytes32 x) { assembly { let value := sload(keccak256(example.slot, div(sub(sload(example.slot), 1), 2))) let ptr := 0x40 // Free memory pointer mstore(ptr, value) x := keccak256(ptr, div(sub(sload(example.slot), 1), 2)) } }

To understand better the code:

  • example.slot returns 0.
  • div(sub(sload(example.slot), 1), 2)) is the reverse operation from the docs:

For byte arrays that store data which is 32 or more bytes long, the main slot p stores length * 2 + 1 and the data is stored as usual in keccak256(p).

alberto
  • 3,343
  • 2
  • 12
  • 21
  • Is add(_data, 0x20) the storage location for the data? – Ahmed Ihsan Tawfeeq Aug 19 '21 at 08:25
  • @scorpion9979 Is where the data starts, yes. Because the first 32 bytes is for the length, so you need to count after this 32 bytes to get the data. – alberto Aug 19 '21 at 08:28
  • Oh, it's the memory location for data because memory layout always has first 32 bytes for length, and then the consequent 32-byte locations for data without any packing (elements padded with zeros). – Ahmed Ihsan Tawfeeq Aug 19 '21 at 08:32
  • Would be great if you could also include an example where the function input is a storage reference. – Ahmed Ihsan Tawfeeq Aug 19 '21 at 08:32
  • @scorpion9979 Done. Just do the same, get the value in storage and then save it in memory. After that, you need to indicate the pointer where the value is stored and the length to compute the ´keccak256` hash. – alberto Aug 19 '21 at 17:08