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 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