CipherFS
开发中 · 未发布 · 格式可能变化

任务:持久化格式与算法升级改造

2026-10-13 立项。目标是满足已确认需求"格式与算法升级"一节。项目未发布,不需要兼容现有数据;现有测试全部通过是回归基线,新增格式验收不得放宽旧断言。改造期间不加功能;具体边界见 ADR 005。

现状

  • 15 个生产 src 文件引用 bincode 1.3(含错误转换和测试模块),位置编码没有字段标签,不能跳过未知字段。文件:cipherfs-core 的 error.rs、index/{membership,records,retirement,segment,snapshot}.rs、storage/metadata_store.rs、vault.rs、vault/{authority_keys,devices,maintenance,recovery,snapshot,sync}.rs;cipherfs-sync 的 pairing.rs。另有集成测试 core/tests/pages.rs、sync/tests/retirement_gc.rs;锁文件还通过未使用的 async-session 和 Iroh umbrella 的 RPC 依赖闭包引入它。
  • VersionId、RetirementId、快照 frontier 和上传清单 commitment 使用带现有派生标签的 BLAKE3,原像为 bincode;版本验证会解码后重编码。普通成员/退休记录由段外签名认证;设备请求、恢复 enrollment 与 RecoveryEnvelope 有独立元组签名。配对 transcript 用 ticket-secret keyed BLAKE3 MAC/SAS,不是独立 Ed25519 签名。上传清单当前清空授权证明后重编码取 commitment。
  • 容器头是手写的:段 CFSSEG01 固定头 104 bytes;快照 CFSSNP01/CFSSNP02 固定头 112 bytes,载荷为 AEAD 密封的 bincode,末尾 Ed25519 签名。02 还有未加密但受签名/AAD 认证的 authority 长度和原始段向量;快照写 02,上传清单复用 01。恢复对象是 bincode RecoveryEnvelope,keys 单独非对称密封。
  • metadata.redb 有 31 张表:18 张使用 bincode 后本机密封;config 整体未密封,含各自加密的 wraps;还有明文 bincode、原始加密签名段、密封密钥、BE 整数/位置和空标记。settings 没有 schema 号。CAS 另有 3 张表,含整数和手工位置编码,同属本机数据库改造范围。
  • 对象名 i/<device>/<seq>-<hash>-<len>、p/<hh>/<hash>-<len>、n/<frontier_hash>-<hash>-<len>、u/<hash>-<len> 中哈希和设备 ID 是裸 hex,隐含 BLAKE3 和 Ed25519;v/、s/ 是随机 16-byte ID,r/ 的 epoch 是派生身份,不能都视为公钥。
  • 内容层已有算法号:ContentBody.suite 是 (u8, u8),分别编码 EncryptionAlgorithm/HashAlgorithm,XChaCha20Poly1305=1、Aes256Gcm=2、ChaCha20Poly1305=3,Blake3=1、Sha256=2、Sha512=3。内容当前只接受 Blake3;注册号不等于已启用。保留全部既有数值。
  • 密钥派生标签已带版本(cipherfs index v6、cipherfs version id v1 等),不改。

设计决定

  1. 编码用 protobuf,proto3,包名 cipherfs.v1,文件 crates/cipherfs-core/proto/cipherfs.proto。生成的 Rust 代码提交进仓库(crates/cipherfs-core/src/wire/generated.rs),由 scripts/projects.sh proto 重新生成;生成器是工作区内一个小 crate,用 prost-build 加 protox(纯 Rust,不需要 protoc 二进制)。build.rs 不得在构建时调用任何外部工具。不使用宿主 protoc;proto 注释必须单独写在声明上一行,废弃字段号 reserved。
  2. 身份即字节。定义两个通用封装:HashedBytes { bytes body }(身份由 body 派生)和 SignedBytes { bytes body; Signature signature }。各被哈希或签名的记录按原有载体携带封装;段中的版本、成员、退休等保留原始 record body,配对消息与恢复对象保留各自原始 body;写入方编码一次,哈希和签名只算在 body 上,读取方先验再解码 body,数据库、重开、快照与转发保留原始字节及未知字段。普通记录仍由段签名认证,不新增独立记录签名;配对保持原有 MAC。VersionId 的派生标签保持 cipherfs version id v1,原像改为 body 字节。删除所有"解码后重编码再比对"的代码。
  3. 算法标识。新增 Digest { HashAlgorithm algorithm; bytes value }、Signature { SignatureAlgorithm algorithm; bytes value }、PublicKey { PublicKeyAlgorithm algorithm; bytes value },签名 Ed25519=1、公钥 Ed25519=1/X25519=2,以及 KdfAlgorithm(Argon2id=1)。Rust 侧对应类型实现 Display/FromStr,文本形式 b3.<base58>、sha256.<base58>、sha512.<base58>、ed25519.<base58>、x25519.<base58>,base58 用比特币字母表,前导零字节编码为前导 1。解析时校验长度:b3/sha256 为 32 字节、sha512 为 64、ed25519 公钥 32/签名 64、x25519 公钥 32。CLI、Web、日志、FFI 的 JSON 一律用文本形式。
  4. 算法注册表写在 docs/algorithms.zh.md(加英文版),hash、signature/public-key(两套枚举)、kdf、aead、chunking;每条有数值 ID、文本标识、状态 active/deprecated、deprecated_after。实现遇到未知或过期算法返回明确错误,不可降级。
  5. 仓库钉算法。Genesis 记录增加 AlgorithmPolicy { hash, signature, kdf, repeated aead };应用任何记录前检查其算法在策略内,不符合拒绝;bootstrap 先核对 TrustAnchor 绑定的 Genesis,再检查同段算法,拒绝不落库候选钥或 frontier。运行中切换策略的记录类型只在 ADR 里定义,不实现。
  6. 格式号与能力通告。段和快照头的 magic 升为 CFSSEG02、CFSSNP03,去掉对 01/02 的解码;头后紧跟大端 format: u32(当前 1);头中的公钥、签名、AEAD 号及 format 都被签名/AAD 认证。MemberRecord 增加 max_format: u32;入会原像绑定该值,已有本人 MemberUpdate 路径支持可选能力更新,值至少为 1。写入方取本机实际上限与全部未撤销成员最新通告的最小值;空成员集初始写 1。读到高 format 明确报错并停止应用该设备后续段,其他无依赖设备继续;未知 record 类型同样拒绝,不得过滤后推进 frontier。
  7. 本机数据库。metadata 与 CAS 数据库值改 protobuf;settings 存 schema: u32,只有明确新建库可初始化。打开时低 schema 逐级事务迁移、高 schema 报错,已有库缺失视为损坏;保持各表既有加密边界。VaultConfig 改 protobuf 并加 kdf 算法字段。
  8. 对象名。哈希和设备 ID 改为文本形式:i/ed25519.<b58>/<seq:016x>-b3.<b58>-<len>、p/<b58 前两字符>/b3.<b58>-<len>、n/ed25519.<b58>-b3.<b58>-<len>、u/b3.<b58>-<len>,v/<b58>、s/<b58> 保留 namespace 内随机 16-byte ID,r/b3.<epoch-b58>-b3.<b58>-<len> 标注派生身份。n/ 改为设备前缀时,frontier 原始 bytes/digest 继续在认证载荷内承诺和验证。解析时未知算法前缀的对象忽略并记日志,不可作为权限或 GC 删除依据。
  9. 测试向量。crates/cipherfs-core/tests/vectors/ 放固定输入与期望字节、ID、签名的黄金文件,覆盖版本记录、段、快照、配置、每种文本形式。测试比对字节,不仅比对结构;包含未知字段的认证 body 经重开和快照后须逐字保留。

交付顺序

每步结束时 scripts/projects.sh test 工作区完整验证全部通过后单独提交,再进下一步;定向测试不能代替整套门槛。

  1. ADR 005(中英文):决策、备选方案、不实现的切换机制设计;ADR 004 标注"由 005 扩展到所有结构"。
  2. 算法注册表文档和 Digest/Signature/PublicKey 类型及文本形式,先不改线上格式。
  3. proto 定义、生成器 crate、scripts/projects.sh proto,提交生成代码。
  4. 被哈希/签名记录改为封装形式,VersionId 和各签名改为算 body 字节。
  5. 段与快照换 protobuf 载荷,新 magic 与 format 号,成员能力通告,写出格式取最小值。
  6. metadata/CAS redb 值、VaultConfig、本机加密封装算法号、schema 与迁移框架。
  7. 对象名改造,目录存放点与 S3 存放点的解析、列举、GC 同步更新。
  8. 删除直接依赖及测试调用;移除未使用 async-session,将仅使用 net API 的 Iroh umbrella 换为已锁定 iroh-net 0.28.2,保留发现特征与协议,重新解析 lock,使间接依赖也不再出现 bincode。
  9. 测试向量;更新 requirements.zh.md(如有偏差)、IMPLEMENTATION_AUDIT.md(新增一节,附运行日志)、architecture、rust-api、各 crate README;TODO.md 删除本项。

约束

  • 宿主只跑 scripts/projects.sh check|clippy|format;完整测试用 scripts/projects.sh test(容器)。不在宿主安装任何第三方工具、包或工具链。
  • 私钥、库密钥、凭据和用户明文不进入日志、测试向量和文档;向量只含公开标识/签名/密文及合成元数据。
  • 文档保持简短:README 只写当前行为,证据写进审计。文档中不出现其他项目名称。
  • 每一步单独提交,提交信息说明改了哪一层。

验收

  • scripts/projects.sh test 全部通过;scripts/projects.sh check 和 clippy 无新警告。
  • rg -n bincode crates/ Cargo.toml Cargo.lock 无结果,含生成代码、集成测试和间接依赖。
  • 测试向量存在且通过;手动改任一向量的一个字节测试失败。
  • 两台设备(容器内现有 P2P 测试夹具)一台把 max_format 通告为 1、另一台支持 2 时,写出格式为 1;伪造 format 为 3 的段及该设备后续段不推进 frontier,其他无因果依赖设备的合法段继续应用;拒绝的 bootstrap 不落库候选钥。
  • 审计新增小节列出上述运行证据。

仓库中的源文件