链下签名实现

这篇具有很好参考价值的文章主要介绍了链下签名实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是签名

比如我们在使用 opensea 的时候,经常会提示我们进行数字签名,如下图:
链下签名实现
用户进行 sign 确认,即用自己的私钥对一段数据进行签名,得到一个 signature,其他人可以使用你私钥对应的公钥,对 signature 进行验证,从而证明你是私钥的持有者。签名后的数据有如下作用:

  • 验证身份:验证私钥持有人
  • 完整性:防止数据被篡改
  • 不可否认:持有人无法否认签名

我们在区块链中发起的每一笔交易(转账、对合约写操作)都是使用私钥签名过的,矿工会在打包前对每笔交易进行校验。具体逻辑如图:
链下签名实现
签名的核心:

  • 使用私钥进行签名,公钥进行验证
  • 不对原文进行签名,而是对原文的hash进行签名(为什么这样做呢?主要是因为 hash 计算的不可逆可以防篡改,如果是对原文签名,中间人攻击可以将密文和原文都改了,最后解密出来数据还是一致的,但其实数据已经被篡改了)

ECDSA 合约

我们将对 openzeppelin 中的 ECDSA 标准合约进行拆解学习,整个签名验证过程可分为四个阶段:

  • 阶段一:打包原始消息,生成 hash
  • 阶段二:添加前缀,生成以太坊签名 hash,用于最终校验
  • 阶段三:解析签名,获得解析的地址 1
  • 阶段四:校验地址 1 与实际签名的地址是否一致
    链下签名实现

阶段一:打包原始消息

在以太坊的 ECDSA 标准中,被签名的消息为一组数据的 hash 值(由 keccak256 算法生成的 byte32 类型的数据),我们可以使用abi.encodePacked(打包函数)将任意多个参数进行打包,此处为:address 和uint256 类型

function getMessageHash(address _to, uint _amount) public pure returns(bytes32) {
    return keccak256(abi.encodePacked(_to, _amount));
}

输入参数:0xc783df8a850f42e7f7e57013759c285caa701eb6, 100
输出:0xcfb170482914a76ca8521405f52699df67c7ebb8e3899f27cc8265ebdab98a36
链下签名实现

阶段二:生成以太坊签名 hash

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

function getEthSignedMessageHash(bytes32 _messageHash) public pure returns(bytes32) {
        return keccak256(
            // 这是标准字符串: \x19Ethereum Signed Message:\n
            // 32 表示后面的哈希内容长度
            abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)
        );
}

输入参数:0xcfb170482914a76ca8521405f52699df67c7ebb8e3899f27cc8265ebdab98a36
输出:0x60a7e355f6d1a5885594e145ce67bd165a3e63337806f576b7b417d31cdb20da
链下签名实现
接着生成签名,这里有两种方式:

  1. metamask 生成签名
    复制 metamask 账户地址,F12 打开控制台 -> console,输入如下内容然后回车(注意这里的 hash 使用的是“消息 hash”):
ethereum.send('eth_requestAccounts')
account = "0xFA172d92bC2A12bD780757927B31E3B2CEdE9950"
hash = "0xcfb170482914a76ca8521405f52699df67c7ebb8e3899f27cc8265ebdab98a36"
ethereum.request({method: "personal_sign", params: [account, hash]})

点击签名
链下签名实现
签名成功后,得到签名:
链下签名实现
2. etherjs 生成签名
在hardhat的test文件夹下创建sign.ts

const { expect } = require("chai")
const { ethers } = require("hardhat")

describe("Signature", function () {
  it("signature", async function () {
    // 0xc783df8a850f42e7f7e57013759c285caa701eb6
    let privateKey = '0xc5e8f61d1ab959b397eecc0a37a6517b8e67a0e7cf1f4bce5591f3ed80199122'
    console.log('private:', privateKey);

    const signer = new ethers.Wallet(privateKey);
    console.log('address :', signer.address);

    const amount = 100

    let msgHash = ethers.utils.solidityKeccak256(
      ["address", "uint256"], [signer.address, amount]
    )

    console.log('msgHash:', msgHash);
    const sig = await signer.signMessage(ethers.utils.arrayify(msgHash))

    console.log('signature:', sig);
  })
})

运行单元测试:npx hardhat test,可以得到相同的签名

阶段三:恢复地址

先对 signature 签名分割得到 r, s, v ,然后结合以太坊签名消息,利用内联汇编得出公钥(即 metamask 账户地址),下面的 recoverSigner() 函数实现了上述步骤:

function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) public pure returns (address) {
        (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);

        // 返回解析出来的签名地址
        return ecrecover(_ethSignedMessageHash, v, r, s);
    }

    // 分割签名
    function splitSignature(bytes memory sig) public pure returns(bytes32 r, bytes32 s, uint8 v) {
        require(sig.length == 65, "invalid signature length");

        // 通过读取内存数据 根据规则进行截取 返回 r, s, v 数据
        assembly {
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))
            v := byte(0, mload(add(sig, 96)))
        }
    }

阶段四:验证

接下来,我们只需要比对恢复的公钥与签名者公钥 _signer 是否相等。若相等,则签名有效;否则,签名无效

function verify(bytes32 _ethSignedMessageHash, bytes memory _signature, address _signer) public pure returns(bool) {
        return recoverSigner(_ethSignedMessageHash, _signature) == _signer;
    }

链下签名实现白名单

核心逻辑文章来源地址https://www.toymoban.com/news/detail-428132.html

  • 将白名单用户地址和 tokenId 签名入库
  • 用户 mint 铸造时,传入签名,在 mint 中进行校验,只有校验为 true 的用户才可以 mint,从而完成白名单功能
function mint(uint256 _tokenId, bytes memory _signature) external {
        // 将用户地址和_tokenId打包消息
        bytes32 _msgHash = getMessageHash(msg.sener, _tokenId); 

        // 计算以太坊签名消息
        bytes32 _ethSignedMessageHash = getEthSignedMessageHash(_msgHash);

        // ECDSA检验通过
        require(verify(_ethSignedMessageHash, _signature), "Invalid signature");

        // 地址没有mint过
        require(!mintedAddress[_account], "Already minted!"); 
        // 铸造
        _mint(_account, _tokenId);
        // 铸造记录
        mintedAddress[_account] = true;
}

到了这里,关于链下签名实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • EIP-712签名介绍以及使用hardhat实现

    EIP-712是一种高级安全的交易签名方法。使用该标准不仅可以签署交易并且可以验证签名,而且可以将数据与签名以用户可见内容的方式一起传递到智能合约中,并且可以根据该数据验证签名以了解签名者是否是实际发送该签名的人要在交易中调用的数据。 EIP-712提出了数据的

    2024年02月02日
    浏览(36)
  • 链下数据认证

    由于区块链无法自己获取链下数据,也无法向链下系统传输数据,所以才能在安全和可靠性上做到极致,整个网络只需要使用区块链账本中已经存储的数据针对一组简单的true/false问题达成共识即可,比如“公钥持有者是否使用对应的私钥对交易签名?”、“公钥地址中是否有

    2024年01月21日
    浏览(32)
  • git的常规使用,比如本地和Coding建立连接

    安装好git,自行去网上拉取下载即可 https://git-scm.com/ 安装好以后,右键鼠标,出现如下图(git功能),表示安装成功 步骤一:在本地上新建一个项目文件夹,例如test 在该test文件夹中,鼠标右键,选择Git Bash Here 出现以下git弹窗,输入git clone “网址路径”,如下图,点击回

    2024年01月24日
    浏览(32)
  • 统一使用某一个包管理工具,比如yarn pnpm

    原因:前端每个人的习性不一样,有人用npm 有人用yarn等包管理工具,混合下载插件容易出bug,就用个小工具锁住就行了,只能使用yarn或者pnpm反向下载依赖和下载插件。不然就报错 改为pnpm的例子,就把yarn改为pnpm就可以了 if (!/ pnpm /.test(process.env.npm_execpath || \\\'\\\')) { 在scripts下添

    2024年02月10日
    浏览(46)
  • nginx使用openssl自签名,实现https登录

    1.确认nginx是否已安装SSL模块 查验方法:进入sbin目录,执行以下语句,显示结果如标记所示则表示安装成功 ./nginx -V  2.确认系统以安装SSL工具,开始制作证书 选择一个存放证书的路径,执行以下语句即可: (1)生成密钥,得到文件private.key openssl genpkey -algorithm RSA -out private

    2024年02月14日
    浏览(44)
  • C++调用openssl实现国标sm2签名算法的使用

    SM2算法基于ECC椭圆曲线算法,广泛用于区块链、HTTPS 等需要非对称加密的场景。是基于椭圆曲线数学理论实现的一种非对称加密算法。相比RSA,ECC优势是可以使用更短的密钥,来实现与RSA相当或更高的安全。 下面链接可以了解一些关于SM2的基础知识。 椭圆曲线加密算法(E

    2024年01月24日
    浏览(35)
  • 从零开发短视频电商 使用nimbus-jose-jwt进行对称签名和非对称签名的JWT实现

    JWT的基础介绍可以参见这个地址:https://jwt.io/introduction,下面都是从上面摘录的。 JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种 紧凑且自包含 的方式,用于 安全地在各方之间传输信息 ,其格 式为JSON对象 。这些 信息可以被验证和信任 ,因为它们是 数字签名

    2024年02月12日
    浏览(44)
  • 当我们谈笔记的时候,我们在谈什么

      文章具体内容如图,感谢妙友分享好文🎉 本篇内容来源于网站Untag @Minja 上传的内容《当我们谈笔记的时候,我们在谈什么》 如有侵权请联系删除! 

    2024年02月07日
    浏览(43)
  • 关于实现 Vue 动态数据显示,比如数字 0 或 1 怎么显示为 男 或 女等等的动态显示实现方法

    test.vue 文件演示: 以上关于数据 test.data 是数字格式的动态数据显示,有两种实现方法可以实现,方法二的灵活性比较好(比较推荐) 1. Vue中动态展示数据的字典项

    2024年02月09日
    浏览(29)
  • 使用SSH从公网服务器简易使用内网任意机器服务,比如从外部下载代码

    如果有一个台外部的机器waibu-host, 位于阿里云, 腾讯云, 亚马逊, azure云等等;  假设你想从这个waibu-host上访问公司任意服务,下载代码, 访问http服务,等等, 或者你机器上的服务, 不需要额外工具, 只要ssh 反向就可以实现;   借个图, 如下:   举个例子, 如果你想从公司内部通过git

    2024年04月24日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包