I am converting my tests from web3.js to ethers.js for redundancy. Web3JS signatures are compatible with openzeppelin, but ethers.js is not.
I've noticed there are some differences in how each package perform signature verification and am curious what is the explanation.
My use case is to send signed parameters to be verified on chain using openzeppelin's ECDSA
contract Verification is ECDSA {
function getRecover(bytes32 sigHash, bytes memory sig) public pure returns (address) {
return sigHash.toEthSignedMessageHash().recover(sig);
}
}
// Parameters
sigHash = '0x648978d27edc284b1a72048fdeb2147d5292601d09ba43b3fb29ca0307777d9e'
user.address = '0xD9995BAE12FEe327256FFec1e3184d492bD94C31'
user.privateKey = '0x7ab741b57e8d94dd7e1a29055646bafde7010f38a900f55bbd7647880faa6ee8'
// Compute signatures
let sigEJS = await user.signMessage(sigHash)
let sigWJS = (web3.eth.accounts.sign(sigHash, user.privateKey)).signature
sigEJS --> '0x8db049dbdd96c030a1723a057e6ca5aa2298764249eabd9d6a13040d5c526c9f23e0c6607eda80f96af6a1f26d669e2412fe356fbc7556cb71686a97556bba581c'
sigWJS --> '0xdc8b5fe7a3174d1f3aa38175893dcacc15c2bdfce71126576b4395a9b96e3600593bdc3af47f7b8592a7bb1540e546945986080a85f9ecf48ae746a709bba0c91b'
// Compute ECRECOVER
await Verification.getRecover(sigHash, sigWJS) --> '0xD9995BAE12FEe327256FFec1e3184d492bD94C31'
await Verification.getRecover(sigHash, sigEJS) --> '0x5A8B991627bd17cdA2f2Cc1C5E07E8922E767F9B'
ethers.utils.verifyMessage(sigHash, sigWJS) --> '0x07e17feCCaD85Db39a4c722d05b5c9b968e7A3fb'
ethers.utils.verifyMessage(sigHash, sigEJS) --> '0xD9995BAE12FEe327256FFec1e3184d492bD94C31'
web3.eth.accounts.recover(sigHash, sigWJS, false) --> '0xD9995BAE12FEe327256FFec1e3184d492bD94C31'
web3.eth.accounts.recover(sigHash, sigEJS, false) --> '0x508bD95152655c71adCEcbA418F4c826310ec327'
Keep in mind that hashMessage takes in either a string (UTF-8 message), or an array (e.g. Uint8Array) which is processed as binary data.
The string "0x648978d27edc284b1a72048fdeb2147d5292601d09ba43b3fb29ca0307777d9e" is 66 bytes long. What you probably want is the binary data of length 32, i.e.
let sigHashBytes = ethers.utils.arrayify(sigHash);
let sigEJS = await user.signMessage(sigHashBytes);
ethers.utils.verifyMessage(sigHashBytes, sigEJS);
Let me know if that helps. :)
Nice :) That did the trick.
Most helpful comment
Nice :) That did the trick.