# Ethereum线下签名实现

By [puhahaha](https://paragraph.com/@puhahaha) · 2023-11-09

---

步骤
--

*   创建并打包原始消息
    
    原始消息：”Hello, Web3.”
    
    消息哈希：0xb0a90a95a2e95f53bc8a27629ce3d3b8c32507b1889e418e308b4ecb0d01554c
    
*   生成以太坊签名哈希
    
    签名哈希：0x8eea87c68554dc0b647493d38a4b53aeea63c6841b10290714ff5f65ff08f2d5
    
*   Metamask签名消息
    
    打开浏览器前端console，输入
    
    ethereum.send('eth\_requestAccounts') account = "以太坊签名账户地址" hash = "消息哈希" ethereum.request({method: "personal\_sign", params: \[account, hash\]})
    
    得到签名：
    
    0x7ac68849793e559e457718a22f0b122ec3f9c94ed2a5163283d6a55d3c3c32c05e2eaeaa81766fe6c6ce82e971f66a943a7dfa34a9f3d40ede2fb66ea4d698b01c
    
*   验签
    
    使用签名地址、以太坊签名哈希、签名，验签
    

代码
--

    // SPDX-License-Identifier: GPL-3.0
    
    pragma solidity >=0.8.2 <0.9.0;
    
    contract test {
        function getMessageHash(string memory message) public pure returns(bytes32) {
        return keccak256(abi.encodePacked(message));
        }
        
        function getEthSignedMessageHash(bytes32 _messageHash) public pure returns(bytes32) {
            return keccak256(
                // 这是标准字符串: \x19Ethereum Signed Message:\n
                // 32 表示后面的哈希内容长度
                abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)
            );
         }
    
         function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) public pure returns (address) {
            (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
    
            // 返回解析出来的签名地址
            return ecrecover(_ethSignedMessageHash, v, r, s);
        }
    
        // 分割签名
        function splitSignature(bytes memory sig) public pure returns(bytes32 r, bytes32 s, uint8 v) {
            require(sig.length == 65, "invalid signature length");
    
            // 通过读取内存数据 根据规则进行截取 返回 r, s, v 数据
            assembly {
                r := mload(add(sig, 32))
                s := mload(add(sig, 64))
                v := byte(0, mload(add(sig, 96)))
            }
        }
    
        function verify(bytes32 _ethSignedMessageHash, bytes memory _signature, address _signer) public pure returns(bool) {
            return recoverSigner(_ethSignedMessageHash, _signature) == _signer;
        }
    
    }

---

*Originally published on [puhahaha](https://paragraph.com/@puhahaha/ethereum)*
