16 releases
0.2.9 | Apr 2, 2025 |
---|---|
0.2.8 | Mar 24, 2025 |
0.2.7 | May 19, 2024 |
0.2.6 | Jul 29, 2023 |
0.1.1 | Nov 13, 2019 |
#5 in #ecies
9,736 downloads per month
Used in 34 crates
(17 directly)
61KB
1K
SLoC
eciesrs
Elliptic Curve Integrated Encryption Scheme for secp256k1/curve25519 in Rust, based on pure-Rust secp256k1/curve25519 implementation.
ECIES functionalities are built upon AES-256-GCM/XChaCha20-Poly1305 and HKDF-SHA256.
This is the Rust version of eciesjs.
This library can be compiled to the WASM target at your option, see WASM compatibility.
Quick start
no_std
is enabled by default. You can enable std
with std
feature.
ecies = {version = "0.2", features = ["std"]} # MSRV is 1.65
use ecies::{decrypt, encrypt, utils::generate_keypair};
const MSG: &str = "hello world🌍";
let (sk, pk) = generate_keypair();
#[cfg(all(not(feature = "x25519"), not(feature = "ed25519")))]
let (sk, pk) = (&sk.serialize(), &pk.serialize());
#[cfg(feature = "x25519")]
let (sk, pk) = (sk.as_bytes(), pk.as_bytes());
#[cfg(feature = "ed25519")]
let (sk, pk) = (&sk, &pk);
let msg = MSG.as_bytes();
assert_eq!(
msg,
decrypt(sk, &encrypt(pk, msg).unwrap()).unwrap().as_slice()
);
Elliptic curve configuration
Optional x25519/ed25519 support
You can choose to use x25519 (key exchange function on curve25519) or ed25519 (signature algorithm on curve25519) instead of secp256k1:
ecies = {version = "0.2", features = ["x25519"]} # recommended
ecies = {version = "0.2", features = ["ed25519"]} # or if you know what you are doing
Secp256k1-specific configuration
Some behaviors can be configured by global static variable:
pub struct Config {
pub is_ephemeral_key_compressed: bool,
pub is_hkdf_key_compressed: bool
}
On is_ephemeral_key_compressed: true
, the payload would be like: 33 Bytes + AES
instead of 65 Bytes + AES
.
On is_hkdf_key_compressed: true
, the hkdf key would be derived from ephemeral public key (compressed) + shared public key (compressed)
instead of ephemeral public key (uncompressed) + shared public key (uncompressed)
.
use ecies::config::{Config, update_config};
update_config(Config {
is_ephemeral_key_compressed: true,
is_hkdf_key_compressed: true
});
For compatibility, make sure different applications share the same configuration. Normally configuration is only updated once on initialization, if not, beware of race condition.
Symmetric cipher configuration
Optional pure Rust AES backend
You can choose to use OpenSSL implementation or pure Rust implementation of AES-256-GCM:
ecies = {version = "0.2", default-features = false, features = ["aes-rust"]}
Due to some performance problem, OpenSSL is the default backend.
Pure Rust implementation is sometimes useful, such as building on WASM:
cargo build --no-default-features --features aes-rust --target=wasm32-unknown-unknown
Build on x86 CPUs
If you select the pure Rust backend on modern x86 CPUs, consider building with
RUSTFLAGS="-Ctarget-cpu=sandybridge -Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"
It can speed up AES encryption/decryption. This would be no longer necessary when aes-gcm
supports automatic CPU detection.
Build on ARM CPUs
On ARM CPUs (like Apple), consider building with
RUSTFLAGS="--cfg aes_armv8"
Optional pure Rust XChaCha20-Poly1305 backend
You can also enable a pure Rust XChaCha20-Poly1305 backend.
ecies = {version = "0.2", default-features = false, features = ["xchacha20"]}
On ARM CPUs, enable SIMD with
RUSTFLAGS="--cfg chacha20_force_neon"
WASM compatibility
It's also possible to build to the wasm32-unknown-unknown
target (or wasm32-wasip2
) with the pure Rust backend. Check out this repo for more details.
Security
Why AES-256-GCM and HKDF-SHA256
AEAD scheme like AES-256-GCM should be your first option for symmetric ciphers, with unique IVs in each encryption.
For key derivation functions on shared points between two asymmetric keys, HKDFs are proven to be more secure than simple hash functions like SHA256.
Why XChaCha20-Poly1305 instead of AES-256-GCM
XChaCha20-Poly1305 is a competitive alternative to AES-256-GCM because it's fast and constant-time without dedicated hardware acceleration (resistant to cache-timing attacks). It also has longer nonce length to alleviate the risk of birthday attacks when nonces are generated randomly.
Cross-language compatibility
All functionalities are mutually checked among different languages: Python, Rust, JavaScript and Golang.
Security audit
Following dependencies are audited:
Benchmark
On Mac mini M4 Pro (24 GB) on Apr 2, 2025, secp256k1 only.
Rust version: 1.85.0 (4d91de4e4 2025-02-17)
AES backend (OpenSSL)
$ cargo bench --no-default-features --features aes-openssl
encrypt 100M time: [29.237 ms 29.827 ms 30.628 ms]
Found 2 outliers among 10 measurements (20.00%)
1 (10.00%) low mild
1 (10.00%) high mild
encrypt 200M time: [86.005 ms 88.055 ms 89.282 ms]
decrypt 100M time: [17.222 ms 17.568 ms 17.977 ms]
Found 1 outliers among 10 measurements (10.00%)
1 (10.00%) high mild
decrypt 200M time: [38.884 ms 39.324 ms 39.693 ms]
Found 1 outliers among 10 measurements (10.00%)
1 (10.00%) high mild
AES backend (Pure Rust)
$ export RUSTFLAGS="--cfg aes_armv8"
$ cargo bench --no-default-features --features aes-rust
encrypt 100M time: [120.40 ms 122.63 ms 127.09 ms]
Found 1 outliers among 10 measurements (10.00%)
1 (10.00%) high severe
encrypt 200M time: [253.86 ms 256.43 ms 258.01 ms]
decrypt 100M time: [113.73 ms 114.05 ms 114.39 ms]
decrypt 200M time: [236.41 ms 237.82 ms 239.12 ms]
XChaCha20 backend
$ export RUSTFLAGS="--cfg chacha20_force_neon"
$ cargo bench --no-default-features --features xchacha20
encrypt 100M time: [120.24 ms 120.98 ms 121.63 ms]
encrypt 200M time: [257.24 ms 261.22 ms 264.06 ms]
decrypt 100M time: [114.39 ms 114.94 ms 116.03 ms]
decrypt 200M time: [238.09 ms 240.60 ms 242.55 ms]
Changelog
See CHANGELOG.md.
Dependencies
~3–10MB
~110K SLoC