Published on

Keccak Abi encodePacked with JavaScript

Authors

One thing that can be quite confusing when working with Ethereum is that keccak is often used interchangeably with sha3. In the Ethereum space they do appear to be the same thing. Where it can get confusing is when you are using a library on the JavaScript side to try generate them (for testing or in your dApp).

To illustrate this lets say we have a person contract that has a function that simply returns the keccak256 hash of a hardcoded value as below:

pragma solidity ^0.4.24;

contract Person {

    struct PersonDetails{
        string name;
        string surname;
        uint256 age;
        address someRandomAddress;
    }

    PersonDetails private john = PersonDetails({
        name: "John",
        surname: "Smith",
        age: 33,
        someRandomAddress: 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d
    });

    function personHash() external view returns (bytes32) {
        return keccak256(
            abi.encodePacked(
                john.name,
                john.surname,
                john.age,
                john.someRandomAddress
            )
        );
    }
}

How do you generate a keccak like this in JavaScript/Web3?

This stumped me for a while but after a bit of digging I worked out how. I wrote a simple truffle test to demonstrate:

const Person = artifacts.require('Person')
const { soliditySha3 } = require('web3-utils')

contract('Person', ([admin]) => {
  let personContract
  beforeEach(async () => {
    personContract = await Person.new()
  })

  describe('personHash', () => {
    it('should hash the inputs using keccack256', async () => {
      const personHash = await personContract.personHash.call()
      const soliditySha3Expected = soliditySha3(
        'John',
        'Smith',
        33,
        '0x06012c8cf97BEaD5deAe237070F9587f8E7A266d'
      )

      expect(personHash).to.equal(soliditySha3Expected)
    })
  })
})

If you run this test you will see that it passes without issue. Some things to note about the above setup:

  • web3-utils: you will need to npm install web3-utils --save to use this.
    • The documentation for what is in this and some examples can be found here.
    • The documentation specifically for using keccack256 can be found here.
  • Ordering of Parameters: In a hashing function the order is very important and will result in a different hash if changed.
  • Random Address: I threw in the cryptokitties address just to illustrate how it works if you have that in your struct.
  • soliditySha3 parameter type inference: Based on the documentation you do not need to specify the types for the parameters you use - the util infers the types.
    • These rules are detailed here.
  • soliditySha3: as I mentioned in the beggining of this post sha3 is the same as keccak in the Ethereum world
    • The JavaScript util for this also seems abi.encodePacked for you on the JavaScript side.