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