实验 0:Rust 环境与实验约定
目标
本实验不实现密码算法,而是建立后续实验共同使用的工程边界:
- 初始化 Rust library crate;
- 区分玩具数学代码与真实曲线上的协议实现;
- 约定错误处理、随机数和秘密类型规则;
- 建立最小测试与格式检查流程。
前置条件
- 已安装稳定版 Rust 和 Cargo;
- 当前目录是本学习工程根目录;
- 已阅读导读。
检查环境:
rustc --version
cargo --version
git status --short --branch
任务 1:初始化 library crate
在仓库根目录执行:
cargo init --lib .
选择 library 而不是 binary,因为协议逻辑、测试和不同实验程序应与命令行界面分离。
建议逐步形成下面的结构:
src/
lib.rs
toy_field.rs # 实验 1 的 F17,不进入协议路径
shamir.rs # 先用 F17 验证,再扩展到 Scalar
transcript.rs
schnorr.rs
frost/
mod.rs
types.rs
round1.rs
round2.rs
aggregate.rs
tests/
shamir_properties.rs
protocol_negative.rs
第一天不需要一次创建所有文件。只在开始对应实验时增加模块。
任务 2:记录依赖边界
第一版协议实验建议使用兼容的依赖族:
[dependencies]
curve25519-dalek = { version = "4.1", features = ["digest", "rand_core", "zeroize"] }
sha2 = "0.10"
rand_core = { version = "0.6.4", features = ["getrandom"] }
subtle = "2.6"
zeroize = { version = "1.8", features = ["zeroize_derive"] }
thiserror = "2"
[dev-dependencies]
rand_chacha = "0.3"
proptest = "1"
hex = "0.4"
trybuild = "1" # 对 move-only 等编译期 API 约束做 UI 测试
这里固定 rand_core 0.6 是为了与 curve25519-dalek 4.x 常用 API 保持 trait 兼容。不要看到更大的版本号就单独升级;开始编码时应再次核对所锁定版本的文档。
实验 1 的玩具有限域可以暂时完全不依赖这些密码库。
任务 3:建立代码规则
在动手前,把以下规则写入模块文档或项目约定:
toy_field.rs中的值可以打印,但类型名或模块名必须明确标记Toy;真实曲线协议不得依赖它。- 协议秘密类型不派生
Copy、Debug或默认Serialize。 - nonce 类型由签名函数按值消费,不提供复制接口。
- 网络或文件输入的解析返回
Result,不得对敌手输入unwrap()。 - transcript 编码显式定义字段顺序和长度,不哈希
Debug或 JSON。 - 固定种子 RNG 只用于测试,协议默认使用
OsRng。
任务 4:建立验证命令
每个实验结束前运行:
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
当加入文档测试后,再确认 cargo test --doc 通过。
验收标准
cargo test可以运行;- 玩具数学代码和真实曲线协议的职责在文件、类型名和注释中有明确区别;
- 仓库中没有真实私钥、助记词或生产数据;
- 你能解释为什么测试 RNG 不能进入签名路径;
- 你能指出哪些依赖提供基础原语,哪些协议逻辑必须自己实现。
观察记录
在学习日志中回答:
- 哪些 bug 可以被 Rust 类型系统减少?
- 哪些协议错误无法由内存安全阻止?
- 为什么
zeroize有帮助,但不能保证秘密从系统中彻底消失?
安全警告
本实验建立的是教学工程纪律,不是生产安全认证。即使所有 lint 和测试通过,也不能证明密码协议正确或实现具有常量时间性质。