I have an Ethereum Dapp, which requires the user to sign a transaction to prove their identity. The app uses web3.eth.personal.sign(nonce, coinbase)... to sign a nonce generated in my back end.

It seems that signing with only Metamask, and signing with Ledger Nano on Metamask produce different hashes. So my question is:

Is there a difference in how ledger signs transactions compared to web3.eth.personal.sign?

  • 2
    Having this same problem. My Nano X is producing a signature that I can't verify locally. I can make transactions on ethereum, but for whatever reason when I try to write code to verify the javascript + mm + ledger generated signature, on the server side (php), it fails to verify. Something to do with the recovery value (last byte) Oct 17, 2021 at 8:12
  • 1
    I'm having the same issue with my Nano S. Did you figure anything out?
    – Chin Leung
    Nov 10, 2021 at 20:48

2 Answers 2


Ledger produces vrs signatures with a canonical v value of {0,1}, while Ethereum's ecrecover call only accepts a non-standard v value of {27,28}. More on that here.

Metamask handles this internally when signing directly through it without going through a Ledger, since it uses ecsign that normalizes the v value for Ethereum. But when signing a message on a Ledger and then relay the resulting signature to Metamask, the v value is still going to be {0,1}.

For UI developers, here is where web3 libs shine. If we look into how ethers.js implements this, we could see that its implementation for splitSignature manipulates a given signature's v value and normalizes it for Ethereum.


I have this same problem and fixed it by replacing the v inside ledger signature curve:

def adapt_ledger(vrs):
  new_v = vrs[0]
  if new_v == 0:
    new_v = 27
  if new_v == 1:
    new_v = 28
  return (new_v, vrs[1], vrs[2])

Somehow ledger used 0 and 1 instead of 27-31.

I lost the source to this solution but I found it in a discussion somewhere. Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.