1use wasm_bindgen::prelude::*;
18use js_sys::Uint8Array;
19use getrandom::getrandom;
20use ed25519_dalek::{PublicKey, SecretKey, Signature, Verifier, ExpandedSecretKey};
21
22#[wasm_bindgen]
23pub fn generate_keypair() -> Result<js_sys::Object, JsValue> {
24 let mut seed = [0u8; 32];
26 getrandom(&mut seed).map_err(|e| JsValue::from_str(&format!("rng error: {}", e)))?;
27
28 let secret = SecretKey::from_bytes(&seed).map_err(|e| JsValue::from_str(&e.to_string()))?;
29 let public = PublicKey::from(&secret);
30
31 let sk_arr = Uint8Array::from(&secret.to_bytes()[..]);
32 let pk_arr = Uint8Array::from(&public.to_bytes()[..]);
33
34 let obj = js_sys::Object::new();
35 js_sys::Reflect::set(&obj, &JsValue::from_str("secretKey"), &sk_arr.into())?;
36 js_sys::Reflect::set(&obj, &JsValue::from_str("publicKey"), &pk_arr.into())?;
37
38 Ok(obj)
39}
40
41#[wasm_bindgen]
42pub fn sign(message: &[u8], secret_key: &[u8]) -> Result<Uint8Array, JsValue> {
43 if secret_key.len() != 32 {
44 return Err(JsValue::from_str("secret_key must be 32 bytes"));
45 }
46
47 let secret = SecretKey::from_bytes(secret_key).map_err(|e| JsValue::from_str(&e.to_string()))?;
48 let public = PublicKey::from(&secret);
49 let expanded = ExpandedSecretKey::from(&secret);
50
51 let sig: Signature = expanded.sign(message, &public);
52 Ok(Uint8Array::from(&sig.to_bytes()[..]))
53}
54
55#[wasm_bindgen]
56pub fn verify(message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<bool, JsValue> {
57 if signature.len() != 64 {
58 return Err(JsValue::from_str("signature must be 64 bytes"));
59 }
60 if public_key.len() != 32 {
61 return Err(JsValue::from_str("public_key must be 32 bytes"));
62 }
63
64 let sig = Signature::from_bytes(signature).map_err(|e| JsValue::from_str(&e.to_string()))?;
65 let public = PublicKey::from_bytes(public_key).map_err(|e| JsValue::from_str(&e.to_string()))?;
66
67 Ok(public.verify(message, &sig).is_ok())
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn sign_and_verify_roundtrip() {
76 let mut seed = [0u8; 32];
77 getrandom(&mut seed).expect("rng");
78 let secret = SecretKey::from_bytes(&seed).unwrap();
79 let public = PublicKey::from(&secret);
80 let message = b"hello wasm";
81
82 let expanded = ExpandedSecretKey::from(&secret);
83 let sig = expanded.sign(message, &public);
84
85 assert!(public.verify(message, &sig).is_ok());
86 }
87}