Skip to content

Commit 947eeb6

Browse files
authored
Add compressed argument to encapsulate/decapsulate functions (#141)
1 parent 06a7171 commit 947eeb6

File tree

7 files changed

+43
-35
lines changed

7 files changed

+43
-35
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 0.2.10
4+
5+
- Add homemade rwlock for `no_std`
6+
- Add `zeroize` feature for x25519/ed25519
7+
- Add `compressed` argument to encapsulate/decapsulate functions
8+
- Note: this might break a little of client code but can be easily fixed
9+
310
## 0.2.9
411

512
- Add ed25519 support

Cargo.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ecies"
3-
version = "0.2.9"
3+
version = "0.2.10"
44
# docs
55
authors = ["Weiliang Li <to.be.impressive@gmail.com>"]
66
description = "Elliptic Curve Integrated Encryption Scheme for secp256k1"
@@ -31,7 +31,7 @@ curve25519-dalek = { version = "4.1.3", default-features = false, features = [
3131
x25519-dalek = { version = "2.0.1", default-features = false, features = [
3232
"static_secrets",
3333
], optional = true }
34-
ed25519-dalek = { version = "~2.1.1", default-features = false, optional = true }
34+
ed25519-dalek = { version = "~2.1.1", default-features = false, optional = true } # msrv 1.60
3535

3636
# symmetric ciphers
3737
# aes (openssl)
@@ -49,7 +49,7 @@ hkdf = { version = "0.12.4", default-features = false }
4949
sha2 = { version = "0.10.8", default-features = false }
5050

5151
# random number generator
52-
getrandom = { version = "0.2.15", default-features = false }
52+
getrandom = { version = "0.2.16", default-features = false }
5353
rand_core = { version = "0.6.4", default-features = false, features = [
5454
"getrandom",
5555
] }
@@ -63,9 +63,9 @@ parking_lot = { version = "=0.12.4", optional = true } # msrv 1.64
6363

6464
[target.'cfg(all(target_arch = "wasm32", target_os="unknown"))'.dependencies]
6565
# only for js (browser or node). if it's not js, like substrate, it won't build
66-
getrandom = { version = "0.2.15", default-features = false, features = ["js"] }
66+
getrandom = { version = "0.2.16", default-features = false, features = ["js"] }
6767
once_cell = { version = "1.21.3", default-features = false, features = ["std"] }
68-
wasm-bindgen = { version = "0.2.100", default-features = false }
68+
wasm-bindgen = { version = "0.2.104", default-features = false }
6969

7070
[target.'cfg(all(target_arch = "wasm32", not(target_os="unknown")))'.dependencies]
7171
# for wasm32-wasip2
@@ -108,7 +108,7 @@ wasm-bindgen-test = "0.3.54"
108108
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
109109
futures-util = "0.3.31"
110110
reqwest = "0.12.23"
111-
tokio = { version = "1.44.1", default-features = false, features = [
111+
tokio = { version = "1.47.1", default-features = false, features = [
112112
"rt-multi-thread",
113113
] }
114114

src/elliptic/ed25519.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ pub fn generate_keypair() -> (SecretKey, PublicKey) {
3737
}
3838

3939
/// Calculate a shared symmetric key of our secret key and peer's public key by hkdf
40-
pub fn encapsulate(sk: &SecretKey, peer_pk: &PublicKey) -> Result<SharedSecret, Error> {
40+
pub fn encapsulate(sk: &SecretKey, peer_pk: &PublicKey, _compressed: bool) -> Result<SharedSecret, Error> {
4141
let sender_point = to_public_key(sk).to_bytes();
4242
let shared_point = multiply(sk, peer_pk)?;
4343
Ok(hkdf_derive(&sender_point, shared_point.compress().as_bytes()))
4444
}
4545

4646
/// Calculate a shared symmetric key of our public key and peer's secret key by hkdf
47-
pub fn decapsulate(pk: &PublicKey, peer_sk: &SecretKey) -> Result<SharedSecret, Error> {
47+
pub fn decapsulate(pk: &PublicKey, peer_sk: &SecretKey, _compressed: bool) -> Result<SharedSecret, Error> {
4848
let shared_point = multiply(peer_sk, pk)?;
4949
Ok(hkdf_derive(pk, shared_point.compress().as_bytes()))
5050
}

src/elliptic/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ mod tests {
2727
fn test_key_exchange() {
2828
let (sk1, pk1) = generate_keypair();
2929
let (sk2, pk2) = generate_keypair();
30-
assert_eq!(encapsulate(&sk2, &pk1).unwrap(), decapsulate(&pk2, &sk1).unwrap());
30+
assert_eq!(
31+
encapsulate(&sk2, &pk1, false).unwrap(),
32+
decapsulate(&pk2, &sk1, false).unwrap()
33+
);
3134
}
3235
}

src/elliptic/secp256k1.rs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use rand_core::OsRng;
33
pub use libsecp256k1::{Error, PublicKey, SecretKey};
44

55
use crate::compat::Vec;
6-
use crate::config::is_hkdf_key_compressed;
76
use crate::consts::SharedSecret;
87
use crate::symmetric::hkdf_derive;
98

@@ -15,20 +14,18 @@ pub fn generate_keypair() -> (SecretKey, PublicKey) {
1514
}
1615

1716
/// Calculate a shared symmetric key of our secret key and peer's public key by hkdf
18-
pub fn encapsulate(sk: &SecretKey, peer_pk: &PublicKey) -> Result<SharedSecret, Error> {
17+
pub fn encapsulate(sk: &SecretKey, peer_pk: &PublicKey, compressed: bool) -> Result<SharedSecret, Error> {
1918
let mut shared_point = *peer_pk;
2019
shared_point.tweak_mul_assign(sk)?;
2120
let sender_point = &PublicKey::from_secret_key(sk);
22-
// TODO: move compressed: bool to arg
23-
Ok(get_shared_secret(sender_point, &shared_point, is_hkdf_key_compressed()))
21+
Ok(get_shared_secret(sender_point, &shared_point, compressed))
2422
}
2523

2624
/// Calculate a shared symmetric key of our public key and peer's secret key by hkdf
27-
pub fn decapsulate(pk: &PublicKey, peer_sk: &SecretKey) -> Result<SharedSecret, Error> {
25+
pub fn decapsulate(pk: &PublicKey, peer_sk: &SecretKey, compressed: bool) -> Result<SharedSecret, Error> {
2826
let mut shared_point = *pk;
2927
shared_point.tweak_mul_assign(peer_sk)?;
30-
// TODO: move compressed: bool to arg
31-
Ok(get_shared_secret(pk, &shared_point, is_hkdf_key_compressed()))
28+
Ok(get_shared_secret(pk, &shared_point, compressed))
3229
}
3330

3431
/// Parse secret key bytes
@@ -105,9 +102,14 @@ mod known_tests {
105102
let pk3 = PublicKey::from_secret_key(&sk3);
106103

107104
assert_eq!(
108-
encapsulate(&sk2, &pk3).unwrap().to_vec(),
105+
encapsulate(&sk2, &pk3, false).unwrap().to_vec(),
109106
decode_hex("6f982d63e8590c9d9b5b4c1959ff80315d772edd8f60287c9361d548d5200f82")
110107
);
108+
109+
assert_eq!(
110+
encapsulate(&sk2, &pk3, true).unwrap().to_vec(),
111+
decode_hex("b192b226edb3f02da11ef9c6ce4afe1c7e40be304e05ae3b988f4834b1cb6c69")
112+
);
111113
}
112114

113115
#[cfg(all(not(feature = "xchacha20"), not(feature = "aes-short-nonce")))]
@@ -212,32 +214,28 @@ mod error_tests {
212214

213215
#[cfg(test)]
214216
mod config_tests {
215-
use super::known_tests::get_sk;
216-
use super::{encapsulate, generate_keypair, PublicKey};
217+
use super::generate_keypair;
217218

218219
use crate::config::{reset_config, update_config, Config};
219-
use crate::utils::tests::decode_hex;
220-
use crate::{decrypt, encrypt};
220+
use crate::{decrypt, encrypt, Error};
221221

222222
const MSG: &str = "helloworld🌍";
223223

224224
#[test]
225-
pub fn test_known_hkdf_config() {
226-
let sk2 = get_sk(2);
227-
let sk3 = get_sk(3);
228-
let pk3 = PublicKey::from_secret_key(&sk3);
225+
pub fn test_hkdf_key_config() {
226+
let (sk, pk) = generate_keypair();
227+
let (sk, pk) = (&sk.serialize(), &pk.serialize_compressed());
229228

230229
update_config(Config {
231230
is_hkdf_key_compressed: true,
232231
..Config::default()
233232
});
234233

235-
assert_eq!(
236-
encapsulate(&sk2, &pk3).unwrap().to_vec(),
237-
decode_hex("b192b226edb3f02da11ef9c6ce4afe1c7e40be304e05ae3b988f4834b1cb6c69")
238-
);
234+
let encrypted = encrypt(pk, MSG.as_bytes()).unwrap();
235+
assert_eq!(MSG.as_bytes(), &decrypt(sk, &encrypted).unwrap());
239236

240237
reset_config();
238+
assert_eq!(decrypt(sk, &encrypted).unwrap_err(), Error::InvalidMessage);
241239
}
242240

243241
#[test]
@@ -277,8 +275,8 @@ mod wasm_tests {
277275

278276
#[wasm_bindgen_test]
279277
fn test_config() {
278+
super::config_tests::test_hkdf_key_config();
280279
super::config_tests::test_ephemeral_key_config();
281-
super::config_tests::test_known_hkdf_config();
282280
}
283281

284282
#[wasm_bindgen_test]

src/elliptic/x25519.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ pub fn generate_keypair() -> (SecretKey, PublicKey) {
3030
}
3131

3232
/// Calculate a shared symmetric key of our secret key and peer's public key by hkdf
33-
pub fn encapsulate(sk: &SecretKey, peer_pk: &PublicKey) -> Result<SharedSecret, Error> {
33+
pub fn encapsulate(sk: &SecretKey, peer_pk: &PublicKey, _compressed: bool) -> Result<SharedSecret, Error> {
3434
let shared_point = sk.diffie_hellman(peer_pk);
3535
let sender_point = PublicKey::from(sk);
3636
Ok(hkdf_derive(sender_point.as_bytes(), shared_point.as_bytes()))
3737
}
3838

3939
/// Calculate a shared symmetric key of our public key and peer's secret key by hkdf
40-
pub fn decapsulate(pk: &PublicKey, peer_sk: &SecretKey) -> Result<SharedSecret, Error> {
40+
pub fn decapsulate(pk: &PublicKey, peer_sk: &SecretKey, _compressed: bool) -> Result<SharedSecret, Error> {
4141
let shared_point = peer_sk.diffie_hellman(pk);
4242
Ok(hkdf_derive(pk.as_bytes(), shared_point.as_bytes()))
4343
}

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mod elliptic;
2222
#[cfg(not(feature = "std"))]
2323
mod sync;
2424

25-
use config::{get_ephemeral_key_size, is_ephemeral_key_compressed};
25+
use config::{get_ephemeral_key_size, is_ephemeral_key_compressed, is_hkdf_key_compressed};
2626
use elliptic::{decapsulate, encapsulate, generate_keypair, parse_pk, parse_sk, pk_to_vec, Error};
2727
use symmetric::{sym_decrypt, sym_encrypt};
2828

@@ -39,7 +39,7 @@ pub fn encrypt(receiver_pub: &[u8], msg: &[u8]) -> Result<Vec<u8>, Error> {
3939
let receiver_pk = parse_pk(receiver_pub)?;
4040
let (ephemeral_sk, ephemeral_pk) = generate_keypair();
4141

42-
let sym_key = encapsulate(&ephemeral_sk, &receiver_pk)?;
42+
let sym_key = encapsulate(&ephemeral_sk, &receiver_pk, is_hkdf_key_compressed())?;
4343
let encrypted = sym_encrypt(&sym_key, msg).ok_or(Error::InvalidMessage)?;
4444

4545
let is_compressed = is_ephemeral_key_compressed();
@@ -71,6 +71,6 @@ pub fn decrypt(receiver_sec: &[u8], msg: &[u8]) -> Result<Vec<u8>, Error> {
7171
let ephemeral_pk = parse_pk(&msg[..key_size])?;
7272
let encrypted = &msg[key_size..];
7373

74-
let sym_key = decapsulate(&ephemeral_pk, &receiver_sk)?;
74+
let sym_key = decapsulate(&ephemeral_pk, &receiver_sk, is_hkdf_key_compressed())?;
7575
sym_decrypt(&sym_key, encrypted).ok_or(Error::InvalidMessage)
7676
}

0 commit comments

Comments
 (0)