1个不稳定版本
0.1.0 | 2021年2月16日 |
---|
#1771在密码学
14,350每月下载量
在131个crate(5个直接)中使用
100KB
848 行
ed25519-dalek-fiat
使用Rust实现的快速高效ed25519密钥生成、签名和验证。
关于
这是ed25519-dalek
项目的精简分支,其主要区别是将原始的curve25519-dalek
依赖项替换为curve25519-dalek-fiat
。这允许使用由fiat-crypto
项目提供的正式验证的后端,其中原语曲线操作是从Coq算术正确性的证明中提取出来的。
文档
文档可在此处找到。
安装
要安装,请在项目的Cargo.toml
中添加以下内容
ed25519-dalek-fiat = "0.1.0"
基准测试
在3.30 GHz运行的Intel Skylake i9-7900X上,不启用TurboBoost,此代码实现了以下性能基准
∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench
Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek)
Finished release [optimized] target(s) in 3.11s
Running target/release/deps/ed25519_benchmarks-721332beed423bce
Ed25519 signing time: [15.617 us 15.630 us 15.647 us]
Ed25519 signature verification time: [45.930 us 45.968 us 46.011 us]
Ed25519 keypair generation time: [15.440 us 15.465 us 15.492 us]
通过启用avx2后端(在具有兼容微架构的机器上),签名验证的性能得到了显著提高
∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS=-Ctarget_cpu=native
∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features=avx2_backend
Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek)
Finished release [optimized] target(s) in 4.28s
Running target/release/deps/ed25519_benchmarks-e4866664de39c84d
Ed25519 signing time: [15.923 us 15.945 us 15.967 us]
Ed25519 signature verification time: [33.382 us 33.411 us 33.445 us]
Ed25519 keypair generation time: [15.246 us 15.260 us 15.275 us]
相比之下,Golang中相应的包表现如下
∃!isisⒶmistakenot:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench .
BenchmarkKeyGeneration 30000 47007 ns/op
BenchmarkSigning 30000 48820 ns/op
BenchmarkVerification 10000 119701 ns/op
ok github.com/agl/ed25519 5.775s
使密钥生成和签名平均快2倍,验证快2.5-3倍,具体取决于avx2的可用性。当然,这只是我的机器,这些结果——远非严格——应持保留态度。
将其转换为大致的周期数:我们用3.3的系数将纳秒转换为3300 MHz CPU的每秒周期数,即验证110256周期,签名52618周期,这与手动优化的汇编实现具有竞争力。
此外,如果您使用的是rand
crate中的CSPRNG,则nightly
功能将启用那里的u128
/i128
功能,从而可能提高性能。
如果您的协议或应用程序能够批量签名以进行验证,那么verify_batch()
函数的性能得到了显著提升。在上述英特尔Skylake i9-7900X上,验证96个签名的批处理耗时1.7673毫秒。这意味着每个签名验证大约需要18.4094微秒,或者大约60750个周期,比原始论文中给出的批量验证速度快了一倍以上(这很可能不是一个公平的比较,因为那是一台Nehalem机器)。测试名称中/
后面的数字指的是批处理的大小
∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS=-Ctarget_cpu=native
∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features=avx2_backend batch
Compiling ed25519-dalek v0.8.0 (file:///home/isis/code/rust/ed25519-dalek)
Finished release [optimized] target(s) in 34.16s
Running target/release/deps/ed25519_benchmarks-cf0daf7d68fc71b6
Ed25519 batch signature verification/4 time: [105.20 us 106.04 us 106.99 us]
Ed25519 batch signature verification/8 time: [178.66 us 179.01 us 179.39 us]
Ed25519 batch signature verification/16 time: [325.65 us 326.67 us 327.90 us]
Ed25519 batch signature verification/32 time: [617.96 us 620.74 us 624.12 us]
Ed25519 batch signature verification/64 time: [1.1862 ms 1.1900 ms 1.1943 ms]
Ed25519 batch signature verification/96 time: [1.7611 ms 1.7673 ms 1.7742 ms]
Ed25519 batch signature verification/128 time: [2.3320 ms 2.3376 ms 2.3446 ms]
Ed25519 batch signature verification/256 time: [5.0124 ms 5.0290 ms 5.0491 ms]
正如您所看到的,每种机器都有一个最优的批处理大小,因此您可能想要在您的目标CPU上测试基准,以发现最佳的大小。对于这台机器,每批大约100个签名是最优的
此外,得益于Rust,这个实现既具有类型安全,也具有内存安全。它还比能够阅读qhasm的人更容易阅读,使其更容易被审计。我们认为,最终,这些特性——结合速度——比仅仅周期数更有价值。
关于签名可变形性的说明
本库产生的签名是可变形的,正如在原始论文中讨论的那样
虽然我们的Signature
结构体的标量组件严格来说不是可变形的,因为从字节反序列化Signature
时已经放置了减法检查,但对于这个crate中的所有类型的签名,仍然存在由于群元素组件可能存在可变形性的问题。
我们可以通过乘以曲线共因子来消除后者的可变形性属性,但这会使我们的实现不匹配现有所有其他实现的行为。截至本文写作时,RFC 8032,“Edwards曲线数字签名算法(EdDSA)”,“建议执行更强的检查。虽然我们同意应该执行更强的检查,但我们认为,一个人不应该在事隔十年之后改变“ed25519验证”的定义,从而与每个其他实现不兼容。
然而,如果您需要这样做,请参阅verify_strict()
函数的文档,该函数对群元素执行完整的检查。此功能默认可用。
如果出于某种原因——尽管我们强烈建议您不要——您需要遵守原始的ed25519签名规范,如上文中论文摘录所示,您可以通过--features='legacy_compatibility'
禁用标量可变形性检查。我们强烈反对这样做。
legacy_compatibility
功能
默认情况下,这个库在签名反序列化时对签名字段的标量组件执行更严格的可变形性检查。这种更严格的检查,即s < \ell
,其中\ell
是基点的阶,是由RFC8032
规定的。然而,该RFC是在原始论文发布十年后标准化的,正如上面所述,(通常错误地)声称可变形性无关紧要。
因此,大多数ed25519实现仅执行有限的、更复杂的三位最高位未置位的检查。如果您需要与旧版实现兼容,包括
- ed25519-donna
- Golang的/x/crypto ed25519
- libsodium(仅在构建时使用
-DED25519_COMPAT
) - NaCl的“ref”实现
- 可能还有其他很多
然后启用 ed25519-dalek
的 legacy_compatibility
功能。请注意并提前警告,这样做允许签名可变形,这意味着对于相同消息,可能存在两个不同且“有效”的签名与相同的密钥,这在许多情况下显然非常危险,包括但不限于身份验证协议和加密货币交易。
verify_strict()
函数
签名标量组件不是唯一可能引起签名可变形的来源。用于签名验证的公钥和签名组元素组件也是可变形的,因为它们可能包含由于 curve25519 群不是素数阶,而是有小的8为陪数的小扭量成分。
如果您想消除这种签名可变形的来源,请查阅 verify_strict()
函数的文档。
关于随机数生成的一点说明
原始论文的规范和 RFC8032 标准化并没有精确地指定如何生成随机数,除了使用 CSPRNG(密码学安全随机数生成器)之外。特别是在签名验证的情况下,安全证明依赖于遮蔽因子/非重复数的唯一性,因此,这些随机数样本对敌手来说应该是不可预测的。正因为如此,当前在密码学家中普遍认为,优先选择合成随机数是更安全的。
为了解释合成随机数,我们首先应该解释 ed25519-dalek
如何处理生成确定性随机数的方式。由于这种模式有可能打开用户对故障攻击的途径,即控制批量验证所有输入(即公钥、签名和消息)的攻击者可以专门地构造它们以诱导故障(例如,在RAM中错误翻转位,过热处理器等),因此默认情况下禁用了此模式。在确定性模式下,我们通过创建基于公输入的 Fiat-Shamir 转换的 PRNG来为 PRNG(用于生成我们的遮蔽因子/非重复数)设置种子。这种模式对于需要强大可审计性保证的协议以及没有访问安全系统/芯片提供的随机数的协议可能很有用。可以通过 --features='batch_deterministic'
启用此功能。请注意,我们不支持确定性签名,因为其中存在许多陷阱,包括意外重复使用非重复数泄露密钥。
在默认模式下,我们在完全确定性模式下做同样的事情,但根据系统/芯片提供的随机数,额外推动底层 keccak-f1600 函数(用于基于提供的转写基于的 PRNG)向前。这提供了合成随机数,即基于确定性和非确定性数据的随机数。这样做的原因是防止种子不佳的系统 RNG 毁掉签名验证方案的安全性。
特性
#![no_std]
这个库旨在符合 #![no_std]
。如果需要批量验证(--features='batch'
),请启用 std
或 alloc
功能之一。
夜间编译器
要使您的应用程序构建 ed25519-dalek
并默认启用夜间功能,请改为
[dependencies.ed25519-dalek]
version = "1"
features = ["nightly"]
当使用 cargo build --features="nightly"
构建时,若要启用夜间功能,请将以下内容添加到 Cargo.toml
[features]
nightly = ["ed25519-dalek/nightly"]
Serde
要启用 serde 支持,使用 ed25519-dalek
的 serde
功能构建。
特定架构的后端
默认情况下,ed25519-dalek
会构建针对 curve25519-dalek
的 u64_backend
功能,它使用 Rust 的 i128
功能来实现大约是 u32_backend
功能的两倍速度。然而,当针对 32 位系统时,您可能想要使用 cargo build --no-default-features --features="u32_backend"
进行编译。如果您正在为具有 avx2 指令的机器构建,还有实验性的 simd_backend
,目前包括 avx2 或 avx512 后端。要使用它们,请使用以下命令编译:RUSTFLAGS="-C target_cpu=native" cargo build --no-default-features --features="simd_backend"
批量签名验证
批量签名验证的标准变体(即,使用许多不同公钥在许多不同消息上生成的许多签名)可通过 batch
功能获得。它使用上述所提到的合成随机数。
确定性批量签名验证
与上述相同的批量签名验证概念,但使用纯确定性随机数可以通过 batch_deterministic
功能启用。
依赖项
~2.2–3.5MB
~81K SLoC