mithril_aggregator/tools/
single_signature_authenticator.rs1use slog::{Logger, debug};
2use std::sync::Arc;
3
4use mithril_common::StdResult;
5use mithril_common::entities::{SingleSignature, SingleSignatureAuthenticationStatus};
6use mithril_common::logging::LoggerExtensions;
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 SingleSignature,
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.expect_verify_single_signature().returning(|_, _| Ok(()));
85 multi_signer
86 .expect_verify_single_signature_for_next_stake_distribution()
87 .returning(|_, _| Ok(()));
88
89 Self {
90 multi_signer: Arc::new(multi_signer),
91 logger: crate::test::TestLogger::stdout(),
92 }
93 }
94
95 pub(crate) fn new_that_reject_everything() -> Self {
96 let mut multi_signer = crate::multi_signer::MockMultiSigner::new();
97 multi_signer
98 .expect_verify_single_signature()
99 .returning(|_, _| Err(anyhow::anyhow!("error")));
100 multi_signer
101 .expect_verify_single_signature_for_next_stake_distribution()
102 .returning(|_, _| Err(anyhow::anyhow!("error")));
103
104 Self {
105 multi_signer: Arc::new(multi_signer),
106 logger: crate::test::TestLogger::stdout(),
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use anyhow::anyhow;
114
115 use mithril_common::test::entities_extensions::SingleSignatureTestExtension;
116
117 use crate::multi_signer::MockMultiSigner;
118 use crate::test::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 = SingleSignature {
135 authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
136 ..SingleSignature::fake("party_id", &signed_message)
137 };
138
139 let authenticator = SingleSignatureAuthenticator::new(
140 mock_multi_signer(|mock_config| {
141 mock_config.expect_verify_single_signature().returning(|_, _| Ok(()));
142 }),
143 TestLogger::stdout(),
144 );
145
146 authenticator
147 .authenticate(&mut single_signature, &signed_message)
148 .await
149 .unwrap();
150
151 assert_eq!(
152 single_signature.authentication_status,
153 SingleSignatureAuthenticationStatus::Authenticated
154 );
155 }
156
157 #[tokio::test]
158 async fn single_signature_against_valid_signed_message_for_next_stake_distribution_is_authenticated()
159 {
160 let signed_message = "signed_message".to_string();
161 let mut single_signature = SingleSignature {
162 authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
163 ..SingleSignature::fake("party_id", &signed_message)
164 };
165
166 let authenticator = SingleSignatureAuthenticator::new(
167 mock_multi_signer(|mock_config| {
168 mock_config
169 .expect_verify_single_signature()
170 .returning(|_, _| Err(anyhow!("error")));
171 mock_config
172 .expect_verify_single_signature_for_next_stake_distribution()
173 .returning(|_, _| Ok(()));
174 }),
175 TestLogger::stdout(),
176 );
177
178 authenticator
179 .authenticate(&mut single_signature, &signed_message)
180 .await
181 .unwrap();
182
183 assert_eq!(
184 single_signature.authentication_status,
185 SingleSignatureAuthenticationStatus::Authenticated
186 );
187 }
188
189 #[tokio::test]
190 async fn single_signature_against_invalid_signed_message_for_current_and_next_stake_distribution_is_not_authenticated()
191 {
192 let signed_message = "signed_message".to_string();
193 let mut single_signature = SingleSignature {
194 authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
195 ..SingleSignature::fake("party_id", &signed_message)
196 };
197
198 let authenticator = SingleSignatureAuthenticator::new(
199 mock_multi_signer(|mock_config| {
200 mock_config
201 .expect_verify_single_signature()
202 .returning(|_, _| Err(anyhow!("verify_single_signature error")));
203 mock_config
204 .expect_verify_single_signature_for_next_stake_distribution()
205 .returning(|_, _| {
206 Err(anyhow!(
207 "verify_single_signature_for_next_stake_distribution error"
208 ))
209 });
210 }),
211 TestLogger::stdout(),
212 );
213
214 authenticator
215 .authenticate(&mut single_signature, &signed_message)
216 .await
217 .unwrap();
218
219 assert_eq!(
220 single_signature.authentication_status,
221 SingleSignatureAuthenticationStatus::Unauthenticated
222 );
223 }
224
225 #[tokio::test]
226 async fn single_signature_previously_authenticated_but_fail_new_authentication_is_now_unauthenticated()
227 {
228 let signed_message = "signed_message".to_string();
229 let mut single_signature = SingleSignature {
230 authentication_status: SingleSignatureAuthenticationStatus::Authenticated,
231 ..SingleSignature::fake("party_id", &signed_message)
232 };
233
234 let authenticator = SingleSignatureAuthenticator::new(
235 mock_multi_signer(|mock_config| {
236 mock_config
237 .expect_verify_single_signature()
238 .returning(|_, _| Err(anyhow!("verify_single_signature error")));
239 mock_config
240 .expect_verify_single_signature_for_next_stake_distribution()
241 .returning(|_, _| {
242 Err(anyhow!(
243 "verify_single_signature_for_next_stake_distribution error"
244 ))
245 });
246 }),
247 TestLogger::stdout(),
248 );
249
250 authenticator
251 .authenticate(&mut single_signature, &signed_message)
252 .await
253 .unwrap();
254
255 assert_eq!(
256 single_signature.authentication_status,
257 SingleSignatureAuthenticationStatus::Unauthenticated
258 );
259 }
260}