- Notifications
You must be signed in to change notification settings - Fork233
Fast and efficient ed25519 signing and verification in Rust.
License
dalek-cryptography/ed25519-dalek
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
This repo has beenmoved. Please direct all issues and pull requests to the new repo.
This repo will remain here in a read-only state for historical purposes.
Fast and efficient Rust implementation of ed25519 key generation, signing, andverification.
To imported25519-dalek
, add the following to the dependencies section ofyour project'sCargo.toml
:
ed25519-dalek ="1"
To use the latest prerelease (see changesbelow),use the following line in your project'sCargo.toml
:
ed25519-dalek ="2.0.0-rc.3"
This crate is#[no_std]
compatible withdefault-features = false
.
Feature | Default? | Description |
---|---|---|
alloc | ✓ | Whenpkcs8 is enabled, implementsEncodePrivateKey /EncodePublicKey forSigningKey /VerifyingKey , respectively. |
std | ✓ | Implementsstd::error::Error forSignatureError . Also enablesalloc . |
zeroize | ✓ | ImplementsZeroize andZeroizeOnDrop forSigningKey |
rand_core | EnablesSigningKey::generate | |
batch | Enablesverify_batch for verifying many signatures quickly. Also enablesrand_core . | |
digest | EnablesContext ,SigningKey::{with_context, sign_prehashed} andVerifyingKey::{with_context, verify_prehashed, verify_prehashed_strict} for Ed25519ph prehashed signatures | |
asm | Enables assembly optimizations in the SHA-512 compression functions | |
pkcs8 | EnablesPKCS#8 serialization/deserialization forSigningKey andVerifyingKey | |
pem | Enables PEM serialization support for PKCS#8 private keys and SPKI public keys. Also enablesalloc . | |
legacy_compatibility | Unsafe: Disables certain signature checks. Seebelow | |
hazmat | Unsafe: Exposes thehazmat module for raw signing/verifying. Misuse of these functions will expose the private key, as in thesigning oracle attack. |
SeeCHANGELOG.md for a list of changes made in past version of this crate.
- Bump MSRV from 1.41 to 1.60.0
- Bump Rust edition
- Bump
signature
dependency to 2.0 - Make
digest
an optional dependency - Make
zeroize
an optional dependency - Make
rand_core
an optional dependency - Adoptcurve25519-backend selection over features
- Make all batch verification deterministic remove
batch_deterministic
(#256) - Remove
ExpandedSecretKey
API ((#205)[#205]) - Rename
Keypair
→SigningKey
andPublicKey
→VerifyingKey
- Make
hazmat
feature to expose,ExpandedSecretKey
,raw_sign()
,raw_sign_prehashed()
,raw_verify()
, andraw_verify_prehashed()
Documentation is availablehere.
All on-by-default features of this library are covered bysemantic versioning (SemVer).SemVer exemptions are outlined below for MSRV and public API.
Releases | MSRV |
---|---|
2.x | 1.60 |
1.x | 1.41 |
From 2.x and on, MSRV changes will be accompanied by a minor version bump.
Breaking changes to SemVer-exempted components affecting the public API will be accompanied by some version bump.
Below are the specific policies:
Releases | Public API Component(s) | Policy |
---|---|---|
2.x | Dependenciesdigest ,pkcs8 andrand_core | Minor SemVer bump |
ed25519-dalek
is designed to prevent misuse. Signing is constant-time, all signing keys are zeroed when they go out of scope (unlesszeroize
is disabled), detached public keyscannot be used for signing, and extra functions likeVerifyingKey::verify_strict
are made available to avoid known gotchas.
Further, this crate has no—and in fact forbids—unsafe code. You can opt in to using some highly optimized unsafe code that resides incurve25519-dalek
, though. Seebelow for more information on backend selection.
Performance is a secondary goal behind correctness, safety, and clarity, but weaim to be competitive with other implementations.
Benchmarks are run usingcriterion.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"
On an Intel 10700K running at stock comparing between thecurve25519-dalek
backends.
Benchmark | u64 | simd +avx2 | fiat |
---|---|---|---|
signing | 15.017 µs | 13.906 µs -7.3967% | 15.877 μs +5.7268% |
signature verification | 40.144 µs | 25.963 µs -35.603% | 42.118 μs +4.9173% |
strict signature verification | 41.334 µs | 27.874 µs -32.660% | 43.985 μs +6.4136% |
batch signature verification/4 | 109.44 µs | 81.778 µs -25.079% | 117.80 μs +7.6389% |
batch signature verification/8 | 182.75 µs | 138.40 µs -23.871% | 195.86 μs +7.1737% |
batch signature verification/16 | 328.67 µs | 251.39 µs -23.744% | 351.55 μs +6.9614% |
batch signature verification/32 | 619.49 µs | 477.36 µs -23.053% | 669.41 μs +8.0582% |
batch signature verification/64 | 1.2136 ms | 936.85 µs -22.543% | 1.3028 ms +7.3500% |
batch signature verification/96 | 1.8677 ms | 1.2357 ms -33.936% | 2.0552 ms +10.039% |
batch signature verification/128 | 2.3281 ms | 1.5795 ms -31.996% | 2.5596 ms +9.9437% |
batch signature verification/256 | 4.1868 ms | 2.8864 ms -31.061% | 4.6494 μs +11.049% |
keypair generation | 13.973 µs | 13.108 µs -6.5062% | 15.099 μs +8.0584% |
If your protocol or application is able to batch signatures for verification,theverify_batch
function has greatly improved performance.
As you can see, there's an optimal batch size for each machine, so you'll likelywant to test the benchmarks on your target CPU to discover the best size.
Abackend refers to an implementation of elliptic curve and scalar arithmetic. Different backends have different use cases. For example, if you demand formally verified code, you want to use thefiat
backend (as it was generated fromFiat Crypto).
Backend selection details and instructions can be found in thecurve25519-dalek docs.
The standard variants of batch signature verification (i.e. many signatures made with potentially many different public keys over potentially many different messages) is available via thebatch
feature. It uses deterministic randomness, i.e., it hashes the inputs (usingmerlin
, which handles transcript item separation) and uses the result to generate random coefficients. Batch verification requires allocation, so this won't function in heapless settings.
Thevalidation criteria of a signature scheme are the criteria that signatures and public keys must satisfy in order to be accepted. Unfortunately, Ed25519 has some underspecified parts, leading to different validation criteria across implementations. For a very good overview of this, seeHenry's post.
In this section, we mention some specific details about our validation criteria, and how to navigate them.
A signature scheme is considered to producemalleable signatures if a passive attacker with knowledge of a public keyA, messagem, and valid signatureσ' can produce a distinctσ' such thatσ' is a valid signature ofm with respect toA. A scheme is only malleable if the attacker can do thiswithout knowledge of the private key corresponding toA.
ed25519-dalek
is not a malleable signature scheme.
Some other Ed25519 implementations are malleable, though, such aslibsodium withED25519_COMPAT
enabled,ed25519-donna,NaCl's ref10 impl, and probably a lot more.If you need to interoperate with such implementations and accept otherwise invalid signatures, you can enable thelegacy_compatibility
flag.Do not enablelegacy_compatibility
if you don't have to, because it will make your signatures malleable.
Note:CIRCL has no scalar range check at all. We do not have a feature flag for interoperating with the larger set of RFC-disallowed signatures that CIRCL accepts.
Asignature forgery is what it sounds like: it's when an attacker, given a public keyA, creates a signatureσ and messagem such thatσ is a valid signature ofm with respect toA. Since this is the core security definition of any signature scheme, Ed25519 signatures cannot be forged.
However, there's a much looser kind of forgery that Ed25519 permits, which we callweak key forgery. An attacker can produce a special public keyA (which we call aweak public key) and a signatureσ such thatσ is a valid signature ofany messagem, with respect toA, with high probability. This attack is acknowledged in theEd25519 paper, and caused an exploitable bug in the Scuttlebutt protocol (paper, section 7.1). TheVerifyingKey::verify()
function permits weak keys.
We provideVerifyingKey::verify_strict
(andverify_strict_prehashed
) to help users avoid these scenarios. These functions perform an extra check onA, ensuring it's not a weak public key. In addition, we provide theVerifyingKey::is_weak
to allow users to perform this check before attempting signature verification.
As mentioned above, weak public keys can be used to produce signatures for unknown messages with high probability. This means that sometimes a weak forgery attempt will fail. In fact, it can fail up to 7/8 of the time. If you callverify()
twice on the same failed forgery, it will return an error both times, as expected. However, if you callverify_batch()
twice on two distinct otherwise-valid batches, both of which contain the failed forgery, there's a 21% chance that one fails and the other succeeds.
Why is this? It's becauseverify_batch()
does not do the weak key testing ofverify_strict()
, and it multiplies each verification equation by some random coefficient. If the failed forgery gets multiplied by 8, then the weak key (which is a low-order point) becomes 0, and the verification equation on the attempted forgery will succeed.
Sinceverify_batch()
is intended to be high-throughput, we think it's best not to put weak key checks in it. If you want to prevent weird behavior due to weak public keys in your batches, you should callVerifyingKey::is_weak
on the inputs in advance.
About
Fast and efficient ed25519 signing and verification in Rust.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.