量子安全比特币交易(第一部分)

本文介绍了量子安全比特币交易(QSB)的第一部分,详细阐述了如何通过哈希和Lamport签名替代ECDSA来抵御量子攻击。

QSB 论文 的可视化指南 今年早些时候,Robin Linus 发布了 Binohash,一种无需软分叉即可在比特币脚本中实现交易内省的方法。QSB 论文将 Binohash 中的核心 ECDSA 谜题替换为哈希到签名谜题。

你不需要了解 Binohash 也能跟随本指南,我们会解释我们使用的所有内容。

注意:这并不是一个将比特币迁移到后量子时代的严肃计划。论文本身称之为最后手段。但它读起来很有价值,因为它展示了如何灵活运用 Script。

比特币交易通常使用 ECDSA 签名。

该签名承诺了交易。

如果交易中的任何内容发生变化,签名就会失效。

Image

让我们看看签名是如何构建的。

Image

看 z:

s 依赖于 z,而 z 依赖于交易数据。

如果我们改变交易 → z 改变 → 签名失效

记住这一点,这对后续所有内容至关重要。

1- 量子攻击

比特币容易受到量子攻击,这是因为 Shor 算法

[1]

这是因为量子计算机可以使用 Shor 算法从公钥中恢复私钥。

Image

这就是问题的所在:

Alice 想给 Bob 发送 10 BTC。她用她的私钥签名交易并广播。

Eve(攻击者)有一台量子计算机。她监视内存池,看到 Alice 的交易等待被挖矿。

该交易揭示了:Alice 的公钥

Image

Eve 在 Alice 的公钥上运行 Shor 算法 → 恢复 Alice 的私钥

现在 Eve 可以随意花费 Alice 的 UTXO。她用相同的输入(相同的 UTXO)构建自己的交易,但将输出发送给自己而不是 Bob。

她用 Alice 的私钥签名并广播。

Image

如果矿工首先包含 Eve 的交易,Bob 永远收不到 BTC。

2- 使用哈希代替 ECDSA

如果量子计算机可以破解 ECDSA,我们可以依赖什么?

答案:哈希

我们在比特币中使用的哈希函数不依赖于椭圆曲线。

它们具有原像抗性:给定一个输出,很难找到产生它的输入。

Shor 算法无法逆转哈希

Image

还有另一种量子算法,Grover 算法

[2]

确实会影响哈希函数,但只是削弱它们。它减少了执行暴力搜索所需的时间。

使用 Grover 算法,256 位密钥的原像抗性将接近 128 位密钥的安全性。

所以:

  • SHA-256:2²⁵⁶ → 2¹²⁸

  • RIPEMD-160:2¹⁶⁰ → 2⁸⁰

这更弱了,但 2⁸⁰ 仍然远超出当今量子攻击者的能力,特别是因为 Grover 算法无法并行化。

3- QSB 策略

QSB 论文建立在使用哈希代替 ECDSA 的想法之上。

策略是:

“移除对椭圆曲线的安全依赖。仅保留基于哈希的安全性。”

4- QSB 思路

第一步:推导出交易的一个指纹 D。

第二步:用 Lamport 签名签署 D(参见我们上一篇关于 Lamport 签名的文章)。

由于 Lamport 签名是后量子的,并且 D 绑定整个交易,攻击者无法在不伪造 Lamport 签名的情况下替换成不同的交易。为什么这能阻止 Eve:

如果 Eve 改变交易 → D 改变

→ 需要一个新的 Lamport 签名

→ 需要秘密哈希原像

→ Eve 没有它们 ✗

这就是核心思想。

第二步是容易的部分。

第一步(构建 D)是所有工作发生的地方。

我们将在接下来的部分逐步分解第一步:

  • 交易固定

  • 寻找 D:第一轮

  • 寻找 D:第二轮

5- 交易固定

让我们从交易固定开始。

在这一步中,Alice 创建一笔交易并“固定”它。

意思是:对交易的任何更改都变得代价高昂。

为了实现这一点,我们使用两个技巧。

技巧 1:公钥恢复 通常,ECDSA 是这样工作的:

私钥 → 公钥 → 签名。

但 ECDSA 也可以反向工作

[3]

如果你有:

  • 一个签名

  • 消息哈希 z

你可以恢复公钥:签名 + 消息 z → 公钥

public_key = Recover(signature, z)

(此步骤不需要私钥)

Image

如果你喜欢数学:

Q = r⁻¹(sR − zG)

注意:Q 依赖于 z,而 z 依赖于交易数据

如果我们改变交易 → z 改变 → 恢复的公钥改变

技巧 2:假签名(sig_nonce)

ECDSA 签名有两个值:r 和 s。

当编码为 DER

[0]

时,如下所示:

0x30 <total_len> 0x02 <r_len> <r>  0x02 <s_len> <s> <flag>

Image

技巧:构建尽可能小的 DER 签名,其中:

  • r = 1 字节

  • s = 1 字节

这产生了一个 9 字节的签名。

这是一个硬编码的假签名。它满足 DER 编码规则,但没有人签署任何东西。它只需要看起来像一个有效的签名。

Image

我们称其为 sig_nonce

sig_nonce = 30 07 02 01 [r] 02 01 [s] 01

Image

这个 sig_nonce 被硬编码在锁定脚本中。

Image

如果图中的锁定脚本看起来令人困惑,别担心。在本指南结束时,你将能够逐行阅读它。目前,唯一值得注意的是它有多短:只需 5 个操作码来固定一笔交易(Binohash* 需要 13 个)。

  • Binohash

[4]

是本文在其基础上构建的方案。我们将在后面的指南中介绍它。

推导 key_nonce

现在我们将两个技巧结合起来:

  1. 公钥恢复

  2. 假签名(sig_nonce

我们在 sig_nonce 上使用 Recover() 来计算 key_nonce,一个与假签名对应的公钥:

key_nonce = Recover(sig_nonce, z)

Alice 在链下计算它,使用她发给 Bob 的支出交易作为 z 的值。她在解锁脚本中提供 key_nonce。

Image

key_nonce 现在被绑定到支出交易。更改任何内容 → z 改变 → key_nonce 改变。

我们到了哪里?让我们暂时缩小视野。记住目标:构建一个指纹 D,该指纹绑定到 Alice 发给 Bob 的精确支出交易。Eve 不应该能够在不破坏对 D 的 Lamport 签名的情况下,替换成将钱发送给她自己而非 Bob 的不同交易。

为了构建 D,我们需要两件事:

  1. 一个依赖于支出交易的值。更改交易 → 该值改变。

  2. 一种使更改交易变得代价高昂的方法。这样就没有人能廉价地尝试数百万次变化以获得与 #1 相同的值。

我们刚刚解决了第一个问题。✓ key_nonce = Recover(sig_nonce, z) 与交易绑定。更改任何内容 → z 改变 → key_nonce 改变。

但这本身并没有用。我们仍然需要第二个条件。让我们接下来做这个。

那么是什么让它变得昂贵?

如果没有固定,Eve 可以这样做:

她看到 Alice 的交易在内存池中,并想将其替换为自己的交易。因为她更改了交易输出以将钱发送给自己而不是 Bob,所以她尝试的每个交易变体都会产生不同的 z,进而产生不同的 key_nonce,进而产生不同的 D。因此,她廉价地运行成千上万个变体,寻找一个导致 D 与 Alice 原始交易匹配的变体。然后她可以重用 Alice 的 Lamport 签名。

这对 Eve 来说既廉价又快速。

Image

(我们将在第 2 部分中确切看到 D 是如何构建的。现在,只需知道 Eve 的整个攻击依赖于廉价地搜索交易)

我们需要让每一次尝试都付出实际的工作。具体来说,每次尝试大约需要 2⁴⁶ 次哈希操作。

还记得 Alice 在她的解锁脚本中提供的 <key_puzzle> 吗?这就是哈希到签名谜题的用武之地。

Image

哈希到签名谜题(sig_puzzle)

思路如下。

脚本获取 key_nonce 并使用 RIPEMD-160 对其进行哈希处理

RIPEMD-160(key_nonce) → 20 个看似随机的字节

让我们称这 20 个字节为:

sig_puzzle = RIPEMD-160(key_nonce)

现在技巧来了:我们希望这 20 个字节(sig_puzzle)看起来像一个有效的 DER 编码签名。正如我们之前所见,DER 签名具有以下结构:

30 [len] 02 [r-len] [r] 02 [s-len] [s] [flag]

得到看起来像有效 DER 的字节串的概率非常低,大约为 2⁴⁶ 分之一

所以大多数尝试都会失败。

但在多次尝试后,RIPEMD-160(key_nonce) 会产生看起来像有效 DER 签名的字节。

这就是谜题。

Image

如果 key_nonce 保持不变,RIPEMD-160(key_nonce) 总是给出相同的输出。

诀窍在于 Alice 可以更改 key_nonce。

请记住:key_nonce 依赖于 z。而 z 依赖于交易数据。

因此 Alice 可以调整交易字段,例如:

  • nLocktime

  • nSequence

  • 等等。

每次调整都会得到:

新交易

→ 新 z

→ 新 key_nonce

→ 新 RIPEMD-160(key_nonce)

所以 RIPEMD-160 是确定性的,但 Alice 不断给它新的输入。

好的,但我们如何在 Script 中检查有效的 DER?

使用 OP_CHECKSIG 作为 DER 验证器:

我们将 sig_puzzle(那 20 个字节)作为签名输入 OP_CHECKSIG:

  • 如果 CHECKSIG 通过 → ✓ 有效 DER → 谜题解决

  • 如果 CHECKSIG 失败 → ✗ 无效 → 重试

Image

交易固定(总结)

现在我们知道我们在寻找什么:

一笔交易,其中:RIPEMD-160(key_nonce) 看起来像一个有效的 DER 签名。

大多数尝试都失败。

因此 Alice 不断调整交易,直到某个输出具有 DER 形状。

平均而言,这大约需要 2⁴⁶ 次尝试。

这就是固定。

一旦 Alice 找到一笔可行的交易,之后对它的任何更改都意味着重新开始并重做大约 2⁴⁶ 的工作。

等等,那 key_puzzle 呢?:

还记得之前,当 Alice 的解锁脚本是 <key_puzzle> <key_nonce> 时?

我们告诉过你先忽略 key_puzzle。

现在我们可以解释它了。

key_puzzle 只是另一个恢复的公钥,这次是针对 sig_puzzle。Alice 使用之前相同的 Recover() 技巧在链下计算它:

key_puzzle = Recover(sig_puzzle, z)

Image

脚本执行:

还记得前面的固定脚本吗?现在我们逐步运行它:

解锁脚本:
&lt;key_puzzle> &lt;key_nonce>

锁定脚本:
&lt;sig_nonce>
OP_OVER
OP_CHECKSIGVERIFY
OP_RIPEMD160
OP_SWAP
OP_CHECKSIGVERIFY

脚本执行两次检查。

  • key_nonce 绑定到这笔交易。

  • RIPEMD-160(key_nonce) 作为与 key_puzzle 一起使用的签名有效。

现在让我们逐步执行堆栈。

Image

在第 2 部分中,我们将涵盖:

  • SIGHASH_SINGLE 漏洞

  • 150 个虚拟签名

  • FindAndDelete

  • 查找摘要 D

  • 使用 HORS 签署 D

参考文献

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

0 条评论

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