☰
哈希链与校验和如何工作?hashsigs-ts的WOTS+签名验证机制逐行拆解
2026/10/16 17:48:33 网站建设 项目流程

哈希链与校验和如何工作?hashsigs-ts的WOTS+签名验证机制逐行拆解

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

hashsigs-ts 是一个用 TypeScript 实现的后量子哈希签名库,核心是 WOTS+(Winternitz One-Time Signature Plus)一次性签名算法。本文带你逐行拆解 src/wotsplus.ts:哈希链如何被“续完”、校验和如何防止节点替换、以及签名验证最后一步的哈希比对究竟在验证什么。

🧩 为什么“哈希链”能当签名用?

传统数字签名依赖大数分解、椭圆曲线等“难题”;而哈希签名只依赖哈希函数本身的安全性,即使量子计算机也难以攻破,因此被称为后量子签名的有力候选。

WOTS+ 是最经典的哈希签名算法之一,三个关键词先记住:

  • 哈希链:从一个秘密起点反复哈希,终点是公开的;链可以“往前走”,但不能“往回走”
  • 一次性:一对密钥只能安全地签一次消息,所以叫 One-Time Signature(上层 XMSS 树结构负责密钥复用,本库专注底层 WOTS+)
  • Plus:WOTS+ 的“加号”指每一步哈希前先与一个随机化元素做异或(XOR),防止跨链碰撞等结构性攻击

📌 一句话原理:签名 = 出示哈希链的某个中间节点;验证 = 从该节点继续哈希,能走到公钥终点即通过。

⚙️ 关键参数速览:32 字节哈希如何变成 2144 字节签名

构造器 WOTSPlus 会根据哈希函数输出长度和链长w自动推导全部参数。以默认的 keccak256(32 字节输出、w = 16)为例:

参数含义默认值
hashLen哈希输出长度(字节)32
chainLen链长 w,必须取 4 或 1616
numMessageChunks消息分段数 len₁ = ⌈256/4⌉64
numChecksumChunks校验和分段数 len₂3
numSignatureChunks签名总分段数 len₁+len₂67
signatureSize签名总字节数 67×322144 字节
publicKeySize公钥长度(32 种子 + 32 哈希)64 字节

validateParameters 会强制链长为 2 的幂且只能是 4 或 16——这是为了与 XMSS 标准(RFC 8391)保持兼容。

🔗 验证第一步:把消息“解码”成链索引

验证开始前,消息必须先翻译成“每条哈希链取第几个节点”。这一步由 computeMessageHashChainIndexes 完成,包含两个动作:

  1. base-w 编码(toBaseW):把 32 字节消息按每字节拆成高、低 4 比特,得到 64 个 0~15 的数字——每个数字就是对应哈希链上的取点位置
  2. 计算校验和(checksum):sum = Σ(15 − 索引ᵢ),最大值为 64×15=960,再把 sum 用 base-16 表示,得到 3 个额外的链索引

校验和为什么不可或缺?

假设只有 base-w 编码、没有校验和:攻击者把某条链的签名节点换成更靠前的节点,继续往前哈希仍然能命中公钥终点——伪造的签名照样验证通过!

校验和正是所有索引的“互补和”:任何一次索引替换都会让 sum 对不上,验证立刻失败。这就是校验和存在的唯一目的,也是 WOTS+ 比原始 Winternitz 签名更安全的核心原因。

🪝 验证第二步:从公钥种子重建随机化元素

公钥并没有保存 67 条链的全部终点(那要 2144 字节),而是压缩成 64 字节:前 32 字节是公开种子,后 32 字节是所有链终点拼接后的哈希。

入口函数 verify 逐行看:

  • L281:校验公钥长度必须为 64 字节
  • L285:切出前 32 字节作为publicSeed
  • L286:切出后 32 字节作为publicKeyHash
  • L288:调用 generateRandomizationElements 从种子重建 67 个随机化元素

内部通过伪随机函数 prf 生成:哈希(0x03 ‖ seed ‖ 序号)。开头的0x03是域分离前缀,保证这批随机化元素不会和其他用途的哈希输出混淆。

🔁 验证第三步:把哈希链“续完”

核心循环在 verifyWithRandomizationElements 中,精简后只有三行逻辑:

const chainIdx = chainSegments[i]; // base-w 编码得到的链索引 const numIterations = this.chainLen - chainIdx - 1; // 距离链终点还差几跳 const segment = this.chain(signature[i], randomizationElements, chainIdx, numIterations);

chain 函数负责一跳一跳地续链:先把当前值与该位置的随机化元素异或,再哈希——对应 WOTS+ 公式 c_k(i)。签名者只“走完”了 chainIdx 跳,验证者替它走完剩下的 chainLen − chainIdx − 1 跳,两者恰好拼接成同一条链。

✅ 最后一步:比对公钥哈希

拿到 67 条链重建出的终点后,全部拼接再哈希一次,最后用 BufferUtil.equals 做逐字节比较:相等则返回true,不相等返回false。一次完整的 WOTS+ 签名验证到此结束。

⚠️ 提醒:WOTS+ 是一次性签名,同一密钥对不能重复使用。生产环境中需搭配 XMSS 等树状结构做多签名,本库(见 package.json 中的关键词pqcrypto/post-quantum)提供的是最底层的安全原语。

🧪 用测试向量交叉验证

test 文件基于 Vitest 覆盖了:密钥对生成、空签名必须被拒绝、签名→验证闭环、以及批量验证。更重要的是它还加载了固定测试向量 wotsplus_keccak256.json——其中包含 67 个公钥链段、消息与签名等数据,用于跨语言实现的一致性比对,这是确认“哈希每一步都没算错”的标准做法。

本地运行方式:

git clone https://gitcode.com/gh_mirrors/ha/hashsigs-ts cd hashsigs-ts npm install npm test

📚 总结:五步看懂 WOTS+ 验证

步骤动作对应代码
1拆分公钥(种子 + 哈希)verify
2重建随机化元素generateRandomizationElements
3消息 → base-w 索引 + 校验和computeMessageHashChainIndexes
4异或随机元素后续完哈希链chain
5比对公钥哈希verifyWithRandomizationElements

WOTS+ 的签名验证可以浓缩成一句话:把消息解码成链索引,从每个签名节点续完哈希链,再确认所有链终点拼出的哈希等于公钥。其中,哈希链提供“不可逆”,校验和防“节点替换”,随机化元素防“结构性攻击”——三者缺一不可,这就是 hashsigs-ts 这套后量子哈希签名的完整机制。

更多细节可参考模块导出文件 src/index.ts 与 README.md。

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

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

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

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

立即咨询