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?

3
  • What do you mean with "neutral input"? Any input (uint, string, bytes...)?
    – alberto
    Aug 18, 2021 at 16:37
  • @alberto meaning an input to the line assembly keccack256 that along with the intended input would give the same result as calling the Solidity keccack256 with one input. Aug 18, 2021 at 17:22
  • Hope I have understood your comment correctly.
    – alberto
    Aug 19, 2021 at 8:07

1 Answer 1

1

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).

5
  • Is add(_data, 0x20) the storage location for the data? Aug 19, 2021 at 8: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, 2021 at 8: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). Aug 19, 2021 at 8:32
  • Would be great if you could also include an example where the function input is a storage reference. Aug 19, 2021 at 8: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, 2021 at 17:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.