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