Michael.W基于Foundry精读Openzeppelin第32期——SignatureChecker.sol

news2024/12/23 5:30:05

Michael.W基于Foundry精读Openzeppelin第32期——SignatureChecker.sol

      • 0. 版本
        • 0.1 SignatureChecker.sol
      • 1. 目标合约
      • 2. 代码精读
        • 2.1 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)

0. 版本

[openzeppelin]:v4.8.3,[forge-std]:v1.5.6

0.1 SignatureChecker.sol

Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/cryptography/SignatureChecker.sol

SignatureChecker库是一个用于链上签名验证的helper库。该库提供的验签函数既支持EOA账户地址的签名验证也支持IERC1271标准合约地址的签名验证。

IERC1271标准往往用于智能合约钱包的签名,例如Argent和Gnosis Safe。

注:关于IERC1271标准的详细解读参见:https://www.learnblockchain.cn/article/6443

1. 目标合约

封装SignatureChecker library成为一个可调用合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/utils/cryptography/MockSignatureChecker.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol";

contract MockSignatureChecker {
    using SignatureChecker for address;

    function isValidSignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) external view returns (bool){
        return signer.isValidSignatureNow(hash, signature);
    }
}

全部foundry测试合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/utils/cryptography/SignatureChecker.t.sol

2. 代码精读

2.1 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)

凭借签名地址、签名内容以及签名本身来验证签名有效性。

需要注意的是:与ECDSA的EOA地址验签不同,基于IERC1271标准的合约地址验签结果是可以改变的。可能在区块高度N和N+1上,IERC1271的验签结果是相反的。

    function isValidSignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
    	// 将输入的signer当做EOA账户地址,使用ECDSA.tryRecover()以及签名内容和签名还原出signer地址
        (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
        if (error == ECDSA.RecoverError.NoError && recovered == signer) {
        	// 如果ECDSA.tryRecover返回的错误类型为ECDSA.RecoverError.NoError且还原出的signer地址与输入signer地址相同,说明signer地址确实为EOA地址,并且通过验签。返回true
            return true;
        }
				
		// 如果没有通过EOA地址验签,那么再假定signer为IERC1271标准的合约地址。使用IERC1271标准的isValidSignature()函数进行验签
		// 本库使用直接staticcall的方式来调用signer合约的isValidSignature()方法
        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
        );
        
        // 如果staticcall调用成功且返回值只占32字节,同时返回值为IERC1271.isValidSignature的selector,表明通过IERC1271标准的验签——即返回true
        // 如果不满足以上条件,说明本次既不通过EOA地址验签也不通过IERC1271合约地址验签。可认作是无效的签名,返回false
        return (success &&
            result.length == 32 &&
            abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
    }

foundry代码验证

contract SignatureCheckerTest is Test {
    using ECDSA for bytes;

    MockSignatureChecker msc = new MockSignatureChecker();
    uint eoaSignerPrivateKeyInERC1271 = 1024;
    MockERC1271 me = new MockERC1271(vm.addr(eoaSignerPrivateKeyInERC1271));
    uint signerPrivateKey = 2048;
    address signerAddress = vm.addr(signerPrivateKey);

    function test_IsValidSignatureNow_AsEOAAddress() external {
        // case 1: return true with correct eoa signature
        bytes32 digestHash = bytes("Michael.W").toEthSignedMessageHash();
        (uint8 v, bytes32 r, bytes32 s) = vm.sign(signerPrivateKey, digestHash);
        bytes memory signature = bytes.concat(r, s, bytes1(v));

        assertTrue(msc.isValidSignatureNow(
                signerAddress,
                digestHash,
                signature
            ));

        // case 2: return false with incorrect eoa signature
        bytes memory incorrectSignature = bytes.concat(r, s, bytes1(v + 1));
        assertFalse(msc.isValidSignatureNow(
                signerAddress,
                digestHash,
                incorrectSignature
            ));
    }

    function test_IsValidSignatureNow_AsIERC1271Address() external {
        // case 1: return true with valid signature of ERC1271
        bytes32 digestHash = bytes("Michael.W").toEthSignedMessageHash();
        (uint8 v, bytes32 r, bytes32 s) = vm.sign(eoaSignerPrivateKeyInERC1271, digestHash);
        bytes memory signature = bytes.concat(r, s, bytes1(v));

        assertTrue(msc.isValidSignatureNow(
                address(me),
                digestHash,
                signature
            ));

        // case 2: return true with invalid signature of ERC1271
        bytes memory incorrectSignature = bytes.concat(r, s, bytes1(v + 1));

        assertFalse(msc.isValidSignatureNow(
                address(me),
                digestHash,
                incorrectSignature
            ));

        // case 3: return false when the signer contract address is not the implementor of IERC1271
        (v, r, s) = vm.sign(eoaSignerPrivateKeyInERC1271, digestHash);
        signature = bytes.concat(r, s, bytes1(v));

        assertFalse(msc.isValidSignatureNow(
                address(new NotImplementIERC1271()),
                digestHash,
                signature
            ));
    }
}

contract MockERC1271 is IERC1271 {
    using ECDSA for bytes32;

    address _signerEOA;

    constructor(address signerEOA){
        _signerEOA = signerEOA;
    }

    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue){
        return hash.recover(signature) == _signerEOA ? IERC1271.isValidSignature.selector : bytes4(0);
    }
}

contract NotImplementIERC1271 {}

ps:
本人热爱图灵,热爱中本聪,热爱V神。
以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
如果需要转发,麻烦注明作者。十分感谢!

在这里插入图片描述

公众号名称:后现代泼痞浪漫主义奠基人

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/940169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为OD机试 - 云短信平台优惠活动 - 回溯(Java 2023 B卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷&#…

教师如何有效地发放开学通知并收集签名回执?

老师在即将开学时,希望能够向家长发送开学通知,并确认家长已经收到通知。接下来教给各位老师如何完成这个需求的步骤: 好消息!博主给大家争取到的易查分福利,只需要在注册时输入邀请码:xmt66,就…

从AD迁移至AAD,看体外诊断领军企业如何用网络准入方案提升内网安全基线

摘要: 某医用电子跨国集团中国分支机构在由AD向AzureAD Global迁移时,创新使用宁盾网络准入,串联起上海、北京、无锡等国内多个职场与海外总部,实现平滑、稳定、全程无感知的无密码认证入网体验,并通过合规基线检查,确…

CAD的清除命令如何使用?CAD的清除命令使用方法

CAD广泛应用于土木建筑、装饰装潢、城市规划、园林设计、电子电路、机械设计、服装鞋帽、航空航天、轻工化工等诸多领域,因此CAD越来越成为一项基本技能,很多用人岗位都会要求会使用CAD,为帮助更多人快速学会CAD,而且CAD的使用本身…

taobao.trade.fullinfo.get(获取单笔交易的详细信息)天猫国际站店铺订单接口方法

淘宝交易API taobao.trade.fullinfo.get(获取单笔交易的详细信息) 获取单笔交易的详细信息 1. 只有单笔订单的情况下Trade数据结构中才包含商品相关的信息 2. 获取到的Order中的payment字段在单笔子订单时包含物流费用,多笔子订单时不包含物…

STM32--SPI通信与W25Q64(2)

STM32–SPI通信与W25Q64(1) 文章目录 SPI外设特征 SPI框图传输模式主模式全双工连续传输 非连续传输硬件SPI读写W25Q64 SPI外设 STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担。 特…

leetcode 496. 下一个更大元素 I

2023.8.28 这题提供暴力解法和单调栈法两种方法。 暴力解&#xff1a; class Solution { public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {vector<int> ans(nums1.size(),-1);for(int i0; i<nums1.size…

『FastGithub』一款.Net开源的稳定可靠Github加速神器,轻松解决GitHub访问难题

&#x1f4e3;读完这篇文章里你能收获到 如何使用FastGithub解决Github无法访问问题了解FastGithub的工作原理 文章目录 一、前言二、项目介绍三、访问加速原理四、FastGithub安装1. 项目下载2. 解压双击运行3. 运行效果4. GitHub访问效果 一、前言 作为开发者&#xff0c;会…

springMVC之拦截器

文章目录 前言一、拦截器的配置二、拦截器的三个抽象方法三、多个拦截器的执行顺序总结 前言 拦截器 一、拦截器的配置 SpringMVC中的拦截器用于拦截控制器方法的执行 SpringMVC中的拦截器需要实现HandlerInterceptor SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置&…

数字化智能工厂信息化系统集成整合规划建设方案[150页word]

导读&#xff1a;原文《150页6万字数字化智能工厂信息化系统集成整合规划建设方案》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 数字化智能工厂建设方案 设备智…

大数据学习:Hive常用函数

Hive常用函数 1. Hive的参数传递 1.1 Hive命令行 查看hive命令的参数 [hadoopnode03 ~]$ hive -help语法结构: hive [-hiveconf xy]* [<-i filename>]* [<-f filename>|<-e query-string>][-S] 说明&#xff1a; -i 从文件初始化HQL。-e从命令行执行指定…

LVDS 2-port RGB 转 MIPI参数计算

有一些显示器是只给了屏幕的参数&#xff0c;屏幕输入的参数不一定&#xff0c;可能是输出的MIPI 给显示器&#xff0c;显示内部转换后是LVDS RGB&#xff0c;因此需要转换。 屏幕参数 转换为MIPI参数

当我焦虑时,我从CSDN的博主身上学到了什么?

文章目录 前言一、思考为什么会产生差距1.1 懒惰1.2 没有合理的规划学习时间 二、我该如何做&#xff1f;2.1 认真生活规律作息2.2 做事就是0和1 结语 前言 我们在学习的过程当中总会遇到一些比我们自己优秀的人&#xff0c;不论你是在更好的985或211院校学习&#xff0c;还是…

计算系统丢失CONCRT140.dll文件的四种解决方法(亲测可用)

今天&#xff0c;我将为大家分享一个关于计算机技术的问题——计算系统丢失CONCRT140.dll文件的四种解决方法。希望我的分享能够帮助到大家&#xff0c;解决你们在日常生活和工作中遇到的困扰。 CONCRT140.dll是Windows操作系统中的一个动态链接库文件&#xff0c;它包含了一些…

迅为RK3588开发板Android12 设置系统默认不锁屏

修改 frameworks/base/packages/SettingsProvider/res/values/defaults.xml 文件&#xff0c;修改为如下 所示&#xff1a; - <bool name"def_lockscreen_disabled">false</bool> <bool name"def_lockscreen_disabled">true</bool&…

Linux————LNMT搭建

一、原理 搭建一个基于Linux系统的Web服务器&#xff0c;使用Nginx作为反向代理服务器&#xff0c;Tomcat作为应用服务器&#xff0c;MySQL作为数据库服务器。 Linux操作系统 基于Linux的操作系统 Nginx Nginx是一款高性能的Web服务器和反向代理服务器&#xff0…

传承精神 缅怀伟人——湖南多链优品科技有限公司赴韶山开展红色主题活动

8月27日上午&#xff0c; 湖南多链优品科技有限公司全体员工怀着崇敬之情&#xff0c;以红色文化为引领&#xff0c;参加了毛泽东同志诞辰130周年的纪念活动。以董事长程小明为核心的公司班子成员以及全国优秀代表近70人一行专赴韶山&#xff0c;缅怀伟人毛泽东同志的丰功伟绩。…

Jenkins自动化部署-Jenkins的安装

首先我们需要安装docker 安装 yum-utils包 yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 --skip-broken 设置镜像地址 yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce…

经过6年发展,NIST发布三种可以抵御量子计算机未来攻击的算法标准草案

近日&#xff0c;美国国家标准与技术研究院&#xff08;NIST&#xff09;发布了2022年选定的四种算法中的三种算法的标准草案&#xff1a;CRYSTALS–KYBER、CRYSTALS–Dilithium和SPHINCS&#xff0c;第四种算法FALCON的标准草案将在大约一年内发布。 近年关于量子计算机的研究…

302 | 异常 exception

异常处理 快捷键 CtrlAltt 一般来说&#xff0c;运行时异常可不做处理&#xff0c;因为太常见了&#xff0c;影响代码执行效率&#xff1b;而编译时异常是编译器必须处理的异常 两类异常 Error 严重错误&#xff0c;程序崩溃&#xff1a;JVM无法解决的严重问题&#xff0c;如…