从种子到公钥承诺:hashsigs-rs密钥派生与public_key_commitment绑定机制图解
从种子到公钥承诺hashsigs-rs密钥派生与public_key_commitment绑定机制图解【免费下载链接】hashsigs-rsHash-based post quantum signatures in Rust项目地址: https://gitcode.com/gh_mirrors/ha/hashsigs-rshashsigs-rs 是一个用 Rust 编写的基于哈希的后量子数字签名库其核心 SHRINCS 签名方案只需用一个 32 字节种子即可确定性派生出整套密钥材料并用public_key_commitment公钥承诺把公钥各部件捆成一个防篡改的指纹。本文图解这一从种子到承诺的完整链路。一、为什么一个种子派生一切在传统 RSA/ECC 体系里私钥通常只有一串数字。而哈希签名SPHINCS 一类的密钥材料更庞大多条 WOTS 链的种子、PRF 种子、树根……如果每个部件都用独立随机数生成备份和恢复会变得非常混乱。hashsigs-rs 的做法是所有秘密材料都由同一个种子配合不同的域标签确定性派生。这意味着✅ 备份只需保存一个种子丢失可从种子完整重建密钥✅ 相同种子 相同参数 → 完全相同的密钥对可复现、可审计✅ 各部件种子互相隔离stateful链路的泄露不会污染stateless链路派生入口是 signer.rs 中的keygen函数。二、keygen 全景一个种子裂变成 8 类字段调用ShrincsSigner::keygen(seed_material, max_stateful_signatures)后种子会按域标签分裂成 6 个 32 字节种子再进一步算出 2 个树根派生产物域标签示例用途stateful_sk_seedshrincs-stateful-sk-seed派生有状态 WOTS-C 链的秘密stateful_prf_seedshrincs-stateful-prf-seed派生消息随机化值stateful_pk_seedshrincs-stateful-pk-seed有状态树的公开种子stateless_sk_seedshrincs-stateless-sk-seedFORS-C 与超树的秘密种子stateless_prf_seedshrincs-stateless-prf-seed无状态消息随机化值pk_seedshrincs-pk-seed全局公开种子stateful_root—有状态不平衡树的根可签次数上限决定树形hypertree_root—无状态 FORS 超树顶层根这 10 个字段全部存放在 shrincs_signer_types.rs 的ShrincsSigningKey结构体中。注意它的Debug实现把所有秘密字段显示为redacted——连调试日志都不会泄露种子 ️派生的密码学胶水derive32真正干活的是 shrincs_signer_utils.rs 里的derive32pub(crate) fn derive32(domain: [u8], seed: [u8], data: [u8]) - [u8; HASH_LEN] { hash_packed([domain, seed, data]) }hash_packed等价于 Solidity 的keccak256(abi.encodePacked(...))实现见 shrincs_common.rs——把各段字节紧密拼接、无填充、无长度前缀后做一次 Keccak-256。域标签就像抽屉编号同一个种子塞进不同抽屉得到互不相关的种子从源头杜绝了不同用途种子之间的关联。三、公钥四件套commitment 是怎么算出来的keygen 最终产出的PublicKey定义见 shrincs_verifier_types.rs包含 4 个部件PublicKey ├── stateful_public_key 72 字节 stateful_pk_seed(32) || stateful_root(32) || max_signatures(4, 大端) ├── pk_seed 32 字节无状态路径的公开种子 ├── hypertree_root 32 字节超树顶层根 └── public_key_commitment 32 字节前三者的指纹拼装规则在两处有状态公钥的字节布局encode_stateful_public_key 按pk_seed || root || max_signatures(大端 u32)拼接与验证侧解码严格逐字节一致。承诺值public_key_commitment 函数计算hash_packed([ bshrincs-public-key/, PROFILE_NAME.as_bytes(), // 编译期安全参数档如 256s / 128s stateful_public_key, pk_seed, hypertree_root, ])这里有两个精妙设计 绑定参数档profile标签里带上了PROFILE_NAME不同安全参数档的公钥永远不会产生相同的承诺值杜绝跨档位碰撞。承诺先于验证验证器收到的第一个参数就是expected_public_key_commitment32 字节它比完整公钥短得多适合放在链上或账户状态里做锚点。四、绑定机制篡改任意 1 字节承诺即失效public_key_commitment的价值在于它是抗篡改的完整性锚。验证器在 verifier.rs 中每次校验都会重新计算承诺并比对matches_expected_public_key_commitment改动stateful_public_key的任何 1 字节 → 承诺不匹配 → 验证失败用 A 的种子 B 的树根做字段拼接→ 同样被拒绝仓库中的负向测试 public_key_commitment_rejects_tampered_component 正是演示这一点翻转stateful_public_key[0]的一个比特后原先有效的签名立即无法通过验证。这就是绑定二字的含义——公钥各部件被承诺值锁成一体谁也不能偷梁换柱。五、导入密钥时的安全准则重新计算从不信任当你通过exportSigningKeyUnsafe()备份又导入签名密钥时入口signer.rs 的import_signing_key实现遵循never trust原则从种子重新计算stateful_root和hypertree_root与导入数据中存储的树根比对不一致被篡改或字段拼接直接返回失败公钥含承诺值由重新计算结果派生绝不采用调用方提供的版本配套测试 import_rejects_tampered_roots 覆盖了根被篡改、跨密钥字段拼接等攻击场景。六、快速上手三步生成你的第一对密钥通过 WASM 封装src/wasm/整个流程只需几行 JavaScriptimport { loadShrincsWasm } from quip.network/hashsigs-wasm; const wasm await loadShrincsWasm(); // 种子至少 32 字节十六进制第二个参数为有状态签名预算1..4096 const keypair wasm.shrincsKeygen(0x ab.repeat(32), 16); const publicKey keypair.publicKey(); console.log(publicKey.publicKeyCommitment); // 32 字节承诺值此时你手里就有了statefulPublicKey、pkSeed、hypertreeRoot、publicKeyCommitment四件套。账户层用承诺值做身份锚点详见 docs/hashsig-rs.md 的 Cryptographic layout 章节跨语言Solidity 侧一致性由 tests/test_vectors.rs 与 tests/test_vectors/ 下的 JSON 测试向量保障。七、关键结论速记一个种子定乾坤6 个域标签种子 2 个树根全部由derive32确定性派生承诺即指纹keccak256(shrincs-public-key/ || profile || 公钥部件...)把整个公钥锁死️验证先验承诺改 1 字节即失效导入时重算不信任备份极简只需保存种子与叶子计数即可完整重建签名能力理解这条种子 → 派生 → 公钥 → 承诺的链路你就掌握了 hashsigs-rs 安全模型的地基。【免费下载链接】hashsigs-rsHash-based post quantum signatures in Rust项目地址: https://gitcode.com/gh_mirrors/ha/hashsigs-rs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考