本文深入探讨了以太坊中数字签名的概念及其在密码学安全中的作用。
前言:本文不面向新手,假定读者具备以太坊和/或 Solidity 的知识。
以太坊上的交易是由外部账户(EOA)发起的签名消息。然而,这种简单的描述还有更多内容,因为并非所有此类消息都是有效的交易。有效的交易必须包含以下必需参数:Nonce、Recipient、Value、Data、Gas price、Gas limit、Chain Id 以及 v、r、s,并且交易必须使用 EOA 的私钥进行签名(我们稍后会看到原因)。
如果事先不了解数字签名的组成部分就理解数字签名的概念,对某些人来说可能有点困难,所以我们首先尝试解释其中一些概念(当然,这些概念在以太坊书中都有详细介绍)。 Nonce 是 Number used ONCE(仅使用一次的数字)的首字母缩写。它是一个整数,用于跟踪从帐户签名和传输的消息数量。它每次交易都会递增,并且一个 nonce 不能使用多次。任何使用已使用过的 nonce 签名的交易都会被网络拒绝。
Value 是随消息转发的以太币或代币的数量。仅包含 value 的交易称为“付款”。
Data 是随交易转发的有效负载。这些主要是指向合约帐户的函数调用(包含函数选择器的负载),因为大多数 EOA 不包含字节码,因此无法处理此类调用。仅包含数据的交易称为“调用”。除此之外,交易还可以同时包含数据和 value,或者什么都不包含。 Chain ID 表示交易要发送到的区块链网络。链 ID 的使用意味着为一个区块链创建的交易在另一个区块链上无效。这可以保护交易免受重放攻击,因为交易在发送到另一个网络时会失效。(有关更多信息,请参见 EIP-155)。
v、r、s 是从 EOA 私钥生成的签名变量,用于数字签名的创建和验证。(稍后详细介绍)。
私钥是密码学中用于创建公钥和签署交易的一组秘密的随机生成的整数。这些密钥既不需要也不在以太坊网络上传输,它们是 EOA 的独有财产和责任,并且任何有权访问它们的人都可以访问从该私钥生成的所有帐户。 现在,我们如何从私钥生成公钥?魔法。 以太坊使用公钥密码学(也称为非对称密码学)来创建公钥-私钥对。椭圆曲线密码学(一种非对称密码学的形式)用于使用椭圆曲线算法 secp256k1 在不可逆的方程中从私钥计算公钥。
请记住两件事:
i)“公钥是椭圆曲线上的一个点,这意味着它是一组满足椭圆曲线方程的 x 和 y 坐标”。因此,公钥是将两个数字连接在一起,每个数字代表椭圆曲线上的一个点。
ii)用于计算这些点的椭圆曲线算法是一种单向函数。在实践中,从私钥计算公钥非常容易,但逆转该过程并恢复生成该公钥的私钥是不可能的。这意味着该算法无法逆转以获得生成公钥的私钥。即使是量子计算机也无法做到这一点。
现在我们了解了公钥和私钥的概念以及它们的生成方式,让我们更进一步解释交易在广播到网络之前是如何序列化的。 序列化是通过使用特定函数(算法)来创建特定字节序列来准备签名的消息以广播到以太坊网络的概念。用于格式化交易的函数是网络上普遍接受的标准,使得使用此标准格式化的交易在区块链上被接受,而与任何特定节点使用的库、语言或应用程序无关。在以太坊网络上,用于此目的的标准是 RLP 编码算法(递归长度前缀算法)。
数字签名与传统的官方签名同义。它只是在互联网上授权交易或消息的一种方式。任何签名的交易都包含数字签名,并且该签名是此类消息有效性的证明。 数字签名非常重要,因为它们提供了交易来源帐户的证明(Solidity 中的 tx.origin ),并且此类交易的签名者不能否认该签名来自他的帐户。数字签名还提供证据表明消息或交易的内容未被篡改,因为消息内容的任何更改都会产生与原始签名完全不同的签名。
在较低级别,数字签名是从椭圆曲线数字签名算法(ECDSA)生成的,该算法由两部分组成。第一部分是签名创建算法,第二部分是签名验证算法。 当私钥签署已序列化的交易时,将创建数字签名。实际上,此处的序列化交易是 RLP 编码消息的 Keccak256 哈希。用于签名交易的数学函数是:
S i g = Fsig(Fkeccak256(m), k)
其中:k = 签名私钥 m= RLP 编码的消息 Fkeccak256 = Keccak256 哈希函数 Fsig = 签名算法 Sig = 结果签名 函数 Fsig 生成一个签名 (S i g),该签名生成两个值 r 和 s,这两个值对于签名验证至关重要。S i g = r, s
(更多信息请参见下面引用的以太坊书籍)。 我发现 Svetlin Nakov(博士)的这个解释非常详细,因此很有帮助: “ECDSA 签名算法 (RFC 6979) 将消息 msg**+ 私钥 privKey 作为输入,并生成一个签名作为输出,该签名由一对整数 {r, s} 组成。 ...计算出的签名 {r, s} 是一对整数,每个整数的范围为 [1…n-1]。它对随机点 R = k G 进行编码,以及一个证明 s,确认签名者知道消息 h 和私钥 privKey。从理论上讲,可以使用相应的 pubKey 验证该证明 s。” (有关更多信息或链接,请参见参考文献)。
这由 ECDSA 算法的第二部分处理。要验证交易,必须具有签名(r 和 s)、序列化的交易和公钥。此公钥必须与最初用于签署交易的私钥相对应。签名验证算法采用这些列出的组件,并根据签名是否有效返回一个布尔值;true 表示有效签名,false 表示无效签名。所涉及的数学计算和过程很复杂,无法在本文中介绍,但以下是验证过程的总结(再次,如 Svetlin Nakov 的书中所述):
i. 使用签名期间使用的相同密码哈希函数计算消息哈希。 ii. 计算签名证明的模逆,即签名生成函数的逆(参见上面的函数)。 iii. 从 x 坐标恢复签名期间生成的随机点 r。 iv. 从 R' 生成其 x 坐标:r' = R'.x v. 通过比较 r' == r 来计算签名验证结果 “签名验证的一般思想是使用公钥恢复点 R',并检查它是否与签名过程中随机生成的同一点 R 相同。” 同样,这是 Sveltin Nakov 对整个签名生成和验证概念的简单总结: “签名签名通过使用私钥 privKey 和消息哈希 h 将随机点 R(仅由其 x 坐标表示)通过椭圆曲线转换编码为数字 s,该数字 s 是消息签名者知道私钥 privKey 的证明。由于 ECDLP 问题的难度,签名 {r, s} 无法泄露私钥。 签名验证使用公钥 pubKey 和消息哈希 h 将签名中的证明数字 s 解码回其原始点 R,并将恢复的 R 的 x 坐标与签名中的 r 值进行比较。” 如果恢复的 x 坐标 r' 与签名期间随机生成的 r 相同,则签名有效。
正如已经解释的那样,在使用椭圆曲线密码学生成公钥时,每次都会生成两个可能的公钥。这是因为椭圆曲线算法在 x 轴上对称,因此对于生成的任何 x 值,都有两个可能的值适合该曲线;x 轴的每一侧各一个。 现在的问题是,此算法如何选择正确的 x 值与 y 值连接?这就是 v 的用武之地。 根据以太坊黄皮书,“ v ∈ {27,28}+chainId∗2 。这个值是公钥签名的一部分,用以从签名中消除公钥的歧义。”
为了更简单,vr 介于两个可能的生成值 R 和 R' 之间。如果 vR 是正确的值,如果 vR'。 为了更清楚,这是以太坊书中的一个片段: “在区块 #2,675,000 中,以太坊实施了“Spurious Dragon”硬分叉,除其他更改外,该分叉引入了一种新的签名方案,该方案包括交易重放保护(防止在一个网络上重放用于另一个网络的交易)。这种新的签名方案在 EIP-155 中指定。此更改会影响交易及其签名的形式,因此必须注意三个签名变量中的第一个(即 v),它采用两种形式之一,并指示哈希交易消息中包含的数据字段。 ...特殊的签名变量 v 指示两件事:链 ID 和恢复标识符,以帮助 ECDSArecover 函数检查签名。它被计算为 27 或 28 之一,或者作为链 ID 的两倍加 35 或 36。 ...恢复标识符(在“旧样式”签名中为 27 或 28,在完整的 Spurious Dragon 样式交易中为 35 或 36)用于指示公钥的 y 分量的奇偶校验。” Spurious Dragon 升级的全部想法是缓解重放攻击和签名可延展性的安全挑战,这是通过将链 ID 和恢复标识符引入变量 v 来实现的。
ecrecover 是 Solidity 中的一个全局函数,用于签名验证。它接受消息哈希和签名验证变量 v、r、s,并返回一个地址。然后可以将返回的地址与其他地址进行比较以找到匹配项。
address signer = ecrecover(msgHash, v, r, s);
安全警告:由于上述已解释的原因,上面的 ecrecover 函数容易受到签名重放攻击,因此请务必避免在合约中使用它。Openzeppelin 的 ECDSA 库是为此目的而安全且经过测试的。 结论 密码学是区块链技术的基础。像区块链这样的用于价值交换和交易的公共系统应该是 100% 安全的,并且还应该确保数据完整性、真实性和机密性。 数字签名是一种有效的方法,不仅可以跟踪交易来源,还可以确定交易在签名和传输后不会受到损害。变量 v、r、s 使数字签名的创建和验证成为可能。 如果你觉得本文有趣,或者对密码学感兴趣,可以参考以下资源。
https://ethereum.stackexchange.com/questions/45461/verify-ecdsa-signature-in-solidity -> ECDSA 和签名验证实现 https://ethereum.stackexchange.com/questions/79302/why-do-we-use-serialize-function-of-ethereumjs-tx-package-before-broadcastin -> RLP 编码和 tx 序列化 https://ethereum.github.io/yellowpaper/paper.pdf -> 以太坊黄皮书 https://github.com/ethereumbook/ethereumbook/blob/develop/06transactions.asciidoc#digital-signatures -> 以太坊书籍:数字签名 https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages -> Sveltin Nakov:数字签名 https://medium.com/cryptronics/signature-replay-vulnerabilities-in-smart-contracts-3b6f7596df57 -> 签名漏洞
- 原文链接: coinsbench.com/understan...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!