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?
- 4,524
- 2
- 19
- 47
-
What do you mean with "neutral input"? Any input (uint, string, bytes...)? – alberto Aug 18 '21 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. – Ahmed Ihsan Tawfeeq Aug 18 '21 at 17:22
-
Hope I have understood your comment correctly. – alberto Aug 19 '21 at 08:07
1 Answers
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,0x20is 32 bytes inhex.
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:
- We need to load the value in storage. Please read the following sections of the docs: Layout of State Variables in Storage and Mappings and Dynamic Arrays.
- Then save the value in memory, preferably in the free memory pointer (
0x40) - Compute the
keccak256function by indicating the pointer and the length of the data.
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.slotreturns0.div(sub(sload(example.slot), 1), 2))is the reverse operation from the docs:
For byte arrays that store data which is
32or more bytes long, the main slotpstoreslength * 2 + 1and the data is stored as usual inkeccak256(p).
- 3,343
- 2
- 12
- 21
-
-
@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