When I sign a string with the web3.eth.sign() method and web3.eth.accounts.sign() method. The result value of the two signatures is different. I don't know why these two results are different.
I'm using the latest web3.js. And the private key is from metamask.
This is my code
await ethereum.enable();
web3 = new Web3(web3.currentProvider);
let accounts = await web3.eth.getAccounts();
let msg = "sign this message"
let prefix = "\x19Ethereum Signed Message:\n" + msg.length
let msgHash1 = web3.utils.sha3(prefix+msg)
let sig1 = await web3.eth.sign(msgHash1, accounts[0]);
let privateKey = "0xcfb51f3737044cb4bfb49cbb10ae67d79ee81523d7065e95972cc23ed914e95e"
let sigObj = await web3.eth.accounts.sign(msgHash1, privateKey)
let sig2 = sigObj.signature;
console.log(sig1)
console.log(sig2)
And this is result.
When I sign a string with the web3.eth.sign() method and web3.eth.accounts.sign() method. The result value of the two signatures is different. I don't know why these two results are different.
I'm using the latest web3.js. And the private key is from metamask.
This is my code
await ethereum.enable();
web3 = new Web3(web3.currentProvider);
let accounts = await web3.eth.getAccounts();
let msg = "sign this message"
let prefix = "\x19Ethereum Signed Message:\n" + msg.length
let msgHash1 = web3.utils.sha3(prefix+msg)
let sig1 = await web3.eth.sign(msgHash1, accounts[0]);
let privateKey = "0xcfb51f3737044cb4bfb49cbb10ae67d79ee81523d7065e95972cc23ed914e95e"
let sigObj = await web3.eth.accounts.sign(msgHash1, privateKey)
let sig2 = sigObj.signature;
console.log(sig1)
console.log(sig2)
And this is result.
Share Improve this question edited Dec 5, 2022 at 19:11 TylerH 21.1k77 gold badges79 silver badges112 bronze badges asked Nov 19, 2020 at 11:35 juunleeJayjuunleeJay 911 silver badge3 bronze badges 1- My guess is that one method adds message prefix, another does not. You can verify this by walking through the relevant source code with step-by-step debugger. – Mikko Ohtamaa Commented Nov 21, 2020 at 12:48
3 Answers
Reset to default 4The source code shows that the difference is that web3.eth.accounts.sign
prefixes and hashes the message before signing it.
In your example pass in msg
instead of msgHash
to eth.accounts.sign
:
So this signature:
const msg = 'hello world'
const { signature } = await web3.eth.accounts.sign(msg, privateKey)
will produce the same signature as eth.sign
with hashed message:
const msg = 'hello world'
const msgHash = web3.eth.accounts.hashMessage(msg)
const signature = await web3.eth.sign(accounts[0], msgHash)
The short answer is this is by design (for the best of my understanding), to prevent interpretation of a signed Ethereum transaction as other data (for example a meta transaction, verified by a smart contract logic).
More relevant details: https://ethereum.stackexchange./questions/35425/web3-js-eth-sign-vs-eth-accounts-sign-producing-different-signatures
web3.eth.sign
and web3.eth.accounts.sign
generate the same signature in web3.js v1.3.4 .
Correct me if I am wrong, It seems web3.eth.sign
calls web3.eth.accounts.sign
under the hood, here