# Eth智能合约签名校验 - 可用于实现多签合约

By [zhongxuqi](https://paragraph.com/@zhongxuqi) · 2023-01-31

---

1\. 对message进行签名
----------------

    from eth_account.messages import encode_defunct
    from web3 import Web3
    from eth_keys import keys
    
    KEY = ... # 填写账户私钥
    w3 = Web3(Web3.HTTPProvider(<input eth node url/>)) # 请填写以太坊的节点url
    account = w3.eth.account.from_key(KEY)
    print('address: ', account.address)
    rawText = 'hello' # 签名message
    signedMessage = account.sign_message(encode_defunct(text=rawText))
    print('message hash: ', signedMessage.messageHash.hex())
    # print(signedMessage)
    print('v: ', int(signedMessage.v))
    print('r: ', hex(signedMessage.r))
    print('s: ', hex(signedMessage.s))
    print('signature: ', signedMessage.signature.hex())
    print(w3.eth.account.recover_message(encode_defunct(text=rawText), signature=signedMessage.signature))
    

2\. 执行脚本，得到
-----------

    address:  0x1c74c86906d91766e143e1d009C8604b66001363
    message hash:  0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750
    v:  28
    r:  0x5a0121bea4f2c1e9e6aad76bd3e06191a533c0b53a77df31e3b6310dbf4f698f
    s:  0x17216a4bfd7cf812bf2a6d9b44122c807880a5cb3de403d4baa8e0fb352189dd
    signature:  0x5a0121bea4f2c1e9e6aad76bd3e06191a533c0b53a77df31e3b6310dbf4f698f17216a4bfd7cf812bf2a6d9b44122c807880a5cb3de403d4baa8e0fb352189dd1c
    0x1c74c86906d91766e143e1d009C8604b66001363
    

3\. 智能合约代码
----------

    pragma solidity ^0.8.13;
    
    contract VerifySign{
      //公匙：0x1c74c86906d91766e143e1d009C8604b66001363
      //sha3(msg): 0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 (web3.sha3("abc");)
      //签名后的数据：0x7eeb34fb6770d2b935de3657652e8060033ec47f57d10acbcc6a4b4d69f82db12d8ddd81e67a01a4a51a0e658760e895bab90a24cc0d7803800098be779ea1d91c
    
      //将原始数据按段切割出来指定长度
      function slice(bytes memory data, uint start, uint len) private returns (bytes memory) {
        bytes memory b = new bytes(len);
    
        for(uint i = 0; i < len; i++){
          b[i] = data[i + start];
        }
    
        return b;
      }
    
      //bytes转换为bytes32
      function bytesToBytes32(bytes memory source) private returns (bytes32 result) {
        assembly {
            result := mload(add(source, 32))
        }
      }
    
        // "\x19Ethereum Signed Message:\n{{len}}"
      function VerifyMessageV1(bytes32 messageHash, uint8 _v, bytes32 _r, bytes32 _s) public pure returns (address signer) {
        signer = ecrecover(messageHash, _v, _r, _s);
      }
    
      address addr;
      bytes32 r; bytes32 s; uint8 v;
      function VerifyMessageV2(bytes32 messageHash, bytes memory signedString) public {
        r = bytesToBytes32(slice(signedString, 0, 32));
        s = bytesToBytes32(slice(signedString, 32, 32));
        v = uint8(slice(signedString, 64, 1)[0]);
        addr = ecrecover(messageHash, v, r, s);
      }
    
      function getSignCheckResult() public view returns (address _addr, bytes32 _r, bytes32 _s, uint8 _v){
        _addr = addr;
        _v = v;
        _r = r;
        _s = s;
      }
    }
    

4\. 部署智能合约到remix
----------------

[https://remix.ethereum.org/](https://remix.ethereum.org/)

5\. 执行VerifyMessageV1函数
-----------------------

输入参数：

    {
        "messageHash": "0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750",
        "signedString": "28",
        "_r": "0x5a0121bea4f2c1e9e6aad76bd3e06191a533c0b53a77df31e3b6310dbf4f698f",
        "_s": "0x17216a4bfd7cf812bf2a6d9b44122c807880a5cb3de403d4baa8e0fb352189dd",
    }
    

返回结果：

    {
        "signer": "0x1c74c86906d91766e143e1d009C8604b66001363",
    }
    

signer和签名账户的地址一致

6\. 执行VerifyMessageV2函数
-----------------------

输入参数：

    {
        "messageHash": "0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750",
        "signedString": "0x5a0121bea4f2c1e9e6aad76bd3e06191a533c0b53a77df31e3b6310dbf4f698f17216a4bfd7cf812bf2a6d9b44122c807880a5cb3de403d4baa8e0fb352189dd1c",
    }
    

执行getSignCheckResult，返回结果：

    {
        "_addr": "0x1c74c86906d91766e143e1d009C8604b66001363",
        "_r": "0x5a0121bea4f2c1e9e6aad76bd3e06191a533c0b53a77df31e3b6310dbf4f698f",
        "_s": "0x17216a4bfd7cf812bf2a6d9b44122c807880a5cb3de403d4baa8e0fb352189dd",
        "_v": "28",
    }
    

\_addr和签名账户的地址一致

---

*Originally published on [zhongxuqi](https://paragraph.com/@zhongxuqi/eth)*
