1use crate::{
2 crypto_helper::{
3 KesPeriod, ProtocolOpCert, ProtocolSignerVerificationKey,
4 ProtocolSignerVerificationKeySignature,
5 },
6 entities::{PartyId, Stake},
7};
8use std::fmt::{Debug, Formatter};
9
10use serde::{Deserialize, Serialize};
11use sha2::{Digest, Sha256};
12
13#[derive(Clone, Eq, Serialize, Deserialize)]
15pub struct Signer {
16 pub party_id: PartyId,
20
21 pub verification_key: ProtocolSignerVerificationKey,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
28 pub verification_key_signature: Option<ProtocolSignerVerificationKeySignature>,
29
30 #[serde(skip_serializing_if = "Option::is_none")]
34 pub operational_certificate: Option<ProtocolOpCert>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
39 pub kes_period: Option<KesPeriod>,
40}
41
42impl PartialEq for Signer {
43 fn eq(&self, other: &Self) -> bool {
44 self.party_id.eq(&other.party_id)
45 }
46}
47
48impl PartialOrd for Signer {
49 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
50 Some(self.cmp(other))
51 }
52}
53
54impl Ord for Signer {
55 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
56 self.party_id.cmp(&other.party_id)
57 }
58}
59
60impl Signer {
61 pub fn new(
63 party_id: PartyId,
64 verification_key: ProtocolSignerVerificationKey,
65 verification_key_signature: Option<ProtocolSignerVerificationKeySignature>,
66 operational_certificate: Option<ProtocolOpCert>,
67 kes_period: Option<KesPeriod>,
68 ) -> Signer {
69 Signer {
70 party_id,
71 verification_key,
72 verification_key_signature,
73 operational_certificate,
74 kes_period,
75 }
76 }
77
78 pub fn vec_from<T: Into<Signer>>(from: Vec<T>) -> Vec<Self> {
80 from.into_iter().map(|f| f.into()).collect()
81 }
82
83 pub fn compute_hash(&self) -> String {
85 let mut hasher = Sha256::new();
86 hasher.update(self.party_id.as_bytes());
87 hasher.update(self.verification_key.to_json_hex().unwrap().as_bytes());
88
89 if let Some(verification_key_signature) = &self.verification_key_signature {
90 hasher.update(verification_key_signature.to_json_hex().unwrap().as_bytes());
91 }
92 if let Some(operational_certificate) = &self.operational_certificate {
93 hasher.update(operational_certificate.to_json_hex().unwrap().as_bytes());
94 }
95 hex::encode(hasher.finalize())
96 }
97}
98
99impl Debug for Signer {
100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101 let should_be_exhaustive = f.alternate();
102 let mut debug = f.debug_struct("Signer");
103 debug.field("party_id", &self.party_id);
104
105 match should_be_exhaustive {
106 true => debug
107 .field(
108 "verification_key",
109 &format_args!("{:?}", self.verification_key),
110 )
111 .field(
112 "verification_key_signature",
113 &format_args!("{:?}", self.verification_key_signature),
114 )
115 .field(
116 "operational_certificate",
117 &format_args!("{:?}", self.operational_certificate),
118 )
119 .field("kes_period", &format_args!("{:?}", self.kes_period))
120 .finish(),
121 false => debug.finish_non_exhaustive(),
122 }
123 }
124}
125
126impl From<SignerWithStake> for Signer {
127 fn from(other: SignerWithStake) -> Self {
128 Signer::new(
129 other.party_id,
130 other.verification_key,
131 other.verification_key_signature,
132 other.operational_certificate,
133 other.kes_period,
134 )
135 }
136}
137
138#[derive(Clone, Eq, Serialize, Deserialize)]
140pub struct SignerWithStake {
141 pub party_id: PartyId,
145
146 pub verification_key: ProtocolSignerVerificationKey,
148
149 #[serde(skip_serializing_if = "Option::is_none")]
153 pub verification_key_signature: Option<ProtocolSignerVerificationKeySignature>,
154
155 #[serde(skip_serializing_if = "Option::is_none")]
159 pub operational_certificate: Option<ProtocolOpCert>,
160
161 #[serde(skip_serializing_if = "Option::is_none")]
164 pub kes_period: Option<KesPeriod>,
165
166 pub stake: Stake,
168}
169
170impl PartialEq for SignerWithStake {
171 fn eq(&self, other: &Self) -> bool {
172 self.party_id.eq(&other.party_id)
173 }
174}
175
176impl PartialOrd for SignerWithStake {
177 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
178 Some(self.cmp(other))
179 }
180}
181
182impl Ord for SignerWithStake {
183 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
184 self.party_id.cmp(&other.party_id)
185 }
186}
187
188impl SignerWithStake {
189 pub fn new(
191 party_id: PartyId,
192 verification_key: ProtocolSignerVerificationKey,
193 verification_key_signature: Option<ProtocolSignerVerificationKeySignature>,
194 operational_certificate: Option<ProtocolOpCert>,
195 kes_period: Option<KesPeriod>,
196 stake: Stake,
197 ) -> SignerWithStake {
198 SignerWithStake {
199 party_id,
200 verification_key,
201 verification_key_signature,
202 operational_certificate,
203 kes_period,
204 stake,
205 }
206 }
207
208 pub fn from_signer(signer: Signer, stake: Stake) -> Self {
210 Self {
211 party_id: signer.party_id,
212 verification_key: signer.verification_key,
213 verification_key_signature: signer.verification_key_signature,
214 operational_certificate: signer.operational_certificate,
215 kes_period: signer.kes_period,
216 stake,
217 }
218 }
219
220 pub fn compute_hash(&self) -> String {
222 let mut hasher = Sha256::new();
223 hasher.update(self.party_id.as_bytes());
224 hasher.update(self.verification_key.to_json_hex().unwrap().as_bytes());
225
226 if let Some(verification_key_signature) = &self.verification_key_signature {
227 hasher.update(verification_key_signature.to_json_hex().unwrap().as_bytes());
228 }
229
230 if let Some(operational_certificate) = &self.operational_certificate {
231 hasher.update(operational_certificate.to_json_hex().unwrap().as_bytes());
232 }
233 hasher.update(self.stake.to_be_bytes());
234 hex::encode(hasher.finalize())
235 }
236}
237
238impl Debug for SignerWithStake {
239 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
240 let should_be_exhaustive = f.alternate();
241 let mut debug = f.debug_struct("SignerWithStake");
242 debug.field("party_id", &self.party_id).field("stake", &self.stake);
243
244 match should_be_exhaustive {
245 true => debug
246 .field(
247 "verification_key",
248 &format_args!("{:?}", self.verification_key),
249 )
250 .field(
251 "verification_key_signature",
252 &format_args!("{:?}", self.verification_key_signature),
253 )
254 .field(
255 "operational_certificate",
256 &format_args!("{:?}", self.operational_certificate),
257 )
258 .field("kes_period", &format_args!("{:?}", self.kes_period))
259 .finish(),
260 false => debug.finish_non_exhaustive(),
261 }
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use crate::test_utils::{MithrilFixtureBuilder, fake_keys};
268
269 use super::*;
270
271 #[test]
272 fn test_stake_signers_from_into() {
273 let verification_key = MithrilFixtureBuilder::default()
274 .with_signers(1)
275 .build()
276 .signers_with_stake()[0]
277 .verification_key;
278 let signer_expected = Signer::new("1".to_string(), verification_key, None, None, None);
279 let signer_with_stake =
280 SignerWithStake::new("1".to_string(), verification_key, None, None, None, 100);
281
282 let signer_into: Signer = signer_with_stake.into();
283 assert_eq!(signer_expected, signer_into);
284 }
285
286 #[test]
287 fn test_signer_compute_hash() {
288 const HASH_EXPECTED: &str =
289 "02778791113dcd8647b019366e223bfe3aa8a054fa6d9d1918b6b669de485f1c";
290
291 assert_eq!(
292 HASH_EXPECTED,
293 Signer::new(
294 "1".to_string(),
295 fake_keys::signer_verification_key()[3].try_into().unwrap(),
296 None,
297 None,
298 None,
299 )
300 .compute_hash()
301 );
302 assert_ne!(
303 HASH_EXPECTED,
304 Signer::new(
305 "0".to_string(),
306 fake_keys::signer_verification_key()[3].try_into().unwrap(),
307 None,
308 None,
309 None
310 )
311 .compute_hash()
312 );
313 assert_ne!(
314 HASH_EXPECTED,
315 Signer::new(
316 "1".to_string(),
317 fake_keys::signer_verification_key()[0].try_into().unwrap(),
318 None,
319 None,
320 None
321 )
322 .compute_hash()
323 );
324 }
325
326 #[test]
327 fn test_signer_with_stake_compute_hash() {
328 const EXPECTED_HASH: &str =
329 "9a832baccd04aabfc419f57319e3831a1655a95bf3bf5ed96a1167d1e81b5085";
330 let signers = MithrilFixtureBuilder::default()
331 .with_signers(2)
332 .build()
333 .signers_with_stake();
334 let signer = signers[0].clone();
335
336 assert_eq!(EXPECTED_HASH, signer.compute_hash());
337
338 {
339 let mut signer_different_party_id = signer.clone();
340 signer_different_party_id.party_id = "whatever".to_string();
341
342 assert_ne!(EXPECTED_HASH, signer_different_party_id.compute_hash());
343 }
344 {
345 let mut signer_different_verification_key = signer.clone();
346 signer_different_verification_key.verification_key = signers[1].verification_key;
347
348 assert_ne!(
349 EXPECTED_HASH,
350 signer_different_verification_key.compute_hash()
351 );
352 }
353 {
354 let mut signer_different_stake = signer.clone();
355 signer_different_stake.stake += 20;
356
357 assert_ne!(EXPECTED_HASH, signer_different_stake.compute_hash());
358 }
359 }
360}