I'm searching for vulnrabilities and I have the following code:
function hash(
address[] memory addresses,
uint256[] memory values,
bytes[] memory data,
bytes32 description
) public returns (uint256) {
return uint256(keccak256(abi.encode(targets, values, data, description)));
}
Can the function receive different inputs and return the same value? If yes, is there an example? If not, why not, and how is abi.encode handle these types?
I am aware that keccak256 is secure but if abi.encode is not secure than the keccack256 safety is poitless.
Best Answer
It depends on what you mean by 'different values'.
But essentially, yes, abi.encode can return the same encoding when given different sets of parameters:
It can get a bit harder with dynamic parameters (variable length arrays) but not impossible neither :
Now whether that's actually usable is another question... the decode step requires a signature to interpret the encoding, and even if you used a different set of values to generate the same encoding, with a unique signature on the receiving end there will be no difference...
For example :
does not revert, even though the value given to the encoder are different, the output is the same so the interpretation on the callee's side is also the same.
Both encoding are interpreted as "a" by the function wantsAnA because it is explicitely looking for an encoding compatible with its signature : a string.
So the key takeaway is that if abi.encode generate the same output, it's the same encoding... so at a binary level there is no difference at all. So for your specific example, it's as if the "true" values were given as parameter, this is not a vulnerability, just a very contrived way of doing the same thing.
EDIT
If as you say you must respect input types, there will be no collision. You only deal with dynamic arrays, the encoding for those are :
For example : the string "a" from the previous examples is encoded as :
offset :
0x0000000000000000000000000000000000000000000000000000000000000020
length :
0x0000000000000000000000000000000000000000000000000000000000000001
data[0] :
0x6100000000000000000000000000000000000000000000000000000000000000
Everything is padded to 32 bytes and changing anything, length or data, will change the final output in the respective words. Static types are also immune to collision with different values (as long as there is padding and input types are respected).
By strictly respecting the same input types there is no collision possible with abi.encode and different input values. If they are different, they differ in actual data or in length/data either way this will be reflected in the encoding.