mithril_signer/services/
single_signer.rs1use std::sync::Arc;
2
3use anyhow::Context;
4use async_trait::async_trait;
5use hex::ToHex;
6use slog::{Logger, info, trace, warn};
7use thiserror::Error;
8
9use mithril_common::crypto_helper::{KesPeriod, KesSigner, ProtocolInitializer};
10use mithril_common::entities::{
11 PartyId, ProtocolMessage, ProtocolParameters, SingleSignature, Stake,
12};
13use mithril_common::logging::LoggerExtensions;
14use mithril_common::protocol::{SignerBuilder, SingleSigner as ProtocolSingleSigner};
15use mithril_common::{StdError, StdResult};
16
17use crate::dependency_injection::EpochServiceWrapper;
18
19pub struct MithrilProtocolInitializerBuilder {}
21
22impl MithrilProtocolInitializerBuilder {
23 pub fn build(
25 stake: &Stake,
26 protocol_parameters: &ProtocolParameters,
27 kes_signer: Option<Arc<dyn KesSigner>>,
28 kes_period: Option<KesPeriod>,
29 ) -> StdResult<ProtocolInitializer> {
30 let mut rng = rand_core::OsRng;
31 let protocol_initializer = ProtocolInitializer::setup(
32 protocol_parameters.to_owned().into(),
33 kes_signer,
34 kes_period,
35 stake.to_owned(),
36 &mut rng,
37 )?;
38
39 Ok(protocol_initializer)
40 }
41}
42
43#[cfg_attr(test, mockall::automock)]
45#[async_trait]
46pub trait SingleSigner: Sync + Send {
47 async fn compute_single_signature(
49 &self,
50 protocol_message: &ProtocolMessage,
51 ) -> StdResult<Option<SingleSignature>>;
52
53 fn get_party_id(&self) -> PartyId;
55}
56
57#[derive(Error, Debug)]
59pub enum SingleSignerError {
60 #[error("the protocol signer creation failed")]
62 ProtocolSignerCreationFailure(#[source] StdError),
63
64 #[error("Signature Error")]
66 SignatureFailed(#[source] StdError),
67
68 #[error("Aggregate verification key computation Error")]
70 AggregateVerificationKeyComputationFailed(#[source] StdError),
71}
72
73pub struct MithrilSingleSigner {
75 party_id: PartyId,
76 epoch_service: EpochServiceWrapper,
77 logger: Logger,
78}
79
80impl MithrilSingleSigner {
81 pub fn new(party_id: PartyId, epoch_service: EpochServiceWrapper, logger: Logger) -> Self {
83 Self {
84 party_id,
85 epoch_service,
86 logger: logger.new_with_component_name::<Self>(),
87 }
88 }
89
90 async fn build_protocol_single_signer(&self) -> StdResult<ProtocolSingleSigner> {
91 let epoch_service = self.epoch_service.read().await;
92 let protocol_initializer =
93 epoch_service.protocol_initializer()?.as_ref().with_context(|| {
94 format!(
95 "Can not Sign or Compute AVK, No protocol initializer found for party_id: '{}'",
96 self.party_id.clone()
97 )
98 })?;
99
100 let builder = SignerBuilder::new(
101 &epoch_service.current_signers_with_stake().await?,
102 &protocol_initializer.get_protocol_parameters().into(),
103 )
104 .with_context(|| "Mithril Single Signer can not build signer")
105 .map_err(SingleSignerError::ProtocolSignerCreationFailure)?;
106
107 let single_signer = builder
108 .restore_signer_from_initializer(self.party_id.clone(), protocol_initializer.clone())
109 .with_context(|| {
110 format!(
111 "Mithril Single Signer can not restore signer with party_id: '{}'",
112 self.party_id.clone()
113 )
114 })
115 .map_err(SingleSignerError::ProtocolSignerCreationFailure)?;
116
117 Ok(single_signer)
118 }
119}
120
121#[async_trait]
122impl SingleSigner for MithrilSingleSigner {
123 async fn compute_single_signature(
124 &self,
125 protocol_message: &ProtocolMessage,
126 ) -> StdResult<Option<SingleSignature>> {
127 let protocol_single_signer = self.build_protocol_single_signer().await?;
128
129 info!(
130 self.logger, "Signing protocol message";
131 "protocol_message" => #?protocol_message,
132 "signed message" => protocol_message.compute_hash().encode_hex::<String>()
133 );
134 let signature = protocol_single_signer
135 .sign(protocol_message)
136 .with_context(|| {
137 format!(
138 "Mithril Single Signer can not sign protocol_message: '{protocol_message:?}'"
139 )
140 })
141 .map_err(SingleSignerError::SignatureFailed)?;
142
143 match &signature {
144 Some(signature) => {
145 trace!(
146 self.logger,
147 "Party #{}: lottery #{:?} won", signature.party_id, &signature.won_indexes
148 );
149 }
150 None => {
151 warn!(
152 self.logger,
153 "No signature computed, all lotteries were lost"
154 );
155 }
156 };
157
158 Ok(signature)
159 }
160
161 fn get_party_id(&self) -> PartyId {
163 self.party_id.clone()
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use std::sync::Arc;
170 use tokio::sync::RwLock;
171
172 use crate::database::repository::{ProtocolInitializerRepository, StakePoolStore};
173 use crate::database::test_helper::main_db_connection;
174 use crate::services::MithrilEpochService;
175 use crate::test_tools::TestLogger;
176 use mithril_common::crypto_helper::ProtocolClerk;
177 use mithril_common::entities::{Epoch, ProtocolMessagePartKey};
178 use mithril_common::test::builder::MithrilFixtureBuilder;
179 use mithril_persistence::store::StakeStorer;
180
181 use super::*;
182
183 #[tokio::test]
184 async fn compute_single_signature_success() {
185 let snapshot_digest = "digest".to_string();
186 let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
187 let current_signer = &fixture.signers_fixture()[0];
188 let clerk = ProtocolClerk::new_clerk_from_signer(¤t_signer.protocol_signer);
189 let avk = clerk.compute_aggregate_verification_key();
190 let logger = TestLogger::stdout();
191 let connection = Arc::new(main_db_connection().unwrap());
192 let stake_store = {
193 let store = Arc::new(StakePoolStore::new(connection.clone(), None));
194 store
195 .save_stakes(
196 Epoch(10).offset_to_signer_retrieval_epoch().unwrap(),
197 fixture.stake_distribution(),
198 )
199 .await
200 .unwrap();
201 store
202 };
203 let protocol_initializer_store =
204 Arc::new(ProtocolInitializerRepository::new(connection, None));
205 let epoch_service =
206 MithrilEpochService::new(stake_store, protocol_initializer_store, logger.clone())
207 .set_data_to_default_or_fake(Epoch(10))
208 .alter_data(|data| {
209 data.protocol_initializer = Some(current_signer.protocol_initializer.clone());
210 data.current_signers = fixture.signers();
211 });
212
213 let single_signer = MithrilSingleSigner::new(
214 current_signer.party_id(),
215 Arc::new(RwLock::new(epoch_service)),
216 logger,
217 );
218
219 let mut protocol_message = ProtocolMessage::new();
220 protocol_message.set_message_part(ProtocolMessagePartKey::SnapshotDigest, snapshot_digest);
221 let sign_result = single_signer
222 .compute_single_signature(&protocol_message)
223 .await
224 .expect("single signer should not fail")
225 .expect("single signer should produce a signature here");
226
227 let expected_message = protocol_message.compute_hash().as_bytes().to_vec();
228 let decoded_sig = sign_result.to_protocol_signature();
229 assert!(
230 decoded_sig
231 .verify(
232 &fixture.protocol_parameters().into(),
233 ¤t_signer.protocol_signer.get_verification_key(),
234 ¤t_signer.protocol_signer.get_stake(),
235 &avk,
236 &expected_message
237 )
238 .is_ok(),
239 "produced single signature should be valid"
240 );
241 }
242}