Skip to content

Commit ebdea24

Browse files
committed
Add SingleSignatureAuthenticator in aggregator
1 parent 5d81f67 commit ebdea24

File tree

4 files changed

+224
-1
lines changed

4 files changed

+224
-1
lines changed

mithril-aggregator/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub use store::{
5757
};
5858
pub use tools::{
5959
CExplorerSignerRetriever, SignersImporter, SignersImporterPersister, SignersImporterRetriever,
60+
SingleSignatureAuthenticator,
6061
};
6162

6263
#[cfg(test)]

mithril-aggregator/src/tools/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod genesis;
66
pub mod mocks;
77
mod remote_file_uploader;
88
mod signer_importer;
9+
mod single_signature_authenticator;
910

1011
pub use certificates_hash_migrator::CertificatesHashMigrator;
1112
pub use digest_helpers::extract_digest_from_path;
@@ -15,6 +16,7 @@ pub use remote_file_uploader::{GcpFileUploader, RemoteFileUploader};
1516
pub use signer_importer::{
1617
CExplorerSignerRetriever, SignersImporter, SignersImporterPersister, SignersImporterRetriever,
1718
};
19+
pub use single_signature_authenticator::*;
1820

1921
#[cfg(test)]
2022
pub use remote_file_uploader::MockRemoteFileUploader;
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
use slog::{debug, Logger};
2+
use std::sync::Arc;
3+
4+
use mithril_common::entities::{SingleSignatureAuthenticationStatus, SingleSignatures};
5+
use mithril_common::StdResult;
6+
7+
use crate::MultiSigner;
8+
9+
/// Authenticates single signatures against a signed message.
10+
pub struct SingleSignatureAuthenticator {
11+
multi_signer: Arc<dyn MultiSigner>,
12+
logger: Logger,
13+
}
14+
15+
impl SingleSignatureAuthenticator {
16+
/// Creates a new `SingleSignatureAuthenticator`.
17+
pub fn new(multi_signer: Arc<dyn MultiSigner>, logger: Logger) -> Self {
18+
Self {
19+
multi_signer,
20+
logger,
21+
}
22+
}
23+
24+
/// Authenticates a single signature against a signed message.
25+
pub async fn authenticate(
26+
&self,
27+
single_signature: &mut SingleSignatures,
28+
signed_message: &str,
29+
) -> StdResult<()> {
30+
let is_authenticated = match self
31+
.multi_signer
32+
.verify_single_signature(signed_message, single_signature)
33+
.await
34+
{
35+
Ok(()) => {
36+
debug!(
37+
self.logger,
38+
"Single signature party authenticated for current stake distribution";
39+
"party_id" => &single_signature.party_id,
40+
);
41+
true
42+
}
43+
Err(_error) => {
44+
// Signers may detect epoch changes before the aggregator and send
45+
// new signatures using the next epoch stake distribution
46+
if self
47+
.multi_signer
48+
.verify_single_signature_for_next_epoch(signed_message, single_signature)
49+
.await
50+
.is_ok()
51+
{
52+
debug!(
53+
self.logger,
54+
"Single signature party authenticated for next stake distribution";
55+
"party_id" => &single_signature.party_id,
56+
);
57+
true
58+
} else {
59+
debug!(
60+
self.logger,
61+
"Single signature party not authenticated";
62+
"party_id" => &single_signature.party_id,
63+
);
64+
false
65+
}
66+
}
67+
};
68+
69+
single_signature.authentication_status = if is_authenticated {
70+
SingleSignatureAuthenticationStatus::Authenticated
71+
} else {
72+
SingleSignatureAuthenticationStatus::Unauthenticated
73+
};
74+
75+
Ok(())
76+
}
77+
}
78+
79+
#[cfg(test)]
80+
mod tests {
81+
use anyhow::anyhow;
82+
83+
use crate::multi_signer::MockMultiSigner;
84+
use crate::test_tools::TestLogger;
85+
86+
use super::*;
87+
88+
fn mock_multi_signer(
89+
multi_signer_mock_config: impl FnOnce(&mut MockMultiSigner),
90+
) -> Arc<MockMultiSigner> {
91+
let mut multi_signer = MockMultiSigner::new();
92+
multi_signer_mock_config(&mut multi_signer);
93+
Arc::new(multi_signer)
94+
}
95+
96+
#[tokio::test]
97+
async fn single_signature_against_valid_signed_message_for_current_stake_distribution_is_authenticated(
98+
) {
99+
let signed_message = "signed_message".to_string();
100+
let mut single_signature = SingleSignatures {
101+
authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
102+
..SingleSignatures::fake("party_id", &signed_message)
103+
};
104+
105+
let authenticator = SingleSignatureAuthenticator::new(
106+
mock_multi_signer(|mock_config| {
107+
mock_config
108+
.expect_verify_single_signature()
109+
.returning(|_, _| Ok(()));
110+
}),
111+
TestLogger::stdout(),
112+
);
113+
114+
authenticator
115+
.authenticate(&mut single_signature, &signed_message)
116+
.await
117+
.unwrap();
118+
119+
assert_eq!(
120+
single_signature.authentication_status,
121+
SingleSignatureAuthenticationStatus::Authenticated
122+
);
123+
}
124+
125+
#[tokio::test]
126+
async fn single_signature_against_valid_signed_message_for_next_stake_distribution_is_authenticated(
127+
) {
128+
let signed_message = "signed_message".to_string();
129+
let mut single_signature = SingleSignatures {
130+
authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
131+
..SingleSignatures::fake("party_id", &signed_message)
132+
};
133+
134+
let authenticator = SingleSignatureAuthenticator::new(
135+
mock_multi_signer(|mock_config| {
136+
mock_config
137+
.expect_verify_single_signature()
138+
.returning(|_, _| Err(anyhow!("error")));
139+
mock_config
140+
.expect_verify_single_signature_for_next_epoch()
141+
.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_invalid_signed_message_for_current_and_next_stake_distribution_is_not_authenticated(
159+
) {
160+
let signed_message = "signed_message".to_string();
161+
let mut single_signature = SingleSignatures {
162+
authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
163+
..SingleSignatures::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!("verify_single_signature error")));
171+
mock_config
172+
.expect_verify_single_signature_for_next_epoch()
173+
.returning(|_, _| Err(anyhow!("verify_single_signature_for_next_epoch error")));
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::Unauthenticated
186+
);
187+
}
188+
189+
#[tokio::test]
190+
async fn single_signature_previously_authenticated_but_fail_new_authentication_is_now_unauthenticated(
191+
) {
192+
let signed_message = "signed_message".to_string();
193+
let mut single_signature = SingleSignatures {
194+
authentication_status: SingleSignatureAuthenticationStatus::Authenticated,
195+
..SingleSignatures::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_epoch()
205+
.returning(|_, _| Err(anyhow!("verify_single_signature_for_next_epoch error")));
206+
}),
207+
TestLogger::stdout(),
208+
);
209+
210+
authenticator
211+
.authenticate(&mut single_signature, &signed_message)
212+
.await
213+
.unwrap();
214+
215+
assert_eq!(
216+
single_signature.authentication_status,
217+
SingleSignatureAuthenticationStatus::Unauthenticated
218+
);
219+
}
220+
}

mithril-common/src/entities/single_signatures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub struct SingleSignatures {
3434
}
3535

3636
/// Status of the authentication of the signer that emitted the signature
37-
#[derive(Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
37+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
3838
pub enum SingleSignatureAuthenticationStatus {
3939
/// We could authenticate the signer that emitted the signature
4040
Authenticated,

0 commit comments

Comments
 (0)