技术:如何在 Solidity 中验证签名消息

这是一个使用MetaMask签名消息,然后在链上进行验证的实用教程。

00.jpg

介绍

这是一个使用MetaMask签名消息,然后在链上进行验证的实用教程。

这里有一个demo:https://leon-do.github.io/ecrecover/

签名

Sign Message

  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 });
  }

需注意:

  • 这是使用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)来验证地址。

11.jpg

用例:Unity Gaming

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

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

// 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);

然后,玩家可以与智能合约进行交互,领取奖品。

22.jpg

Source:https://www.web3.university/article/how-to-verify-a-signed-message-in-solidity

关于

ChinaDeFi - ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。

本文首发于:https://mp.weixin.qq.com/s/cS90RBgcmj8ZrxkBLo0GLg

  • 发表于 2022-06-17 14:13
  • 阅读 ( 407 )
  • 学分 ( 1 )
  • 分类:Solidity

1 条评论

请先 登录 后评论
ChinaDeFi 去中心化金融社区
ChinaDeFi 去中心化金融社区

94 篇文章, 66 学分