主页 > imtoken钱包安卓版 > 6.5 数字签名(ECDSA)

6.5 数字签名(ECDSA)

imtoken钱包安卓版 2023-02-12 06:25:17

6.5.1 数字签名如何工作

数字签名是一种数学方案,由两部分组成:第一部分是使用私钥(签名密钥)从消息(交易)创建签名的算法; 第二部分是一种算法,允许任何人给出给定的基础算法,用于消息和公钥验证签名。

6.5.1.1 创建数字签名

在比特币的 ECDSA 算法实现中,被签名的“消息”是交易,或者更确切地说是交易中特定数据子集的散列(参见 参考资料)。 签名密钥是用户的私钥,结果就是签名:

((Sig = F{sig}(F{hash}(m), dA))) 这里:

有关 ECDSA 数学的更多详细信息,请访问 。

函数 Fsig 生成由两个值组成的签名 Sig,通常称为 R 和 S:

  1. Sig = (R, S)

现在已经计算出 R 和 S 这两个值,然后使用称为可分辨编码规则或 DER 的国际标准编码方案将它们序列化为字节流。

6.5.1.2 签名序列化(DER)

让我们再看看爱丽丝创建的交易。 在交易输入中有一个解锁脚本,其中包含以下来自爱丽丝钱包的 DER 编码签名:

  1. 3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301

这个签名是由 Alice 的钱包生成的 R 和 S 值的序列化字节流比特币地址密钥,证明她拥有授权使用该输出的私钥。 序列化格式包含以下9个元素:

看看您是否可以使用此列表解码 Alice 的序列化(DER 编码)签名。 重要的数字是R和S; 其余数据是 DER 编码方案的一部分。

6.5.2 验证签名

要验证签名,必须具有签名(R 和 S)、序列化交易和公钥(对应于用于创建签名的私钥)。 本质上,签名验证意味着“只有生成该公钥的私钥的所有者才能在该交易中生成该签名。”

签名验证算法采用消息(交易或其部分的散列)、签名者的公钥和签名(R 和 S 值),如果签名对该消息和公钥有效,则返回 TRUE 值。

6.5.3 签名哈希类型(SIGHASH)

数字签名应用于消息,在比特币中,应用于交易本身。 签名是指签名者对特定交易数据的承诺。 在最简单的形式中,签名应用于整个交易,从而提交所有输入、输出和其他交易字段。 但是,签名也只能提交交易数据的一个子集,这对我们将在本节中看到的许多场景都很有用。

比特币签名使用 SIGHASH 标志来显示交易数据的哪一部分包含在由私钥签名的哈希中。 SIGHASH 标志是附加到签名的单个字节。 每个签名都有一个随输入变化的 SIGHASH 标志。 如果一个交易有三个签名输入,就会有三个带有不同 SIGHASH 标志的签名,每个签名签署(提交)交易的不同部分。

请记住,每个输入都可能在其解锁脚本中包含一个签名。 因此,包含多个输入的交易可以有多个签名,不同的 SIGHASH 标志在每个输入中提交交易的不同部分。 另请注意,比特币交易可能包含来自不同“所有者”的输入,这些“所有者”可能只在部分构造(且无效)的交易中签署一个输入,需要与其他人合作收集所有必要的签名以使交易有效。 许多 SIGHSASH 标志类型只有在考虑到许多参与者在比特币网络之外协作以仅更新部分签名的交易时才有意义。

SIGHASH标志位共有三个:ALL、NONE和SINGLE,如下表6-3所示。

表 6-3 SIGHASH 类型及含义

SIGHASH 标志值说明

全部

0x01

应用于所有输出输入的签名

没有任何

0x02

签名仅适用于所有输入,不包括任何输出

单身的

0x03

签名应用于与签名输入具有相同索引号的所有输入和输出

还有一个修饰符标志 SIGHASH_ANYONECANPAY,它可以与前面的每个标志结合使用。 当 ANYONECANPAY 被设置时,只有一个输入被签名,其余的(和它们的序列号)保持开放以供修改。 ANYONECANPAY的值为0x80,通过按位或运算,得到如下表6-4所示的组合标志位:

表 6-4 带有修饰符的 SIGHASH 类型及其含义

SIGHASH 标志值说明

所有|任何人都可以支付

0x81

应用于一个输入和所有输出的签名

无|任何人都可以支付

0x82

应用于输入的签名,不包括任何输出

单身|任何人都可以支付

0x83

签名应用于具有相同索引号的输入和输出

这些标志组合在下面的图 6-7 中进行了总结。

图6-7

图 6-7 不同 sighash 组合汇总

在签名和验证期间应用 sighash 标志的方式是复制交易并截断其中的一些字段(设置为零长度和空)。 然后将交易序列化,在序列化交易的末尾加上SIGHASH标志,对结果进行哈希,得到的哈希值就是签名的“消息”。 根据使用的 SIGHASH 标志,交易的不同部分被截断。 生成的哈希值取决于交易中数据的不同子集。 在散列之前的最后一步,通过包含 SIGHASH,签名提交为 SIGHASH 类型,因此不能更改(例如由矿工)。

提示:所有 SIGHASH 类型都签署到事务的 nLocktime 字段(请参阅参考资料)。 此外,SIGHASH 类型本身在签名之前附加到交易中,因此一旦签名就无法修改。

在 Alice 的交易示例中(参见 参考资料),我们看到 DER 编码签名的最后一部分是 01,也就是 SIGHASH_ALL 标志。 这会导致锁定交易数据,因此爱丽丝的签名会提交所有输入和输出状态。 这是最常见的签名形式。

让我们看看其他一些 SIGHASH 类型以及如何在实践中使用它们:

所有 | 任何人都可以支付

这种结构可用于进行“众筹”交易,其中试图筹集资金的人可以构建一个具有单一输出的交易,该输出将“目标”金额支付给众筹发起人。 这样的交易显然是无效的,因为它没有输入。 但现在其他人可以添加自己的输入来修改它,从而实现捐赠。 他们用 ALL|ANYONECANPAY 签署自己的输入,除非收集到足够的输入达到输出的价值,否则交易无效,每次捐赠都是“抵押”,直到筹集到全部目标金额,筹款人无法收取.

没有任何

此结构可用于创建特定金额的“不记名支票”或“空白支票”。 它对输入做出承诺,但允许更改输出锁定脚本。 任何人都可以将自己的比特币地址写入输出锁定脚本并赎回交易。 但是,输出值本身被签名锁定。

无 | 任何人都可以支付

这种结构可以用来建造“吸尘器”。 用户的钱包里有微型 UTXO比特币地址密钥,因为微型 UTXO 的面值不足以支付交易费用,所以用户无法花费这些费用。 通过这种类型的签名,微小的 UTXO 可以捐赠给任何人,随时收集和使用。

有一些建议修改或扩展 SIGHASH 系统。 其中之一是 Blockstream 的 Glenn Willen 作为 Elements 项目的一部分提出的 Bitmask Sighash 模式。 它的目的是创建一个灵活的 SIGHASH 类型的替代方案,允许使用“任意的、矿工可重写的输入和输出位掩码”来表示“更复杂的合同预承诺方案,例如在分布式资产交换中。” 已签署更改报价”。

注意:您不会在用户的钱包应用程序中看到 SIGHASH 标志作为一项功能。 除了极少数例外,钱包构建 P2PKH 脚本并使用 SIGHASH_ALL 标志对其进行签名。 要使用不同的 SIGHASH 标志,必须编写软件来构造和签署交易。 更重要的是,特殊用途的比特币应用程序可以将 SIGHASH 标志用于新目的。

6.5.4 ECDSA 数学

如前所述,签名由数学函数 Fsig 创建,该函数生成由两个值 R 和 S 组成的签名。在本节中,我们将更详细地了解 Fsig 函数。

签名算法首先生成一个临时(临时)公私密钥对。 这个临时密钥对用于在涉及签名私钥和交易哈希的转换之后计算 R 和 S 值。

临时密钥对基于随机数 k,用作临时私钥。 从k,生成相应的临时公钥P(用P = k G计算,与推导比特币公钥相同); 见章节)。 数字签名的R值是临时公钥P*的横坐标。

在此基础上,算法计算出签名的S值,使得:

S = k-1 (Hash(m) + dA * R) mod n

在:

验证是签名生成函数的逆函数,使用 R、S 值和公钥计算一个值 P,它是椭圆曲线上的一个点(创建签名时使用的临时公钥):

P = S-1 哈希(m) G + S-1 R Qa

在:

如果计算出的点 P 的 x 坐标等于 R,则验证者断定签名有效。

请注意,在验证签名时,私钥既不知道也不会泄露。

提示:ECDSA 是一个相当复杂的数学问题,完整的解释超出了本书的范围。 有一些很棒的在线指南可以一步步指导您:搜索“ECDSA explained”或试试这个:。

6.5.5 签名中随机性的重要性

正如我们在 中看到的,签名生成算法使用随机密钥 k 作为临时公私密钥对的基础。 k 的值并不重要,只要它是随机的即可。 如果使用相同的 k 值在不同的消息(交易)上生成两个签名,则任何人都可以计算出签名私钥。 在签名算法中使用相同的k值会导致私钥泄露!

警告 如果签名算法在两个不同的交易中使用相同的 k 值,则可以计算出私钥并将其暴露给全世界!

这不仅在理论上是可能的,我们已经看到这个问题导致在比特币交易签名算法的几种不同实现中暴露私钥。 人们无意中重复使用了 k 的值,从而窃取了资金。 重用 k 个值的最常见原因是未正确初始化随机数生成器。

为避免此漏洞,行业最佳实践不是使用以熵为种子的随机数生成器来生成 k,而是使用以交易数据本身为种子的确定性随机过程。 这确保了每笔交易产生不同的 k 值。 Internet 工程任务组发布的 RFC 6979 中定义了用于确定性初始化 k 值的行业标准算法。

如果您正在部署一种在比特币中签署交易的算法,您必须使用 RFC 6979 或类似的确定性随机算法来确保为每笔交易生成不同的 k 值。