spawn_wasm_ecdsa/
lib.rs

1use wasm_bindgen::prelude::*;
2use wasm_bindgen::JsValue;
3use serde::{Serialize, Deserialize};
4use sha2::{Sha256, Digest}; // SHA-256 for hashing
5use k256::ecdsa::{Signature, VerifyingKey};
6use web_sys::console;
7use k256::ecdsa::signature::Verifier;  // `Verifier` trait'ini ekledik
8
9/// Enum representing possible ECDSA errors
10/// Provides detailed feedback during signature verification failure.
11#[derive(Debug, Serialize, Deserialize)]
12pub enum ECDSAError {
13    InvalidSignatureFormat,
14    InvalidSignatureLength,
15    InvalidSignatureRecovery,
16    InvalidPublicKey,
17}
18
19impl std::fmt::Display for ECDSAError {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        match *self {
22            ECDSAError::InvalidSignatureFormat => write!(f, "Invalid signature format"),
23            ECDSAError::InvalidSignatureLength => write!(f, "Invalid signature length"),
24            ECDSAError::InvalidSignatureRecovery => write!(f, "Failed to recover public key"),
25            ECDSAError::InvalidPublicKey => write!(f, "Invalid public key"),
26        }
27    }
28}
29
30/// Struct for ECDSA signature verification using k256 crate.
31#[wasm_bindgen]
32pub struct ECDSAVerifier;
33
34#[wasm_bindgen]
35impl ECDSAVerifier {
36    /// Initializes a new instance of ECDSAVerifier.
37    #[wasm_bindgen(constructor)]
38    pub fn new() -> ECDSAVerifier {
39        ECDSAVerifier
40    }
41
42    /// Verifies a signature using a message, signature, and public key.
43    /// 
44    /// # Arguments:
45    /// * `message` - The message that was signed.
46    /// * `signature` - The digital signature to verify, provided as a hex string.
47    /// * `public_key` - The signer's public key, provided as a hex string.
48    /// 
49    /// # Returns:
50    /// * A boolean indicating whether the signature is valid or not.
51    /// 
52    /// # Errors:
53    /// * Returns a descriptive error if the signature format is invalid, or the signature fails verification.
54    pub fn verify_signature(
55        &self,
56        message: &str,
57        signature: &str,
58        public_key: &str,
59    ) -> Result<bool, JsValue> {
60        // Log the verification process
61        console::log_1(&"Starting signature verification...".into());
62
63        // Hash the input message using SHA-256
64        let msg_hash = self.hash_message(message);
65
66        // Decode the signature and public key from hex and check for length errors
67        let signature_bytes = hex::decode(signature).map_err(|_| JsValue::from_str("Invalid signature format"))?;
68        if signature_bytes.len() != 64 {
69            return Err(JsValue::from_str("Signature length is invalid"));
70        }
71
72        let pubkey_bytes = hex::decode(public_key).map_err(|_| JsValue::from_str("Invalid public key format"))?;
73        if pubkey_bytes.len() != 33 {
74            return Err(JsValue::from_str("Public key length is invalid"));
75        }
76
77        // Convert the message hash, signature, and public key into appropriate types
78        let sig = Signature::from_der(&signature_bytes).map_err(|_| JsValue::from_str("Invalid signature"))?;
79        let pubkey = VerifyingKey::from_sec1_bytes(&pubkey_bytes).map_err(|_| JsValue::from_str("Invalid public key"))?;
80
81        // Perform the signature verification using k256
82        pubkey.verify(&msg_hash, &sig).map_err(|e| JsValue::from_str(&e.to_string()))?;
83
84        console::log_1(&"Verification complete.".into());
85
86        Ok(true)
87    }
88
89    /// Hashes the message using SHA-256.
90    /// This function is used internally to prepare the message for signature verification.
91    pub fn hash_message(&self, message: &str) -> Vec<u8> {
92        let mut hasher = Sha256::new();
93        hasher.update(message.as_bytes());
94        hasher.finalize().to_vec() // Return the resulting hash
95    }
96}
97
98/// Unit tests for ECDSAVerifier.
99/// These tests cover valid signature verification, invalid signatures, and incorrect public keys.
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn test_verify_signature() {
106        let verifier = ECDSAVerifier::new();
107        let message = "Test message";
108        let signature = "3045022100ebf...";  // Mock signature for testing
109        let public_key = "03a0...";  // Mock public key for testing
110
111        let result = verifier.verify_signature(message, signature, public_key);
112        assert!(result.is_ok());
113        assert!(result.unwrap());
114    }
115
116    #[test]
117    fn test_invalid_signature() {
118        let verifier = ECDSAVerifier::new();
119        let message = "Test message";
120        let invalid_signature = "invalid_sig";
121        let public_key = "03a0...";  // Mock public key for testing
122
123        let result = verifier.verify_signature(message, invalid_signature, public_key);
124        assert!(result.is_err());
125    }
126
127    #[test]
128    fn test_invalid_public_key() {
129        let verifier = ECDSAVerifier::new();
130        let message = "Test message";
131        let signature = "3045022100ebf...";  // Mock signature for testing
132        let invalid_public_key = "invalid_pubkey";
133
134        let result = verifier.verify_signature(message, signature, invalid_public_key);
135        assert!(result.is_err());
136    }
137}