抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

验证签名

1. 签名代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/*
1. message to sign
2. hash(message)
3. sign(hash(message), private key) | offchain
4. ecrecover(hash(message), signature) == signer
*/

contract VerifySig {

// verify 验证签名函数
function verify(address _signer, string memory _message, bytes memory _sig)
external pure returns(bool)
{

bytes32 messageHash = getMessageHash(_message); // 对输入的消息进行 hash运算
bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash); // 对输入消息进行二次hash

return recover(ethSignedMessageHash, _sig) == _signer; // 判断公钥的地址是否与_signer 相等?
}


function getMessageHash(string memory _message) public pure returns(bytes32) {
return keccak256(abi.encodePacked(_message)); // 对消息进行hash运算
}


function getEthSignedMessageHash(bytes32 _messageHash) public pure returns(bytes32) {
//在消息中加入 "\x19Ethereum Signed Message:\n32" 字符串,将该字符串和 _messageHash 打包并进行hash运算
return keccak256(abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
_messageHash));
}

function recover(bytes32 _ethSignedMessageHash, bytes memory _sig)
public pure returns(address)
{
(bytes32 r, bytes32 s, uint8 v) = _split(_sig); // 将_sig 分割为 r, s, v三个部分
return ecrecover(_ethSignedMessageHash, v, r, s);

}

function _split(bytes memory _sig) internal pure
returns(bytes32 r, bytes32 s, uint8 v)
{
require(_sig.length == 65, "invalud signature length");

assembly {
// add(_sig, 32) 指跳过32位长度, 去获取_sig 中的一个32位数据
r := mload(add(_sig, 32))

// add(_sig, 64) 指跳过64位长度, 去获取_sig 中的一个32位数据
s := mload(add(_sig, 64))

// add(_sig, 96) 指跳过96位长度, 去获取_sig 中的一个32位数据
// byte(0, mload(add(_sig, 96))) 返回32位中的第一个值
v := byte(0, mload(add(_sig, 96)))
}
}
}

2. 心得参悟:

2.1 ecrecover()函数,作用:在solidity中是,将签名的公钥返回。即,假如我使用我的🦊账户给消息进行签名,得到一个签名;在ecrecover() 函数中传入 以太坊签名消息(对消息进行二次 hash运算的结果) ,和签名的组成部分 r , s, v,最终返回的结果为 我🦊钱包的账户地址(公钥) 概括:ecrecover()函数通过传入的”以太坊签名消息” 和 “签名的(r s v)组成部分” 返回公钥(🦊钱包账户地址的前身)

2.2 计算以太坊签名消息: 消息可以是能被执行的交易,也可以是其他任何形式。为了避免用户误签了恶意交易,EIP191提倡在消息前加上"\x19Ethereum Signed Message:\n32"字符,并再做一次keccak256哈希,作为以太坊签名消息。经过toEthSignedMessageHash()函数处理后的消息,不能被用于执行交易:

1
2
3
4
5
function getEthSignedMessageHash(bytes32 _messageHash) public pure returns(bytes32) {
return keccak256(abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
_messageHash)); //在消息中加入 "\x19Ethereum Signed Message:\n32" 字符串,将该字符串和_messageHash 打包并进行hash运算
}

3. 数字签名的相关知识链接

评论



政策 · 统计 | 本站使用 Volantis 主题设计