mithril_signer/services/
single_signer.rs

1use anyhow::{anyhow, Context};
2use async_trait::async_trait;
3use hex::ToHex;
4use slog::{info, trace, warn, Logger};
5use std::path::PathBuf;
6use thiserror::Error;
7
8use mithril_common::crypto_helper::{KESPeriod, ProtocolInitializer};
9use mithril_common::entities::{
10    PartyId, ProtocolMessage, ProtocolParameters, SingleSignatures, Stake,
11};
12use mithril_common::logging::LoggerExtensions;
13use mithril_common::protocol::{SignerBuilder, SingleSigner as ProtocolSingleSigner};
14use mithril_common::{StdError, StdResult};
15
16use crate::dependency_injection::EpochServiceWrapper;
17
18/// This is responsible for creating new instances of ProtocolInitializer.
19pub struct MithrilProtocolInitializerBuilder {}
20
21impl MithrilProtocolInitializerBuilder {
22    /// Create a ProtocolInitializer instance.
23    pub fn build(
24        stake: &Stake,
25        protocol_parameters: &ProtocolParameters,
26        kes_secret_key_path: Option<PathBuf>,
27        kes_period: Option<KESPeriod>,
28    ) -> StdResult<ProtocolInitializer> {
29        let mut rng = rand_core::OsRng;
30        let protocol_initializer = ProtocolInitializer::setup(
31            protocol_parameters.to_owned().into(),
32            kes_secret_key_path,
33            kes_period,
34            stake.to_owned(),
35            &mut rng,
36        )?;
37
38        Ok(protocol_initializer)
39    }
40}
41
42/// The SingleSigner is the structure responsible for issuing SingleSignatures.
43#[cfg_attr(test, mockall::automock)]
44#[async_trait]
45pub trait SingleSigner: Sync + Send {
46    /// Computes single signatures
47    async fn compute_single_signatures(
48        &self,
49        protocol_message: &ProtocolMessage,
50    ) -> StdResult<Option<SingleSignatures>>;
51
52    /// Get party id
53    fn get_party_id(&self) -> PartyId;
54}
55
56/// SingleSigner error structure.
57#[derive(Error, Debug)]
58pub enum SingleSignerError {
59    /// Cryptographic Signer creation error.
60    #[error("the protocol signer creation failed")]
61    ProtocolSignerCreationFailure(#[source] StdError),
62
63    /// Signature Error
64    #[error("Signature Error")]
65    SignatureFailed(#[source] StdError),
66
67    /// Avk computation Error
68    #[error("Aggregate verification key computation Error")]
69    AggregateVerificationKeyComputationFailed(#[source] StdError),
70}
71
72/// Implementation of the SingleSigner.
73pub struct MithrilSingleSigner {
74    party_id: PartyId,
75    epoch_service: EpochServiceWrapper,
76    logger: Logger,
77}
78
79impl MithrilSingleSigner {
80    /// Create a new instance of the MithrilSingleSigner.
81    pub fn new(party_id: PartyId, epoch_service: EpochServiceWrapper, logger: Logger) -> Self {
82        Self {
83            party_id,
84            epoch_service,
85            logger: logger.new_with_component_name::<Self>(),
86        }
87    }
88
89    async fn build_protocol_single_signer(&self) -> StdResult<ProtocolSingleSigner> {
90        let epoch_service = self.epoch_service.read().await;
91        let protocol_initializer =
92            epoch_service
93                .protocol_initializer()?
94                .as_ref()
95                .ok_or(anyhow!(
96                    "Can not Sign or Compute AVK, No protocol initializer found for party_id: '{}'",
97                    self.party_id.clone()
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_signatures(
124        &self,
125        protocol_message: &ProtocolMessage,
126    ) -> StdResult<Option<SingleSignatures>> {
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 signatures = protocol_single_signer
135            .sign(protocol_message)
136            .with_context(|| {
137                format!(
138                    "Mithril Single Signer can not sign protocol_message: '{:?}'",
139                    protocol_message
140                )
141            })
142            .map_err(SingleSignerError::SignatureFailed)?;
143
144        match &signatures {
145            Some(signature) => {
146                trace!(
147                    self.logger,
148                    "Party #{}: lottery #{:?} won",
149                    signature.party_id,
150                    &signature.won_indexes
151                );
152            }
153            None => {
154                warn!(
155                    self.logger,
156                    "No signature computed, all lotteries were lost"
157                );
158            }
159        };
160
161        Ok(signatures)
162    }
163
164    /// Get party id
165    fn get_party_id(&self) -> PartyId {
166        self.party_id.clone()
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use std::sync::Arc;
173    use tokio::sync::RwLock;
174
175    use crate::database::repository::{ProtocolInitializerRepository, StakePoolStore};
176    use crate::database::test_helper::main_db_connection;
177    use crate::services::MithrilEpochService;
178    use crate::test_tools::TestLogger;
179    use mithril_common::crypto_helper::ProtocolClerk;
180    use mithril_common::entities::{Epoch, ProtocolMessagePartKey};
181    use mithril_common::test_utils::MithrilFixtureBuilder;
182    use mithril_persistence::store::StakeStorer;
183
184    use super::*;
185
186    #[tokio::test]
187    async fn compute_single_signature_success() {
188        let snapshot_digest = "digest".to_string();
189        let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
190        let current_signer = &fixture.signers_fixture()[0];
191        let clerk = ProtocolClerk::from_signer(&current_signer.protocol_signer);
192        let avk = clerk.compute_avk();
193        let logger = TestLogger::stdout();
194        let connection = Arc::new(main_db_connection().unwrap());
195        let stake_store = {
196            let store = Arc::new(StakePoolStore::new(connection.clone(), None));
197            store
198                .save_stakes(
199                    Epoch(10).offset_to_signer_retrieval_epoch().unwrap(),
200                    fixture.stake_distribution(),
201                )
202                .await
203                .unwrap();
204            store
205        };
206        let protocol_initializer_store =
207            Arc::new(ProtocolInitializerRepository::new(connection, None));
208        let epoch_service =
209            MithrilEpochService::new(stake_store, protocol_initializer_store, logger.clone())
210                .set_data_to_default_or_fake(Epoch(10))
211                .alter_data(|data| {
212                    data.protocol_initializer = Some(current_signer.protocol_initializer.clone());
213                    data.current_signers = fixture.signers();
214                });
215
216        let single_signer = MithrilSingleSigner::new(
217            current_signer.party_id(),
218            Arc::new(RwLock::new(epoch_service)),
219            logger,
220        );
221
222        let mut protocol_message = ProtocolMessage::new();
223        protocol_message.set_message_part(ProtocolMessagePartKey::SnapshotDigest, snapshot_digest);
224        let sign_result = single_signer
225            .compute_single_signatures(&protocol_message)
226            .await
227            .expect("single signer should not fail")
228            .expect("single signer should produce a signature here");
229
230        let expected_message = protocol_message.compute_hash().as_bytes().to_vec();
231        let decoded_sig = sign_result.to_protocol_signature();
232        assert!(
233            decoded_sig
234                .verify(
235                    &fixture.protocol_parameters().into(),
236                    &current_signer.protocol_signer.verification_key(),
237                    &current_signer.protocol_signer.get_stake(),
238                    &avk,
239                    &expected_message
240                )
241                .is_ok(),
242            "produced single signature should be valid"
243        );
244    }
245}