saa_custom/eth/
eth.rs

1
2use saa_common::{CredentialId, AuthError, Binary, String, ToString, Verifiable };
3use saa_schema::wasm_serde;
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#[wasm_serde]
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        self.signer.as_bytes().to_vec()
24    }
25
26    fn hrp(&self) -> Option<String> {
27        #[cfg(feature = "injective")]
28        {
29            return Some("inj".to_string());
30        }
31        None
32    }
33
34    fn validate(&self) -> Result<(), AuthError> {
35        if self.signature.len() < 65 {
36            return Err(AuthError::MissingData("Signature must be at least 65 bytes".to_string()));
37        }
38        let signer_bytes = hex::decode(&self.signer[2..])
39            .map_err(|e| AuthError::generic(e.to_string()))?;
40
41        if signer_bytes.len() != 20 {
42            return Err(AuthError::MissingData("Signer must be 20 bytes".to_string()));
43        }
44        Ok(())
45    }
46
47
48    #[cfg(feature = "native")] 
49    fn verify(&self) -> Result<(), AuthError> {
50        let signature = &self.signature.to_vec();
51        let key_data = saa_common::crypto::secp256k1_recover_pubkey(
52            &preamble_msg_eth(&self.message), 
53            &signature[..64], 
54            get_recovery_param(signature[64])?
55        )?;
56        let hash = saa_common::hashes::keccak256(&key_data[1..]);
57        let recovered = String::from_utf8(
58            hash[12..].to_vec()
59        ).map_err(|_| AuthError::RecoveryMismatch)?;
60    
61        ensure!(self.signer == recovered, AuthError::RecoveryMismatch);
62        Ok(())
63    }
64
65
66    #[cfg(feature = "wasm")]
67    fn verify_cosmwasm(&self, api: &dyn saa_common::cosmwasm::Api) -> Result<(), AuthError> {
68        
69        let signature = &self.signature.to_vec();
70        
71        let key_data = api.secp256k1_recover_pubkey(
72            &preamble_msg_eth(&self.message), 
73            &signature[..64], 
74            get_recovery_param(signature[64])?
75        )?;
76    
77        let hash = saa_common::hashes::keccak256(&key_data[1..]);
78
79        let addr_bytes = hex::decode(&self.signer[2..])
80            .map_err(|e| AuthError::generic(e.to_string()))?;
81        
82        ensure!(addr_bytes == hash[12..], AuthError::RecoveryMismatch);
83        Ok(())
84    }
85
86
87}
88