30分钟看懂WOTS+一次性签名:用hashsigs-ts讲透后量子密码核心原理
2026/9/1 10:28:52 网站建设 项目流程

30分钟看懂WOTS+一次性签名:用hashsigs-ts讲透后量子密码核心原理

【免费下载链接】hashsigs-tsHash-based signatures in typescript, WOTS+项目地址: https://gitcode.com/gh_mirrors/ha/hashsigs-ts

hashsigs-ts 是一个用 TypeScript 实现的后量子密码哈希签名库,完整实现了 WOTS+(Winternitz One-Time Signature Plus)一次性签名算法。如果你一直听说"量子计算机要破解现有密码",却想真正搞懂基于哈希的签名到底靠什么抗量子,这篇文章就是你的入门指南——不堆公式,用这个只有 400 行核心代码的开源项目,把原理一次讲透。

为什么后量子密码里有个"土办法"?

大多数数字签名(RSA、ECDSA)的安全性建立在"大数分解""椭圆曲线离散对数"这类数学难题上。而量子计算机上的 Shor 算法恰好能高效解决这些难题——这是"后量子密码(PQC)"诞生的原因。

但还有一个"土办法"完全绕开了这些难题:哈希函数(hash-based signatures)。它的安全性只依赖一件事——哈希函数是单向的:

给定输出,几乎不可能反推出输入。

这件事连量子计算机都很难加速破解,所以基于哈希的签名被公认为后量子密码里理论基础最扎实的方案,也是 NIST PQC 标准化中 XMSS/XMSS^MT(RFC 8391)的底层技术。

而 WOTS+ 就是这类算法的"最小可用单元"——名字里的One-Time(一次性)是它最大的特点,也是理解它的关键。

WOTS+ 核心原理:一条"只能往前走"的链

哈希链:单向门的核心

想象一条链条,每一环都是上一环做哈希的结果:

sk → H(sk) → H(H(sk)) → H(H(H(sk))) → ... → 终点
  • 私钥:链条的起点sk
  • 公钥:链条的终点(公开,任何人都知道)
  • 签名:消息告诉你"从第几环出发",你就把那一环的值交出去

验证方拿到签名值后,沿着链继续做哈希,直到链条终点,看是否等于公开的公钥。对上了,说明签名者确实知道链条起点(私钥)。

妙处在于:从第 5 环你无法反推出第 3 环,所以提前拿到某个中间值,等于什么都没拿到。

"一次性"从何而来?

问题在于:如果你用同一个链条给两条消息签名,交出了第 3 环和第 4 环,攻击者就能从第 3 环出发走到终点,再一路"倒退"逼近起点,最终复原私钥。

⚠️ 所以 WOTS+ 的公钥只能对一条消息签名一次,这就是 One-Time 的由来。

两条增强:"+" 和 Checksum

WOTS+ 相比原始 WOTS 做了两处加固:

增强做法目的
Checksum(校验和)把"每个链用了多少步"的补数做校验和,追加到签名末尾防止攻击者篡改消息让链"滑步",窃取更早的链节点
随机化元素用公开种子派生出一组随机掩码,与链上每个节点 XOR 后再哈希防止"任意状态"攻击,让每条链的推进路径都不同

在 hashsigs-ts 中,这两处分别实现在 checksum 校验和计算 和 generateRandomizationElements 随机化元素生成。

走进 hashsigs-ts:结构极简,参数讲究

项目结构非常清爽,核心逻辑就一个文件:

  • 核心算法:src/wotsplus.ts ——WOTSPlus类,约 400 行
  • 对外导出:src/index.ts —— 只导出WOTSPlus类和HashFunction类型
  • 单元测试:src/wotsplus.test.ts
  • 测试向量:test/test_vectors/wotsplus_keccak256.json(含 Keccak-256 公钥分段、签名、随机化元素的完整十六进制数据)

关键参数:w = 16 的取舍

WOTS+ 有一个调参核心w(源码中叫 chainLen,遵循 XMSS RFC 8391 只允许 4 或 16)。它决定把消息按 4 进制还是 16 进制切片,每片对应一条哈希链:

参数w = 4w = 16
链的数量(32字节哈希下)128 条64 条
签名大小更大更小 ✅
签名耗时更快 ✅更慢
安全性更高略低

默认w = 16+ Keccak-256 时,构造函数 自动算出:64 条消息链 + 3 条校验和链 = 67 个签名块,签名 2144 字节、公钥仅 64 字节。这就是哈希签名的经典特征:公钥极小、签名较大——非常适合签名一次、验证百万次的场景。

三步用起来的完整流程

hashsigs-ts 的 API 只有三个方法,与原理一一对应:

import { WOTSPlus } from 'hashsigs-ts'; import { keccak_256 } from '@noble/hashes/sha3'; const wotsPlus = new WOTSPlus(keccak_256); // ① 选哈希函数(w 默认 16) const { publicKey, privateKey } = wotsPlus.generateKeyPair(privateSeed, publicSeed); // ② 生成密钥对 const signature = wotsPlus.sign(privateKey, publicSeed, messageHash); // ③ 签名 wotsPlus.verify(publicKey, messageHash, signature); // ④ 验证,返回 true/false

对应源码入口:generateKeyPair 生成密钥对、sign 签名、verify 验证。

三个容易踩的坑(源码中都有显式校验):

  1. 消息必须是 32 字节——因为签名前先把消息哈希成固定长度(见 messageLen 注释),任何长度都先过一遍哈希;
  2. 公钥 = 32字节公开种子 + 32字节公钥哈希,种子用来重建随机化元素,所以验证方不需要额外状态;
  3. chainLen必须是 2 的幂且为 4 或 16,否则会直接抛错(见 validateParameters)。

测试向量:跨语言对拍的依据

test/test_vectors/wotsplus_keccak256.json 里存放了其他语言实现产出的密钥/签名/随机化元素,测试用例 会逐条用verifyverifyWithRandomizationElements复算,保证 TypeScript 实现与参考实现字节级一致——这也是理解每条链结构最直观的"教材":publicKeySegments数组正好 67 个 32 字节分段,与参数表完全吻合。

WOTS+ 的短板,谁来补?

诚实地说,WOTS+ 有两个工程痛点:

  • 一次性限制:签一条消息就要换一套公钥,实际系统不可能手动换;
  • 签名较大:2144 字节对某些场景偏重。

标准答案是分层树结构(XMSS / XMSS^MT):把树每一层的节点都用 WOTS+ 签名,父节点公钥覆盖所有子节点,通过"路径"实现一次性使用与公钥验证。可以这样理解两者关系:

WOTS+ 是砖,XMSS 是用它盖的房子。hashsigs-ts 专注把"砖"做到位,树结构留给你按需搭建。

另外,由于私钥只是种子哈希、状态极简,这类签名天然适合智能合约、嵌入式设备、浏览器前端等资源受限环境——这也正是 TypeScript 实现的实用价值。

写在最后:30 分钟复盘

用一张图串起全文:

消息 (任意长度) │ Keccak-256 哈希 ▼ 32 字节消息哈希 │ 按 16 进制切成 64 片 + 3 片校验和 ▼ 67 条哈希链,各取第 x_i 环 → 2144 字节签名 │ 验证:沿链走到终点,比对 64 字节公钥 ▼ 信任 ✅

一句话总结:WOTS+ 用"哈希链只能往前走"的单向性换取了对量子的免疫,用"校验和 + 随机化"堵住了篡改漏洞;代价是一次性使用和较大的签名。而 hashsigs-ts 用 400 行代码把这三件事写得一清二楚——读懂 src/wotsplus.ts,你就拿到了后量子密码哈希签名路线的第一把钥匙。🔑

  • 项目说明:README.md
  • 构建与测试配置:tsup.config.ts、vitest.config.ts
  • 许可协议:COPYING(AGPL-3.0-or-later)

【免费下载链接】hashsigs-tsHash-based signatures in typescript, WOTS+项目地址: https://gitcode.com/gh_mirrors/ha/hashsigs-ts

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询