面对量子计算,区块链缺的不是新算法,是把账户安全迁过去的路

最近整个币圈又开始密集讨论抗量子(Post-Quantum)的问题。Ethereum 社区把很大一部分路线图叙事放在下一步如何向抗量子过渡上,社交媒体上甚至流传着一种让人紧张的说法:只要你的钱包地址曾经发过哪怕一笔交易,你的公钥就已经暴露在链上了,应该趁现在赶紧把资产全部转移到全新的钱包地址去。
很多朋友来问我们的看法,我的回答先放在最前面:Don't panic(不要恐慌)。
把一个抗量子签名算法加进密码学库里,其实没有大家想象的那么神秘。对一条已经在运行的区块链来说,真正棘手的问题从来不是“怎么验证一种新签名”,而是“怎么让全网存量账户在不作废旧收款地址、不被抢跑劫持、也不把交易体积撑爆的前提下,平滑换上新钥匙”。
这就是为什么我们在 2018 年设计 ArcBlock 区块链的第一版时,没有去押注某一个当时远未定型的抗量子算法,而是先做了两件更基础的事:用自描述的 did:abt: 把身份与具体加密算法解耦,并在协议层内置了原生的账户迁移(Account Migration)机制。这项设计在 2019 年提交专利申请,并于 2022 年正式获得美国专利授权(US11388010B2)[1]。
不过,光躺在七八年前的设计上是不够的。在我们即将进行的 ArcBlock 链升级与全量安全审计中,我们重新把“一旦量子威胁逼近,存量账户怎么迁”这件事从头到尾推演了一遍,发现过去认为“只要支持 account_migrate 就万事大吉”的想法,其实漏掉了几个非常具体的工程死角。
这篇文章想把这些底层逻辑掰开讲清楚:量子计算到底威胁区块链的哪一层?为什么 Bitcoin、Ethereum 和 Solana 改起来各有各的包袱?我们在最新升级里具体补上了哪些安全拼图?以及作为普通用户,今天到底该做什么、不该做什么。
量子计算机到底威胁什么,不威胁什么?
每次聊到量子计算,最容易混为一谈的是两类完全不同的密码学原语:哈希函数(Hash)和非对称公钥签名(Digital Signature)。
区块链用哈希函数(比如 SHA-256、SHA3-256、Keccak-256)来串联账本、生成 Merkle 证明,以及从公钥计算地址摘要。量子计算里的 Grover 算法对哈希原像与第二原像搜索(即从哈希反推公钥或伪造匹配的账本块)只能提供“平方根级别”的加速,把 256 位哈希的抗反推强度降到相当于经典计算的 128 位。要在 2^128 的空间里暴力穷举,即便动用地球上可预见的全部算力也依然不可行。只要哈希够长,账本历史和未暴露公钥的地址摘要在量子面前依然稳固。
真正受威胁的是椭圆曲线签名算法,包括 Bitcoin 和 Ethereum 用的 secp256k1、Solana 和我们常用的 Ed25519,以及手机安全芯片 Passkey 使用的 P-256。它们的安全根基是椭圆曲线离散对数问题:给你私钥算公钥很容易,但给你公钥反推私钥在经典计算机上算不出来。
如果未来某一天,具备足够容错逻辑量子比特的密码学相关量子计算机(CRQC)真的造出来了,Shor 算法就可以在多项式时间内从已经公开的公钥反推出私钥。
这就解释了为什么社区里有人会提醒“注意发过交易的账户”:
- 从未发过交易的哈希型地址:如果一个地址只是公钥经过
SHA3或Keccak哈希后的摘要,在你只收款、从未用它签名发交易之前,链上只有那串哈希值,连原始公钥都没有公开。哪怕今天就有量子计算机,它对着一串哈希也无从下手。 - 已经发过交易的账户:只要这个账户对外签发过一笔交易,为了能让全网节点验签,交易里就必须附上原始公钥(或者像 Ethereum 那样可以从签名
(v, r, s)中直接恢复出公钥)。从那一刻起,这把公钥就已经永远刻在链上公开账本里了。
理解这一层区分很有必要。但为什么即便知道“发过交易会公开公钥”,我依然建议大家不要现在就慌忙去搬家钱包?我们先看看不同公链在底层账户模型上的差异,答案自然就清楚了。
为什么老牌公链面对抗量子会觉得棘手?
Bitcoin、Ethereum 和 Solana 都是非常优秀的系统,它们今天在抗量子过渡上面临的阻力,并不是工程师不够聪明,而是当年立项时为了各自的优先目标,把账户地址和单一签名算法绑得太死了。
| 公链体系 | 地址与公钥的关系 | 什么时候暴露原始公钥 | 原生协议级账户迁移 | 切换抗量子算法的主要工程阻力 |
|---|---|---|---|---|
| Bitcoin | 早期 P2PK 直接用公钥;P2PKH/P2WPKH 用公钥哈希;Taproot (P2TR) 直接在输出脚本中包含变形公钥 | P2PK 与 P2TR 创建即公开;P2PKH 首次花费后公开(若复用旧地址收款则持续暴露) | 无(UTXO 模型无账户状态,只能发交易把币转去新地址) | 数百万枚早期/休眠 P2PK 比特币无法被动迁移;每次换算法都要求全网用户手动把 UTXO 搬到新地址 [4] |
| Ethereum (EOA) | 0x 地址取自 keccak256(secp256k1_pubkey) 的后 20 字节 | 发出第一笔交易时,任何人可从链上签名 (v, r, s) 恢复出完整公钥 | 无原生迁移交易;依赖智能合约钱包或 ERC-4337 / EIP-7702 账户抽象改造 [4] | 全网数亿存量 EOA 地址与 secp256k1 硬绑定,换算法必须借助复杂的账户抽象升级路径 |
| Solana | 钱包地址直接就是 32 字节 Ed25519 原始公钥的 Base58 编码 | 地址生成并分享给别人的那一秒,原始公钥就已经完全公开 | 普通外部账户无原生密钥轮换(仅合约 Program Derived Address 可由程序控制) | 地址本身就是公钥,没法靠哈希隐藏;且单包 1,232 字节的交易上限装不下一枚几千字节的抗量子签名 |
| ArcBlock (OCAP) | 26 字节自描述 did:abt:,含 RoleType / KeyType / HashType 头与 20 字节公钥哈希 | 发出第一笔交易(或主动声明)时公开当前公钥;未出账前仅暴露 SHA3 哈希 | Day 1 内置 AccountMigrateTx(获批专利 US11388010B2),维护 migratedFrom / migratedTo 链上重定向 [1] | 已有算法分派与迁移轨道;重点在于堵死已暴露公钥的抢跑风险,并放宽大体积签名的管线预算 |
先看 Bitcoin。中本聪最早写的脚本里有大量 P2PK(Pay-to-Public-Key)输出,原始公钥直接裸露在账本上;后来的 P2PKH 把公钥藏在了哈希后面,但只要你花过一次钱又继续拿原地址收款,公钥还是暴露了;到了近年的 Taproot(BIP-341),为了脚本效率又把 32 字节的变形公钥直接放回了输出里 [4]。更重要的是,Bitcoin 没有“账户”这个状态对象,要换抗量子钥匙,唯一办法是每个人自己发交易把所有 UTXO 转到新地址去。
Ethereum 则是另一种情况。普通用户手里的 0x 外部账户(EOA),地址虽然是公钥的 Keccak-256 哈希,但底层验证逻辑写死了只认 secp256k1 这一种椭圆曲线,而且协议里没有“给这个 EOA 换一把公钥”的原生交易。一旦你要换算法,原来的 0x 地址就验证不了新签名。正因如此,Ethereum 才需要花好几年时间推进 ERC-4337 和 EIP-7702 账户抽象,先把千万个死板的 EOA 改造成可编程的合约账户,然后才能谈换签名算法的事 [4]。
至于 Solana,它当年为了追求极致的吞吐和验签速度,直接拿 32 字节的 Ed25519 原始公钥本身当作钱包地址。连哈希这一层遮挡都省掉了,意味着你的收款地址贴出去的那一刻,公钥就已经公开。而且 Solana 早期把整笔交易严格限制在单个网络数据包(1,232 字节)以内,而今天主流的抗量子签名动辄两三千字节,连一笔单签交易都塞不进去。
把这三家的历史包袱摆在一起,就能看明白:抗量子最难的不是数学,是存量账本的搬家工程。
我们从第一版留下的伏笔:自描述 DID 与账户迁移专利
我们在 2018 年设计 ArcBlock 的去中心化身份(did:abt:)和 OCAP 链状态机时,做了一个当时看起来有点“啰嗦”、今天回头看却省掉无数麻烦的决定。
在很多链上,地址只是一串没有元数据的哈希字节;而在 did:abt: 的 26 字节二进制结构里,最前面的 16 比特是一个自描述的协议头,明确编码了三个字段:6 比特 RoleType(角色类型)| 5 比特 KeyType(密钥算法类型)| 5 比特 HashType(哈希算法类型),后面才是 20 字节的公钥哈希与 4 字节校验和。
也就是说,我们的链从第一天起就没有假设全世界永远只用一种签名算法。 Ed25519 好用,我们就用 Ed25519;需要兼容以太坊生态,同一个协议头切到 secp256k1 就能直接验签;我们在 v1.19.x 引入手机安全芯片原生的 Passkey(WebAuthn P-256)账户支持时,同样不需要推翻任何已有地址体系。将来纳入 NIST 标准化的抗量子算法,在身份层只是增加一个 KeyType 枚举值。
但光能生成新算法的账户还不够。如果一个老用户已经用了好几年 Ed25519 账户,朋友、合作伙伴和各种应用手里存的都是他的旧地址,怎么办?
为了解决这个问题,我们在第一版链协议里直接做进了原生的账户迁移交易 AccountMigrateTx(account_migrate),也就是前面提到的美国授权专利 US11388010B2 [1]。我们在《换了私钥,旧地址收到的转账怎么办?》里专门对照 SDK 源码讲过它的工作方式:
- 当你把旧账户 A 迁移到新密钥对应的新账户 B 时,链的状态机不会抹掉历史,而是在底层建立双向的
migratedFrom与migratedTo指针链; - 迁移生效后,旧私钥 A 立即失去发起未来交易的权限(任何再用 A 私钥签发的新交易都会被管线直接以
ACCOUNT_MIGRATED拒绝),但 A 过去签过的历史记录依然可以用旧公钥验真; - 如果别人或外部系统继续向旧地址 A 转账、或者默认按迁移链查询状态,链端会自动沿着
migratedTo关系把结果和转入路由到最新的目标账户 B(即使以后 B 再迁到 C,也会一路寻址到终端)。
所以我们过去几年的基本思路一直很直接:平时大家尽管用最成熟、签名最短、硬件支持最好的经典加密算法;等到哪天量子计算真的露出实用苗头,或者 NIST 的抗量子标准完全成熟,用户发一笔 account_migrate,就能把账户控制权平滑移交到抗量子密钥生成的新账户上,连收款关系都不会断。
为什么“只支持迁移”还不够?我们在最新链升级里补上的三块拼图
直到最近准备新一轮 ArcBlock 链升级、并对整个交易协议与执行管线做地毯式安全审计时,我们自己给自己挑了刺:
假如明天真的出现量子威胁,或者某个已公开公钥的账户密钥面临泄露风险,光靠第一版那个 account_migrate,真的能安全迁过去吗?
仔细推演之后,我们发现原本的设计有三个很具体的软肋,并在这次升级里把它们逐一补齐了。
1. 已暴露公钥的抢跑死结:引入 KERI 预轮转承诺与强制双签
设想这样一个场景:你的账户 A 以前发过交易,公钥 PK1 已经公开在链上。如果攻击者(无论是通过传统手段盗取了热私钥,还是未来用量子算法从暴露的 PK1 算出了私钥)和你同时行动,谁先发出 account_migrate,谁就能把账户迁到自己的新地址去。
更危险的是,我们在审计旧版 migrate.ts 代码时发现,早期实现只校验了迁出方 from 的单方签名,没有强制要求目标新账户 to 也附上私钥持有证明(Proof-of-Possession)。这不仅意味着一旦迁出交易填错目标公钥就会把账户永久锁进没有私钥的“黑洞”,还可能让攻击者利用抢注或代理授权(delegator)制造混乱。
在本次升级中,我们对 account_migrate 做了两层硬核收紧:
第一层,是吸纳 KERI(Key Event Receipt Infrastructure)标准里的密钥预轮转承诺(Key Pre-Rotation,nextKeyCommitment)机制 [3]。简单说,你在账户完全安全的时候,就可以预先生成下一把备用钥匙(甚至直接是一把从未面世的抗量子算法钥匙)PK2,但不公开 PK2 本身,只在当前账户状态里写下它的哈希承诺 nextKeyCommitment = Hash(PK2)。
注意这里的区别:因为链上只存了下一把钥匙的哈希,哪怕你当前正在用的 PK1 每天都在发交易、公钥早就暴露在外,甚至某天 PK1 被人攻破了,攻击者也拿不走你的账户。因为链在执行 account_migrate 时会强制核对新公钥的哈希是否等于事先锁定的 nextKeyCommitment;对不上,直接返回 INVALID_PRE_ROTATION_KEY 拒绝执行。同时我们还修复了状态复制时的承诺消费逻辑,确保每一次迁移都会原子性地消费掉旧承诺并轮转到新的承诺,绝不允许重放。
第二层,是全面启用 from + to 强制双签名校验(VerifyMultiSigV2)。现在每一笔账户迁移,必须同时由旧密钥 from 和新密钥 to 共同签名,当场证明你确实握有新账户的私钥;同时协议层显式禁止任何代理授权(delegator)发起或参与迁移,并在迁移完成的瞬间自动清空旧账户遗留的所有出向委托授权(delegatedTo)。
这两刀切下去,“既不暴露下一把公钥,又不怕当前公钥被抢跑,还不会迁进黑洞”这道安全防线才算真正合拢。
2. 抗量子签名的“体积膨胀”:管线字节预算与单次规范编码
第二个过去容易忽略的问题,是抗量子算法惊人的体积。
我们习惯了 Ed25519 的轻巧:公钥 32 字节,签名 64 字节,加起来不到 100 字节。但看看 NIST 在 2024 年 8 月正式定稿发布的两项主力抗量子签名标准 [2]:
| 签名算法 | 标准状态 | 公钥大小 | 签名大小 | 公钥 + 签名合计 |
|---|---|---|---|---|
| Ed25519(当前常用) | 经典椭圆曲线 | 32 Bytes | 64 Bytes | 96 Bytes |
| secp256k1(BTC / ETH) | 经典椭圆曲线 | 33 / 65 Bytes | 64-72 Bytes | ~105 Bytes |
| FN-DSA-512 / Falcon-512 | NIST 抗量子草案(格密码) | 897 Bytes | ~666 Bytes | ~1,563 Bytes(约 16 倍) |
| ML-DSA-65 / Dilithium3 | NIST FIPS 204(格密码主力标准)[2] | 1,952 Bytes | 3,309 Bytes | 5,261 Bytes(约 55 倍) |
| SLH-DSA-128f / SPHINCS+ | NIST FIPS 205(纯哈希无状态签名)[2] | 32 Bytes | 17,088 Bytes | 17,120 Bytes(约 178 倍) |
哪怕选用综合性能最均衡的 NIST 主力标准 ML-DSA-65(Dilithium3),单次签名的公钥加签名体积也超过了 5 KB,是 Ed25519 的 50 多倍。如果一笔多签交易(MultiSig)或者多输入交易里包含三四个这样的签名,光签名字段就会飙升到 15 KB 到 20 KB。
如果链的底层协议还是按十年前“一笔交易最多 4 KB”的硬限制去卡,或者在多签验证循环里每验一个签名都把整笔大交易重新序列化一遍,抗量子账户一上线就会把执行管线卡死。
所以在这次链升级中,我们提前清理了这条跑道:
- 放宽多方交易字节上限并精确计量附加载荷:我们将多输入输出交易(
transfer_v3)和多签上限扩展到了 64 输入输出与 32 重多签,将对应协议的maxTxSize提升至 16 KB 至 32 KB,并在verify-tx-size管线中为txExtra、协签信封(coSignature)留出了明确受控的字节窗口(4 KiB 至 8 KiB),统一纳入存储成本核算; - 消除多签验证的
O(N²)重复编码:在VerifyMultiSigV2管线中,将交易字节的规范化编码(Canonical Protobuf / CBOR)提取到签名校验循环之外,无论挂载多少个大体积签名都只做一次序列化; - 按剥离签名后的
unsignedTxHash查重:交易防重放不再单纯依赖包含签名本身的哈希,而是对剥离掉所有签名和可变extra载荷后的交易主体计算确定性摘要,从根源上杜绝大体积签名或混合签名变体带来的可延展性(Malleability)隐患。
3. 链下凭证的长期有效性与抗量子哈希披露
除了链上账户,还有一个地方需要未雨绸缪:可验证凭证(Verifiable Credentials, VC)。
链上账户可以通过 account_migrate 随时换钥匙,但发给用户的长期凭证或隐私证明如果在底层过度依赖特定的椭圆曲线配对(Pairing),将来同样会面临算法老化的问题。在很多号称“零知识证明(ZK)”的区块链方案里,其实只用到了简洁计算证明(Succinctness),并没有做到真正的隐私零知识,反而背上了极重的电路和曲线包袱。
在这次升级中,我们在 @arcblock/vc 里落地了原生的 SD-JWT / SD-VC 选择性披露凭证,底层直接采用抗量子的 SHA3-256 盐值哈希承诺(Salted Hash Commitments)来隐藏未披露字段。需要向验证方证明某个字段时,只需披露对应字段的明文与盐值即可核对哈希,完全不依赖脆弱的椭圆曲线电路;同时,经过链上 Checkpoint 锚定的历史签名记录,也能清晰区分“迁移前由旧钥匙合法签发的历史事实”与“迁移后新钥匙的当前控制权”。
这里也要实事求是地交个底:今天我们的生产环境钱包和链上日常交易,默认使用的依然是 Ed25519、secp256k1 和硬件 Passkey(P-256),并没有今天就切换成几千字节的 ML-DSA 签名。 在整个硬件生态、手机安全芯片(Secure Enclave)和浏览器标准还没有原生普及后量子签名之前,强行让普通用户每天顶着 50 倍的签名体积在软件内存里跑新算法,既不必要,也不划算。
工程上更负责任的做法,是把身份格式、协议级迁移专利、预轮转哈希锁和管线容量全部就位,把“换算法”从一场伤筋动骨的硬分叉灾难,变成一次随时可以触发的常规账户升级。
给普通用户的建议:今天到底该做什么?
回到文章开头那个让人焦虑的传言:“既然发过交易的地址会公开公钥,我现在是不是应该立刻建一个新钱包,把所有资产手动转过去,以后每发一笔交易都换一个新钱包?”
从纯理论密码学上说,提出这个想法的人看到了“哈希隐藏公钥”与“签名公开公钥”的区别,这是一个审慎的技术观察。但在现实工程与日常资产安全上,我们强烈建议你不要因此恐慌,更不要现在就匆忙动手去手动搬家钱包。
原因非常简单:能够破解 256 位椭圆曲线的实用量子计算机今天并不存在;但因为慌乱手动转移钱包而导致的丢币,每天都在真实发生。
我们在社区和行业里见过太多这样的惨剧:有人听说旧钱包不安全,半夜急匆匆新建钱包,助记词随手截了个图或者没核对备份就把全部资产转了过去,结果第二天手机重置,资产永久归零;有人在跨链或换地址时粘错了首尾相似的钓鱼地址;还有人轻信了搜索广告里弹出来的所谓“抗量子钱包一键升级工具”,亲手签下了掏空账户的恶意授权。
用今天 100% 真实存在的人为操作风险,去防御一个尚在实验室早期阶段、且协议层已经有成熟迁移方案应对的远期威胁,是一笔非常不划算的账。
如果你希望把账户安全做得更扎实,今天真正值得做的只有三件小事:
- 保持冷静,切勿盲目手动搬家资产:不需要因为你的地址发过交易,就急着把资产拆碎转去一堆连自己都记不清备份在哪的新地址。
- 警惕任何打着“抗量子升级”旗号的钓鱼链接:任何要求你输入助记词、私钥或签署陌生授权来“升级抗量子账户”的第三方网页,100% 是骗局。真正的协议级升级只会通过官方钱包与链协议原生提供。
- 用好硬件级身份与日常权限分离:相比担心远期的量子计算,今天更现实的防线是避免在浏览器软件内存里裸奔明文私钥。优先使用基于设备安全芯片的 Passkey 账户,日常高频交互用受限的委托授权(Delegation),把主控钥匙留在低频安全边界内。
七八年前我们写下 did:abt: 的多算法头部、提交 US11388010B2 账户迁移专利时,想的就是有一天加密世界终究要面对算法换代。那时候我们留好了门;而在即将到来的这次链升级里,我们又给这扇门加上了 nextKeyCommitment 预轮转锁、强制双签校验和充裕的管线通道。
当未来某一天真的需要换上抗量子新钥匙时,你不需要把所有朋友手里的收款地址改一遍,更不需要半夜提心吊胆地手动清空钱包。在钱包里确认一次受保护的账户迁移,剩下的寻址与状态延续,交给链本身去完成就够了。
参考资料
[1] Tian Chen, Zhihong Mao(ArcBlock, Inc.):US11388010B2 - Blockchain account migration,2019 年 10 月 18 日申请,2022 年 7 月 12 日获美国专利商标局(USPTO)正式授权。本站书目与解读见《区块链账户迁移》与《换了私钥,旧地址收到的转账怎么办?》。
[2] NIST(美国国家标准与技术研究院):FIPS 204 - Module-Lattice-Based Digital Signature Standard (ML-DSA) 与 FIPS 205 - Stateless Hash-Based Digital Signature Standard (SLH-DSA),2024 年 8 月正式发布,定义了抗量子数字签名标准及其公钥、签名尺寸参数。
[3] Samuel M. Smith:Key Event Receipt Infrastructure (KERI),提出通过预先承诺下一把轮换公钥的哈希摘要(Pre-Rotation Commitment)来抵御当前活跃密钥泄露或抢跑攻击。
[4] Bitcoin BIP-341: Taproot: SegWit version 1 spending rules(说明 P2TR 输出直接包含 32 字节公钥)与 Ethereum EIP-7702: Set EOA account code(说明外部账户向可编程验证过渡的机制)。