mithril_common/entities/
single_signatures.rs

1use mithril_stm::stm::StmSig;
2use serde::{Deserialize, Serialize};
3use std::fmt::{Debug, Formatter};
4
5use crate::{
6    crypto_helper::ProtocolSingleSignature,
7    entities::{LotteryIndex, PartyId},
8};
9
10/// SingleSignatures represent single signatures originating from a participant in the network
11/// for a digest at won lottery indexes
12#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
13pub struct SingleSignatures {
14    /// The unique identifier of the signer
15    pub party_id: PartyId,
16
17    /// The single signature of the digest
18    pub signature: ProtocolSingleSignature,
19
20    /// The indexes of the won lotteries that lead to the single signatures
21    #[serde(rename = "indexes")]
22    pub won_indexes: Vec<LotteryIndex>,
23
24    /// Status of the authentication of the signer that emitted the signature
25    #[serde(skip)]
26    pub authentication_status: SingleSignatureAuthenticationStatus,
27}
28
29/// Status of the authentication of the signer that emitted the signature
30#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
31pub enum SingleSignatureAuthenticationStatus {
32    /// The signer that emitted the signature is authenticated
33    Authenticated,
34    /// The signer that emitted the signature is not authenticated
35    #[default]
36    Unauthenticated,
37}
38
39impl SingleSignatures {
40    /// `SingleSignatures` factory
41    pub fn new<T: Into<PartyId>>(
42        party_id: T,
43        signature: ProtocolSingleSignature,
44        won_indexes: Vec<LotteryIndex>,
45    ) -> SingleSignatures {
46        SingleSignatures {
47            party_id: party_id.into(),
48            signature,
49            won_indexes,
50            authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
51        }
52    }
53
54    /// Convert this [SingleSignatures] to its corresponding [MithrilStm Signature][StmSig].
55    pub fn to_protocol_signature(&self) -> StmSig {
56        self.signature.clone().into()
57    }
58
59    /// Check that the signer that emitted the signature is authenticated
60    pub fn is_authenticated(&self) -> bool {
61        self.authentication_status == SingleSignatureAuthenticationStatus::Authenticated
62    }
63}
64
65cfg_test_tools! {
66impl SingleSignatures {
67    /// Create a fake [SingleSignatures] with valid cryptographic data for testing purposes.
68    pub fn fake<TPartyId: Into<String>, TMessage: Into<String>>(party_id: TPartyId, message: TMessage) -> Self {
69        use crate::entities::{ProtocolParameters};
70        use crate::test_utils::{MithrilFixtureBuilder, StakeDistributionGenerationMethod};
71
72        let party_id = party_id.into();
73        let message = message.into();
74
75        let fixture = MithrilFixtureBuilder::default()
76            .with_stake_distribution(StakeDistributionGenerationMethod::Custom(
77                std::collections::BTreeMap::from([(party_id.to_string(), 100)]),
78            ))
79            .with_protocol_parameters(ProtocolParameters::new(1, 1, 1.0))
80            .build();
81        let signature = fixture.signers_fixture()[0].sign(&message).unwrap();
82
83        Self {
84            party_id,
85            signature: signature.signature,
86            won_indexes: vec![10, 15],
87            authentication_status: SingleSignatureAuthenticationStatus::Unauthenticated,
88        }
89    }
90}
91}
92
93impl Debug for SingleSignatures {
94    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
95        let is_pretty_printing = f.alternate();
96        let mut debug = f.debug_struct("SingleSignatures");
97        debug
98            .field("party_id", &self.party_id)
99            .field("won_indexes", &format_args!("{:?}", self.won_indexes));
100
101        match is_pretty_printing {
102            true => debug
103                .field("signature", &format_args!("{:?}", self.signature))
104                .finish(),
105            false => debug.finish_non_exhaustive(),
106        }
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use crate::{crypto_helper::tests_setup::setup_message, test_utils::MithrilFixtureBuilder};
114
115    #[test]
116    fn single_signatures_should_convert_to_protocol_signatures() {
117        let message = setup_message();
118        let fixture = MithrilFixtureBuilder::default().with_signers(1).build();
119        let signer = &fixture.signers_fixture()[0];
120        let protocol_sigs = signer
121            .protocol_signer
122            .sign(message.compute_hash().as_bytes())
123            .unwrap();
124
125        let signature = SingleSignatures::new(
126            signer.signer_with_stake.party_id.to_owned(),
127            protocol_sigs.clone().into(),
128            protocol_sigs.indexes.clone(),
129        );
130
131        assert_eq!(protocol_sigs, signature.to_protocol_signature());
132    }
133}