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?
-
What do you mean with "neutral input"? Any input (uint, string, bytes...)?– albertoCommented 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.– Ahmed Ihsan TawfeeqCommented Aug 18, 2021 at 17:22
-
Hope I have understood your comment correctly.– albertoCommented Aug 19, 2021 at 8:07
1 Answer
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 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
keccak256
function 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.slot
returns0
.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 slotp
storeslength * 2 + 1
and the data is stored as usual inkeccak256(p)
.
-
Is
add(_data, 0x20)
the storage location for the data? Commented 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.– albertoCommented 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). Commented Aug 19, 2021 at 8:32
-
Would be great if you could also include an example where the function input is a storage reference. Commented Aug 19, 2021 at 8:32
-
1