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
keccak256
produces identical results to itssha3
so everything in this thread applies tokeccak256
.