Skip to content

Instantly share code, notes, and snippets.

@danfinlay
Created March 9, 2020 19:17
Show Gist options
  • Save danfinlay/33afe20a4ddb5c40bc899b5ddb99ff78 to your computer and use it in GitHub Desktop.
Save danfinlay/33afe20a4ddb5c40bc899b5ddb99ff78 to your computer and use it in GitHub Desktop.
Low level signing method roadmap
  • low-level signing method
@tynes
Copy link

tynes commented Mar 14, 2020

According to the KeyRingController docs, the message must already be hashed.

The eth_sign method will receive the incoming data, alread hashed,
and must sign that hash, and then return the raw signed hash.

https://github.com/MetaMask/KeyringController/blob/0e2fdda6d237b4c2a8711719f27ca017285af317/docs/keyring.md#signmessageaddress-data

What are the chances that there are some dapps out there not hashing before they pass data in? Maybe there is a check for 32 bytes someplace?

@prestwich
Copy link

Oh dear. Not hashing would be very bad.

@prestwich
Copy link

On the bright side, this means we can already sign opaque Bitcoin transactions. I had assumed hashing was enforced 🤔

@prestwich
Copy link

Okay. So I just verified experimentally that web3.eth.sign signs the raw digest already.

To reproduce:

> const cb = function (err, result) {
    if (err) return console.error(err)
    console.log('SIGNED:' + result.result)
  };

> ethereum.sendAsync({
  method: 'eth_sign',
  params: [myAddr, '0'.repeat(32)]
}, cb);

< SIGNED: 0x S R V

Then recovered that signature to the account ID using riemann-ether. This implies that we can already do what we want, provided that the MetaMask behavior doesn't change to match the geth behavior

@prestwich
Copy link

prestwich commented Mar 15, 2020

placing this here for future reference. uses utils from bitcoin-spv

function srvToDER(srvStr) {
  let srv = '';
  if (srvStr.slice(0, 2) === '0x') {
    srv = srvStr.slice(2);
  } else {
    srv = srvStr;
  }
  let s = deserializeHex(safeSlice(srv, 0, 64));
  const r = deserializeHex(safeSlice(srv, 64, 128));

  // Trim to minimal encoding.
  // If there is a leading 0 and the next bit is 0, trim the lead.
  while (s[0] === 0 && s[1] & 0x80 !== 0) {
    s = safeSlice(s, 1);
  }
  while (r[0] === 0 && r[1] & 0x80 !== 0) {
    r = safeSlice(r, 1);
  }

  const encR = concatUint8Arrays(new Uint8Array([0x02, r.length]), r);
  const encS = concatUint8Arrays(new Uint8Array([0x02, s.length]), s)

  return concatUint8Arrays(
    new Uint8Array([0x30, encR.length + encS.length]),
    encR,
    encS
  );
}

@tynes
Copy link

tynes commented Mar 15, 2020

@prestwich
Copy link

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