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}