3个版本
2.0.0-pre.3 | 2023年2月2日 |
---|---|
2.0.0-pre.1 | 2023年1月5日 |
#12 in #ed25519-key
105KB
1K SLoC
ed25519-dalek
快速高效的Rust实现ed25519密钥生成、签名和验证。
使用
稳定
要导入ed25519-dalek
,将以下内容添加到您项目Cargo.toml
的依赖关系部分
ed25519-dalek = "1"
测试版
要使用最新的预发布版本(见下文更改),在您的项目Cargo.toml
中使用以下行
ed25519-dalek = "2.0.0-pre.0"
功能标志
此包与#[no_std]
兼容,默认情况下不启用功能default-features = false
。
功能 | 默认? | 描述 |
---|---|---|
alloc |
✓ | 当启用pkcs8 时,为SigningKey 和VerifyingKey 分别实现EncodePrivateKey和 |
std |
✓ | 为SignatureError 实现std::error::Error 。同时启用alloc 。 |
zeroize |
✓ | 为SigningKey 实现Zeroize 和ZeroizeOnDrop 。 |
rand_core |
启用SigningKey::generate 。 |
|
batch |
启用 verify_batch 以快速验证多个签名。同时启用 rand_core 。 |
|
摘要 |
启用 Context ,SigningKey::{with_context, sign_prehashed} 和 VerifyingKey::{with_context, verify_prehashed, verify_prehashed_strict} 以支持 Ed25519ph 预哈希签名 |
|
汇编 |
在 SHA-512 压缩函数中启用汇编优化 | |
pkcs8 |
启用 SigningKey 和 VerifyingKey 的 PKCS#8 序列化/反序列化 |
|
pem |
启用 PKCS#8 私钥和 SPKI 公钥的 PEM 序列化支持。同时启用 alloc 。 |
|
向后兼容 |
不安全: 禁用某些签名检查。详见 下面 |
主要变更
有关此crate过去版本中做出的变更列表,请参阅 CHANGELOG.md。
2.0.0 版本的破坏性变更
- 将 MSRV 从 1.41 提升至 1.60.0
- 提升 Rust 版本
- 将
signature
依赖项提升到 2.0 - 使 curve25519-backend 选择 更自动化
- 将
digest
设置为可选依赖项 - 将
zeroize
设置为可选依赖项 - 将
rand_core
设置为可选依赖项 - 使所有批量验证确定化,移除
batch_deterministic
(#256) - 移除
ExpandedSecretKey
API ((#205)https://github.com/dalek-cryptography/ed25519-dalek/pull/205) - 将
Keypair
重命名为SigningKey
,将PublicKey
重命名为VerifyingKey
文档
文档可在 此处 获取。
兼容性策略
此库的所有默认启用功能均受 语义版本控制 (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 |
小版本号提升 |
安全性
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='--cfg curve25519_dalek_backend="simd" -C target_cpu=native'
cargo +nightly bench --features "batch"
在运行在标准配置的英特尔10700K处理器上,比较curve25519-dalek
后端。
基准测试 | u64 | simd +avx2 | fiat |
---|---|---|---|
签名 | 15.017 µs | 13.906 µs -7.3967% | 15.877 µs +14.188% |
签名验证 | 40.144 µs | 25.963 µs -35.603% | 42.118 µs +62.758% |
严格签名验证 | 41.334 µs | 27.874 µs -32.660% | 43.985 µs +57.763% |
批签名验证/4 | 109.44 µs | 81.778 µs -25.079% | 117.80 µs +43.629% |
批签名验证/8 | 182.75 µs | 138.40 µs -23.871% | 195.86 µs +40.665% |
批签名验证/16 | 328.67 µs | 251.39 µs -23.744% | 351.55 µs +39.901% |
批签名验证/32 | 619.49 µs | 477.36 µs -23.053% | 669.41 µs +39.966% |
批签名验证/64 | 1.2136 ms | 936.85 µs -22.543% | 1.3028 ms +38.808% |
批签名验证/96 | 1.8677 ms | 1.2357 ms -33.936% | 2.0552 ms +66.439% |
批签名验证/128 | 2.3281 ms | 1.5795 ms -31.996% | 2.5596 ms +61.678% |
批签名验证/256 | 4.1868 ms | 2.8864 ms -31.061% | 4.6494 ms +61.081% |
密钥对生成 | 13.973 µs | 13.108 µs -6.5062% | 15.099 µs +15.407% |
批处理性能
如果您的协议或应用能够批量签名进行验证,verify_batch
函数将大幅提高性能。
如您所见,每台机器都有一个最佳批量大小,因此您可能需要在自己的目标CPU上测试基准测试,以发现最佳大小。
特定于(微)架构的后端
后端是指椭圆曲线和标量算术的实现。不同的后端有不同的用例。例如,如果您需要形式化验证的代码,您希望使用fiat
后端(因为它是由Fiat Crypto生成的)。如果您需要尽可能高的性能,您可能希望使用simd
后端。
后端选择细节和说明可以在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–3MB
~62K SLoC