1

Before Solidity v0.5, keccak256() took multiple arguments, and after v0.5 it requires a single bytes argument. Which of the two encoding types, encode/encodePacked, did the compiler use?

2 Answers 2

1

It was abi.encodePacked(). keccak256(abi.encodePacked(a, b, c)) on 0.5+ is equivalent to keccak256(a, b, c) in earlier versions.

Solidity v0.5.0 Breaking Changes > Semantic and Syntactic Changes

The functions .call(), .delegatecall(), staticcall(), keccak256(), sha256() and ripemd160() now accept only a single bytes argument. Moreover, the argument is not padded. This was changed to make more explicit and clear how the arguments are concatenated. Change every .call() (and family) to a .call("") and every .call(signature, a, b, c) to use .call(abi.encodeWithSignature(signature, a, b, c)) (the last one only works for value types). Change every keccak256(a, b, c) to keccak256(abi.encodePacked(a, b, c)).

8
  • Thank you. Very appreciated, helps a lot. I Yes I saw that text on the v0.5 update docs. But could be interpreted different ways, since keccak256(a, b, c) is not forced to be changed to abi.encodePacked, can also be changed to abi.encode, or, just any bytes sequence. I realized after your answer that I could just test myself in Remix by using compiler older than v0.5, did so, and you are correct.
    – Johan
    Oct 23, 2021 at 21:54
  • Yes I agree that the wording could be more explicit but I think that in context it's still clear enough that the new version is meant to give you the same hash. The purpose of the change was just to make the lack of padding explicit and not change behavior.
    – cameel
    Oct 24, 2021 at 8:54
  • I don't think it is very explicit but since it can easily just be tested, it does not matter as much. I'm not complaining, I now understand what change was made and why, and thank you a lot for your answer that pointed me in the right direction.
    – Johan
    Oct 24, 2021 at 20:41
  • re: the purpose, I'm pretty sure it was that there is a major security issue with encodePacked, and that prioritizing cheap hash function for large pre-images had to be abandoned. In my own contract I just use abi.encode now, since the inputs are 32-byte words and "packing" adds nothing, and since people often use 32-byte words, "packing" is only meaningful in some cases (but if one had to be chosen as standard, I would have gone with packing too if not for the security issue... )
    – Johan
    Oct 24, 2021 at 20:44
  • 1
    yeah that one but I wouldn't call it "collisions" since it is the exact same pre-image. so it actually isn't a hash collision
    – Johan
    Oct 25, 2021 at 9:57
1

Thanks to Cameel's answer I realized that I could just test myself in Remix using compiler older than v0.5. I did so, because I wanted to verify the answer, and it was correct. Since this approach is good for other noobs to use, I post it here as an answer. Solidity version has to be one that has included the abi.encode/encodePacked methods (added in v0.4.24), but not changed keccak256(a, b, c) into keccak256(abi.encodePacked(a, b, c)), done in v0.5.

pragma solidity ^0.4.26;

contract Test {
    
    function pre_v0_5_keccak256encodingFormatStandard() external returns (bool, bool) {
        return (
            keccak256(abi.encodePacked(uint8(4))) == keccak256(uint8(4)),
            keccak256(abi.encode(uint8(4))) == keccak256(uint8(4))
            );
    }    
}

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.