//web3 code
let hash = web3.utils.soliditySha3("String"); //if replace "String" with "0" "123" etc , ecrecover returns wrong address
console.log("hash", web3.utils.soliditySha3("\x19Ethereum Signed Message:\n32", hash))
let signature = await web3.eth.personal.sign(hash, currentAccount);
console.log("signature", signature);
let r = signature.slice(0, 66);
let s = "0x" + signature.slice(66, 130);
let v = web3.utils.hexToNumberString("0x" + signature.slice(130, 132));
console.log("r", r);
console.log("s", s);
console.log("v", v);
//solidity code
function extractSigner(
uint8 v,
bytes32 r,
bytes32 s
) internal view returns (address) {
string memory n = toString(nonce); //nonce corresponding to "String" in web3 code above
bytes32 hash = keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(bytes(n))
)
);
return ecrecover(hash, v, r, s);
}
the whole process is, sign the string using web3js, and input the v,r,s in solidity. If the toSignString contains any letters, solidity returns the proper address. But if toSignString only consists of number, solidity returns a wrong address, why?
Best Answer
Your issue is here :
As per the documentation, a non numerical string will be interpreted as
string
while a numerical string input will be interpreted asuint256
but on the solidity side you are interpreting the bytes asstring
input. The abi encoding being different, you are not verifying the same data that was signed.A quick fix if you want to ensure a string interpretation on the signer side :
That way, whatever data is passed at
soliditiSha3
will be interpreted as string, matching the verifier's logic and allowing you to recover the proper address.