Skip to content

Instantly share code, notes, and snippets.

@alexanderattar
Forked from backus/signTypedData.js.md
Last active July 22, 2019 21:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexanderattar/a6355ec8649b3819752037e709af8bef to your computer and use it in GitHub Desktop.
Save alexanderattar/a6355ec8649b3819752037e709af8bef to your computer and use it in GitHub Desktop.
How signTypedData works

I couldn't find a good explanation of each step of signTypedData EIP with examples of inputs and outputs at each step. I wanted this so I could keep track.

Say this is our private key

const privKey = new Buffer(
  "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3",
  "hex"
);

Then we have the following public address:

const ethWallet = require("ethereumjs-wallet");
const wallet = ethWallet.fromPrivateKey(privKey);

const address = wallet.getAddressString();
console.log(address); // 0x627306090abab3a6e1400e9345bc60c78a8bef57

Say we want to sign the following data:

const params = [
  {
    type: "uint256",
    name: "age",
    value: 24
  },
  {
    type: "string",
    name: "name",
    value: "John"
  }
];

Using eth-sig-util we can sign some typed data with this private key:

const ethSigUtil = require("eth-sig-util");
const signature = ethSigUtil.signTypedData(privKey, {
  data: params
});

console.log(signature);
// 0x5dabb5919c805eb67fd8e651a8bb99b1a1b7359ad64b8719bc5a83281bf171ee1349a75c125b8534176df1e290d8510370df23459f18f609cb36963596fca0ad1b

What is going into this signature?

We are generating two hashes:

  1. Self describing schema including the names
  2. The actual values

In this case:

// 1. Self describing schema including the names
const schema = ["uint256 age", "string name"];

// 2. The actual values
const values = [24, "John"];

Each of these gets their own soliditySha3 digest:

const ethAbi = require("ethereumjs-abi");

const schemaHash = ethAbi.soliditySHA3(["string", "string"], schema);
const valuesHash = ethAbi.soliditySHA3(["uint256", "string"], values);

The values in this case being:

const ethUtil = require("ethereumjs-util");

console.log("schemaHash", ethUtil.bufferToHex(schemaHash));
console.log("valuesHash", ethUtil.bufferToHex(valuesHash));

// schemaHash 0x14efe1ecfe90efb39fdfe9c5234f86f12fa4b14af779d269a9f88e860f10207b
// valuesHash 0xaa7488f6657d5525a284ac67916e66434a8b74d178eb9882de911876a3e2f864

Finally, these output values are hashed together:

const signatureHash = ethAbi.soliditySHA3(
  ["bytes32", "bytes32"],
  [schemaHash, valuesHash]
);

console.log("signatureHash", ethUtil.bufferToHex(signatureHash));
// signatureHash 0x884fd1fbda0e0d34ec6a0bcf5bb8293304efa29cee22f251bd0420a66cd546a7

With the signature hash calculated, it is a simple ecsign now:

const sig = ethUtil.ecsign(signatureHash, privKey);
const rpcSig = ethUtil.toRpcSig(sig.v, sig.r, sig.s);
console.log("Signature", rpcSig);

// Signature 0x5dabb5919c805eb67fd8e651a8bb99b1a1b7359ad64b8719bc5a83281bf171ee1349a75c125b8534176df1e290d8510370df23459f18f609cb36963596fca0ad00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment