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