systemslibrarian/PostQuantum.SecretSharing
GitHub: systemslibrarian/PostQuantum.SecretSharing
面向 .NET 的后量子阈值秘密共享库,可将高价值密钥拆分为 K-of-N 份实现多人托管,低于法定人数时在数学上不泄露任何信息。
Stars: 0 | Forks: 0
# PostQuantum.SecretSharing
[](https://github.com/systemslibrarian/PostQuantum.SecretSharing/actions/workflows/ci.yml)
[](https://github.com/systemslibrarian/PostQuantum.SecretSharing/actions/workflows/codeql.yml)
[](https://scorecard.dev/viewer/?uri=github.com/systemslibrarian/PostQuantum.SecretSharing)
[](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/LICENSE)
**你的加密系统最薄弱的环节,就在于那把无人知晓该存于何处的重要密钥。**
将一个高价值的秘密拆分为 *N* 份,只需其中的任意 *K* 份即可将其还原 —
而任何 *K−1* 份都会**在数学上不泄露任何信息**。没有任何单个人、单台机器或
备份会成为单点故障或单点攻破的弱点。
```
┌─ share 1 → IT Director
├─ share 2 → SRE on-call
master key ──[ 3-of-5 split ]──┼─ share 3 → Security lead any 3 of 5
(32 bytes) ├─ share 4 → Offsite safe rebuild it;
└─ share 5 → Legal/compliance any 2 reveal
nothing
```
```
dotnet add package PostQuantum.SecretSharing --version 2.2.0
```
```
using PostQuantum.SecretSharing;
using System.Security.Cryptography;
byte[] masterKey = RandomNumberGenerator.GetBytes(32);
// Split 3-of-5 and hand each share to a different custodian.
SecretShare[] shares = ShamirSecretSharing.Split(masterKey, new SharePolicy(Threshold: 3, TotalShares: 5));
foreach (SecretShare s in shares)
File.WriteAllBytes($"share-{s.ShareIndex}.pqss", s.Export());
// ...later, any three custodians convene and rebuild the key.
SecretShare[] quorum = new[]
{
SecretShare.Import(File.ReadAllBytes("share-1.pqss")),
SecretShare.Import(File.ReadAllBytes("share-3.pqss")),
SecretShare.Import(File.ReadAllBytes("share-5.pqss")),
};
using ZeroizingBuffer recovered = ShamirSecretSharing.Reconstruct(quorum);
// recovered.Span == masterKey, and is wiped from pinned memory on Dispose.
```
这就是其核心理念。围绕这一理念,我们提供了一个 `pqss` CLI、可运行的示例、仪式
文档、威胁模型、模糊测试以及审计工具包 — 本 README 的其余部分将重点介绍
*何时你需要它* 以及 *如何正确使用它*。
### 为什么选择它而不是通用的 Shamir 库?
教科书式的 Shamir 代码片段 — 或像
[SecretSharingDotNet](https://www.nuget.org/packages/SecretSharingDotNet) 这样的通用包 — 能够拆分
秘密并将其片段交给你。数学原理只是其中最简单的 5%。本库是围绕另外的 95% 构建的 —
即保持*分享片段*的可信度以及*操作仪式*的可行性:
- **常数时间、无查表的 GF(2⁸) 数学运算。** 没有依赖于秘密索引的对数/反对数表
查表操作 — 这是 Shamir 实现中典型的 cache-timing 泄漏漏洞。
- **经过身份验证的分享片段(ML-DSA-65 / FIPS 204)。** 能够检测被篡改或
替换的分享片段,并将其绑定至*你的*分发者密钥。通用库只会返回原始的
域点,没有任何可供验证的内容。
- **严格、规范化、自我描述的分享格式(`.pqss`)。** 版本化、
失败即停止,经过模糊测试,并具备精确到字节的规范 — 而不是那些需要你自行
构建框架、控制版本并验证的裸 `BigInteger` 或 base64 数据块。
- **固定、清零、页锁定的秘密内存。** 重建后的秘密会存入
`ZeroizingBuffer` 中,GC 无法对其进行重定位和复制,并在释放时擦除 — 而不是
将 `string`/`byte[]` 遗留给垃圾回收器分散处理。
- **用于低熵秘密的内置封装助手。** `WrappedSecret` 会拆分
一个随机的 KEK 并使用 AES-256-GCM 封装你的真实秘密,从而消除
naive 拆分密码时容易遭遇的离线猜测预言机风险。
- **仪式工具与操作文档。** 一个真正的 `pqss` CLI、五个可运行的
示例,以及一份受托人操作指南 — 而不仅仅是让你独自去连接调用的 `Split()`。
如果你需要的仅仅是多项式数学运算,那么通用库就足够了。但如果这个秘密
*重要到需要拆分*,那么围绕它的身份验证、格式、内存清理和
仪式才是真正的核心任务 — 而这正是本包的用武之地。
## 需求所在:一个密钥何时变成一种隐患
几乎每个安全系统最终都会拥有一把**过于重要以至于绝不能丢失,又因过于危险而绝不能集中保管**的密钥。将其放在一台机器上,那台机器就会成为
单点故障。用一个密码保护它,这个密码就会成为
单点猜测突破口。将其交给一个管理员,那个管理员就会成为
单点信任。
秘密共享可以化解这种单点隐患。由你来决定法定人数:“这 5 个人中的任意 3 人”,“这 2 人加上 1 个备用人员”,“9 名董事会成员中的 5 人”。低于
法定人数时,分享片段将是无用的 — 不是“难以破解”,而是可证明地不含
任何信息。
### 本库解决的具体问题
| 你拥有… | 痛点 | 本库为你提供的方案 |
|-----------|----------|---------------------|
| **代码/发布签名密钥** | 单个开发者即可单方面签名 — 或者丢失密钥导致发布中止 | `M-of-N` 托管:无单一签名者,无单一丢失风险 |
| **根 CA / 信任锚私有密钥** | 整个 PKI 都依赖于 HSM/保险柜中的一个文件 | 法定托管 + 分发者身份验证的分享片段(ML-DSA-65) |
| **数据库 / 磁盘主密钥 (KEK)** | 串联盲点为 1;如果唯一的持有者不在了,数据就会丢失 | 可由任何法定人数恢复,对丢失的分享片段具有生存能力 |
| **云 KMS / vault unseal/root 密钥** | 应急访问仅仅是一张便利贴或一个共享的密码短语 | 真正的 `K-of-N` 应急访问,取代可猜测的秘密 |
| **加密钱包种子 / 金库密钥** | 单一的种子短语 = 单一的被盗或丢失风险 | 跨人员和地点的阈值托管 |
| **“上帝模式”管理员 / root 凭据** | 某个人悄无声息地掌握着全部访问权限 | 需要法定人数才能组合凭据 |
| **备份加密密钥** | 密钥被存放在它们所保护的备份旁边 | 跨部门/站点分发密钥分享片段 |
### 相比密码或单个文件,你能获得的优势
- **无单点妥协风险。** 窃取一个(或任意 `K−1`)分享片段会得到
关于秘密的*零*信息。这是可证明的,而非仅仅是“计算上
昂贵”。
- **无单点故障。** 丢失最多 `N−K` 个分享片段,你仍然可以恢复。
- **无猜测性。** 与密码不同,分享片段是全熵数据;在低于法定人数时
没有任何可以被暴力破解的内容。
- **抵御量子计算机。** 其保密性保证是信息论意义上的 —
它不依赖于任何量子计算机可能解决的问题(见下文)。
- **可防篡改。** 在身份验证模式下,被替换或损坏的分享片段会被
检测到并拒绝,而不是被默默使用。
## 30 秒了解工作原理
你秘密的每一个字节都会成为有限域 GF(2⁸) 上一个 `K−1` 次随机多项式的常数项。“分享片段”就是该多项式在一个特定点 `x` 处求值的结果。`K` 个点能唯一确定一个 `K−1` 次的多项式
(因此 `K` 个分享片段可重建秘密);`K−1` 个点与*每一个*
可能的常数项都同等程度地契合(因此它们不会透露任何信息)。这第二个事实就是
信息论意义上的保证。
你永远不需要为了使用该库而去了解其背后的数学原理 — 但你应该知道一个
诚实的警告:该*方案*是无条件安全的;而*实现*
(身份验证、内存清理、完整性检查)则是常规的工程设计,
在此处及 [`docs/THREAT-MODEL.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/THREAT-MODEL.md) 中都有平实清晰的记录。
## 快速开始
### 1. 无身份验证的拆分(仅完整性检查)
适用于分享片段存放在受信任的存储中,且你只需要检测*意外*
损坏或分享片段混淆的情况。
```
using PostQuantum.SecretSharing;
using System.Security.Cryptography;
byte[] secret = RandomNumberGenerator.GetBytes(32); // a 256-bit key
SecretShare[] shares = ShamirSecretSharing.Split(secret, new SharePolicy(3, 5));
byte[][] files = shares.Select(s => s.Export()).ToArray(); // canonical .pqss bytes
CryptographicOperations.ZeroMemory(secret); // done with the plaintext
// Reconstruct from EXACTLY 3 shares (passing more is rejected — see FAQ).
SecretShare[] quorum = files.Take(3).Select(SecretShare.Import).ToArray();
using ZeroizingBuffer recovered = ShamirSecretSharing.Reconstruct(quorum);
Console.WriteLine(recovered.Span.SequenceEqual(secret)); // (if you kept a copy)
```
### 2. 带有身份验证的拆分(分发者签名的分享片段 — net10.0)
适用于分享片段需经过不受信任的人员传递,且你必须检测
**被篡改或替换的**分享片段的情况。分发者使用 ML-DSA-65
(FIPS 204) 对每一个分享片段进行签名;重建时会针对你**在带外固定 (pin)** 的公钥进行验证。
```
using PostQuantum.SecretSharing;
using System.Security.Cryptography;
byte[] secret = RandomNumberGenerator.GetBytes(32);
using MlDsa65ShareAuthenticator dealer = MlDsa65ShareAuthenticator.Generate();
ReadOnlyMemory dealerPublicKey = dealer.PublicKey; // PIN this (print it, store in config, read it aloud)
SecretShare[] shares = ShamirSecretSharing.Split(secret, new SharePolicy(3, 5), dealer);
CryptographicOperations.ZeroMemory(secret);
// Every share must be signed by the pinned dealer key, or reconstruction throws.
SecretShare[] quorum = /* import any 3 shares */ Array.Empty();
using ZeroizingBuffer recovered = ShamirSecretSharing.Reconstruct(quorum, dealerPublicKey);
```
### 3. 安全处理秘密
重建过程会返回一个 `ZeroizingBuffer`,而不是 `byte[]`。它被分配在
固定对象堆上(GC 无法对其进行重定位和隐式复制),并在
释放时被清零。**请务必使用 `using`**,并且不要将 `Span` 复制到长生命周期的数组中。
```
using (ZeroizingBuffer key = ShamirSecretSharing.Reconstruct(quorum))
{
using var aes = new AesGcm(key.Span, tagSizeInBytes: 16);
// ...use key.Span for the minimum time needed...
} // key is wiped here
```
## 选择 K 和 N
| 目标 | 建议策略 | 原因 |
|------|------------------|-----|
| 合理的默认值 | **3-of-5** | 容忍丢失 2 个分享片段;抵抗任意 2 人的串通 |
| 双人规则 + 备用 | 2-of-3 | 任一对(或备用人员)均可行动 |
| 高度保障 | 5-of-9 | 更高的串通壁垒,同时对丢失具有容忍度 |
| 避免 | 2-of-2 | 丢失任一片段 -> 秘密永远丢失;无冗余 |
| 禁用 | 1-of-N | 每一个片段*就是*秘密本身 — 本库拒绝执行 `K=1` |
经验法则:选择 **K**,使得现实中容易串通的任何子集都无法达到该阈值,
并选择 **N − K ≥ 2**,这样即使你丢失了两个片段,依然可以恢复。限制:
`2 ≤ K ≤ N ≤ 255`,秘密长度为 `1..65536` 字节。参见
[`docs/OPERATIONS.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/OPERATIONS.md) 了解如何运行实际的操作仪式。
## 安全拆分低熵秘密(封装模式)
**切勿直接拆分密码、PIN 或短密码。** 每个分享片段都
带有 HKDF 校验值,这使得*单个*分享持有者能够对
可猜测的秘密进行离线暴力破解(参见“何时不应使用本库”)。相反,应该拆分一个随机
密钥,并用该密钥封装你的真实秘密。
本库通过 `WrappedSecret` 为你实现了这一点:
```
using PostQuantum.SecretSharing;
using System.Text;
byte[] realSecret = Encoding.UTF8.GetBytes("correct horse battery staple"); // low entropy!
// Generates a random KEK, AES-256-GCM-seals your secret, and splits the KEK.
WrappedSplit w = WrappedSecret.Split(realSecret, new SharePolicy(3, 5));
// w.Shares → give to trustees
// w.Envelope → store anywhere; it is NOT secret
// Recover: any 3 KEK shares + the envelope.
using ZeroizingBuffer recovered = WrappedSecret.Reconstruct(
new[] { w.Shares[0], w.Shares[2], w.Shares[4] }, w.Envelope);
```
其底层机制完全就是下面的模式 — 此处明确展示,以防你想要
自行管理封装信封:
```
using PostQuantum.SecretSharing;
using System.Security.Cryptography;
byte[] realSecret = Encoding.UTF8.GetBytes("correct horse battery staple"); // low entropy!
// 1. Generate a full-entropy key-encryption key and encrypt the real secret.
byte[] kek = RandomNumberGenerator.GetBytes(32);
byte[] nonce = RandomNumberGenerator.GetBytes(AesGcm.NonceByteSizes.MaxSize);
byte[] ciphertext = new byte[realSecret.Length];
byte[] tag = new byte[AesGcm.TagByteSizes.MaxSize];
using (var aes = new AesGcm(kek, tag.Length))
aes.Encrypt(nonce, realSecret, ciphertext, tag);
// 2. Split the KEK (high entropy ⇒ the check-value oracle is harmless), and store
// nonce + ciphertext + tag alongside the shares (they are not secret).
SecretShare[] shares = ShamirSecretSharing.Split(kek, new SharePolicy(3, 5));
CryptographicOperations.ZeroMemory(kek);
// 3. To recover: reconstruct the KEK, then decrypt.
using ZeroizingBuffer recoveredKek = ShamirSecretSharing.Reconstruct(/* 3 shares */ shares.Take(3).ToList());
byte[] plaintext = new byte[ciphertext.Length];
using (var aes = new AesGcm(recoveredKek.Span, tag.Length))
aes.Decrypt(nonce, ciphertext, tag, plaintext);
```
## API 参考
| 成员 | 用途 |
|--------|---------|
| `SharePolicy(int Threshold, int TotalShares)` | `K-of-N` 策略。`2 ≤ K ≤ N ≤ 255`。 |
| `ShamirSecretSharing.Split(secret, policy)` | 拆分为 `N` 个无身份验证的分享片段。 |
| `ShamirSecretSharing.Split(secret, policy, dealer)` | 拆分为 `N` 个经分发者签名的分享片段。 |
| `ShamirSecretSharing.Reconstruct(shares)` | 从**确切的 K 个**分享片段重建;返回一个 `ZeroizingBuffer`。 |
| `ShamirSecretSharing.Reconstruct(shares, expectedDealerPublicKey)` | 功能同上,但要求每个分享片段都必须通过针对被固定密钥的验证。 |
| `ShamirSecretSharing.Refresh(shares, newPolicy?, expectedDealerPublicKey?, newDealer?)` | 轮换托管权:使用新的 `splitId` 将相同的秘密重新拆分为新的分享片段(旧分享片段将停止互通)。 |
| `WrappedSecret.Split(secret, policy[, dealer])` | 针对低熵/大体积秘密的安全路径:随机 KEK + AES-256-GCM 信封;拆分 KEK。返回 `WrappedSplit { Shares, Envelope }`。 |
| `WrappedSecret.Reconstruct(shares, envelope[, expectedDealerPublicKey])` | 重建 KEK 并解密信封;返回一个 `ZeroizingBuffer`。 |
| `DealerCommitment.Compute(secret)` / `.Verify(secret, commitment)` | 发布对预期秘密的一次性承诺;法定人数确认他们恢复的*正是*那个值(非完整 VSS — 见下文)。 |
| `SecretShare.Export()` | 用于分发/存储的规范化 `.pqss` 字节流。 |
| `SecretShare.Import(bytes)` | 对 `.pqss` 字节流进行严格、失败即停止的解析。 |
| `SecretShare.{Threshold, TotalShares, ShareIndex, SecretLength, SplitId, Authentication, DealerPublicKey}` | 公共元数据。(原始 `y` 数据被故意**不**公开暴露。) |
| `ZeroizingBuffer.Span` / `.Length` / `.IsMemoryLocked` / `.Dispose()` | 对恢复的秘密提供固定的、页锁定的(尽力而为)、清零的访问。 |
| `IShareAuthenticator` | 分发者签名者抽象(`Kind`, `PublicKey`, `Sign`)。 |
| `MlDsa65ShareAuthenticator` *(net10.0)* | `Generate()`, `ImportPrivateKey()`, `ExportPrivateKey()`, `PublicKey`, `Sign()`。 |
| `ShareAuthenticationKind` | `None` (0) 或 `MlDsa65` (1)。 |
## 唯一的无条件声明 — 及其精确的边界
Shamir 的方案是信息论安全的**:`K−1` 个分享片段向**任何**对手泄露的
秘密信息为
零 — 无论是经典计算机还是量子计算机,也无论其计算能力如何。这是关于该方案的一个数学事实,而
不是计算复杂度的假设。未来没有任何算法或机器能削弱它。
该保证仅针对**方案本身**。每一个*真实*的风险都存在于
**实现中** — 分享片段身份验证、侧信道、内存清理,以及
校验值预言机。我们绝不会让营销语言模糊这两者:
- **方案是无条件的。** `K−1` 个分享片段 = 零信息。毋庸置疑。
- **而实现则是你必须信任工程环节的地方。** 我们如实记录了
每一个信任点,包括那些并不光彩的缺陷。
这个包被称为 *post-quantum* 出于两个具体原因,
没有一个是“我们强化了 Shamir”:
1. 其核心安全声明**作为数学事实能够抵御量子计算机的威胁**。
2. 其身份验证层使用 **ML-DSA-65 (FIPS 204)** — 一种抗量子
签名方案 — 来针对分发者对分享片段进行身份验证。
### 安全层
| 层级 | 机制 | 保证 |
|-------|-----------|-----------|
| **秘密的保密性** | 基于 GF(2⁸) 的 Shamir | 信息论安全。`K−1` 个分享片段绝不泄露任何信息,永远抵御任何对手。 |
| **分享片段的真实性** | ML-DSA-65 / FIPS 204 (可选) | 计算安全(抗量子)。当你固定了分发者密钥时,能够检测被篡改/替换的分享片段。 |
| **分享片段的完整性** | HKDF-SHA256 校验值 | 在重建时检测意外损坏 / 不匹配的分享片段。**警告:** 对于*低熵*秘密,这也是一个离线猜测预言机。 |
## 用一段话概述信任模型
`expectedDealerPublicKey` **就是你的安全锚。** 当你提供它时,每一个分享片段都必须是
经过身份验证的,携带完全相同的该密钥,并通过验证 — 否则重建
将会抛出异常。当你省略它,但分享片段中无论如何都带有签名时,签名
仍将针对*内嵌的*密钥进行验证,作为一种纵深防御措施 — 但请明确
这意味着什么:**仅靠内嵌密钥进行的验证属于自我证明,而非
权威证明。** 一组伪造的分享片段可以内嵌任何密钥并用该密钥进行签名。只有
你通过带外获取的固定密钥才能证明分享片段来自于*你的*
分发者。
## 何时**不应**使用本库
- **你正在拆分低熵秘密(密码、PIN、短密码)。**
完整性校验值存在于每一个分享片段内部,它是一个**离线
暴力破解预言机**:单个分享片段持有者无需任何法定人数即可
测试猜测。对于 32 字节的随机密钥,这无关紧要(搜索空间为 2²⁵⁶)。**请拆分密钥,而不是
密码** — 或者使用内置的
[`WrappedSecret`](#splitting-low-entropy-secrets-safely-the-wrap-pattern) 助手,
它会为你拆分一个随机密钥并封装你的真实秘密。
- **你只有唯一的托管人。** 在一个人之间进行共享是毫无意义的仪式;
直接加密秘密即可。
- **你需要无依赖核心支持的可验证秘密共享 (VSS)。**
一个*恶意的分发者*可能会将不一致的分享片段交给不同的受托人。核心库
只能针对分发者对分享片段进行身份验证*,并提供 `DealerCommitment`(对预期秘密的一次性
发布承诺),但在重建之前,它无法*证明*分享片段之间
是相互一致的。完整的 VSS 需要素数/EC 群而不是 GF(2⁸),因此
它作为独立部分发布于可选的
[`PostQuantum.SecretSharing.Vss`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/VSS-DESIGN.md)
包中(基于 P-256 的 Pedersen VSS,带有可选的 ML-DSA-65 广播签名)— 将其排除在
核心之外,以保持核心的无依赖性。
- **你需要核心库支持*分布式*主动秘密共享。** 核心的 `Refresh`
会轮换分享片段(重新拆分,生成新的 `splitId`),但这由法定人数作为中介 — 它会短暂地重建
秘密。一种在各方(或同位实体集合)之间重新随机化分享片段
*而无需*进行任何重建的协议作为独立部分发布于可选的
[`PostQuantum.SecretSharing.Extensions`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/PROACTIVE-REFRESH.md)
包中(`ProactiveRefresh`)— 将其排除在核心之外,以保持核心的
最小化。
- **你需要 KMS。** 这是一个基础组件,而不是密钥管理服务。
## 横向对比
客观的定位。“✅/❌”描述的是*本库的*选择,而不是对其他替代方案的价值评判
— 每个工具解决的问题不同。
| 能力 | 本库 | 密码加密文件 | 朴素的 XOR 拆分 | Vault 的 Shamir (unseal) | 典型的通用 Shamir 库 |
|---|:--:|:--:|:--:|:--:|:--:|
| 真正的 `K`-of-`N` 阈值 (`K < N`) | ✅ | ❌ | ❌ (需要*全部*片段) | ✅ | ✅ |
| 法定人数下的信息论保密性 | ✅ | ❌ (可暴力破解) | ✅ | ✅ | 通常为 ✅ |
| 抵御量子对手(保密性) | ✅ | ❌ (依赖 KDF/密码假设) | ✅ | ✅ | 通常为 ✅ |
| 常数时间、无查表的域数学运算 | ✅ | n/a | n/a | — | 通常为 ❌ (查表) |
| 经过身份验证的分享片段(防篡改/替换) | ✅ ML-DSA-65 | n/a | ❌ | ❌ | 通常为 ❌ |
| 严格、规范化、自我描述的分享格式 | ✅ `.pqss` | n/a | ❌ | 部分 | 各不相同 |
| 固定 + 清零 + 页锁定的秘密内存 | ✅ | ❌ | ❌ | — | 极少 |
| 内置的低熵封装助手 | ✅ | n/a | ❌ | n/a | ❌ |
| 仪式工具 + 操作指南 | ✅ CLI + 文档 | ❌ | ❌ | ✅ | ❌ |
| 可验证秘密共享(防恶意分发者) | ✅ *(可选包)* | n/a | ❌ | ❌ | 极少 |
| 经过独立审计 | ❌ *(坦白说)* | 各不相同 | n/a | ✅ | 各不相同 |
我们刻意**取得优势**的地方:内存清理、常数时间域数学运算、我们自控的严格
格式、抗量子的分享片段身份验证,以及一流的操作仪式
支持。VSS(恶意分发者检测)作为可选包发布于
[`PostQuantum.SecretSharing.Vss`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/VSS-DESIGN.md)
— 它是基于 P-256 的 Pedersen VSS,带有可选的 ML-DSA-65 广播签名,并将其排除在
无依赖核心之外。我们**尚未**实现的地方:没有独立审计 — 这一点坦白说明,绝不
粉饰(这两个包的构建方式使得进行审计的成本很低;参见
[VSS 审计指南](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/VSS-AUDIT-GUIDE.md))。
## 平台支持矩阵
**核心库不存在平台阻碍。** Shamir 引擎、CBOR 编解码器、
HKDF 校验值以及 `ZeroizingBuffer` 全都是纯托管代码,加上来自 BCL 的 SHA-256/HKDF
— 因此它们**在所有平台上均支持 net8.0,包括 macOS、iOS 和
Android。**
| 组件 | Windows | Linux | macOS | iOS / Android |
|-----------|:-------:|:-----:|:-----:|:-------------:|
| **核心库**(拆分、重建、`.pqss`、校验值、`ZeroizingBuffer`) | ✅ | ✅ | ✅ | ✅ |
| **ML-DSA-65 身份验证器** (`MlDsa65ShareAuthenticator`, net10.0) | ✅ | ✅ (OpenSSL ≥ 3.5) | ❌ (上游) | ❌ |
ML-DSA-65 身份验证器仅在 `net10.0` 下编译,并在运行时
根据 `MLDsa.IsSupported` 进行保护,在不支持 FIPS 204 的平台会抛出 `PlatformNotSupportedException` (并提供指向此
矩阵的提示)。**macOS 在上游缺乏 ML-DSA 支持** — *核心库*在那依然可以完全
运行;只有可选的签名层无法运行。CI 通过在 macOS 上运行完整的 net8.0 测试套件并
跳过 ML-DSA 测试来证明了这一点。
## 目标框架
- **`src`** 多目标框架为 **`net8.0;net10.0`**。
- **测试** 也多目标至相同的框架对;在缺乏 FIPS 204 的平台上,ML-DSA 测试类将在运行时跳过。
- `LangVersion latest`, `nullable enable`, `TreatWarningsAsErrors true`,
确定性构建, SourceLink, 嵌入未跟踪源码, CI 构建标志。
## 失败即停止的保证
每一个解析错误、长度不匹配、策略违规或签名失败,都会在**任何**依赖于秘密的计算运行**之前**抛出一个
**特定的**异常:
| 异常 | 含义 |
|-----------|---------|
| `SecretSharingException` | 以下所有异常的抽象基类。 |
| `ShareFormatException` | 格式错误/不规范的 `.pqss`、类型错误、未知字段、多余尾部字节、与声明模式相矛盾的内容。 |
| `SharePolicyException` | `K`, `N`,秘密长度或分享索引超出范围;重建时分享片段数量不正确。 |
| `ShareAuthenticationException` | 签名未通过验证,或固定的分发者密钥不匹配。 |
| `ShareConsistencyException` | 格式正确但不属于同一次拆分的分享片段(混淆了拆分 ID、元数据、重复的索引),或插值后校验值不匹配。 |
## 设计决策
- **域数学运算中不使用对数/反对数表。** 基于依赖于秘密的值进行表查找是 Shamir 库中典型的 cache-timing 泄漏。
所有的 GF(2⁸) 乘法都是无分支、固定迭代且无查表的。
- **禁止使用 K=1。** 当阈值为 1 时,每一个分享片段*就是*秘密本身 —
这只是安全剧场,而不是共享。本库拒绝执行该操作。
- **我们自控的严格规范化 CBOR。** `.pqss` 解析器仅接受极其微小的、
完全规范化的子集(定长、最短形式的整数、升序的唯一整数键、无多余尾部字节、每个字段具有精确的类型)。纯手写(双向各约 150
行代码),而非引入外部依赖。
- **强制要求精确为 K 的重建。** 重建需要*确切的* `K` 个分享片段,而不是“至少
K”。静默使用子集将会掩盖操作员的错误。
- **公开 API 中无 RNG 注入。** 在秘密共享库中,可注入的 RNG 是一个隐患。测试的确定性来源于已发布的参考向量。
- **固定、会清零的秘密缓冲区。** 重建的秘密会存入
位于固定对象堆上的 `ZeroizingBuffer`,因此 GC 无法重定位(从而隐式
复制)该秘密,并在释放时被清零。
## 常见问题
**这仅仅是 `XOR` 风格的拆分吗?** 不是。朴素的 XOR 拆分需要*所有的*分享片段
才能恢复。这是真正的阈值共享:`N` 个中的任意 `K` 个,且 `K < N`。
**既然 Shamir 是 1979 年发明的,为什么它被认为是“后量子”的?** 保密性保证是基于信息论的,
因此它已经能够抵御量子对手 — 而且可选的身份验证层使用了 ML-DSA-65 (FIPS 204),这是一种后量子签名算法。
**为什么要确切的 K 个片段,而不是“至少 K 个”?** 传递多余的片段通常意味着
操作员的失误(拿错了堆,或者有重复)。强制要求确切的 `K` 能够暴露问题,
而不是悄悄地从某个子集中成功恢复。
**为什么使用 `ZeroizingBuffer` 而不是 `byte[]`?** 这样一来,秘密就会存放在
GC 无法复制的固定内存中,并在 `Dispose` 时被确定性地擦除。
**我可以丢失一个分享片段吗?** 可以 — 最多可以丢失 `N − K` 个。建议规划 `N − K ≥ 2`。
**我可以撤销一个分享片段吗?** 并不能。打印出的片段会永远存在。要移除一个
受托人,**请轮换秘密**并重新拆分;旧的片段之后只能
解锁一个已废弃的秘密。参见 [`docs/OPER.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/OPERATIONS.md)。
**磁盘上的分享片段长什么样?** 一个紧凑且严格规范的 CBOR 映射
(`.pqss`)。字节级格式在 [`docs/SPEC.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/SPEC.md) 中有完整规范。
**它的速度很快吗?** 对于 32 字节密钥进行 3-of-5 拆分
耗时远低于一毫秒;64 KiB 的拆分+重建耗时只需几十毫秒。它是一个基础组件,绝非
性能瓶颈。
## 成熟度
这个包**未经审计**。它是经过精心设计的 — 常数时间域数学运算,
严格的解析器,失败即停止的验证,以及客观的文档 — 但是
*精心设计*和*经过审计*是两个截然不同的概念,我们绝不混淆
它们。请将其视为一个构建良好、尚待独立审查的基础组件。参见
[`docs/KNOWN-GAPS.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/KNOWN-GAPS.md) 和
[`docs/THREAT-MODEL.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/THREAT-MODEL.md) 了解未经修饰的局限性。
## 状态与路线图
**当前版本:`2.2.0`。** 信息论核心及其周围的工程设计
均已功能完备;API 和 `.pqss` 格式已经稳定,并且不会在没有
SemVer 信号的情况下发生更改。核心库、可选的 VSS 包,以及可选的 Extensions 包共享
同一条版本线(参见
[`CHANGELOG.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/CHANGELOG.md));
磁盘上的 `.pqss` 核心格式依然是 **v1**(VSS 包添加了 **v2** 记录)。目前
唯一悬而未决的一项是**独立审计** — 坦白说明,绝不暗示。
| 领域 | 状态 |
|------|:------:|
| 基于 GF(2⁸) 的 Shamir 拆分/重建,常数时间域数学运算 | ✅ 稳定 |
| 严格规范化的 `.pqss` 格式(已规范、已模糊、已属性测试) | ✅ 稳定 |
| HKDF-SHA256 完整性校验值 | ✅ 稳定 |
| `ZeroizingBuffer`(固定的、会清零的、尽力而为的页锁定) | ✅ 稳定 |
| 带有密钥固定的 ML-DSA-65 分发者身份验证 *(net10.0)* | ✅ 稳定 |
| `WrappedSecret`, `Refresh`, `DealerCommitment`,基于片段的验证 | ✅ 稳定 |
| 可验证秘密共享 — Pedersen,可选的 `…Vss` *(net10.0 签名)* | ✅ 已发布 *(未审计)* |
| 分布式主动刷新 — 可选的 `…Extensions` | ✅ 已发布 *(诚实但好奇阶段)* |
| `pqss` CLI,六个示例,完整的文档 | ✅ 稳定 |
| 独立的安全审计 | ⏳ 尚未完成 — *已诚实说明,未作暗示* |
**接下来你可以期待什么**(仅为意向,非承诺 — 详情见
[`ROADMAP.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/ROADMAP.md)):
- **迈向稳定的 `2.x` 版本:** 对 GF(2⁸) 数学运算和
CBOR 编解码器进行独立审查,撰写一份关于真实环境内部实战部署的报告,并开启一段没有
格式/API 变动的静默预览期。
- **`2.x`(附加的,非破坏性的):** 提供更多的生态示例(EF Core 主密钥,
cloud-KMS 混合模式)以及发布更多跨实现的测试向量。用于更高级别仪式助手的可选包
[`…Extensions`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/PROACTIVE-REFRESH.md)
已经**发布**(第一个助手:分布式主动刷新)。
- **可验证秘密共享(可选的,已发布):** 检测
*恶意分发者* — 作为独立的
[`PostQuantum.SecretSharing.Vss`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/VSS-DESIGN.md) 包发布 —
基于 P-256 的 Pedersen VSS,带有可选的 ML-DSA-65 广播签名,并将其排除在
无依赖核心之外。保密性保持为信息论级别;只有对分发者欺诈的
*检测*属于计算性质的(这是一个诚实的折中,已有记录)。传输格式已被锁定
([SPEC §v2](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/SPEC.md)),
向量已发布,并且随附了专门的
[审计指南](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/VSS-AUDIT-GUIDE.md);
迈向稳定的最后一步就是进行一次独立审计。参见
[`docs/KNOWN-GAPS.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/KNOWN-GAPS.md) §1。
- **分布式主动刷新(可选的,已发布):** 在各方之间重新随机化分享片段
— 或者同位实体集合 — *而无需重建秘密*,从而击败移动对手。
作为独立的
[`PostQuantum.SecretSharing.Extensions`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/PROACTIVE-REFRESH.md)
包发布(`ProactiveRefresh`),像核心一样无外部依赖。诚实但处于好奇阶段的
结构(保密性得以保留;对恶意贡献者的破坏行为属于*被检测到*,而不会造成泄漏)。参见 [`docs/KNOWN-GAPS.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/KNOWN-GAPS.md) §5。
无论现在还是将来,这里都**不会**刻意支持的是:一个 KMS,一种直接安全地拆分
低熵秘密的方法(请使用 `WrappedSecret`),或者是抵御功耗/电磁
侧信道及进程内存转储的防御手段。
## 文档
- [`docs/SPEC.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/SPEC.md) — 字节级的 `.pqss` 格式规范(包含一个经过测试固定的十六进制示例)。
- [`docs/THREAT-MODEL.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/THREAT-MODEL.md) — 坦白指明了在/不在范围内的内容。
- [`docs/KNOWN-GAPS.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/KNOWN-GAPS.md) — 真实的局限性,包括不光彩的部分。
- [`docs/AUDIT.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/AUDIT.md) — 审查员的审计工具包:范围、复现步骤、风险评级区域,以及一份检查清单(我们希望让审计变得低成本)。
- [`docs/VSS-DESIGN.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/VSS-DESIGN.md) — 可选的可验证秘密共享 (Pedersen) 包的设计与折中方案,附带 [`docs/VSS-AUDIT-GUIDE.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/VSS-AUDIT-GUIDE.md)(审查员工具包)和 [`docs/test-vectors-vss.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/test-vectors-vss.md)。
- [`docs/PROACTIVE-REFRESH.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/PROACTIVE-REFRESH.md) — 可选的 `…Extensions` 分布式主动刷新(在不重建的情况下重新随机化分享片段)的设计与威胁模型。
- [`docs/OPERATIONS.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/OPERATIONS.md) — 受托人仪式指南。
- [`docs/CASE-STUDY-signing-key.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/CASE-STUDY-signing-key.md) — 一个经过验证、可复现的仪式,用于保护代码签名密钥(附有字节一致和签名证明)。
- [`docs/test-vectors.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/test-vectors.md) — 跨实现测试向量。
- [`samples/`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/tree/main/samples) — 六个可运行的示例:`SignerCustody`(经过验证的 3-of-5 托管),`EnvelopeRecovery`(封装模式,net8.0),`VaultUnseal`(Vault 风格的密封服务),`AspNetCoreDataProtection`(在法定人数背后加密 DP 密钥环),`MaliciousDealerDetected`(可验证秘密共享捕获不一致的分发者,net8.0),以及 `pqss`(一个真实的拆分/检查/验证/合并/刷新 CLI)。
- [`docs/BENCHMARKS.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/BENCHMARKS.md) — 吞吐量数据和常数时间的证据(以及如何复现)。
- [`fuzz/`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/tree/main/fuzz) — 对 `.pqss` 解析器的覆盖率引导(SharpFuzz + libFuzzer)模糊测试;在 CI 中运行。
- [`docs/COMPATIBILITY.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/COMPATIBILITY.md) — `.pqss` 格式稳定性与 SemVer 策略。
- [`docs/SUPPLY-CHAIN.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/docs/SUPPLY-CHAIN.md) — 构建来源、SBOM、可复现的构建,以及如何自己验证发布版本。
- [`CONTRIBUTING.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/CONTRIBUTING.md) — 构建/测试、API 锁定和禁用 API 的门控,以及发布仪式。
- [`ROADMAP.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/ROADMAP.md) — v1 / v1.x / v2 计划。[`CHANGELOG.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/CHANGELOG.md) — 发布历史。
- [`SECURITY.md`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/SECURITY.md) — 如何报告漏洞。
## 许可证
MIT。参见 [`LICENSE`](https://github.com/systemslibrarian/PostQuantum.SecretSharing/blob/main/LICENSE)。
*Soli Deo Gloria — 哥林多前书 10:31*
标签:Shamir门限方案, 信息论安全, 后量子密码, 多人体追踪, 密码学, 手动系统调用, 文档结构分析