2个版本 (1个稳定版)
2.1.1 | 2024年5月12日 |
---|---|
2.0.0-rc.3 | 2024年5月11日 |
#843 在 加密
每月50 次下载
125KB
1.5K SLoC
存档
此仓库已被 迁移。请将所有问题和拉取请求导向新仓库。
出于历史原因,此仓库将保持只读状态。
ed25519-dalek

ed25519密钥生成、签名和验证的Rust快速高效实现。
使用
稳定版
要导入 ed25519-dalek
,请将以下内容添加到项目 Cargo.toml
的依赖项部分
ed25519-dalek = "1"
测试版
要使用最新的预发布版本(见下方的更改 详情),请在项目的 Cargo.toml
中使用以下行
ed25519-dalek = "2.0.0-rc.3"
特性标志
此crate与 #[no_std]
兼容,默认特性 default-features = false
。
特性 | 默认? | 描述 |
---|---|---|
alloc |
✓ | 当启用 pkcs8 时,分别实现了 EncodePrivateKey /EncodePublicKey 用于 SigningKey /VerifyingKey 。 |
std |
✓ | 为 SignatureError 实现了 std::error::Error 。同时启用了 alloc 。 |
zeroize |
✓ | 为 SigningKey 实现了 Zeroize 和 ZeroizeOnDrop 。 |
rand_core |
启用了 SigningKey::generate 。 |
|
batch |
启用了快速验证多个签名的 verify_batch 。同时启用了 rand_core 。 |
|
digest |
为 Ed25519ph 哈希签名启用了 Context 、SigningKey::{with_context, sign_prehashed} 和 VerifyingKey::{with_context, verify_prehashed, verify_prehashed_strict} 。 |
|
asm |
在 SHA-512 压缩函数中启用了汇编优化。 | |
pkcs8 |
为 SigningKey 和 VerifyingKey 启用了 PKCS#8 序列化和反序列化。 |
|
pem |
启用了 PKCS#8 私钥和 SPKI 公钥的 PEM 序列化支持。同时启用了 alloc 。 |
|
legacy_compatibility |
不安全: 禁用某些签名检查。详见 以下内容 | |
hazmat |
不安全: 暴露了 hazmat 模块以进行原始签名/验证。这些函数的误用会暴露私钥,如在 签名预言机攻击 中。 |
主要变更
有关此crate过去版本中进行的变更的列表,请参阅 CHANGELOG.md。
2.0.0 版本的破坏性变更
- 将 MSRV 从 1.41 提升至 1.60.0
- 提升 Rust 版本
- 将
signature
依赖项提升至 2.0 - 将
digest
设为可选依赖项 - 将
zeroize
设为可选依赖项 - 将
rand_core
设为可选依赖项 - 采用功能而非后端选择 curve25519-backend
- 使所有批量验证确定性,移除
batch_deterministic
(#256) - 移除
ExpandedSecretKey
API ((#205)https://github.com/dalek-cryptography/ed25519-dalek/pull/205) - 将
Keypair
重命名为SigningKey
,将PublicKey
重命名为VerifyingKey
- 将
hazmat
功能改为暴露ExpandedSecretKey
、raw_sign()
、raw_sign_prehashed()
、raw_verify()
和raw_verify_prehashed()
文档
文档可在 此处 获取。
兼容性策略
本库的所有默认启用功能都遵循语义版本控制(SemVer)。以下是针对MSRV和公共API的SemVer例外情况。
最低支持Rust版本
发布版本 | MSRV |
---|---|
2.x | 1.60 |
1.x | 1.41 |
从2.x版本开始,MSRV的变化将伴随着次要版本的提升。
公共API SemVer例外情况
影响公共API的SemVer例外组件的破坏性更改将伴随着某些版本提升。
以下是具体政策
发布版本 | 公共API组件 | 政策 |
---|---|---|
2.x | 依赖项 digest 、pkcs8 和 rand_core |
次要SemVer提升 |
安全性
ed25519-dalek
被设计为防止滥用。签名是恒定时间的,所有签名密钥在超出作用域时都会被置零(除非禁用了 zeroize
),断开连接的公钥不能用于签名,并提供了额外功能如 VerifyingKey::verify_strict
以避免已知的陷阱。
此外,此crate没有也不允许使用不安全代码。您可以选择使用位于 curve25519-dalek
中的某些高度优化的不安全代码。有关后端选择的更多信息,请参阅以下内容。
性能
性能是正确性、安全性和清晰度之后的次要目标,但我们力求与其他实现保持竞争力。
基准测试
基准测试使用 criterion.rs 运行。
cargo bench --features "batch"
# Uses avx2 or ifma only if compiled for an appropriate target.
export RUSTFLAGS='-C target_cpu=native'
cargo +nightly bench --features "batch"
在运行在库存状态下的Intel 10700K上,比较 curve25519-dalek
后端。
基准测试 | u64 | simd +avx2 | fiat |
---|---|---|---|
签名 | 15.017 µs | 13.906 µs -7.3967% | 15.877 μs +5.7268% |
签名验证 | 40.144 µs | 25.963 µs -35.603% | 42.118 μs +4.9173% |
严格签名验证 | 41.334 µs | 27.874 µs -32.660% | 43.985 μs +6.4136% |
批量签名验证/4 | 109.44 µs | 81.778 µs -25.079% | 117.80 μs +7.6389% |
批量签名验证/8 | 182.75 µs | 138.40 µs -23.871% | 195.86 μs +7.1737% |
批量签名验证/16 | 328.67 µs | 251.39 µs -23.744% | 351.55 μs +6.9614% |
批量签名验证/32 | 619.49 µs | 477.36 µs -23.053% | 669.41 μs +8.0582% |
批量签名验证/64 | 1.2136 ms | 936.85 µs -22.543% | 1.3028 ms +7.3500% |
批量签名验证/96 | 1.8677 ms | 1.2357 ms -33.936% | 2.0552 ms +10.039% |
批量签名验证/128 | 2.3281 ms | 1.5795 ms -31.996% | 2.5596 ms +9.9437% |
批量签名验证/256 | 4.1868 ms | 2.8864 ms -31.061% | 4.6494 μs +11.049% |
密钥对生成 | 13.973 µs | 13.108 µs -6.5062% | 15.099 μs +8.0584% |
批量性能
如果您的协议或应用程序能够批量验证签名,则 verify_batch
函数的性能将大大提高。
正如您所看到的,每种机器都有一个最佳批量大小,因此您可能需要在目标CPU上测试基准测试以发现最佳大小。
(微)架构特定的后端
后端是指椭圆曲线和标量算术的实现。不同的后端有不同的应用场景。例如,如果您需要形式化验证的代码,您应该使用fiat
后端(因为它是由Fiat Crypto生成的)。
后端选择详情和说明可以在curve25519-dalek文档中找到。
贡献
批量签名验证
批量签名验证的标准变体(即许多使用可能许多不同公钥在不同消息上生成的签名)可以通过batch
功能获得。它使用确定性随机性,即,它对输入进行哈希(使用merlin
,它处理转写项分离)并使用结果生成随机系数。批量验证需要分配,因此它不会在堆栈不足的环境中工作。
验证标准
签名方案的验证标准是签名和公钥必须满足的准则,以便被接受。遗憾的是,Ed25519有一些未明确说明的部分,导致不同实现之间的验证标准不同。有关这方面的良好概述,请参阅Henry的帖子。
在本节中,我们介绍了一些关于我们的验证标准的具体细节以及如何处理它们。
可塑性和legacy_compatibility
功能
如果被动攻击者知道公钥A、消息m和有效签名σ',则可以生成一个不同的σ',使得σ'是关于A的有效签名,则认为签名方案产生可塑签名。只有当攻击者可以在不知道与A对应的私钥的情况下做到这一点时,方案才是可塑的。
ed25519-dalek
不是一个可塑签名方案。
尽管如此,一些其他Ed25519实现是可塑的,例如libsodium(启用ED25519_COMPAT
)、ed25519-donna、NaCl的ref10实现,以及可能还有很多其他。如果您需要与这些实现进行互操作并接受其他无效签名,可以启用legacy_compatibility
标志。如果不需要,请不要启用legacy_compatibility
,因为这会使您的签名变得可塑。
注意:CIRCL根本没有任何标量范围检查。我们没有为与CIRCL接受的较大集合的RFC不允许的签名进行互操作的功能标志。
弱密钥伪造和verify_strict()
签名伪造就像听起来一样:当攻击者,给定公钥A,创建一个签名σ和消息m,使得σ是关于A的有效签名时,就会发生签名伪造。由于这是任何签名方案的核心安全定义,因此Ed25519签名不能被伪造。
然而,Ed25519 允许一种更为宽松的伪造形式,我们称之为 弱密钥伪造。攻击者可以生成一个特殊的公钥 A(我们称之为 弱 公钥)和一个签名 σ,使得 σ 在 A 的作用下是一个有效签名,对应于任何消息 m,以高概率。这种攻击在 Ed25519 论文中被认可,并导致了 Scuttlebutt 协议中的一个可利用的漏洞(论文,第 7.1 节)。VerifyingKey::verify()
函数允许弱密钥。
我们提供了 VerifyingKey::verify_strict
(和 verify_strict_prehashed
)以帮助用户避免这些情况。这些函数对 A 进行额外的检查,确保它不是一个弱公钥。此外,我们还提供了 VerifyingKey::is_weak
以允许用户在尝试签名验证之前执行此检查。
批量验证
如上所述,弱公钥可以以高概率生成未知消息的签名。这意味着有时弱伪造尝试会失败。实际上,它可以失败高达 7/8 的时间。如果你对同一个失败的伪造调用 verify()
两次,它将两次都返回错误,正如预期的那样。然而,如果你对两个不同的有效批次分别调用两次 verify_batch()
,这两个批次都包含失败的伪造,那么有一个 21% 的机会一个会失败而另一个会成功。
为什么会出现这种情况?这是因为 verify_batch()
并没有进行 verify_strict()
的弱密钥测试,并且它会将每个验证方程乘以某个随机系数。如果失败的伪造被乘以 8,那么弱密钥(一个低阶点)变成 0,对尝试伪造的验证方程将会成功。
由于 verify_batch()
的目的是高吞吐量,我们认为最好不在其中放入弱密钥检查。如果你想防止批次中弱公钥引起的奇怪行为,你应该在事先对输入调用 VerifyingKey::is_weak
。
依赖项
~1.7–2.8MB
~59K SLoC