1#[cfg(test)]
2mod tests;
3mod types;
4use std::str::FromStr;
5
6use aes_gcm::{
7 aead::{Aead, AeadCore, OsRng as AesRng},
8 Aes256Gcm, Key, KeyInit, Nonce,
9};
10use secp256k1_zkp::{
11 ecdh, rand::rngs::OsRng as Secp256k1Rng, verify_commitments_sum_to_equal, Generator, Message,
12 PedersenCommitment, PublicKey, Secp256k1, SecretKey,
13};
14use secp256k1_zkp::{ecdsa::Signature, Tweak};
15use secp256k1_zkp::{
16 hashes::{sha256, Hash},
17 Tag,
18};
19use wasm_bindgen::prelude::*;
20
21use types::{AesEncryptedData, Commitment, Did, EncodingType, EncryptedData, KeyPair};
22
23use base64::{engine::general_purpose::STANDARD, Engine as _};
24
25use crate::types::{AesEncryptedDataBytes, EncryptedDataBytes};
26
27#[wasm_bindgen]
28pub fn create_keypair() -> KeyPair {
29 let secp = Secp256k1::new();
30 let (secret_key, public_key) = secp.generate_keypair(&mut Secp256k1Rng);
31 KeyPair::new(
32 public_key.to_string(),
33 secret_key.display_secret().to_string(),
34 )
35}
36
37#[wasm_bindgen]
38pub fn key_to_did(pubkey: String) -> Did {
39 Did::new("did:hp:".to_owned() + &pubkey)
40}
41
42#[wasm_bindgen]
43pub fn did_to_key(did: Did) -> Result<String, JsError> {
44 did.id()
45 .strip_prefix("did:hp:")
46 .map(|s| s.to_string())
47 .ok_or_else(|| JsError::new("Invalid DID format: missing did:hp: prefix"))
48}
49
50#[wasm_bindgen]
51pub fn encrypt(
52 data: String,
53 pubkey: String,
54 encoding_type: EncodingType,
55) -> Result<EncryptedData, JsError> {
56 let secp = Secp256k1::new();
57 let (secret_key, public_key) = secp.generate_keypair(&mut Secp256k1Rng);
59 let encrypt_to_pubkey = secp256k1_zkp::PublicKey::from_str(&pubkey)
61 .map_err(|e| JsError::new(&format!("Invalid public key: {}", e)))?;
62 let shared_secret = ecdh::SharedSecret::new(&encrypt_to_pubkey, &secret_key).secret_bytes();
64
65 let aes_encrypted_data = encrypt_aes(data, hex::encode(&shared_secret), encoding_type)?;
66
67 Ok(EncryptedData::new(
68 public_key.to_string(),
69 pubkey,
70 aes_encrypted_data.data(),
71 aes_encrypted_data.nonce(),
72 ))
73}
74
75#[wasm_bindgen]
76pub fn decrypt(
77 data: EncryptedData,
78 privkey: String,
79 encoding_type: EncodingType,
80) -> Result<String, JsError> {
81 let encrypt_from_pubkey = secp256k1_zkp::PublicKey::from_str(&data.pubkey_from())
83 .map_err(|e| JsError::new(&format!("Invalid public key in data: {}", e)))?;
84 let privkey_to_decrypt = secp256k1_zkp::SecretKey::from_str(&privkey)
86 .map_err(|e| JsError::new(&format!("Invalid private key: {}", e)))?;
87 let shared_secret =
89 ecdh::SharedSecret::new(&encrypt_from_pubkey, &privkey_to_decrypt).secret_bytes();
90
91 decrypt_aes(
92 AesEncryptedData::new(data.data(), data.nonce()),
93 hex::encode(&shared_secret),
94 encoding_type,
95 )
96}
97
98#[wasm_bindgen]
99pub fn encrypt_aes(
100 data: String,
101 key: String,
102 encoding_type: EncodingType,
103) -> Result<AesEncryptedData, JsError> {
104 let hex_key =
106 hex::decode(key).map_err(|e| JsError::new(&format!("Key is malformed: {}", e)))?;
107 let aes_key = Key::<Aes256Gcm>::from_slice(&hex_key);
108 let cipher = Aes256Gcm::new(&aes_key);
109 let nonce = Aes256Gcm::generate_nonce(&mut AesRng); let data_bytes_vec;
112 let data_bytes: &[u8] = match encoding_type {
113 EncodingType::UTF8 => data.as_bytes(),
114 EncodingType::HEX => {
115 data_bytes_vec = hex::decode(data)
116 .map_err(|e| JsError::new(&format!("Wrong hex format data: {}", e)))?;
117 &data_bytes_vec
118 }
119 EncodingType::BASE64 => {
120 data_bytes_vec = STANDARD
121 .decode(data)
122 .map_err(|e| JsError::new(&format!("Wrong base64 format data: {}", e)))?;
123 &data_bytes_vec
124 }
125 };
126 let ciphertext = cipher
127 .encrypt(&nonce, data_bytes)
128 .map_err(|e| JsError::new(&format!("AES encryption failed: {}", e)))?;
129 Ok(AesEncryptedData::new(
130 hex::encode(&ciphertext),
131 hex::encode(&nonce),
132 ))
133}
134#[wasm_bindgen]
135pub fn decrypt_aes(
136 data: AesEncryptedData,
137 key: String,
138 encoding_type: EncodingType,
139) -> Result<String, JsError> {
140 let hex_key =
142 hex::decode(key).map_err(|e| JsError::new(&format!("Key is malformed: {}", e)))?;
143 let aes_key = Key::<Aes256Gcm>::from_slice(&hex_key);
144 let decipher = Aes256Gcm::new(&aes_key);
145 let nonce_bytes =
147 hex::decode(&data.nonce()).map_err(|e| JsError::new(&format!("Invalid nonce: {}", e)))?;
148 let nonce = Nonce::from_slice(&nonce_bytes);
149 let data_bytes =
151 hex::decode(&data.data()).map_err(|e| JsError::new(&format!("Invalid data: {}", e)))?;
152 let decrypted_data = decipher
153 .decrypt(&nonce, data_bytes.as_slice())
154 .map_err(|e| JsError::new(&format!("AES decryption failed: {}", e)))?;
155
156 match encoding_type {
157 EncodingType::UTF8 => String::from_utf8(decrypted_data)
158 .map_err(|e| JsError::new(&format!("Wrong utf8 format data: {}", e))),
159 EncodingType::HEX => Ok(hex::encode(decrypted_data)),
160 EncodingType::BASE64 => Ok(STANDARD.encode(decrypted_data)),
161 }
162}
163
164#[wasm_bindgen]
165pub fn sign(data: String, privkey: String) -> Result<String, JsError> {
166 let secp = Secp256k1::new();
167 let digest = sha256::Hash::hash(data.as_bytes());
168 let message = Message::from_digest(digest.to_byte_array());
169 let secret_key = SecretKey::from_str(&privkey)
170 .map_err(|e| JsError::new(&format!("Invalid private key: {}", e)))?;
171
172 Ok(secp.sign_ecdsa(&message, &secret_key).to_string())
173}
174#[wasm_bindgen]
175pub fn verify(data: String, sig: String, pubkey: String) -> Result<bool, JsError> {
176 let secp = Secp256k1::new();
177 let digest = sha256::Hash::hash(data.as_bytes());
178 let message = Message::from_digest(digest.to_byte_array());
179 let signature = Signature::from_str(&sig)
180 .map_err(|e| JsError::new(&format!("Invalid signature: {}", e)))?;
181 let public_key = PublicKey::from_str(&pubkey)
182 .map_err(|e| JsError::new(&format!("Invalid public key: {}", e)))?;
183
184 match secp.verify_ecdsa(&message, &signature, &public_key) {
185 Ok(_) => Ok(true),
186 Err(_) => Ok(false),
187 }
188}
189#[wasm_bindgen]
190pub fn sha256(data: String) -> String {
191 sha256::Hash::hash(data.as_bytes()).to_string()
192}
193#[wasm_bindgen]
194pub fn ecdh(privkey: String, pubkey: String) -> Result<String, JsError> {
195 let alice = secp256k1_zkp::SecretKey::from_str(&privkey)
197 .map_err(|e| JsError::new(&format!("Invalid private key: {}", e)))?;
198 let bob = secp256k1_zkp::PublicKey::from_str(&pubkey)
200 .map_err(|e| JsError::new(&format!("Invalid public key: {}", e)))?;
201 let shared_secret = ecdh::SharedSecret::new(&bob, &alice);
203 Ok(shared_secret.display_secret().to_string())
204}
205#[wasm_bindgen]
210pub fn pedersen_commit(value: u64, tag: String) -> Commitment {
211 let secp = Secp256k1::new();
212 let blinding_factor = Tweak::new(&mut Secp256k1Rng);
213 let tag = Tag::from(sha256::Hash::hash(tag.as_bytes()).to_byte_array());
214 Commitment::new(
215 PedersenCommitment::new(
216 &secp,
217 value,
218 blinding_factor,
219 Generator::new_unblinded(&secp, tag),
226 )
227 .to_string(),
228 blinding_factor.to_string(),
229 )
230}
231#[wasm_bindgen]
233pub fn pedersen_reveal(commitment: Commitment, value: u64, tag: String) -> Result<bool, JsError> {
234 let secp = Secp256k1::new();
235 let blinding_factor = Tweak::from_str(&commitment.secret_blinding_factor())
236 .map_err(|e| JsError::new(&format!("Wrong blinding factor: {}", e)))?;
237 let tag = Tag::from(sha256::Hash::hash(tag.as_bytes()).to_byte_array());
238
239 let commitment_obj = PedersenCommitment::from_str(&commitment.commitment())
240 .map_err(|e| JsError::new(&format!("Wrong commitment: {}", e)))?;
241
242 Ok(verify_commitments_sum_to_equal(
243 &secp,
244 &vec![PedersenCommitment::new(
245 &secp,
246 value,
247 blinding_factor,
248 Generator::new_unblinded(&secp, tag),
255 )],
256 &vec![commitment_obj],
257 ))
258}
259
260#[wasm_bindgen]
261pub fn sha256_bytes(data: Vec<u8>) -> Vec<u8> {
262 sha256::Hash::hash(&data).to_byte_array().to_vec()
263}
264
265#[wasm_bindgen]
266pub fn encrypt_bytes(data: Vec<u8>, pubkey: String) -> Result<EncryptedDataBytes, JsError> {
267 let secp = Secp256k1::new();
268 let (secret_key, public_key) = secp.generate_keypair(&mut Secp256k1Rng);
270 let encrypt_to_pubkey = secp256k1_zkp::PublicKey::from_str(&pubkey)
272 .map_err(|e| JsError::new(&format!("Invalid public key: {}", e)))?;
273 let shared_secret = ecdh::SharedSecret::new(&encrypt_to_pubkey, &secret_key).secret_bytes();
275
276 let aes_encrypted_data = encrypt_aes_bytes(data, hex::encode(&shared_secret))?;
277
278 Ok(EncryptedDataBytes::new(
279 public_key.to_string(),
280 pubkey,
281 aes_encrypted_data.data(),
282 aes_encrypted_data.nonce(),
283 ))
284}
285
286#[wasm_bindgen]
287pub fn decrypt_bytes(data: EncryptedDataBytes, privkey: String) -> Result<Vec<u8>, JsError> {
288 let encrypt_from_pubkey = secp256k1_zkp::PublicKey::from_str(&data.pubkey_from())
290 .map_err(|e| JsError::new(&format!("Invalid public key in data: {}", e)))?;
291 let privkey_to_decrypt = secp256k1_zkp::SecretKey::from_str(&privkey)
293 .map_err(|e| JsError::new(&format!("Invalid private key: {}", e)))?;
294 let shared_secret =
296 ecdh::SharedSecret::new(&encrypt_from_pubkey, &privkey_to_decrypt).secret_bytes();
297
298 decrypt_aes_bytes(
299 AesEncryptedDataBytes::new(data.data(), data.nonce()),
300 hex::encode(&shared_secret),
301 )
302}
303
304#[wasm_bindgen]
305pub fn encrypt_aes_bytes(data: Vec<u8>, key: String) -> Result<AesEncryptedDataBytes, JsError> {
306 let hex_key =
308 hex::decode(key).map_err(|e| JsError::new(&format!("Key is malformed: {}", e)))?;
309 let aes_key = Key::<Aes256Gcm>::from_slice(&hex_key);
310 let cipher = Aes256Gcm::new(&aes_key);
311 let nonce = Aes256Gcm::generate_nonce(&mut AesRng); let ciphertext = cipher
315 .encrypt(&nonce, &*data)
316 .map_err(|e| JsError::new(&format!("AES encryption failed: {}", e)))?;
317 Ok(AesEncryptedDataBytes::new(ciphertext, nonce.to_vec()))
318}
319#[wasm_bindgen]
320pub fn decrypt_aes_bytes(data: AesEncryptedDataBytes, key: String) -> Result<Vec<u8>, JsError> {
321 let hex_key =
323 hex::decode(key).map_err(|e| JsError::new(&format!("Key is malformed: {}", e)))?;
324 let aes_key = Key::<Aes256Gcm>::from_slice(&hex_key);
325 let decipher = Aes256Gcm::new(&aes_key);
326
327 decipher
328 .decrypt(
329 Nonce::from_slice(data.nonce().as_slice()),
330 data.data().as_slice(),
331 )
332 .map_err(|e| JsError::new(&format!("AES decryption failed: {}", e)))
333}
334
335#[wasm_bindgen(start)]
336pub fn init_panic_hook() -> Result<(), JsValue> {
337 console_error_panic_hook::set_once();
338 Ok(())
339}