mithril_aggregator/tools/
single_signature_authenticator.rs1use slog::{debug, Logger};
2use std::sync::Arc;
3
4use mithril_common::entities::{SingleSignatureAuthenticationStatus, SingleSignatures};
5use mithril_common::logging::LoggerExtensions;
6use mithril_common::StdResult;
7
8use crate::MultiSigner;
9
10pub struct SingleSignatureAuthenticator {
12 multi_signer: Arc<dyn MultiSigner>,
13 logger: Logger,
14}
15
16impl SingleSignatureAuthenticator {
17 pub fn new(multi_signer: Arc<dyn MultiSigner>, logger: Logger) -> Self {
19 Self {
20 multi_signer,
21 logger: logger.new_with_component_name::<Self>(),
22 }
23 }
24
25 pub async fn authenticate(
27 &self,
28 single_signature: &mut SingleSignatures,
29 signed_message: &str,
30 ) -> StdResult<()> {
31 let is_authenticated = match self
32 .multi_signer
33 .verify_single_signature(signed_message, single_signature)
34 .await
35 {
36 Ok(()) => {
37 debug!(
38 self.logger, "Single signature party authenticated for current stake distribution";
39 "party_id" => &single_signature.party_id,
40 );
41 true
42 }
43 Err(_error) => {
44 if self
47 .multi_signer
48 .verify_single_signature_for_next_stake_distribution(
49 signed_message,
50 single_signature,
51 )
52 .await
53 .is_ok()
54 {
55 debug!(
56 self.logger, "Single signature party authenticated for next stake distribution";
57 "party_id" => &single_signature.party_id,
58 );
59 true
60 } else {
61 debug!(
62 self.logger, "Single signature party not authenticated";
63 "party_id" => &single_signature.party_id,
64 );
65 false
66 }
67 }
68 };
69
70 single_signature.authentication_status = if is_authenticated {
71 SingleSignatureAuthenticationStatus::Authenticated
72 } else {
73 SingleSignatureAuthenticationStatus::Unauthenticated
74 };
75
76 Ok(())
77 }
78}
79
80#[cfg(test)]
81impl SingleSignatureAuthenticator {
82 pub(crate) fn new_that_authenticate_everything() -> Self {
83 let mut multi_signer = crate::multi_signer::MockMultiSigner::new();
84 multi_signer
85 .expect_verify_single_signature()
86 .returning(|_, _| Ok(()));
87 multi_signer
88 .expect_verify_single_signature_for_next_stake_distribution()
89 .returning(|_, _| Ok(()));
90
91 Self {
92 multi_signer: Arc::new(multi_signer),
93 logger: crate::test_tools::TestLogger::stdout(),
94 }
95 }
96
97 pub(crate) fn new_that_reject_everything() -> Self {
98 let mut multi_signer = crate::multi_signer::MockMultiSigner::new();
99 multi_signer
100 .expect_verify_single_signature()
101 .returning(|_, _| Err(anyhow::anyhow!("error")));
102 multi_signer
103 .expect_verify_single_signature_for_next_stake_distribution()
104 .returning(|_, _| Err(anyhow::anyhow!("error")));
105
106 Self {
107 multi_signer: Arc::new(multi_signer),
108 logger: crate::test_tools::TestLogger::stdout(),
109 }
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use anyhow::anyhow;
116
117 use crate::multi_signer::MockMultiSigner;
118 use crate::test_tools::TestLogger;
119
120 use super::*;
121
122 fn mock_multi_signer(
123 multi_signer_mock_config: impl FnOnce(&mut MockMultiSigner),
124 ) -> Arc<MockMultiSigner> {
125 let mut multi_signer = MockMultiSigner::new();
126 multi_signer_mock_config(&mut multi_signer);
127 Arc::new(multi_signer)
128 }
129
130 #[tokio::test]
131 async fn single_signature_against_valid_signed_message_for_current_stake_distribution_is_authenticated(
132 ) {
133 let signed_message = "signed_message".to_string();
134 let mut single_signature = SingleSignatures {
135 authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
136 ..SingleSignatures::fake("party_id", &signed_message)
137 };
138
139 let authenticator = SingleSignatureAuthenticator::new(
140 mock_multi_signer(|mock_config| {
141 mock_config
142 .expect_verify_single_signature()
143 .returning(|_, _| Ok(()));
144 }),
145 TestLogger::stdout(),
146 );
147
148 authenticator
149 .authenticate(&mut single_signature, &signed_message)
150 .await
151 .unwrap();
152
153 assert_eq!(
154 single_signature.authentication_status,
155 SingleSignatureAuthenticationStatus::Authenticated
156 );
157 }
158
159 #[tokio::test]
160 async fn single_signature_against_valid_signed_message_for_next_stake_distribution_is_authenticated(
161 ) {
162 let signed_message = "signed_message".to_string();
163 let mut single_signature = SingleSignatures {
164 authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
165 ..SingleSignatures::fake("party_id", &signed_message)
166 };
167
168 let authenticator = SingleSignatureAuthenticator::new(
169 mock_multi_signer(|mock_config| {
170 mock_config
171 .expect_verify_single_signature()
172 .returning(|_, _| Err(anyhow!("error")));
173 mock_config
174 .expect_verify_single_signature_for_next_stake_distribution()
175 .returning(|_, _| Ok(()));
176 }),
177 TestLogger::stdout(),
178 );
179
180 authenticator
181 .authenticate(&mut single_signature, &signed_message)
182 .await
183 .unwrap();
184
185 assert_eq!(
186 single_signature.authentication_status,
187 SingleSignatureAuthenticationStatus::Authenticated
188 );
189 }
190
191 #[tokio::test]
192 async fn single_signature_against_invalid_signed_message_for_current_and_next_stake_distribution_is_not_authenticated(
193 ) {
194 let signed_message = "signed_message".to_string();
195 let mut single_signature = SingleSignatures {
196 authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
197 ..SingleSignatures::fake("party_id", &signed_message)
198 };
199
200 let authenticator = SingleSignatureAuthenticator::new(
201 mock_multi_signer(|mock_config| {
202 mock_config
203 .expect_verify_single_signature()
204 .returning(|_, _| Err(anyhow!("verify_single_signature error")));
205 mock_config
206 .expect_verify_single_signature_for_next_stake_distribution()
207 .returning(|_, _| {
208 Err(anyhow!(
209 "verify_single_signature_for_next_stake_distribution error"
210 ))
211 });
212 }),
213 TestLogger::stdout(),
214 );
215
216 authenticator
217 .authenticate(&mut single_signature, &signed_message)
218 .await
219 .unwrap();
220
221 assert_eq!(
222 single_signature.authentication_status,
223 SingleSignatureAuthenticationStatus::Unauthenticated
224 );
225 }
226
227 #[tokio::test]
228 async fn single_signature_previously_authenticated_but_fail_new_authentication_is_now_unauthenticated(
229 ) {
230 let signed_message = "signed_message".to_string();
231 let mut single_signature = SingleSignatures {
232 authentication_status: SingleSignatureAuthenticationStatus::Authenticated,
233 ..SingleSignatures::fake("party_id", &signed_message)
234 };
235
236 let authenticator = SingleSignatureAuthenticator::new(
237 mock_multi_signer(|mock_config| {
238 mock_config
239 .expect_verify_single_signature()
240 .returning(|_, _| Err(anyhow!("verify_single_signature error")));
241 mock_config
242 .expect_verify_single_signature_for_next_stake_distribution()
243 .returning(|_, _| {
244 Err(anyhow!(
245 "verify_single_signature_for_next_stake_distribution error"
246 ))
247 });
248 }),
249 TestLogger::stdout(),
250 );
251
252 authenticator
253 .authenticate(&mut single_signature, &signed_message)
254 .await
255 .unwrap();
256
257 assert_eq!(
258 single_signature.authentication_status,
259 SingleSignatureAuthenticationStatus::Unauthenticated
260 );
261 }
262}