如何在链上确认以太坊的链下签名

huangapple go评论59阅读模式
英文:

how to confirm ethers off-chain signatures on-chain

问题

以下是代码的翻译部分:

"It's fairly easy to get ethers to get a metamask signature of a given piece of text, but how to confirm the signer onchain seems to be a bigger challenge than I thought. On a client side app with metamask installed I can call:

let provider =  new ethers.providers.Web3Provider(window.ethereum);
let signer = provider.getSigner();
let signature = await signer.signMessage("Please confirm this: 12.315")

Metamask will pop the signing verification dialog with the message , and return a signature after the user approves.

You can pretty easily validate the address that produced the signature off-chain:

let signerAddress = ethers.utils.verifyMessage('Please confirm this: 12.315', sig);

But if you want to send the signature to a smart contract, and confirm the address that produced the signature, its not so easy.

The ECDSA package from OpenZeppelin has a recover() function but it only takes a hash as the "message", not a string. You can hash the string, but that doesn't return the right account:

function getSigner(string memory message, bytes sig) public view returns(address) {
   bytes32 messageHash = keccak256(abi.encodePacked(message));
   address signer = ECDSA.recover(messageHash, sig);
   return signer;
}

Nor does

address signer = ECDSA.recover(ECDSA.toEthSignedMessageHash(message, signature));

So how can validate you validate on-chain that the signature of a message produced off-chain by ethers is in fact the expected signer address?"

英文:

It's fairly easy to get ethers to get a metamask signature of a given piece of text, but how to confirm the signer onchain seems to be a bigger challenge than I thought. On a client side app with metamask installed I can call:

let provider =  new ethers.providers.Web3Provider(window.ethereum);
let signer = provider.getSigner();
let signature = await signer.signMessage("Please confirm this: 12.315")

Metamask will pop the signing verification dialog with the message , and return a signature after the user approves.
You can pretty easily validate the address that produced the signature off-chain:

let signerAddress = ethers.utils.verifyMessage(ethers.utils.verifyMessage('Please confirm this: 12.315', sig);

But if you want to send the signature to a smart contract, and confirm the address that produced the signature, its not so easy.

The ECDSA package from OpenZeppelin has a recover() function but it only takes a hash as the "message', not a string. You can hash the string, but that doesn't return the right account:

function getSigner(string memory message, bytes sig) public view returns(address) {
   bytes32 messageHash = keccak256(abi.encodePacked(message);
   address signer = ECDSA.recover(messageHash, sig);
   return signer;
}

Nor does

address signer = ECDSA.recover(ECDSA.toEthSignedMessageHash(message, signature);

So how can validate you validate on-chain that the signature of a message produced off-chain by ethers is in fact the expected signer address?

答案1

得分: 1

代码部分不要翻译,以下是翻译好的内容:

"After poking around for a while in various posts and videos, I was able to figure out that metamask adds a prefix to the string being signed before the message signature is generated. The prefix added to the message is `\x19Ethereum Signed Message:\n$'' + the length of the message.

So the message used by metamask to produce the signature is actually:

let signedMessage = \x19Ethereum Signed Message:\n${signedMessage.length}${message};

So if your on chain function looks like:
function getSigner(string memory message, bytes memory sig) public view returns(address) {
bytes32 messageHash = keccak256(abi.encodePacked(message));
address signer = ECDSA.recover(messageHash, sig);
return signer;
}

then you should call it like this:

let prefixedMessage = \x19Ethereum Signed Message:\n${message.length}${message}
address = await mycontract.getSigner(prefixedMessage, signature);

Perhaps this will be helpful to somebody."

英文:

After poking around for a while in various posts and videos, I was able to figure out that metamask adds a prefix to the string being signed before the message signature is generated. The prefix added to the message is `\x19Ethereum Signed Message:\n$' + the length of the message.

So the message used by metamask to produce the signature is actually:

let signedMessage = `\x19Ethereum Signed Message:\n${signedMessage.length}${message}`;

So if your on chain function looks like:

function getSigner(string memory message, bytes memory sig) public view returns(address) {
   bytes32 messageHash = keccak256(abi.encodePacked(message));
   address signer = ECDSA.recover(messageHash, sig);
   return signer;
}

then you should call it like this:

let prefixedMessage = `\x19Ethereum Signed Message:\n${message.length}${message}`
  address = await mycontract.getSigner(prefixedMessage, signature);

Perhaps this will be helpful to somebody

huangapple
  • 本文由 发表于 2023年2月18日 09:33:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/75490634.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定