Solidity ecrecover – How to Fix ecrecover Returning Wrong Address for Number-Only toSignString

ecrecoversignaturesolidityweb3js

//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 :

let hash = web3.utils.soliditySha3("String");

As per the documentation, a non numerical string will be interpreted as string while a numerical string input will be interpreted as uint256 but on the solidity side you are interpreting the bytes as string 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 :

let hash = web3.utils.soliditySha3({ type: "string", value: "YOUR-STRING-DATA" });

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.