From f9dbe7c474b39910d0e1a8a2bd9b852339dff70a Mon Sep 17 00:00:00 2001 From: 0xBeWater Date: Wed, 16 Oct 2024 17:19:21 +0800 Subject: [PATCH] 2024.10.16 --- ruoshui.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/ruoshui.md b/ruoshui.md index 9bd3a0de..438af2dc 100644 --- a/ruoshui.md +++ b/ruoshui.md @@ -3633,4 +3633,83 @@ contract ERC4626 is ERC20, IERC4626 { } } ``` +### 2024.10.16 +[EIP712 类型化数据签名](https://eips.ethereum.org/EIPS/eip-712) 比 [EIP191 签名标准(personal sign)](https://eips.ethereum.org/EIPS/eip-191) 要高级安全一些,会展示签名消息的原始数据,用户可以在验证数据符合预期之后签名。 + +签名验证 + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + +contract EIP712Storage { + using ECDSA for bytes32; + + bytes32 private constant EIP712DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + bytes32 private constant STORAGE_TYPEHASH = keccak256("Storage(address spender,uint256 number)"); + bytes32 private DOMAIN_SEPARATOR; + uint256 number; + address owner; + + constructor(){ + DOMAIN_SEPARATOR = keccak256(abi.encode( + EIP712DOMAIN_TYPEHASH, // type hash + keccak256(bytes("EIP712Storage")), // name + keccak256(bytes("1")), // version + block.chainid, // chain id + address(this) // contract address + )); + owner = msg.sender; + } + + /** + * @dev Store value in variable + */ + function permitStore(uint256 _num, bytes memory _signature) public { + // 检查签名长度,65是标准r,s,v签名的长度 + require(_signature.length == 65, "invalid signature length"); + bytes32 r; + bytes32 s; + uint8 v; + // 目前只能用assembly (内联汇编)来从签名中获得r,s,v的值 + assembly { + /* + 前32 bytes存储签名的长度 (动态数组存储规则) + add(sig, 32) = sig的指针 + 32 + 等效为略过signature的前32 bytes + mload(p) 载入从内存地址p起始的接下来32 bytes数据 + */ + // 读取长度数据后的32 bytes + r := mload(add(_signature, 0x20)) + // 读取之后的32 bytes + s := mload(add(_signature, 0x40)) + // 读取最后一个byte + v := byte(0, mload(add(_signature, 0x60))) + } + + // 获取签名消息hash + bytes32 digest = keccak256(abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR, + keccak256(abi.encode(STORAGE_TYPEHASH, msg.sender, _num)) + )); + + address signer = digest.recover(v, r, s); // 恢复签名者 + require(signer == owner, "EIP712Storage: Invalid signature"); // 检查签名 + + // 修改状态变量 + number = _num; + } + + /** + * @dev Return value + * @return value of 'number' + */ + function retrieve() public view returns (uint256){ + return number; + } +} +```