演示 Claude Code 成功调试复杂的低级密码学实现。展示 AI 编程工具在深度技术问题上的突破性能力。
过去几天我写了一个 Go 版本的 ML-DSA 实现,这是 NIST 去年夏天公布的后量子签名算法。我花了四天时间直播编码,周四晚上完成了。除了……验证总是拒绝有效的签名。
$ bin/go test crypto/internal/fips140/mldsa
--- FAIL: TestVector (0.00s)
mldsa_test.go:47: Verify: mldsa: invalid signature
mldsa_test.go:84: Verify: mldsa: invalid signature
mldsa_test.go:121: Verify: mldsa: invalid signature
FAIL
FAIL crypto/internal/fips140/mldsa 2.142s
FAIL
我累坏了,所以尝试调试了半小时然后放弃了,打算明天以清醒的头脑重新开始。
一时兴起,我想让 Claude Code 试试,同时我去查看邮件,从高度集中的状态中恢复过来。我大多期待它会以某种可能有趣的方式失败,或者排除一些问题。
结果,它快速找出了我相对陌生的新型密码学算法实现中一个相当复杂的底层 bug。我之所以分享这个,是因为它让我意识到我对何时调用 AI 工具仍然没有很好的直觉,而且我认为这对任何仍然对 AI 工具的实用性持怀疑态度的人来说是一个绝佳的案例研究。
完全披露:Anthropic 免费给了我几个月的 Claude Max。他们有一天主动联系我,说他们把它送给一些开源维护者。也许这是一个套路,为了在免费优惠券过期后让我付费。也许他们希望我会写这样的东西。也许他们就是好心。无论如何,他们没有要求或建议我写任何关于 Claude Code 的公开文章。现在你知道了。
我用 Opus 4.1 启动了 Claude Code v2.0.28,没有系统提示,并给了它以下提示(包含原样的打字错误):
I implemented ML-DSA in the Go standard library, and it all works except that verification always rejects the signatures. I know the signatures are right because they match the test vector.
YOu can run the tests with "bin/go test crypto/internal/fips140/mldsa"
You can find the code in src/crypto/internal/fips140/mldsa
Look for potential reasons the signatures don't verify. ultrathink
I spot-checked and w1 is different from the signing one.
让我惊讶的是,几分钟后它给了我一个完整的修复。
也许我不应该感到惊讶!也许对更熟悉 AI 工具的人来说,很明显这是一个很好的 AI 任务:一个范围明确、有失败测试的问题。另一方面,这是一个相对陌生的复杂算法的全新实现中的底层问题。
它弄清楚了我已经合并了 HighBits 和 w1Encode 成单一函数供 Sign 使用,然后在 Verify 中重新使用它,而此时 UseHint 已经产生了高位,实际上在 Verify 中对 w1 的高位取了两次。
查看日志,它将实现加载到上下文中,然后立即弄清楚了,没有任何探索性的工具使用!之后它为自己写了一个可爱的小测试,重新实现了验证的一半以确认假设,写了一个平庸的修复,并检查了测试通过。
我扔掉了修复并重构了 w1Encode,让它以高位作为输入,并改变了高位的类型,这既更清楚,又省去了通过 Montgomery 表示的往返。不过,这 100% 为我节省了一些调试时间。
周一,我也刚完成了带有失败测试的签名实现。有两个 bug,我在接下来的几个晚上修复了它们。
第一个 bug 是由于不知何故计算了几个硬编码常数(Montgomery 域中的 1 和 -1)错误。它非常难找,需要大量深度 printf 和猜测。花了我大约一两个小时。
第二个比较简单:最终在签名中编码的值太短了(32 位而不是 32 字节)。相对容易发现,因为只有签名的前四个字节相同,然后签名长度不同。
我认为这些是验证 Claude 能否帮助找到底层密码学代码 bug 的有趣方式,所以我用 Jujutsu 检出了带有 bug 的旧版本,用这个提示启动了一个新的 Claude Code 会话:
I am implementing ML-DSA in the Go standard library, and I just finished implementing signing, but running the tests against a known good test vector it looks like it goes into an infinite loop, probably because it always rejects in the Fiat-Shamir with Aborts loop.
You can run the tests with "bin/go test crypto/internal/fips140/mldsa"
You can find the code in src/crypto/internal/fips140/mldsa
Figure out why it loops forever, and get the tests to pass. ultrathink
它花了一些时间做 printf 调试,追踪不正确的值,方式和我做的很相似,然后弄清楚并修复了错误的常数。Claude 花的时间肯定比我少。印象深刻。
即使测试仍然失败,它在修复该 bug 后也放弃了,所以我启动了一个新的会话(假设对错误常数的上下文在调查独立 bug 时会弊大于利),并给了它这个提示:
I am implementing ML-DSA in the Go standard library, and I just finished implementing signing, but running the tests against a known good test vector they don't match.
You can run the tests with "bin/go test crypto/internal/fips140/mldsa"
You can find the code in src/crypto/internal/fips140/mldsa
Figure out what is going on. ultrathink
它走了几条错误的路线,想了相当长的时间,然后找到了这个。说实话,我最初期望它会失败。
有趣的是 Claude 发现"更简单"的 bug 反而更困难。我的猜测是也许测试失败的大量随机外观的输出不会很好地与它的注意力配合。
它提议的修复是只更新分配的长度而不是容量,但无论如何,重点是找到 bug,我通常希望扔掉修复并自己重写它。
三次成功的单次调试命中,没有任何帮助,这绝对是令人印象深刻的。重要的是,当 LLM 的工作只是通过告诉我 bug 在哪里来为我节省一两个小时时,不需要信任 LLM 或审查其输出,我可以自己推理并修复它。
像往常一样,我希望我们有更好的工具来使用 LLM,不看起来像聊天、自动补全或"给我做一个 PR"。例如,每次测试失败时,如果一个 LLM agent 被踢入去找出原因,并且只在它在我们修复之前找到时才通知我们,那会多好呢?
如需更多底层密码学 bug 实现,请在 Bluesky 上关注我 @filippo.abyssdomain.expert 或在 Mastodon 上关注我 @filippo@abyssdomain.expert。我保证我几乎从不发布关于 AI 的内容。
享受最傻的绒毛。肯定这会在认为 AI 不是工具,而是应该被仇恨或热爱的东西的人眼中为我赎罪。
我的工作由 Geomys 组织支持,这是一个专业 Go 维护者的组织,由 Smallstep、Ava Labs、Teleport、Tailscale 和 Sentry 资助。通过他们的合同,他们确保了我们开源维护工作的可持续性和可靠性,并获得了我和其他 Geomys 维护者专业知识的直接渠道。(在 Geomys 公告中了解更多。)以下是其中一些的一些话!
Teleport — 在过去的五年里,攻击和妥协已经从传统恶意软件和安全漏洞转变为识别和妥协有效的用户帐户和凭证,通过社会工程、凭证盗窃或网络钓鱼。Teleport Identity 旨在通过访问监控消除弱访问模式,通过访问请求最小化攻击面,并通过强制访问审查清除未使用的权限。
Ava Labs — 我们在 Ava Labs 是 AvalancheGo(与 Avalanche Network 交互最广泛使用的客户端的维护者),我们相信开源加密协议的可持续维护和开发对于区块链技术的广泛采用至关重要。我们很荣幸通过我们对 Filippo 和他的团队的持续赞助来支持这项必要而有影响力的工作。