0

The problem occurs when generating a sha256 inside contract. This works fine:

function SimpleHash(string memory val) public returns (bytes32) {
    bytes32 h = sha256(abi.encodePacked(val));
    return h;
}

the h value returned is correctly answered, and I checked it with this piece of code:

const result = await instance.SimpleHash.call('A');
console.log('function return',result);
hash = SHA256('A');
console.log('hash outside the contract', hash.toString(CryptoJS.enc.Hex));

I sent the stirng 'A' to the contract function, and it returned: 0x559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd Very similar to the return of the function outside the contract: 559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd Just a single 0x added in the beginning.

However, if I change the function to receive bytes32 as param, like this:

function SimpleHash(bytes32 val) public returns (bytes32) {
   bytes32 h = sha256(abi.encodePacked(val));
   return h;
}

And then change my javacript code to:

segredo = web3.utils.toHex("A");

const result = await instance.SimpleHash.call(segredo);
console.log('function return',result);

hash = SHA256('A');
console.log('hash outside the contract', hash.toString(CryptoJS.enc.Hex));

Suddenly, the sha256 values are different. In the case above, the hash returned from the contract now is 0x037371bf62c8a2c23f8134fc2c7049fbe698860b888c98b955644c4b8f8f3155 And the correct hash is the same as the ones before.

How do I get the correct hash for the string 'A' sending it as bytes32 param? I'm sure there is something I'm mistaking when sending the param. Maybe it is related to big endian and little endian enconding? Not sure how I would change that in nodeJS thogh.

1

The issue is the representation of the data. When you move to bytes32 the resulting data after abi.encodedPacked has 32 bytes, but the data used for the hash in your code SHA256(A) is not 32 bytes. So you need to pad the hex representation of A with the necessary number of zeros to make it 32 bytes long, because this is what your smart contract is also doing.

Hope this helps.

2
  • This worked! I will explain how I managed to make it work in another comment Sep 27 '21 at 13:27
  • If this solved your question please accept the answer so that other people know that it worked.
    – Jaime
    Sep 27 '21 at 14:25
0

As Jaime pointed above, I had to pad the hex representation with 0's until it had 32 bytes.

I've made the following function to pad the hex string:

function padUntil32Bytes(string) {
    string = string.padEnd(32,'0');
    return string;
}

And created the hash as follows:

secret = web3.utils.toHex('A');
secret = padUntil32Bytes(secret)
const result = await instance.SimpleHash.call(secret);
console.log('function return',result);
hash = SHA256(secret);
console.log('hash outside the contract',hash.toString(CryptoJS.enc.Hex));

Now the hash from solidity and the hash outside, in javascript, match:

function return 0x94c49226434bc7945693fae7428a089ad81084ef4514c28cd9e7f6df2d05c3f5
hash outside the contract 94c49226434bc7945693fae7428a089ad81084ef4514c28cd9e7f6df2d05c3f5

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.