Karim Stekelenburg
Karim Stekelenburg

Reputation: 643

Solidity and Web3 sha3() methods return something else

In my contract, I have a function that returns the sha3 hash of a certain set of values. While running some tests I found that the value returned from this function differs from the hash value generated by web3.utils.sha3() (with identical arguments).

Here is the code:

Solidity

function hashInfo() public onlyOwner view returns (bytes32) {
      bytes32 hash = sha3(
        '0x969A70A4fa9F69D2D655E4B743abb9cA297E5328',
        '0x496AAFA2960f3Ff530716B5334c9aFf4612e3c27',
        'jdiojd',
        'oidjoidj',
        'idjodj',
        12345
      )  
      return hash;
  }

JS (web3)

async function testHash(instance){
  const contractHash = await instance.methods.hashInfo().call({from: '0x969A70A4fa9F69D2D655E4B743abb9cA297E5328'});
  const localHash = web3.utils.sha3(
    '0x969A70A4fa9F69D2D655E4B743abb9cA297E5328',
    '0x496AAFA2960f3Ff530716B5334c9aFf4612e3c27',
    'jdiojd',
    'oidjoidj',
    'idjodj',
    12345
  )
  console.log(contractHash);
  console.log(localHash);
  console.log('local == contract: ' + (contractHash == localHash));
}

The resulting console output is:

0xe65757c5a99964b72d217493c192c073b9a580ec4b477f40a6c1f4bc537be076
0x3c23cebfe35b4da6f6592d38876bdb93f548085baf9000d538a1beb31558fc6d
local == contract: false

Any ideas? Does this have something to do with passing multiple arguments to the functions? I have also tried to convert everything to a string and concatenate them into one single string, but also without success.

I found out there also if a web3 method called web3.utils.soliditySha3(). This too did not work and gave the following result:

0xe65757c5a99964b72d217493c192c073b9a580ec4b477f40a6c1f4bc537be076
0x0cf65f7c81dab0a5d414539b0e2f3807526fd9c15e197eaa6c7706d27aa7a0f8
local == contract: false

Upvotes: 2

Views: 2204

Answers (1)

Matthew Ludwig
Matthew Ludwig

Reputation: 755

I'm happy I came after your update as I was just gonna suggest solditySHA3. Now that you've got the right function your problem is most likely with Soldity packing it's parameters.

As you can see here, sha3 is an alias to keccak256 which tightly packs it's arguments. Following the link on that page takes you here which fully explains how it's handled. Basically just take the inputs to soliditySHA3 and pack the bits as if they were the sizes of the variables you used. So if you hashed two uint32s (32 bits each, 64 total) you need to take the 2 64 bit Javascript numbers and compress them into 1 Javascript number.

For cases where more than 64 bits are needed I believe you can pass sequential ints (sets of 64 bits) to soliditySHA3 or you could use a BigInt. Personally, I usually try to only hash 256 bit variables together to avoid having to manually pack my bits on the JS end, but we all know that space constraints are huge in Solidity. I hope I helped, and let me know if you have further questions.

Upvotes: 2

Related Questions