mithril_signer/services/
single_signer.rs

1use 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
19/// This is responsible for creating new instances of ProtocolInitializer.
20pub struct MithrilProtocolInitializerBuilder {}
21
22impl MithrilProtocolInitializerBuilder {
23    /// Create a ProtocolInitializer instance.
24    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/// The SingleSigner is the structure responsible for issuing [SingleSignature].
44#[cfg_attr(test, mockall::automock)]
45#[async_trait]
46pub trait SingleSigner: Sync + Send {
47    /// Computes single signature
48    async fn compute_single_signature(
49        &self,
50        protocol_message: &ProtocolMessage,
51    ) -> StdResult<Option<SingleSignature>>;
52
53    /// Get party id
54    fn get_party_id(&self) -> PartyId;
55}
56
57/// SingleSigner error structure.
58#[derive(Error, Debug)]
59pub enum SingleSignerError {
60    /// Cryptographic Signer creation error.
61    #[error("the protocol signer creation failed")]
62    ProtocolSignerCreationFailure(#[source] StdError),
63
64    /// Signature Error
65    #[error("Signature Error")]
66    SignatureFailed(#[source] StdError),
67
68    /// Avk computation Error
69    #[error("Aggregate verification key computation Error")]
70    AggregateVerificationKeyComputationFailed(#[source] StdError),
71}
72
73/// Implementation of the SingleSigner.
74pub struct MithrilSingleSigner {
75    party_id: PartyId,
76    epoch_service: EpochServiceWrapper,
77    logger: Logger,
78}
79
80impl MithrilSingleSigner {
81    /// Create a new instance of the MithrilSingleSigner.
82    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    /// Get party id
162    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(&current_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                    &current_signer.protocol_signer.get_verification_key(),
234                    &current_signer.protocol_signer.get_stake(),
235                    &avk,
236                    &expected_message
237                )
238                .is_ok(),
239            "produced single signature should be valid"
240        );
241    }
242}