mithril_signer/services/
single_signer.rs1use std::sync::Arc;
2
3use anyhow::{Context, anyhow};
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().ok_or(anyhow!(
94 "Can not Sign or Compute AVK, No protocol initializer found for party_id: '{}'",
95 self.party_id.clone()
96 ))?;
97
98 let builder = SignerBuilder::new(
99 &epoch_service.current_signers_with_stake().await?,
100 &protocol_initializer.get_protocol_parameters().into(),
101 )
102 .with_context(|| "Mithril Single Signer can not build signer")
103 .map_err(SingleSignerError::ProtocolSignerCreationFailure)?;
104
105 let single_signer = builder
106 .restore_signer_from_initializer(self.party_id.clone(), protocol_initializer.clone())
107 .with_context(|| {
108 format!(
109 "Mithril Single Signer can not restore signer with party_id: '{}'",
110 self.party_id.clone()
111 )
112 })
113 .map_err(SingleSignerError::ProtocolSignerCreationFailure)?;
114
115 Ok(single_signer)
116 }
117}
118
119#[async_trait]
120impl SingleSigner for MithrilSingleSigner {
121 async fn compute_single_signature(
122 &self,
123 protocol_message: &ProtocolMessage,
124 ) -> StdResult<Option<SingleSignature>> {
125 let protocol_single_signer = self.build_protocol_single_signer().await?;
126
127 info!(
128 self.logger, "Signing protocol message";
129 "protocol_message" => #?protocol_message,
130 "signed message" => protocol_message.compute_hash().encode_hex::<String>()
131 );
132 let signature = protocol_single_signer
133 .sign(protocol_message)
134 .with_context(|| {
135 format!(
136 "Mithril Single Signer can not sign protocol_message: '{protocol_message:?}'"
137 )
138 })
139 .map_err(SingleSignerError::SignatureFailed)?;
140
141 match &signature {
142 Some(signature) => {
143 trace!(
144 self.logger,
145 "Party #{}: lottery #{:?} won", signature.party_id, &signature.won_indexes
146 );
147 }
148 None => {
149 warn!(
150 self.logger,
151 "No signature computed, all lotteries were lost"
152 );
153 }
154 };
155
156 Ok(signature)
157 }
158
159 fn get_party_id(&self) -> PartyId {
161 self.party_id.clone()
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use std::sync::Arc;
168 use tokio::sync::RwLock;
169
170 use crate::database::repository::{ProtocolInitializerRepository, StakePoolStore};
171 use crate::database::test_helper::main_db_connection;
172 use crate::services::MithrilEpochService;
173 use crate::test_tools::TestLogger;
174 use mithril_common::crypto_helper::ProtocolClerk;
175 use mithril_common::entities::{Epoch, ProtocolMessagePartKey};
176 use mithril_common::test_utils::MithrilFixtureBuilder;
177 use mithril_persistence::store::StakeStorer;
178
179 use super::*;
180
181 #[tokio::test]
182 async fn compute_single_signature_success() {
183 let snapshot_digest = "digest".to_string();
184 let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
185 let current_signer = &fixture.signers_fixture()[0];
186 let clerk = ProtocolClerk::new_clerk_from_signer(¤t_signer.protocol_signer);
187 let avk = clerk.compute_aggregate_verification_key();
188 let logger = TestLogger::stdout();
189 let connection = Arc::new(main_db_connection().unwrap());
190 let stake_store = {
191 let store = Arc::new(StakePoolStore::new(connection.clone(), None));
192 store
193 .save_stakes(
194 Epoch(10).offset_to_signer_retrieval_epoch().unwrap(),
195 fixture.stake_distribution(),
196 )
197 .await
198 .unwrap();
199 store
200 };
201 let protocol_initializer_store =
202 Arc::new(ProtocolInitializerRepository::new(connection, None));
203 let epoch_service =
204 MithrilEpochService::new(stake_store, protocol_initializer_store, logger.clone())
205 .set_data_to_default_or_fake(Epoch(10))
206 .alter_data(|data| {
207 data.protocol_initializer = Some(current_signer.protocol_initializer.clone());
208 data.current_signers = fixture.signers();
209 });
210
211 let single_signer = MithrilSingleSigner::new(
212 current_signer.party_id(),
213 Arc::new(RwLock::new(epoch_service)),
214 logger,
215 );
216
217 let mut protocol_message = ProtocolMessage::new();
218 protocol_message.set_message_part(ProtocolMessagePartKey::SnapshotDigest, snapshot_digest);
219 let sign_result = single_signer
220 .compute_single_signature(&protocol_message)
221 .await
222 .expect("single signer should not fail")
223 .expect("single signer should produce a signature here");
224
225 let expected_message = protocol_message.compute_hash().as_bytes().to_vec();
226 let decoded_sig = sign_result.to_protocol_signature();
227 assert!(
228 decoded_sig
229 .verify(
230 &fixture.protocol_parameters().into(),
231 ¤t_signer.protocol_signer.get_verification_key(),
232 ¤t_signer.protocol_signer.get_stake(),
233 &avk,
234 &expected_message
235 )
236 .is_ok(),
237 "produced single signature should be valid"
238 );
239 }
240}