Why does ecrecover call in my Solidity code fail to resolve the signer?

ecrecover()is a very useful Solidity function that allows the smart contract to validate that incoming data is properly signed by an expected party. The signing must done according to the technique described here: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign. The resulting signature can then be successfully validated by Solidity withecrecover().

A sample Solidity code to do the validation looks like the following:

  function verify(bytes32  documentHash, uint8[] memory sigV, bytes32[] memory sigR, bytes32[] memory sigS) public {
    bytes memory prefix = "\x19Ethereum Signed Message:\n32";
    bytes32 prefixedProof = keccak256(abi.encodePacked(prefix, documentHash));
    address recovered = ecrecover(prefixedProof, sigV[0], sigR[0], sigS[0]);
    emit LogSignature(documentHash, prefixedProof, recovered);

Therecoveredvalue should be the account address of the Ethereum signer. However sometimes this fails and the value is returned as "0x0000000000000000000000000000000000000000".

The most likely cause of the failure to recover the signer is due to the difference in how different Ethereum implementations returns thevportion of the signature. For a simple explanation of ther,sandvportions of an Ethereum signature, visit this Solidity documentation page. Different Ethereum implementations returns differentvvalues from theeth_signcall. This can catch developers by surprise and can result in the error above.

Basically Solidity expects thevvalue to be either27or28, as explained here. Other values are also possible when signing transactions using EIP 155 schema. But currently theeth_signimplementations do not support EIP 155 signing.

Given the above, the client program that calls the Solidity function must supply avvalue of either27or28. However, when calling the target Ethereum node to sign, differentvvalues may be returned.

testrpcand Ganache, both popular with development environments, return00or01for the V value portion of the signature. So27must be added in order to calculate the correct value.

Geth/Quorum, on the other hand, both return the V value according to the ecrecover technique, with 27 already added.

Protocol eth.sign()supported? To calculate V value from returned signature
Geth Yes web3.utils.toDecimal("0x" + sig.slice(130, 132))
Quorum Yes web3.utils.toDecimal("0x" + sig.slice(130, 132))
Besu No  
testrpc Yes web3.utils.toDecimal("0x" + sig.slice(130, 132)) + 27
Ganache Yes web3.utils.toDecimal("0x" + sig.slice(130, 132)) + 27

A client program must compensate for this difference in order to get the propervvalue. Here's a sample truffle project that demonstrates the difference and what client programs must to do always pass in the propervvalue.

Was this article helpful?
0 out of 0 found this helpful