1use secp256k1::{util::FULL_PUBLIC_KEY_SIZE, Error as SecpError, PublicKey, SecretKey};
2
3pub mod utils;
4
5use utils::{aes_decrypt, aes_encrypt, decapsulate, encapsulate, generate_keypair};
6
7pub fn encrypt(receiver_pub: &[u8], msg: &[u8]) -> Result<Vec<u8>, SecpError> {
8 let receiver_pk = PublicKey::parse_slice(receiver_pub, None)?;
9 let (ephemeral_sk, ephemeral_pk) = generate_keypair();
10
11 let aes_key = encapsulate(&ephemeral_sk, &receiver_pk);
12 let encrypted = aes_encrypt(&aes_key, msg).ok_or(SecpError::InvalidMessage)?;
13
14 let mut cipher_text = Vec::with_capacity(FULL_PUBLIC_KEY_SIZE + encrypted.len());
15 cipher_text.extend(ephemeral_pk.serialize().iter());
16 cipher_text.extend(encrypted);
17
18 Ok(cipher_text)
19}
20
21pub fn decrypt(receiver_sec: &[u8], msg: &[u8]) -> Result<Vec<u8>, SecpError> {
22 let receiver_sk = SecretKey::parse_slice(receiver_sec)?;
23
24 if msg.len() < FULL_PUBLIC_KEY_SIZE {
25 return Err(SecpError::InvalidMessage);
26 }
27
28 let ephemeral_pk = PublicKey::parse_slice(&msg[..FULL_PUBLIC_KEY_SIZE], None)?;
29 let encrypted = &msg[FULL_PUBLIC_KEY_SIZE..];
30
31 let aes_key = decapsulate(&ephemeral_pk, &receiver_sk);
32
33 aes_decrypt(&aes_key, encrypted).ok_or(SecpError::InvalidMessage)
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39 use hex::encode;
40 use utils::{decode_hex, generate_keypair};
41
42 const PYTHON_BACKEND: &str = "https://eciespy.herokuapp.com/";
43 const MSG: &str = "helloworld";
44
45 const BIG_MSG_SIZE: usize = 100 * 1024 * 1024;
46 const BIG_MSG: [u8; BIG_MSG_SIZE] = [1u8; BIG_MSG_SIZE]; fn test_enc_dec(sk: &[u8], pk: &[u8]) {
49 let msg = MSG.as_bytes();
50 assert_eq!(msg, decrypt(sk, &encrypt(pk, msg).unwrap()).unwrap().as_slice());
51
52 let msg = &BIG_MSG;
53 assert_eq!(msg.to_vec(), decrypt(sk, &encrypt(pk, msg).unwrap()).unwrap());
54 }
55
56 #[test]
57 fn attempts_to_decrypt_with_another_key() {
58 let (_, pk1) = generate_keypair();
59
60 let (sk2, _) = generate_keypair();
61
62 assert_eq!(
63 decrypt(
64 &sk2.serialize(),
65 encrypt(&pk1.serialize_compressed(), b"text").unwrap().as_slice()
66 ),
67 Err(SecpError::InvalidMessage)
68 );
69 }
70
71 #[test]
72 fn attempts_to_decrypt_incorrect_message() {
73 let (sk, _) = generate_keypair();
74
75 assert_eq!(decrypt(&sk.serialize(), &[]), Err(SecpError::InvalidMessage));
76
77 assert_eq!(decrypt(&sk.serialize(), &[0u8; 65]), Err(SecpError::InvalidPublicKey));
78 }
79
80 #[test]
81 fn attempts_to_encrypt_with_invalid_key() {
82 assert_eq!(encrypt(&[0u8; 33], b"text"), Err(SecpError::InvalidPublicKey));
83 }
84
85 #[test]
86 fn test_compressed_public() {
87 let (sk, pk) = generate_keypair();
88 let (sk, pk) = (&sk.serialize(), &pk.serialize_compressed());
89 test_enc_dec(sk, pk);
90 }
91
92 #[test]
93 fn test_uncompressed_public() {
94 let (sk, pk) = generate_keypair();
95 let (sk, pk) = (&sk.serialize(), &pk.serialize());
96 test_enc_dec(sk, pk);
97 }
98
99 #[test]
100 fn test_against_python() {
101 use futures_util::FutureExt;
102 use tokio::runtime::Runtime;
103
104 let mut rt = Runtime::new().unwrap();
105
106 let (sk, pk) = generate_keypair();
107
108 let sk_hex = encode(&sk.serialize().to_vec());
109 let uncompressed_pk = &pk.serialize();
110 let pk_hex = encode(uncompressed_pk.to_vec());
111
112 let client = reqwest::Client::new();
113 let params = [("data", MSG), ("pub", pk_hex.as_str())];
114 let res = rt
115 .block_on(
116 client
117 .post(PYTHON_BACKEND)
118 .form(¶ms)
119 .send()
120 .then(|r| r.unwrap().text()),
121 )
122 .unwrap();
123
124 let server_encrypted = decode_hex(&res);
125 let local_decrypted = decrypt(&sk.serialize(), server_encrypted.as_slice()).unwrap();
126 assert_eq!(local_decrypted, MSG.as_bytes());
127
128 let local_encrypted = encrypt(uncompressed_pk, MSG.as_bytes()).unwrap();
129 let params = [("data", encode(local_encrypted)), ("prv", sk_hex)];
130
131 let res = rt
132 .block_on(
133 client
134 .post(PYTHON_BACKEND)
135 .form(¶ms)
136 .send()
137 .then(|r| r.unwrap().text()),
138 )
139 .unwrap();
140
141 assert_eq!(res, MSG);
142 }
143}