如何验证以太坊上的消息签名

  • QuickNode
  • 发布于 2025-01-30 23:29
  • 阅读 21

本文深入探讨了以太坊上的签名生成和验证方法,使用 JavaScript 和 Ethers.js 库展示了如何进行这些操作。文章涵盖了公共和私钥的概念,签名的生成过程以及验证过程,并提供了具体的代码示例,同时还讨论了安全考量和相关工具,为开发者提供了全面的指导。

概述

在一个数据成为新黄金、数字交易成为日常规范的世界里,我们如何确保屏幕另一边的人确实是他所声称的人?这就是加密技术的用武之地,它帮助我们进行验证。在本指南中,我们将更多地了解加密技术和用户签名在以太坊中的基本作用,随后将展示如何使用 JavaScript 验证以太坊上的消息签名。

你将要做的

  • 了解签名生成和验证
  • 使用 Ethers.js 和普通 JavaScript 创建一个 Node.js 脚本,以生成和验证消息签名
  • 审查不同的安全考虑
依赖项 版本
Node.js 18.18.0
elliptic ^6.5.4
keccak256 ^1.0.6
secp256k ^5.0.0
ethers ^6.8.0

你将需要

  • 对以太坊的基本理解
  • 已安装 Node.js 和 npm

本指南灵感来源于以下视频:AI Makes Everything Easy to Fake—Crypto Makes it Hard Again | Balaji Srinivasan at SmartCon 2023。欢迎你去观看以深入了解这个主题。

私钥和公钥

以太坊上有两种类型的账户:外部拥有账户 (EOA)智能合约账户

每个 EOA 都与一对加密密钥相关联:私钥公钥。以太坊地址是从公钥派生而来的。

  • 私钥:一个随机的256位数字。保密非常重要,因为任何可以访问它的人都可以控制与该账户相关的活动。
  • 公钥:从私钥派生而来,是椭圆曲线上的一个点。使用椭圆曲线数字签名算法 (ECDSA),以太坊公钥的长度为512位。

签名生成

当你 签名 一条消息时,你产生了一个加密证明,证明你拥有与给定以太坊地址相关联的私钥,而无需透露私钥本身。这是通过使用 ECDSA 实现的。

以太坊签名用于:

  • 认证交易的发送者。
  • 确保交易数据的完整性。
  • 提供不可否认性:一旦签名,发送者无法否认已发送该交易。

要签名一条消息:

  • 使用 Keccak-256 对消息进行哈希处理,生成256位哈希。
  • 使用该哈希和私钥通过 ECDSA 生成签名。

签名由三个组成部分组成:r、s 和 v:

  • rs 是 ECDSA 算法的输出。
  • v 是恢复 ID,帮助从签名中提取公钥。

签名验证

要验证签名:

  • 你需要消息、签名(rsv)和发送者的公钥或以太坊地址。
  • 使用恢复 ID(v)从签名中提取公钥。
  • 验证签名是否对应于给定的消息哈希和提取的公钥。
  • 如果你只拥有以太坊地址,则从提取的公钥导出它,并将其与给定地址进行比较。

使用 JavaScript 生成签名并验证

我们将学习如何首先使用更手动的方法通过基本 JavaScript 生成和验证签名,接下来的部分将介绍使用流行的 SDK Ethers.js 进行更简单的解决方案。

首先,创建一个项目文件夹并安装所需的依赖项:

mkdir verifySignature
cd verifySignature
echo > index.js && echo > generate.js && echo > verify.js
npm init --y
npm i keccak256 secp256k1 elliptic

然后,打开文件 index.js 并按顺序输入以下代码片段:

导入库

//导入库
const EC = require('elliptic').ec;
const keccak256 = require('keccak256')
const ec = new EC('secp256k1');

导入所需的库(用于 ECDSA 的 elliptic 库和用于以太坊标准 SHA-3 哈希的 keccak 库)。

生成密钥对

//生成密钥对
const key = ec.genKeyPair();
const publicKey = key.getPublic('hex');
const privateKey = key.getPrivate('hex');

使用 elliptic 库生成密钥对,并分别存储每个密钥。

生成签名

//生成签名
const message = "Hello, Ethereum!";
const msgHash = keccak256(Buffer.from(message));
const signature = key.sign(msgHash, 'hex');

验证签名

// 验证签名
const isValid = ec.verify(msgHash, signature, publicKey, 'hex');
console.log(isValid);

输出:

true // 如果签名与其生成的私钥匹配,将输出 true

输出时,日志应在签名与消息哈希和公钥匹配的情况下显示 true。重新强调,此时的 msgHash 将是原始消息的哈希版本。而 signature 指的是通过签名函数生成的实际签名对象。它包含 ECDSA 签名的 vrs 值。最后,publicKey 是与用于创建签名的私钥相对应的公钥。在签名验证的上下文中,该公钥用于确保签名确实是由相应的私钥生成的。

使用 SDK (Ethers.js) 生成签名并验证

为了更方便地进行签名生成和验证,我们可以使用一个方便的 SDK ethers.js

安装

npm install ethers

然后,打开 generate.js 文件,输入以下代码以生成签名:

const { Wallet } = require('ethers');

async function signMessageWithEthers(privateKey, message) {
    const wallet = new Wallet(privateKey);
    const signature = await wallet.signMessage(message);
    return signature;
}

const message = "Hello, Ethereum!";
const privateKey = 'YOUR_PRIVATE_KEY_HERE'; // 确保提供你的私钥,可以带或不带 '0x' 前缀
signMessageWithEthers(privateKey, message).then(signature => {
    console.log(`Signature: ${signature}`);
});

确保用自己的私钥更新 privateKey,然后执行脚本:

node generate.js

你将看到类似以下内容的输出:

Signature: 0x020d671b80fbd20466d8cb65cef79a24e3bca3fdf82e9dd89d78e7a4c4c045bd72944c20bb1d839e76ee6bb69fed61f64376c37799598b40b8c49148f3cdd88a1b

要验证签名,请在 verify.js 文件中输入以下代码:

const { Wallet, verifyMessage } = require('ethers');

const message = "Hello, Ethereum!"
const signature = "0x020d671b80fbd20466d8cb65cef79a24e3bca3fdf82e9dd89d78e7a4c4c045bd72944c20bb1d839e76ee6bb69fed61f64376c37799598b40b8c49148f3cdd88a1b"

function verifyMessageWithEthers(message, signature) {
    const signerAddress = verifyMessage(message, signature);
    return signerAddress;
}

const signerAddress = verifyMessageWithEthers(message, signature);
console.log(`Message signed by: ${signerAddress}`);

执行脚本:

node verify.js

你将看到类似以下内容的输出:

Message signed by: 0xe0f2b924422909626D539b0FBd96239B31767400

这就是你所需要的,仔细检查一下消息是否由相应的公钥签名。

使用 QuickNode 发送交易

以太坊提供了机制,例如 eth_sign,用于签署任意消息。这不仅适用于交易,还适用于任何数据。消息签名在链下验证身份、证明所有权或其他加密证明中非常有用。 QuickNode 支持方法 eth_sendRawTransaction ,该方法接受一个签名的交易对象并将其发送到区块链。

请注意,要创建一个签名的交易对象,你将需要使用像 Ethers.js 这样的 SDK(查阅 signer.signTransaction 函数);如果你希望看到关于这一点的指南,请在指南底部留下反馈!

库和工具

有几个库和工具可以促进消息签名和验证:

  • web3.jsethers.jsweb3.py:常用于以太坊的 JavaScript 库。两者都提供签名和签名验证的函数。
  • MetaMask: 一个流行的以太坊钱包,允许用户签署消息。
  • MyCryptoMyEtherWallet: 提供用户签署任意消息的 UI。

安全考虑

  • 重放攻击:确保签署的消息有某种形式的随机数或时间戳,以防止被重复使用。重放攻击是指利用一个确认的交易试图恶意地再次执行。
  • 钓鱼:用户应小心自己签署的内容。恶意去中心化应用程序可能会诱骗用户签署一个交易,而非一个无害的消息。

测试你的知识

尝试完成简短的测验以巩固你的理解!

🧠 知识检查

以太坊上有哪两种类型的账户?

外部拥有账户 (EOA) 和智能合约账户公账户和私账户用户账户和开发者账户内部账户和外部账户

总结

这就是你需要的!你现在对以太坊上签名的生成和验证有更多的了解了。

我们非常想知道你正在构建的内容。在 Discord 中给我们留言,或者在 Twitter 上关注我们,随时了解最新信息!

我们 ❤️ 反馈!

让我们知道 如果你有任何反馈或新主题的请求。我们很想听到你的声音。

  • 原文链接: quicknode.com/guides/web...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。