Solidity学习-数字签名
一、数字签名的作用?
用于签署交易和批准交易。现在流行链下(消息)签名,链上验证。
二、为什么要用数字签名?
- 证明钱包是本人的,就是本人有这个私钥
- 确保签名过程中这个信息没有被篡改,因为是hash运算
- 可以帮项目方省gas费
三、前端生成签名
...
四、链上验证签名
- 引入openzeppelin ECDSA椭圆曲线签名算法
- 对签名信息进行abi编码
- 进行keccak256 Hash运算
- 添加前缀,如:"\x19Ethereum Signed Message:\n32",可以将计算出的以太坊特定的签名。这样可以防止DApp作恶
- 从签名恢复地址
五、合约示例代码
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; contract VerifySig { address owner; using ECDSA for bytes32; //把库 ECDSA 附加到 bytes32 类型 constructor (){ owner = msg.sender; } function isMessageValid(bytes memory signature, string memory message) public view returns(address, bool){ //将message进行abi编码 bytes memory abiEncode = abi.encodePacked(message); //进行keccak256 hash运算,生成定长的值 bytes32 messageHash = keccak256(abiEncode); //添加前缀 bytes32 ethSignMessageHash = ECDSA.toEthSignedMessageHash(messageHash); //从签名中恢复地址 address singer = ECDSA.recover(ethSignMessageHash, signature); if (owner == singer){ return (singer, true); } else { return (singer, false); } } }
六、合约的测试
部署合约后,我们开始进行测试。
- 设置签名内容
根据此网页说明,使用metamask插件进行对消息的签名;
我MetaMask Account1地址: "0x9848Ab0Fc1E0359975AdfEA57a7968058ab76b57";
"abc"的 hash: "0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45";
- 验证签名是否正确
调用我们合约的函数 isMessageValid()进行验证:
//test 1: decoded input { "bytes signature": "0xedefd08b275cabb3eecef6b58c6d21ee97de10fb11947b2b28d2af544090e1cc4f7f5c5c1bd6e8a6ffe515233f92ab62d981f7f927b3bfb1ba7330c160ea85b51c", "string message": "abc" } decoded output { "0": "address: 0x9848Ab0Fc1E0359975AdfEA57a7968058ab76b57", "1": "bool: true" } //test 2: decoded input { "bytes signature": "0xedefd08b275cabb3eecef6b58c6d21ee97de10fb11947b2b28d2af544090e1cc4f7f5c5c1bd6e8a6ffe515233f92ab62d981f7f927b3bfb1ba7330c160ea85b51c", "string message": "abcd" } decoded output { "0": "address: 0x389bcAbEffFB18e9d175757Ad057573FD043F1f0", "1": "bool: false" } //test 3:输入错误的signature call to VerifySig.isMessageValid call to VerifySig.isMessageValid errored: execution reverted: ECDSA: invalid signature { "originalError": { "code": 3, "data": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001845434453413a20696e76616c6964207369676e61747572650000000000000000", "message": "execution reverted: ECDSA: invalid signature" } }