Ethereum uses KECCAK-256. It should be noted that it does not follow
the FIPS-202 based standard (a.k.a SHA-3), which was finalized in August 2015.
According to this, NIST changed the padding to SHA3-256(M) = KECCAK [512] (M || 01, 256).
This was different from the padding proposed by the Keccak team in The Keccak SHA-3 submission version 3 (final, winning version). The difference is the additional '01' bits appended to the message. People are now calling the "submitted version 3" SHA-3 Keccak hashing "Keccak" and the finalized NIST SHA-3 standard "SHA-3".
Using this online generator and the Solidity Online Compiler, I tested the difference between Keccak-256 and SHA3-256. I hashed the word testing using Ethereum and the 2 SHA3 hashing algorithms:
Ethereum SHA3 function in Solidity = 5f16f4c7f149ac4f9510d9cf8cf384038ad348b3bcdc01915f95de12df9d1b02
Keccak-256 = 5f16f4c7f149ac4f9510d9cf8cf384038ad348b3bcdc01915f95de12df9d1b02
SHA3-256 (NIST Standard) = 7f5979fb78f082e8b1c676635db8795c4ac6faba03525fb708cb5fd68fd40c5e
Jehan's answer is great, but we need to explain one more thing: Why does sha3(1)
in solidity produce b10e2d...fa0cf6
?
This is because solidity's sha3 function hashes its inputs based on the argument types. Thus the value 1
will generate a different hash if it is stored as bytes8
, bytes16
, bytes32
, etc. Since sha3(1)
is being passed 1
as a number literal, it is converted into the smallest necessary type, uint8
1.
8 bits fit into 2 hex characters, so if you pad your input to 2 characters you will get the same result in web3:
Javascript:
web3.sha3(leftPad((1).toString(16), 2, 0), { encoding: 'hex' })
// 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2
Likewise, you can cast the number on the solidity side:
Solidity:
// uint is equivalent to uint256
sha3(uint(1))
// b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
Javascript:
// note that the value is padded by 64 characters to fit 256 bits
web3.sha3(leftPad((1).toString(16), 64, 0), { encoding: 'hex' })
// b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
A note about BigNumber
types:
They don't work automatically with web3.sha3
. You have to convert them to hex first.
Solidity:
sha3(uint(100 ether))
// c7cc234d21c9cfbd4632749fd77669e7ae72f5241ce5895e410c45185a469273
Javascript:
// the .slice is to remove the leading '0x'
web3.sha3(leftPad(web3.toHex(web3.toWei(100)).slice(2).toString(16), 64, 0), { encoding: 'hex' })
// c7cc234d21c9cfbd4632749fd77669e7ae72f5241ce5895e410c45185a469273
EDIT:
I wrote a small lib that provides a version of web3.sha3
that exactly matches the behavior of sha3
in Solidity. Hopefully this clears up all your hashing woes :).
https://github.com/raineorshine/solidity-sha3
Best Answer
A hash function is different to a proof-of-work algorithm. Much of the effort in following a proof-of-work algorithm involves making hashes, but they're distinct things.
Ethash is the proof-of-work algorithm. Keccak-256 is the most commonly-used hash function. Keccak-256 is used internally in places like when making hashes for block headers, but the place you're most likely to run into it, and the place discussed in the post you link, is when making hashes of things in your own Solidity contract. It's possible to implement other hash functions in Solidity for use in Ethereum contracts, but it's most common to use Keccak-256 (which the Ethereum community used to refer to as SHA3.)