以下是在 Foundry 环境中使用 OpenZeppelin 安全创建和验证 ECDSA 签名的最小(可复制粘贴)示例。
合约:Verifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
contract Verifier {
using ECDSA for bytes32;
address public verifyingAddress;
constructor(address _verifyingAddress) {
verifyingAddress = _verifyingAddress;
}
function verifyV1(
string calldata message,
bytes32 r,
bytes32 s,
uint8 v
) public view {
bytes32 signedMessageHash = keccak256(abi.encode(message))
.toEthSignedMessageHash();
require(
signedMessageHash.recover(v, r, s) == verifyingAddress,
"signature not valid v1"
);
}
function verifyV2(
string calldata message,
bytes calldata signature
) public view {
bytes32 signedMessageHash = keccak256(abi.encode(message))
.toEthSignedMessageHash();
require(
signedMessageHash.recover(signature) == verifyingAddress,
"signature not valid v2"
);
}
}
测试 (Verifier.t.sol)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../src/Verify.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "forge-std/console.sol";
contract TestSigs1 is Test {
using ECDSA for bytes32;
Verifier verifier;
address owner;
uint256 privateKey =
0x1010101010101010101010101010101010101010101010101010101010101010;
function setUp() public {
owner = vm.addr(privateKey);
verifier = new Verifier(owner);
}
function testVerifyV1andV2() public {
string memory message = "attack at dawn";
bytes32 msgHash = keccak256(abi.encode(message))
.toEthSignedMessageHash();
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, msgHash);
bytes memory signature = abi.encodePacked(r, s, v);
assertEq(signature.length, 65);
console.logBytes(signature);
verifier.verifyV1(message, r, s, v);
verifier.verifyV2(message, signature);
}
}
即使你将数据类型从 “string” 更改为其他类型,此方法也同样适用。
请注意,OpenZeppelin 支持两种表示签名的方式。通常使用 bytes 版本会更方便,因为这样在传递时只需要处理一个额外的数据。但也请注意,ERC20-Permit 使用的是由三部分组成的签名(r、s、v)。
了解更多
本文被用作我们的 Solidity Bootcamp 的参考资料。
我们还提供免费的 learn solidity 教程。
最初发布于 2023 年 3 月 8 日