I have a smart contract that provides a message to sign and then validates the signer of the message. Something like:
mapping(address => uint) public userNonce;
function getSigner(bytes32 message, bytes32 r, bytes32 s, uint8 v)
public
pure
returns (address)
{
bytes32 prefixedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
address signer = ecrecover(prefixedHash,v,r,s);
return signer;
}
function getMessageToSign(address user, address _operator)
public
view
returns (bytes32)
{
return keccak256(abi.encodePacked(
bytes4(0xe18546ee),
address(this),
userNonce[user], // sequential nonce
_operator
));
}
function prove_me (bytes32 message, bytes32 r, bytes32 s, uint8 v, address _operator)
public
{
address signer = getSigner(message, r, s, v);
bytes32 proof = getMessageToSign(signer, _operator);
require(proof == message);
userNonce[signer] = userNonce[signer] + 1;
// do something on behalf of user
hasUserAllowed[signer] = true;
}
Testing above with dummy private-key and address.
I get a message to sign from smart contract :
dataHash = "0x3c6819779a3c0a163d93e2e1e1168fb5ab424217555132ea356d491002c84e7f"
user1Addr = "0x72f27f62998bc1a2929a72bf753b6a335abd46c0"
user1PvtKey = "0xc73c6b7ad8e821a303871e8a63f8a53c9b6b0cf3977becd94032f3ff7c3055c1"
I sign it using private key belonging to user1:
web3.eth.accounts.sign(dataHash, user1PvtKey);
But when I pass corresponding r,s,v to the getSigner
method, I get a different signer (0x2ad05a181F51975C1bc79b6B1eC1Ab9A86a3fE24)
I know this works if I use web3.sign
but that requires an unlocking account with personal however I prefer signing using the private key.
The signature is different using web3.sign
than web3.eth.sign
.
PS: I know that web3 updated the signing method including chain code as well. But since I can not update my smart contract, how can I sign the message using a private key and smart contract verifies the correct owner?