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/

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和签名账户的地址一致