kms_secp256k1_api/services/mocks/
mock_keys_service.rs

1use crate::{
2    config::Config,
3    services::{crypto_service::CryptoService, keys_service::KeyEntry},
4};
5use base64::Engine;
6use base64::engine::general_purpose::STANDARD;
7use k256::PublicKey;
8use k256::pkcs8::EncodePublicKey;
9use std::{collections::HashMap, sync::Arc};
10use tokio::{
11    sync::Mutex,
12    time::{Duration, sleep},
13};
14use tracing::error;
15
16#[derive(Debug, Clone)]
17pub struct KeyPair {
18    pub private_key: String,
19    pub public_key: String,
20    pub address: String,
21}
22
23pub struct MockKeysService {
24    pub keys: Arc<Mutex<HashMap<String, KeyPair>>>,
25    pub crypto_service: CryptoService,
26}
27
28impl MockKeysService {
29    /// Creates a new instance of `MockKeysService`.
30    ///
31    /// Initializes the internal key storage and creates an underlying `CasperKeysService`.
32    ///
33    /// # Panics
34    ///
35    /// This function will panic if creating the underlying `CasperKeysService` fails.
36    #[must_use]
37    pub fn new(_config: Config, crypto_service: CryptoService) -> Self {
38        Self {
39            keys: Arc::new(Mutex::new(HashMap::new())),
40            crypto_service,
41        }
42    }
43
44    /// Verifies a signature for the given transaction hash and public key.
45    ///
46    /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if invalid.
47    ///
48    /// # Errors
49    ///
50    /// Returns an error if the verification process encounters a failure, such as
51    /// an internal error during signature verification. The error string provides
52    /// details about the failure.
53    pub fn verify(
54        &mut self,
55        transaction_hash_hex: &str,
56        signature_hex: &str,
57        key: &str,
58    ) -> Result<bool, String> {
59        self.crypto_service
60            .verify(transaction_hash_hex, signature_hex, key)
61            .map_err(|e| {
62                let msg = format!("Signature verification failed: {e}");
63                error!("{}", msg);
64                msg
65            })
66    }
67
68    /// Verifies an Ethereum EIP-155 signature for the given transaction hash and public key.
69    ///
70    /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if invalid.
71    ///
72    /// # Errors
73    ///
74    /// Returns an error if the verification process encounters a failure, such as
75    /// an internal error during signature verification. The error string provides
76    /// details about the failure.
77    pub fn verify_eip155(
78        &mut self,
79        transaction_hash_hex: &str,
80        signature_hex: &str,
81        key: &str,
82    ) -> Result<bool, String> {
83        self.crypto_service
84            .verify_eip155(transaction_hash_hex, signature_hex, key)
85            .map_err(|e| {
86                let msg = format!("Signature verification failed: {e}");
87                error!("{}", msg);
88                msg
89            })
90    }
91
92    /// Asynchronously verifies a signature via a simulated Key Management Service (KMS).
93    ///
94    /// Introduces an artificial delay to simulate latency.
95    /// Returns the same results as the [`verify`] method.
96    ///
97    /// # Errors
98    ///
99    /// Returns an error if signature verification fails. The error string provides
100    /// details about the verification failure.
101    ///
102    /// [`verify`]: MockKeysService::verify
103    pub async fn verify_via_kms(
104        &mut self,
105        transaction_hash_hex: &str,
106        signature_hex: &str,
107        key: &str,
108    ) -> Result<bool, String> {
109        sleep(Duration::from_millis(50)).await;
110        self.verify(transaction_hash_hex, signature_hex, key)
111    }
112
113    /// Verifies an EIP-155 signature against the given transaction hash and key,
114    /// introducing a small delay to simulate or throttle KMS behavior.
115    ///
116    /// This method is functionally equivalent to [`MockKeysService::verify_eip155`] but includes a
117    /// `50ms` sleep before performing the verification. This is useful when simulating
118    /// KMS latency or reducing load on dependent services in testing environments.
119    ///
120    /// # Parameters
121    /// - `transaction_hash_hex`: The hex-encoded transaction hash that was signed.
122    /// - `signature_hex`: The hex-encoded EIP-155 signature to verify.
123    /// - `key`: A compressed secp256k1 public key or a KMS alias used to resolve the key.
124    ///
125    /// # Returns
126    /// - `Ok(true)`: If the signature is valid.
127    /// - `Ok(false)`: If the signature is invalid (cryptographic check fails).
128    /// - `Err(String)`: If key resolution or verification fails due to internal errors or invalid input.
129    ///
130    /// # Errors
131    /// Returns an error if the key is invalid, the signature is malformed,
132    /// or the cryptographic operation fails internally.
133    pub async fn verify_via_kms_eip155(
134        &mut self,
135        transaction_hash_hex: &str,
136        signature_hex: &str,
137        key: &str,
138    ) -> Result<bool, String> {
139        sleep(Duration::from_millis(50)).await;
140        self.verify_eip155(transaction_hash_hex, signature_hex, key)
141    }
142
143    /// Deletes a public key from the internal key storage.
144    ///
145    /// Returns `true` if the key existed and was removed, `false` otherwise.
146    pub async fn delete_key(&self, key: &str) -> bool {
147        self.keys.lock().await.remove(key).is_some() // key alias used is key_pair address
148    }
149
150    /// Lists all stored keys with mock metadata.
151    ///
152    /// Returns a vector of `KeyEntry` representing all keys.
153    pub async fn list_keys(&self) -> Vec<KeyEntry> {
154        self.keys
155            .lock()
156            .await
157            .values()
158            .enumerate()
159            .map(|(i, keypair)| {
160                let public_key_base64 = hex::decode(&keypair.public_key)
161                    .ok()
162                    .and_then(|bytes| PublicKey::from_sec1_bytes(&bytes).ok())
163                    .and_then(|pk| pk.to_public_key_der().ok())
164                    .map(|der| STANDARD.encode(der))
165                    .unwrap_or_default();
166
167                KeyEntry {
168                    address: keypair.address.clone().into(),
169                    public_key_base64: public_key_base64.into(),
170                    public_key: Some(keypair.public_key.clone()).into(),
171                    key_id: format!("mock-key-{}", i + 1).into(),
172                }
173            })
174            .collect()
175    }
176
177    /// Inserts a new key pair into the internal storage.
178    ///
179    /// Used to add keys for testing purposes.
180    pub async fn insert_key(&self, key_pair: KeyPair) {
181        let key = key_pair.address.clone(); // key alias used is key_pair address
182        self.keys.lock().await.insert(key, key_pair);
183    }
184}