saa_auth/eth/
eth.rs

1
2use saa_common::{CredentialId, AuthError, Binary, String, ToString, Verifiable };
3use saa_schema::saa_type;
4
5#[cfg(any(feature = "wasm", feature = "native"))]
6use  {
7    super::utils::{get_recovery_param, preamble_msg_eth},
8    saa_common::ensure,
9};
10
11
12#[saa_type]
13pub struct EthPersonalSign {
14    pub message:   Binary,
15    pub signature: Binary,
16    pub signer:    String,
17}
18
19
20impl Verifiable for EthPersonalSign {
21
22    fn id(&self) -> CredentialId {
23        //format!("0x{}", self.signer.to_lowercase())
24        self.signer.to_string()
25    }
26
27    fn hrp(&self) -> Option<String> {
28        #[cfg(feature = "injective")]
29        {
30            return Some("inj".to_string());
31        }
32        None
33    }
34
35    fn validate(&self) -> Result<(), AuthError> {
36        if !self.signer.starts_with("0x") {
37            return Err(AuthError::MissingData("Ethereum `signer` address must start with 0x".to_string()));
38        }
39        if self.signature.len() < 65 {
40            return Err(AuthError::MissingData("Signature must be at least 65 bytes".to_string()));
41        }
42        let signer_bytes = hex::decode(&self.signer[2..])
43            .map_err(|e| AuthError::generic(e.to_string()))?;
44
45        if signer_bytes.len() != 20 {
46            return Err(AuthError::MissingData("Signer must be 20 bytes".to_string()));
47        }
48        Ok(())
49    }
50
51
52    #[cfg(feature = "native")] 
53    fn verify(&self) -> Result<(), AuthError> {
54        let signature = &self.signature.to_vec();
55        let key_data = saa_common::crypto::secp256k1_recover_pubkey(
56            &preamble_msg_eth(&self.message), 
57            &signature[..64], 
58            get_recovery_param(signature[64])?
59        )?;
60        let hash = saa_common::hashes::keccak256(&key_data[1..]);
61
62        let addr_bytes = hex::decode(&self.signer[2..])
63        .map_err(|e| AuthError::generic(e.to_string()))?;
64    
65        ensure!(addr_bytes == hash[12..], AuthError::RecoveryMismatch);
66        
67        Ok(())
68    }
69
70
71    #[cfg(feature = "wasm")]
72    fn verify_cosmwasm(&self, api: &dyn saa_common::wasm::Api) -> Result<(), AuthError> {
73        
74        let signature = &self.signature.to_vec();
75        
76        let key_data = api.secp256k1_recover_pubkey(
77            &preamble_msg_eth(&self.message), 
78            &signature[..64], 
79            get_recovery_param(signature[64])?
80        )?;
81    
82        let hash = saa_common::hashes::keccak256(&key_data[1..]);
83
84        let addr_bytes = hex::decode(&self.signer[2..])
85            .map_err(|e| AuthError::generic(e.to_string()))?;
86        
87        ensure!(addr_bytes == hash[12..], AuthError::RecoveryMismatch);
88
89        Ok(())
90    }
91
92
93}
94