如何在 Solidity 中验证签名消息

公众号:元壤

元壤:一分钟搭建您专属的 NFT 数字藏品平台

如何使用钱包签署消息,并使用 ecrecover 验证链上签名。

https://img.chengxuka.com

介绍

这是一个实用教程,介绍如何使用 MetaMask 签署消息,然后在链上验证。

这是一个Demo:https ://leon-do.github.io/ecrecover/

签名过程

<button onClick="signMessage()">Sign Message</button>

<script
  src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.7.0-rc.0/web3.min.js"
  integrity="sha512-/PTXSvaFzmO4So7Ghyq+DEZOz0sNLU4v1DP4gMOfY3kFu9L/IKoqSHZ6lNl3ZoZ7wT20io3vu/U4IchGcGIhfw=="
  crossorigin="anonymous"
  referrerpolicy="no-referrer"
></script>
<script>
  async function signMessage() {
    if (!window.ethereum) return alert("Please Install Metamask");

    // connect and get metamask account
    const accounts = await ethereum.request({ method: "eth_requestAccounts" });

    // message to sign
    const message = "hello";
    console.log({ message });

    // hash message
    const hashedMessage = Web3.utils.sha3(message);
    console.log({ hashedMessage });

    // sign hashed message
    const signature = await ethereum.request({
      method: "personal_sign",
      params: [hashedMessage, accounts[0]],
    });
    console.log({ signature });

    // split signature
    const r = signature.slice(0, 66);
    const s = "0x" + signature.slice(66, 130);
    const v = parseInt(signature.slice(130, 132), 16);
    console.log({ r, s, v });
  }
</script>

注意:

  • 这是使用personal_sign 方法来防止意外交易支出。这将与\x19Ethereum Signed Message:\n32智能合约中的前缀有关(如下)。
  • 这是对散列消息进行签名。

签名

以下是验证签名所需的信息。在你的智能合约中使用它。

hashedMessage = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8
r = 0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d
s = 0x2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c9
v = 28

智能合约

创建solidity合约。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Verify {

    function VerifyMessage(bytes32 _hashedMessage, uint8 _v, bytes32 _r, bytes32 _s) public pure returns (address) {
        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage));
        address signer = ecrecover(prefixedHashMessage, _v, _r, _s);
        return signer;
    }

}

注意:

  • 注意前缀,\x19Ethereum Signed Message:\n32是验证签名消息所必需的。
  • 前缀与消息一起被散列。
  • ecrecover应该返回签名者的地址。

在 Solidity 中验证

输入散列消息和签名 (r, s, v) 以验证地址。

https://img.chengxuka.com

用例:Unity 游戏

  • 游戏开发者创建一个游戏、服务器和智能合约,如果玩家获胜,则该合约会发放奖品。
  • 玩家获胜并告诉游戏开发者他们获胜了。
  • 游戏服务器向玩家提供一个签名(上面解释过),允许用户进行认领。将此视为优惠券。
  • 然后玩家与合约交互并提交签名(优惠券)以领取他们的奖品。

游戏开发者部署智能合约的示例

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// game developer depoloys contract
contract Verify {

    // game developer's account
    address public owner = 0xdD4c825203f97984e7867F11eeCc813A036089D1;

    // player claims price
    function claimPrize(bytes32 _hashedMessage, uint8 _v, bytes32 _r, bytes32 _s) public view returns (bool) {
        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage));
        address signer = ecrecover(prefixedHashMessage, _v, _r, _s);

        // if the signature is signed by the owner
        if (signer == owner) {
            // give player (msg.sender) a prize
            return true;
        }

        return false;
    }
}

获胜后,玩家从游戏服务器获得签名(优惠券)以领取奖品

0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c91c

玩家在 Unity 中解析签名

string signature = "0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c91c";
string r = signature.Substring(0, 66);
string s = "0x" + signature.Substring(66, 64);
int v = int.Parse(signature.Substring(130, 2), System.Globalization.NumberStyles.HexNumber);

然后玩家可以与智能合约交互以领取他们的奖品。更多信息在这里

https://img.chengxuka.com

true 表示玩家收到了他们的奖品

结论

还有其他问题吗?可以在评论区留言,我们继续探讨。

原文链接:https://blog.chainsafe.io/how-to-verify-a-signed-message-in-solidity-6b3100277424

相关新闻

联系我们

联系我们

133-3118-4066

在线咨询:点击这里给我发消息

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
分享本页
返回顶部