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
243 .field("party_id", &self.party_id)
244 .field("stake", &self.stake);
245
246 match should_be_exhaustive {
247 true => debug
248 .field(
249 "verification_key",
250 &format_args!("{:?}", self.verification_key),
251 )
252 .field(
253 "verification_key_signature",
254 &format_args!("{:?}", self.verification_key_signature),
255 )
256 .field(
257 "operational_certificate",
258 &format_args!("{:?}", self.operational_certificate),
259 )
260 .field("kes_period", &format_args!("{:?}", self.kes_period))
261 .finish(),
262 false => debug.finish_non_exhaustive(),
263 }
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use crate::test_utils::{fake_keys, MithrilFixtureBuilder};
270
271 use super::*;
272
273 #[test]
274 fn test_stake_signers_from_into() {
275 let verification_key = MithrilFixtureBuilder::default()
276 .with_signers(1)
277 .build()
278 .signers_with_stake()[0]
279 .verification_key;
280 let signer_expected = Signer::new("1".to_string(), verification_key, None, None, None);
281 let signer_with_stake =
282 SignerWithStake::new("1".to_string(), verification_key, None, None, None, 100);
283
284 let signer_into: Signer = signer_with_stake.into();
285 assert_eq!(signer_expected, signer_into);
286 }
287
288 #[test]
289 fn test_signer_compute_hash() {
290 const HASH_EXPECTED: &str =
291 "02778791113dcd8647b019366e223bfe3aa8a054fa6d9d1918b6b669de485f1c";
292
293 assert_eq!(
294 HASH_EXPECTED,
295 Signer::new(
296 "1".to_string(),
297 fake_keys::signer_verification_key()[3].try_into().unwrap(),
298 None,
299 None,
300 None,
301 )
302 .compute_hash()
303 );
304 assert_ne!(
305 HASH_EXPECTED,
306 Signer::new(
307 "0".to_string(),
308 fake_keys::signer_verification_key()[3].try_into().unwrap(),
309 None,
310 None,
311 None
312 )
313 .compute_hash()
314 );
315 assert_ne!(
316 HASH_EXPECTED,
317 Signer::new(
318 "1".to_string(),
319 fake_keys::signer_verification_key()[0].try_into().unwrap(),
320 None,
321 None,
322 None
323 )
324 .compute_hash()
325 );
326 }
327
328 #[test]
329 fn test_signer_with_stake_compute_hash() {
330 const EXPECTED_HASH: &str =
331 "9a832baccd04aabfc419f57319e3831a1655a95bf3bf5ed96a1167d1e81b5085";
332 let signers = MithrilFixtureBuilder::default()
333 .with_signers(2)
334 .build()
335 .signers_with_stake();
336 let signer = signers[0].clone();
337
338 assert_eq!(EXPECTED_HASH, signer.compute_hash());
339
340 {
341 let mut signer_different_party_id = signer.clone();
342 signer_different_party_id.party_id = "whatever".to_string();
343
344 assert_ne!(EXPECTED_HASH, signer_different_party_id.compute_hash());
345 }
346 {
347 let mut signer_different_verification_key = signer.clone();
348 signer_different_verification_key.verification_key = signers[1].verification_key;
349
350 assert_ne!(
351 EXPECTED_HASH,
352 signer_different_verification_key.compute_hash()
353 );
354 }
355 {
356 let mut signer_different_stake = signer.clone();
357 signer_different_stake.stake += 20;
358
359 assert_ne!(EXPECTED_HASH, signer_different_stake.compute_hash());
360 }
361 }
362}